Alex Xu 8 місяців тому
батько
коміт
a7b2a5774c
2 змінених файлів з 113 додано та 1 видалено
  1. 36 1
      src/controllers/tweet/index.ts
  2. 77 0
      src/services/twitterService/index.ts

+ 36 - 1
src/controllers/tweet/index.ts

@@ -4,7 +4,10 @@ import NotFoundException from '../../exceptions/NotFoundException'
 import jsonResponseMiddleware, {
   JsonResponse,
 } from '../../middleware/jsonResponse.middleware'
-import twitterService, { GenerateResult } from '../../services/twitterService'
+import twitterService, {
+  GenerateResult,
+  ShotData,
+} from '../../services/twitterService'
 import { PaginationConnection } from 'sequelize-cursor-pagination'
 import { TweetData } from '../../db/models/Tweet'
 import { MODIFY_TOKEN } from '../../constants'
@@ -15,6 +18,11 @@ interface ImportPayload {
   urls: string[]
 }
 
+interface ImportShotPayload {
+  token: string
+  shots: ShotData[]
+}
+
 interface TopPayload {
   token: string
   statusId: string
@@ -47,6 +55,12 @@ export default class TweetController implements Controller {
       jsonResponseMiddleware,
       this.import as RequestHandler
     )
+    this.router.post(
+      '/import_shot',
+      // apiKeyMiddleware(),
+      jsonResponseMiddleware,
+      this.importShot as RequestHandler
+    )
     this.router.post(
       '/top',
       // apiKeyMiddleware(),
@@ -98,6 +112,27 @@ export default class TweetController implements Controller {
       })
   }
 
+  private importShot(
+    request: Request<any, any, ImportShotPayload>,
+    response: JsonResponse<GenerateResult[]>,
+    next: NextFunction
+  ): void {
+    const { shots, token } = request.body
+    if (token !== MODIFY_TOKEN) {
+      response.status(401).jsonError('Unauthorized', 1012)
+      return
+    }
+
+    twitterService
+      .bulkImportShot(shots)
+      .then((tweets) => {
+        response.jsonSuccess(tweets)
+      })
+      .catch((e) => {
+        response.status(500).jsonError('Server Error', 1011)
+      })
+  }
+
   private top(
     request: Request<any, any, TopPayload>,
     response: JsonResponse<boolean>,

+ 77 - 0
src/services/twitterService/index.ts

@@ -195,6 +195,81 @@ async function makeTweetDisabled(
   await tweet.save()
 }
 
+export interface ShotData {
+  url: string
+  shot: string
+}
+
+async function importShot(data: ShotData): Promise<Tweet> {
+  const { shot, url: urlRaw } = data
+
+  try {
+    return await genenrateTweetByPublishAPI(urlRaw)
+  } catch (error) {
+    // if error, use shot
+  }
+
+  if (!shot?.startsWith('https://')) {
+    throw new Error('Invalid shot image URL')
+  }
+
+  const url = urlRaw.trim().split('?')[0]
+  const match = url.match(tweetUrlReg)
+  if (!match) {
+    throw new Error('Invalid tweet URL')
+  }
+
+  const statusId = match[1]
+
+  try {
+    const [tweet, created] = await Tweet.findOrCreate({
+      where: {
+        statusId,
+      },
+      defaults: {
+        statusId,
+        username: '',
+        url,
+        body: data,
+        cleanHTML: '',
+      },
+    })
+
+    if (!created) {
+      tweet.setDataValue('username', '')
+      tweet.setDataValue('url', url)
+      tweet.setDataValue('body', data)
+      tweet.setDataValue('cleanHTML', '')
+      tweet.setDataValue('disabled', false)
+      await tweet.save()
+    }
+
+    return tweet
+  } catch (error: any) {
+    if (error.response?.data?.error) {
+      throw new Error(error.response.data.error)
+    }
+    throw error
+  }
+}
+
+async function bulkImportShot(datas: ShotData[]): Promise<GenerateResult[]> {
+  const results: GenerateResult[] = []
+  for (const data of datas) {
+    try {
+      const tweet = await importShot(data)
+      results.push({ url: data.url, success: true })
+    } catch (e) {
+      results.push({
+        url: data.url,
+        success: false,
+        error: (e as Error).message ?? 'unknown error',
+      })
+    }
+  }
+  return results
+}
+
 const twitterService = {
   getTwitterClient,
   generateAuthURL,
@@ -207,6 +282,8 @@ const twitterService = {
   bulkGenerateTweetsByPublishAPI,
   makeTweetTop,
   makeTweetDisabled,
+  importShot,
+  bulkImportShot,
 }
 
 export default twitterService