|
|
@@ -1,6 +1,10 @@
|
|
|
import * as os from 'node:os';
|
|
|
|
|
|
-import type { IGrowiInfo } from '@growi/core';
|
|
|
+import type {
|
|
|
+ IGrowiInfo,
|
|
|
+ GrowiInfoOptions,
|
|
|
+ IGrowiAdditionalInfoResult,
|
|
|
+} from '@growi/core';
|
|
|
import type { IUser } from '@growi/core/dist/interfaces';
|
|
|
import { GrowiWikiType } from '@growi/core/dist/interfaces';
|
|
|
import { pathUtils } from '@growi/core/dist/utils';
|
|
|
@@ -13,7 +17,12 @@ import { aclService } from '~/server/service/acl';
|
|
|
import { configManager } from '~/server/service/config-manager';
|
|
|
import { getGrowiVersion } from '~/utils/growi-version';
|
|
|
|
|
|
-import type { IGrowiAppAdditionalInfo } from '../../../features/questionnaire/interfaces/growi-app-info';
|
|
|
+// Local preset for full additional info
|
|
|
+const FULL_ADDITIONAL_INFO_OPTIONS = {
|
|
|
+ includeAttachmentInfo: true,
|
|
|
+ includeInstalledInfo: true,
|
|
|
+ includeUserCountInfo: true,
|
|
|
+} as const;
|
|
|
|
|
|
|
|
|
export class GrowiInfoService {
|
|
|
@@ -38,15 +47,24 @@ export class GrowiInfoService {
|
|
|
/**
|
|
|
* Get GROWI information
|
|
|
*/
|
|
|
- getGrowiInfo(): Promise<IGrowiInfo<Record<string, never>>>;
|
|
|
+ getGrowiInfo(): Promise<IGrowiInfo<undefined>>;
|
|
|
|
|
|
/**
|
|
|
- * Get GROWI information with additional information
|
|
|
+ * Get GROWI information with flexible options
|
|
|
+ * @param options options to determine what additional information to include
|
|
|
+ */
|
|
|
+ getGrowiInfo<T extends GrowiInfoOptions>(options: T): Promise<IGrowiInfo<IGrowiAdditionalInfoResult<T>>>;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get GROWI information with additional information (legacy)
|
|
|
* @param includeAdditionalInfo whether to include additional information
|
|
|
+ * @deprecated Use getGrowiInfo(options) instead
|
|
|
*/
|
|
|
- getGrowiInfo(includeAdditionalInfo: true): Promise<IGrowiInfo<IGrowiAppAdditionalInfo>>;
|
|
|
+ getGrowiInfo(includeAdditionalInfo: true): Promise<IGrowiInfo<IGrowiAdditionalInfoResult<typeof FULL_ADDITIONAL_INFO_OPTIONS>>>;
|
|
|
|
|
|
- async getGrowiInfo(includeAdditionalInfo?: boolean): Promise<IGrowiInfo<Record<string, never>> | IGrowiInfo<IGrowiAppAdditionalInfo>> {
|
|
|
+ async getGrowiInfo<T extends GrowiInfoOptions>(
|
|
|
+ optionsOrLegacyFlag?: T | true,
|
|
|
+ ): Promise<IGrowiInfo<IGrowiAdditionalInfoResult<T>> | IGrowiInfo<undefined> | IGrowiInfo<IGrowiAdditionalInfoResult<typeof FULL_ADDITIONAL_INFO_OPTIONS>>> {
|
|
|
|
|
|
const appSiteUrl = this.getSiteUrl();
|
|
|
|
|
|
@@ -66,44 +84,86 @@ export class GrowiInfoService {
|
|
|
type: configManager.getConfig('app:serviceType'),
|
|
|
wikiType,
|
|
|
deploymentType: configManager.getConfig('app:deploymentType'),
|
|
|
- } satisfies IGrowiInfo<Record<string, never>>;
|
|
|
+ } satisfies IGrowiInfo<undefined>;
|
|
|
|
|
|
- if (!includeAdditionalInfo) {
|
|
|
+ if (optionsOrLegacyFlag == null) {
|
|
|
return baseInfo;
|
|
|
}
|
|
|
|
|
|
+ let options: GrowiInfoOptions;
|
|
|
+
|
|
|
+ // Handle different parameter types
|
|
|
+ if (typeof optionsOrLegacyFlag === 'boolean') {
|
|
|
+ // Legacy boolean parameter
|
|
|
+ options = optionsOrLegacyFlag ? FULL_ADDITIONAL_INFO_OPTIONS : {};
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // GrowiInfoOptions parameter
|
|
|
+ options = optionsOrLegacyFlag;
|
|
|
+ }
|
|
|
+
|
|
|
+ const additionalInfo = await this.getAdditionalInfoByOptions(options);
|
|
|
+
|
|
|
+ if (!additionalInfo) {
|
|
|
+ return baseInfo as IGrowiInfo<IGrowiAdditionalInfoResult<T>>;
|
|
|
+ }
|
|
|
+
|
|
|
return {
|
|
|
...baseInfo,
|
|
|
- additionalInfo: await this.getAdditionalInfo(),
|
|
|
- };
|
|
|
+ additionalInfo,
|
|
|
+ } as IGrowiInfo<IGrowiAdditionalInfoResult<T>>;
|
|
|
}
|
|
|
|
|
|
- private async getAdditionalInfo(): Promise<IGrowiAppAdditionalInfo> {
|
|
|
+ private async getAdditionalInfoByOptions<T extends GrowiInfoOptions>(options: T): Promise<IGrowiAdditionalInfoResult<T>> {
|
|
|
const User = mongoose.model<IUser, Model<IUser>>('User');
|
|
|
|
|
|
- // Get the oldest user who probably installed this GROWI.
|
|
|
- const user = await User.findOne({ createdAt: { $ne: null } }).sort({ createdAt: 1 });
|
|
|
- const installedAtByOldestUser = user ? user.createdAt : null;
|
|
|
+ // Check if any option is enabled to determine if we should return additional info
|
|
|
+ const hasAnyOption = options.includeAttachmentInfo || options.includeInstalledInfo || options.includeUserCountInfo;
|
|
|
|
|
|
- const appInstalledConfig = await Config.findOne({ key: 'app:installed' });
|
|
|
- const oldestConfig = await Config.findOne().sort({ createdAt: 1 });
|
|
|
- const installedAt = installedAtByOldestUser ?? appInstalledConfig?.createdAt ?? oldestConfig!.createdAt ?? null;
|
|
|
-
|
|
|
- const currentUsersCount = await User.countDocuments();
|
|
|
- const currentActiveUsersCount = await (User as any).countActiveUsers();
|
|
|
+ if (!hasAnyOption) {
|
|
|
+ return undefined as IGrowiAdditionalInfoResult<T>;
|
|
|
+ }
|
|
|
|
|
|
+ // Include attachment info (required for all additional info)
|
|
|
const activeExternalAccountTypes: IExternalAuthProviderType[] = Object.values(IExternalAuthProviderType).filter((type) => {
|
|
|
return configManager.getConfig(`security:passport-${type}:isEnabled`);
|
|
|
});
|
|
|
|
|
|
- return {
|
|
|
- installedAt,
|
|
|
- installedAtByOldestUser,
|
|
|
- currentUsersCount,
|
|
|
- currentActiveUsersCount,
|
|
|
+ // Build result incrementally with proper typing
|
|
|
+ const partialResult: Partial<{
|
|
|
+ attachmentType: unknown;
|
|
|
+ activeExternalAccountTypes: IExternalAuthProviderType[];
|
|
|
+ installedAt: Date | null;
|
|
|
+ installedAtByOldestUser: Date | null;
|
|
|
+ currentUsersCount: number;
|
|
|
+ currentActiveUsersCount: number;
|
|
|
+ }> = {
|
|
|
attachmentType: configManager.getConfig('app:fileUploadType'),
|
|
|
activeExternalAccountTypes,
|
|
|
};
|
|
|
+
|
|
|
+ if (options.includeInstalledInfo) {
|
|
|
+ // Get the oldest user who probably installed this GROWI.
|
|
|
+ const user = await User.findOne({ createdAt: { $ne: null } }).sort({ createdAt: 1 });
|
|
|
+ const installedAtByOldestUser = user ? user.createdAt : null;
|
|
|
+
|
|
|
+ const appInstalledConfig = await Config.findOne({ key: 'app:installed' });
|
|
|
+ const oldestConfig = await Config.findOne().sort({ createdAt: 1 });
|
|
|
+ const installedAt = installedAtByOldestUser ?? appInstalledConfig?.createdAt ?? oldestConfig?.createdAt ?? null;
|
|
|
+
|
|
|
+ partialResult.installedAt = installedAt;
|
|
|
+ partialResult.installedAtByOldestUser = installedAtByOldestUser;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (options.includeUserCountInfo) {
|
|
|
+ const currentUsersCount = await User.countDocuments();
|
|
|
+ const currentActiveUsersCount = await (User as unknown as { countActiveUsers: () => Promise<number> }).countActiveUsers();
|
|
|
+
|
|
|
+ partialResult.currentUsersCount = currentUsersCount;
|
|
|
+ partialResult.currentActiveUsersCount = currentActiveUsersCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ return partialResult as IGrowiAdditionalInfoResult<T>;
|
|
|
}
|
|
|
|
|
|
}
|