diff --git a/apps/app/src/features/questionnaire/interfaces/proactive-questionnaire-answer.ts b/apps/app/src/features/questionnaire/interfaces/proactive-questionnaire-answer.ts index 439cdf0f4cd..f7084ae76c7 100644 --- a/apps/app/src/features/questionnaire/interfaces/proactive-questionnaire-answer.ts +++ b/apps/app/src/features/questionnaire/interfaces/proactive-questionnaire-answer.ts @@ -1,6 +1,6 @@ import type { IGrowiInfo } from '@growi/core/dist/interfaces'; -import type { IGrowiAppAdditionalInfo } from './growi-app-info'; +import type { IGrowiAppAdditionalInfo, IGrowiAppInfoLegacy } from './growi-app-info'; import type { IUserInfo } from './user-info'; @@ -14,3 +14,14 @@ export interface IProactiveQuestionnaireAnswer { position?: string, occupation?: string, } + +export interface IProactiveQuestionnaireAnswerLegacy { + satisfaction: number, + commentText: string, + growiInfo: IGrowiAppInfoLegacy, + userInfo: IUserInfo, + answeredAt: Date, + lengthOfExperience?: string, + position?: string, + occupation?: string, +} diff --git a/apps/app/src/features/questionnaire/interfaces/questionnaire-answer.ts b/apps/app/src/features/questionnaire/interfaces/questionnaire-answer.ts index 3becab9ed62..5651b01314a 100644 --- a/apps/app/src/features/questionnaire/interfaces/questionnaire-answer.ts +++ b/apps/app/src/features/questionnaire/interfaces/questionnaire-answer.ts @@ -1,7 +1,7 @@ import type { IGrowiInfo } from '@growi/core/dist/interfaces'; import type { IAnswer } from './answer'; -import type { IGrowiAppAdditionalInfo } from './growi-app-info'; +import type { IGrowiAppAdditionalInfo, IGrowiAppInfoLegacy } from './growi-app-info'; import type { IUserInfo } from './user-info'; export interface IQuestionnaireAnswer { @@ -11,3 +11,11 @@ export interface IQuestionnaireAnswer { userInfo: IUserInfo questionnaireOrder: ID } + +export interface IQuestionnaireAnswerLegacy { + answers: IAnswer[] + answeredAt: Date + growiInfo: IGrowiAppInfoLegacy, + userInfo: IUserInfo + questionnaireOrder: ID +} 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 41b269ed396..e1491f7c329 100644 --- a/apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts +++ b/apps/app/src/features/questionnaire/server/service/questionnaire-cron.ts @@ -76,9 +76,11 @@ class QuestionnaireCronService { const resendQuestionnaireAnswers = async() => { const questionnaireAnswers = await QuestionnaireAnswer.find() - .select('-_id -answers._id -growiInfo._id -userInfo._id'); + .select('-_id -answers._id -growiInfo._id -userInfo._id') + .lean(); const proactiveQuestionnaireAnswers = await ProactiveQuestionnaireAnswer.find() - .select('-_id -growiInfo._id -userInfo._id'); + .select('-_id -growiInfo._id -userInfo._id') + .lean(); axios.post(`${questionnaireServerOrigin}/questionnaire-answer/batch`, { // convert to legacy format 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 index 02c1199a35d..1055a2ef50d 100644 --- 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 @@ -1,3 +1,5 @@ +import assert from 'assert'; + import type { IGrowiAppInfoLegacy } from '../../interfaces/growi-app-info'; @@ -6,24 +8,24 @@ type IHasGrowiAppInfoLegacy = T & { }; // eslint-disable-next-line @typescript-eslint/no-explicit-any -function hasGrowiAppInfoLegacy(data: T): data is IHasGrowiAppInfoLegacy { +function isLegacy(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, - }, - }; + if (isLegacy(questionnaireAnswer)) { + return questionnaireAnswer; } - return questionnaireAnswer; + const { additionalInfo, ...rest } = questionnaireAnswer.growiInfo; + assert(additionalInfo != null); + + return { + ...questionnaireAnswer, + growiInfo: { + ...rest, + ...additionalInfo, + }, + }; } diff --git a/apps/app/src/server/crowi/index.js b/apps/app/src/server/crowi/index.js index dc486652fbe..c0b475079fd 100644 --- a/apps/app/src/server/crowi/index.js +++ b/apps/app/src/server/crowi/index.js @@ -76,6 +76,12 @@ class Crowi { /** @type {PassportService} */ passportService; + /** @type {QuestionnaireService} */ + questionnaireService; + + /** @type {QuestionnaireCronService} */ + questionnaireCronService; + /** @type {SearchService} */ searchService; diff --git a/apps/app/test/integration/service/questionnaire-cron.test.ts b/apps/app/test/integration/service/questionnaire-cron.test.ts index 63ebbf2c0fe..2a74fdfa52a 100644 --- a/apps/app/test/integration/service/questionnaire-cron.test.ts +++ b/apps/app/test/integration/service/questionnaire-cron.test.ts @@ -1,14 +1,16 @@ +import { GrowiDeploymentType, GrowiServiceType, GrowiWikiType } from '@growi/core'; // eslint-disable-next-line no-restricted-imports import axios from 'axios'; import mongoose from 'mongoose'; -import { IProactiveQuestionnaireAnswer } from '../../../src/features/questionnaire/interfaces/proactive-questionnaire-answer'; -import { IQuestionnaireAnswer } from '../../../src/features/questionnaire/interfaces/questionnaire-answer'; +import type { IProactiveQuestionnaireAnswer, IProactiveQuestionnaireAnswerLegacy } from '../../../src/features/questionnaire/interfaces/proactive-questionnaire-answer'; +import type { IQuestionnaireAnswer, IQuestionnaireAnswerLegacy } from '../../../src/features/questionnaire/interfaces/questionnaire-answer'; import { StatusType } from '../../../src/features/questionnaire/interfaces/questionnaire-answer-status'; import ProactiveQuestionnaireAnswer from '../../../src/features/questionnaire/server/models/proactive-questionnaire-answer'; import QuestionnaireAnswer from '../../../src/features/questionnaire/server/models/questionnaire-answer'; import QuestionnaireAnswerStatus from '../../../src/features/questionnaire/server/models/questionnaire-answer-status'; import QuestionnaireOrder from '../../../src/features/questionnaire/server/models/questionnaire-order'; +import { AttachmentMethodType } from '../../../src/interfaces/attachment'; import { getInstance } from '../setup-crowi'; const spyAxiosGet = jest.spyOn( @@ -275,13 +277,42 @@ describe('QuestionnaireCronService', () => { growiInfo: { version: '1.0', appSiteUrlHashed: 'c83e8d2a1aa87b2a3f90561be372ca523bb931e2d00013c1d204879621a25b90', + type: GrowiServiceType.cloud, + wikiType: GrowiWikiType.open, + deploymentType: GrowiDeploymentType.others, + additionalInfo: { + installedAt: new Date('2000-01-01'), + installedAtByOldestUser: new Date('2020-01-01'), + currentUsersCount: 100, + currentActiveUsersCount: 50, + attachmentType: AttachmentMethodType.aws, + }, + }, + userInfo: { + userIdHash: '542bcc3bc5bc61b840017a18', + type: 'general', + userCreatedAt: new Date(), + }, + questionnaireOrder: '63a8354837e7aa378e16f0b1', + }; + + const validQuestionnaireAnswerLegacy: IQuestionnaireAnswerLegacy = { + answers: [{ + question: '63c6da88143e531d95346188', + value: '1', + }], + answeredAt: new Date(), + growiInfo: { + version: '1.0', + appSiteUrlHashed: 'c83e8d2a1aa87b2a3f90561be372ca523bb931e2d00013c1d204879621a25b90', + type: GrowiServiceType.cloud, + wikiType: GrowiWikiType.open, + deploymentType: GrowiDeploymentType.others, installedAt: new Date('2000-01-01'), installedAtByOldestUser: new Date('2020-01-01'), - type: 'cloud', currentUsersCount: 100, currentActiveUsersCount: 50, - wikiType: 'open', - attachmentType: 'aws', + attachmentType: AttachmentMethodType.aws, }, userInfo: { userIdHash: '542bcc3bc5bc61b840017a18', @@ -295,6 +326,8 @@ describe('QuestionnaireCronService', () => { validQuestionnaireAnswer, validQuestionnaireAnswer, validQuestionnaireAnswer, + validQuestionnaireAnswerLegacy, + validQuestionnaireAnswerLegacy, ]); const validProactiveQuestionnaireAnswer: IProactiveQuestionnaireAnswer = { @@ -303,13 +336,39 @@ describe('QuestionnaireCronService', () => { growiInfo: { version: '1.0', appSiteUrlHashed: 'c83e8d2a1aa87b2a3f90561be372ca523bb931e2d00013c1d204879621a25b90', + type: GrowiServiceType.cloud, + wikiType: GrowiWikiType.open, + deploymentType: GrowiDeploymentType.others, + additionalInfo: { + installedAt: new Date('2000-01-01'), + installedAtByOldestUser: new Date('2020-01-01'), + currentUsersCount: 100, + currentActiveUsersCount: 50, + attachmentType: AttachmentMethodType.aws, + }, + }, + userInfo: { + userIdHash: '542bcc3bc5bc61b840017a18', + type: 'general', + userCreatedAt: new Date(), + }, + answeredAt: new Date(), + }; + const validProactiveQuestionnaireAnswerLegacy: IProactiveQuestionnaireAnswerLegacy = { + satisfaction: 1, + commentText: 'answer text', + growiInfo: { + version: '1.0', + appSiteUrlHashed: 'c83e8d2a1aa87b2a3f90561be372ca523bb931e2d00013c1d204879621a25b90', + type: GrowiServiceType.cloud, + wikiType: GrowiWikiType.open, + deploymentType: GrowiDeploymentType.others, + // legacy properties installedAt: new Date('2000-01-01'), installedAtByOldestUser: new Date('2020-01-01'), - type: 'cloud', currentUsersCount: 100, currentActiveUsersCount: 50, - wikiType: 'open', - attachmentType: 'aws', + attachmentType: AttachmentMethodType.aws, }, userInfo: { userIdHash: '542bcc3bc5bc61b840017a18', @@ -323,6 +382,8 @@ describe('QuestionnaireCronService', () => { validProactiveQuestionnaireAnswer, validProactiveQuestionnaireAnswer, validProactiveQuestionnaireAnswer, + validProactiveQuestionnaireAnswerLegacy, + validProactiveQuestionnaireAnswerLegacy, ]); crowi.setupCron(); diff --git a/apps/app/test/integration/service/questionnaire.test.ts b/apps/app/test/integration/service/questionnaire.test.ts index 6327a889cd1..e2452003458 100644 --- a/apps/app/test/integration/service/questionnaire.test.ts +++ b/apps/app/test/integration/service/questionnaire.test.ts @@ -3,10 +3,11 @@ import mongoose from 'mongoose'; import { StatusType } from '../../../src/features/questionnaire/interfaces/questionnaire-answer-status'; import QuestionnaireAnswerStatus from '../../../src/features/questionnaire/server/models/questionnaire-answer-status'; import QuestionnaireOrder from '../../../src/features/questionnaire/server/models/questionnaire-order'; +import type Crowi from '../../../src/server/crowi'; import { getInstance } from '../setup-crowi'; describe('QuestionnaireService', () => { - let crowi; + let crowi: Crowi; let user; beforeAll(async() => { @@ -55,15 +56,19 @@ describe('QuestionnaireService', () => { delete growiInfo.osInfo; expect(growiInfo).toEqual({ - activeExternalAccountTypes: ['saml', 'github'], + version: crowi.version, appSiteUrl: 'http://growi.test.jp', - installedAt: new Date('2000-01-01'), - installedAtByOldestUser: new Date('2000-01-01'), - attachmentType: 'aws', - deploymentType: 'growi-docker-compose', type: 'on-premise', - version: crowi.version, wikiType: 'closed', + deploymentType: 'growi-docker-compose', + additionalInfo: { + installedAt: new Date('2000-01-01'), + installedAtByOldestUser: new Date('2000-01-01'), + currentUsersCount: 7, + currentActiveUsersCount: 1, + attachmentType: 'aws', + activeExternalAccountTypes: ['saml', 'github'], + }, }); }); @@ -75,7 +80,7 @@ describe('QuestionnaireService', () => { test('Should return app url string', async() => { const growiInfo = await crowi.questionnaireService.getGrowiInfo(); - expect(growiInfo.appSiteUrl).toBe(null); + expect(growiInfo.appSiteUrl).toBeUndefined(); expect(growiInfo.appSiteUrlHashed).not.toBe('http://growi.test.jp'); expect(growiInfo.appSiteUrlHashed).toBeTruthy(); }); diff --git a/packages/core/src/interfaces/growi-app-info.ts b/packages/core/src/interfaces/growi-app-info.ts index b04505737ea..b7708ae9a38 100644 --- a/packages/core/src/interfaces/growi-app-info.ts +++ b/packages/core/src/interfaces/growi-app-info.ts @@ -21,7 +21,7 @@ export interface IGrowiAdditionalInfo { export interface IGrowiInfo { version: string - appSiteUrl: string | undefined + appSiteUrl?: string appSiteUrlHashed: string type: GrowiServiceType wikiType: GrowiWikiType