diff --git a/apps/app/src/features/questionnaire/server/routes/apiv3/questionnaire.ts b/apps/app/src/features/questionnaire/server/routes/apiv3/questionnaire.ts index a2772628ac6..5a695b711a0 100644 --- a/apps/app/src/features/questionnaire/server/routes/apiv3/questionnaire.ts +++ b/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) { diff --git a/apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts b/apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts index 99a6a9356a1..41b269ed396 100644 --- a/apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts +++ b/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(); }); diff --git a/apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.spec.ts b/apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.spec.ts new file mode 100644 index 00000000000..c7b3d2abb56 --- /dev/null +++ b/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 = { + 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); + }); +}); diff --git a/apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.ts b/apps/app/src/features/questionnaire/server/util/convert-to-legacy-format.ts new file mode 100644 index 00000000000..02c1199a35d --- /dev/null +++ b/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 & { + growiInfo: IGrowiAppInfoLegacy; +}; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function hasGrowiAppInfoLegacy(data: T): data is IHasGrowiAppInfoLegacy { + return !('additionalInfo' in data.growiInfo); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function convertToLegacyFormat(questionnaireAnswer: T): IHasGrowiAppInfoLegacy { + if (!hasGrowiAppInfoLegacy(questionnaireAnswer)) { + const { additionalInfo, ...rest } = questionnaireAnswer.growiInfo; + assert(additionalInfo != null); + + return { + ...questionnaireAnswer, + growiInfo: { + ...rest, + ...additionalInfo, + }, + }; + } + + return questionnaireAnswer; +}