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

convert questionnaire answers to legacy format and add tests for conversion utility

Yuki Takei 1 год назад
Родитель
Сommit
914739813d

+ 8 - 3
apps/app/src/features/questionnaire/server/routes/apiv3/questionnaire.ts

@@ -17,6 +17,7 @@ import { StatusType } from '../../../interfaces/questionnaire-answer-status';
 import ProactiveQuestionnaireAnswer from '../../models/proactive-questionnaire-answer';
 import QuestionnaireAnswer from '../../models/questionnaire-answer';
 import QuestionnaireAnswerStatus from '../../models/questionnaire-answer-status';
+import { convertToLegacyFormat } from '../../util/convert-to-legacy-format';
 
 
 const logger = loggerFactory('growi:routes:apiv3:questionnaire');
@@ -81,7 +82,7 @@ module.exports = (crowi: Crowi): Router => {
 
   router.post('/proactive/answer', accessTokenParser, loginRequired, validators.proactiveAnswer, async(req: AuthorizedRequest, res: ApiV3Response) => {
     const sendQuestionnaireAnswer = async() => {
-      const questionnaireServerOrigin = crowi.configManager.getConfig('app:questionnaireServerOrigin');
+      const questionnaireServerOrigin = configManager.getConfig('app:questionnaireServerOrigin');
       const growiInfo = await crowi.questionnaireService!.getGrowiInfo();
       const userInfo = crowi.questionnaireService!.getUserInfo(req.user ?? null, growiInfo.appSiteUrlHashed);
 
@@ -96,8 +97,10 @@ module.exports = (crowi: Crowi): Router => {
         answeredAt: new Date(),
       };
 
+      const proactiveQuestionnaireAnswerLegacy = convertToLegacyFormat(proactiveQuestionnaireAnswer);
+
       try {
-        await axios.post(`${questionnaireServerOrigin}/questionnaire-answer/proactive`, proactiveQuestionnaireAnswer);
+        await axios.post(`${questionnaireServerOrigin}/questionnaire-answer/proactive`, proactiveQuestionnaireAnswerLegacy);
       }
       catch (err) {
         if (err.request != null) {
@@ -139,8 +142,10 @@ module.exports = (crowi: Crowi): Router => {
         questionnaireOrder: req.body.questionnaireOrderId,
       };
 
+      const questionnaireAnswerLegacy = convertToLegacyFormat(questionnaireAnswer);
+
       try {
-        await axios.post(`${questionnaireServerOrigin}/questionnaire-answer`, questionnaireAnswer);
+        await axios.post(`${questionnaireServerOrigin}/questionnaire-answer`, questionnaireAnswerLegacy);
       }
       catch (err) {
         if (err.request != null) {

+ 10 - 3
apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts

@@ -4,11 +4,12 @@ import loggerFactory from '~/utils/logger';
 import { getRandomIntInRange } from '~/utils/rand';
 
 import { StatusType } from '../../interfaces/questionnaire-answer-status';
-import { IQuestionnaireOrder } from '../../interfaces/questionnaire-order';
+import type { IQuestionnaireOrder } from '../../interfaces/questionnaire-order';
 import ProactiveQuestionnaireAnswer from '../models/proactive-questionnaire-answer';
 import QuestionnaireAnswer from '../models/questionnaire-answer';
 import QuestionnaireAnswerStatus from '../models/questionnaire-answer-status';
 import QuestionnaireOrder from '../models/questionnaire-order';
+import { convertToLegacyFormat } from '../util/convert-to-legacy-format';
 
 const logger = loggerFactory('growi:service:questionnaire-cron');
 
@@ -79,11 +80,17 @@ class QuestionnaireCronService {
       const proactiveQuestionnaireAnswers = await ProactiveQuestionnaireAnswer.find()
         .select('-_id -growiInfo._id -userInfo._id');
 
-      axios.post(`${questionnaireServerOrigin}/questionnaire-answer/batch`, { questionnaireAnswers })
+      axios.post(`${questionnaireServerOrigin}/questionnaire-answer/batch`, {
+        // convert to legacy format
+        questionnaireAnswers: questionnaireAnswers.map(answer => convertToLegacyFormat(answer)),
+      })
         .then(async() => {
           await QuestionnaireAnswer.deleteMany();
         });
-      axios.post(`${questionnaireServerOrigin}/questionnaire-answer/proactive/batch`, { proactiveQuestionnaireAnswers })
+      axios.post(`${questionnaireServerOrigin}/questionnaire-answer/proactive/batch`, {
+        // convert to legacy format
+        proactiveQuestionnaireAnswers: proactiveQuestionnaireAnswers.map(answer => convertToLegacyFormat(answer)),
+      })
         .then(async() => {
           await ProactiveQuestionnaireAnswer.deleteMany();
         });

+ 83 - 0
apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.spec.ts

@@ -0,0 +1,83 @@
+import { GrowiDeploymentType, GrowiServiceType } from '@growi/core/dist/consts';
+import type { IGrowiInfo } from '@growi/core/dist/interfaces';
+import { GrowiWikiType } from '@growi/core/dist/interfaces';
+import { describe, test, expect } from 'vitest';
+
+import { AttachmentMethodType } from '../../../../interfaces/attachment';
+import type { IGrowiAppAdditionalInfo, IGrowiAppInfoLegacy } from '../../interfaces/growi-app-info';
+
+import { convertToLegacyFormat } from './convert-to-legacy-format';
+
+describe('convertToLegacyFormat', () => {
+  test('should return same object when input is already in legacy format', () => {
+    const growiInfoLegacy: IGrowiAppInfoLegacy = {
+      version: '1.0.0',
+      appSiteUrl: 'https://example.com',
+      appSiteUrlHashed: 'hashedUrl',
+      type: GrowiServiceType.cloud,
+      wikiType: GrowiWikiType.open,
+      deploymentType: GrowiDeploymentType.others,
+
+      // legacy properties
+      installedAt: new Date(),
+      installedAtByOldestUser: new Date(),
+      currentUsersCount: 1,
+      currentActiveUsersCount: 1,
+      attachmentType: AttachmentMethodType.local,
+    };
+
+    const legacyData = {
+      someData: 'test',
+      growiInfo: growiInfoLegacy,
+    };
+
+    const result = convertToLegacyFormat(legacyData);
+    expect(result).toStrictEqual(legacyData);
+  });
+
+  test('should convert new format to legacy format', () => {
+    const growiInfo: IGrowiInfo<IGrowiAppAdditionalInfo> = {
+      version: '1.0.0',
+      appSiteUrl: 'https://example.com',
+      appSiteUrlHashed: 'hashedUrl',
+      type: GrowiServiceType.cloud,
+      wikiType: GrowiWikiType.open,
+      deploymentType: GrowiDeploymentType.others,
+
+      additionalInfo: {
+        installedAt: new Date(),
+        installedAtByOldestUser: new Date(),
+        currentUsersCount: 1,
+        currentActiveUsersCount: 1,
+        attachmentType: AttachmentMethodType.local,
+      },
+    };
+    const newFormatData = {
+      someData: 'test',
+      growiInfo,
+    };
+
+    const growiInfoLegacy: IGrowiAppInfoLegacy = {
+      version: '1.0.0',
+      appSiteUrl: 'https://example.com',
+      appSiteUrlHashed: 'hashedUrl',
+      type: GrowiServiceType.cloud,
+      wikiType: GrowiWikiType.open,
+      deploymentType: GrowiDeploymentType.others,
+
+      // legacy properties
+      installedAt: new Date(),
+      installedAtByOldestUser: new Date(),
+      currentUsersCount: 1,
+      currentActiveUsersCount: 1,
+      attachmentType: AttachmentMethodType.local,
+    };
+    const expected = {
+      someData: 'test',
+      growiInfo: growiInfoLegacy,
+    };
+
+    const result = convertToLegacyFormat(newFormatData);
+    expect(result).toStrictEqual(expected);
+  });
+});

+ 29 - 0
apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.ts

@@ -0,0 +1,29 @@
+import type { IGrowiAppInfoLegacy } from '../../interfaces/growi-app-info';
+
+
+type IHasGrowiAppInfoLegacy<T> = T & {
+  growiInfo: IGrowiAppInfoLegacy;
+};
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function hasGrowiAppInfoLegacy<T extends { growiInfo: any }>(data: T): data is IHasGrowiAppInfoLegacy<T> {
+  return !('additionalInfo' in data.growiInfo);
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function convertToLegacyFormat<T extends { growiInfo: any }>(questionnaireAnswer: T): IHasGrowiAppInfoLegacy<T> {
+  if (!hasGrowiAppInfoLegacy(questionnaireAnswer)) {
+    const { additionalInfo, ...rest } = questionnaireAnswer.growiInfo;
+    assert(additionalInfo != null);
+
+    return {
+      ...questionnaireAnswer,
+      growiInfo: {
+        ...rest,
+        ...additionalInfo,
+      },
+    };
+  }
+
+  return questionnaireAnswer;
+}