Просмотр исходного кода

Merge pull request #10096 from weseek/feat/167664-implement-api-to-return-threads-created-by-user-in-creation-order

feat: Implement API to return recent threads
Yuki Takei 9 месяцев назад
Родитель
Сommit
3d7974457b

+ 8 - 2
apps/app/src/features/openai/server/models/thread-relation.ts

@@ -1,10 +1,12 @@
 import { addDays } from 'date-fns';
-import { type Model, type Document, Schema } from 'mongoose';
+import { type Document, Schema, type PaginateModel } from 'mongoose';
+import mongoosePaginate from 'mongoose-paginate-v2';
 
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 
 import { type IThreadRelation, ThreadType } from '../../interfaces/thread-relation';
 
+
 const DAYS_UNTIL_EXPIRATION = 3;
 
 const generateExpirationDate = (): Date => {
@@ -15,7 +17,7 @@ export interface ThreadRelationDocument extends IThreadRelation, Document {
   updateThreadExpiration(): Promise<void>;
 }
 
-interface ThreadRelationModel extends Model<ThreadRelationDocument> {
+interface ThreadRelationModel extends PaginateModel<ThreadRelationDocument> {
   getExpiredThreadRelations(limit?: number): Promise<ThreadRelationDocument[] | undefined>;
 }
 
@@ -47,8 +49,12 @@ const schema = new Schema<ThreadRelationDocument, ThreadRelationModel>({
     default: generateExpirationDate,
     required: true,
   },
+}, {
+  timestamps: { createdAt: false, updatedAt: true },
 });
 
+schema.plugin(mongoosePaginate);
+
 schema.statics.getExpiredThreadRelations = async function(limit?: number): Promise<ThreadRelationDocument[] | undefined> {
   const currentDate = new Date();
   const expiredThreadRelations = await this.find({ expiredAt: { $lte: currentDate } }).limit(limit ?? 100).exec();

+ 67 - 0
apps/app/src/features/openai/server/routes/get-recent-threads.ts

@@ -0,0 +1,67 @@
+import { type IUserHasId } from '@growi/core';
+import { ErrorV3 } from '@growi/core/dist/models';
+import type { Request, RequestHandler } from 'express';
+import { type ValidationChain, query } from 'express-validator';
+import type { PaginateResult } from 'mongoose';
+
+import type Crowi from '~/server/crowi';
+import { accessTokenParser } from '~/server/middlewares/access-token-parser';
+import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
+import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
+import loggerFactory from '~/utils/logger';
+
+import type { ThreadRelationDocument } from '../models/thread-relation';
+import ThreadRelationModel from '../models/thread-relation';
+import { getOpenaiService } from '../services/openai';
+
+import { certifyAiService } from './middlewares/certify-ai-service';
+
+const logger = loggerFactory('growi:routes:apiv3:openai:get-recent-threads');
+
+type GetRecentThreadsFactory = (crowi: Crowi) => RequestHandler[];
+
+type ReqQuery = {
+  page?: number,
+  limit?: number,
+}
+
+type Req = Request<undefined, Response, undefined, ReqQuery> & {
+  user: IUserHasId,
+}
+
+export const getRecentThreadsFactory: GetRecentThreadsFactory = (crowi) => {
+  const loginRequiredStrictly = require('~/server/middlewares/login-required')(crowi);
+
+  const validator: ValidationChain[] = [
+    query('page').optional().isInt().withMessage('page must be a positive integer'),
+    query('page').toInt(),
+    query('limit').optional().isInt({ min: 1, max: 10 }).withMessage('limit must be an integer between 1 and 10'),
+    query('limit').toInt(),
+  ];
+
+  return [
+    accessTokenParser, loginRequiredStrictly, certifyAiService, validator, apiV3FormValidator,
+    async(req: Req, res: ApiV3Response) => {
+      const openaiService = getOpenaiService();
+      if (openaiService == null) {
+        return res.apiv3Err(new ErrorV3('GROWI AI is not enabled'), 501);
+      }
+
+      try {
+        const paginateResult: PaginateResult<ThreadRelationDocument> = await ThreadRelationModel.paginate(
+          { userId: req.user._id },
+          {
+            page: req.query.page ?? 1,
+            limit: req.query.limit ?? 10,
+            sort: { updatedAt: -1 },
+          },
+        );
+        return res.apiv3({ paginateResult });
+      }
+      catch (err) {
+        logger.error(err);
+        return res.apiv3Err(new ErrorV3('Failed to get recent threads'));
+      }
+    },
+  ];
+};

+ 4 - 0
apps/app/src/features/openai/server/routes/index.ts

@@ -23,6 +23,10 @@ export const factory = (crowi: Crowi): express.Router => {
       router.post('/thread', createThreadHandlersFactory(crowi));
     });
 
+    import('./get-recent-threads').then(({ getRecentThreadsFactory }) => {
+      router.get('/threads/recent', getRecentThreadsFactory(crowi));
+    });
+
     import('./get-threads').then(({ getThreadsFactory }) => {
       router.get('/threads/:aiAssistantId', getThreadsFactory(crowi));
     });