Yuki Takei 2 lat temu
rodzic
commit
1641717310

+ 6 - 6
apps/app/src/features/growi-plugin/interfaces/growi-plugin.ts

@@ -8,29 +8,29 @@ export const GrowiPluginResourceType = {
 } as const;
 } as const;
 export type GrowiPluginResourceType = typeof GrowiPluginResourceType[keyof typeof GrowiPluginResourceType];
 export type GrowiPluginResourceType = typeof GrowiPluginResourceType[keyof typeof GrowiPluginResourceType];
 
 
-export type GrowiPluginOrigin = {
+export type IGrowiPluginOrigin = {
   url: string,
   url: string,
   ghBranch?: string,
   ghBranch?: string,
   ghTag?: string,
   ghTag?: string,
 }
 }
 
 
-export type GrowiPlugin<M extends GrowiPluginMeta = GrowiPluginMeta> = {
+export type IGrowiPlugin<M extends IGrowiPluginMeta = IGrowiPluginMeta> = {
   isEnabled: boolean,
   isEnabled: boolean,
   installedPath: string,
   installedPath: string,
   organizationName: string,
   organizationName: string,
-  origin: GrowiPluginOrigin,
+  origin: IGrowiPluginOrigin,
   meta: M,
   meta: M,
 }
 }
 
 
-export type GrowiPluginMeta = {
+export type IGrowiPluginMeta = {
   name: string,
   name: string,
   types: GrowiPluginResourceType[],
   types: GrowiPluginResourceType[],
   desc?: string,
   desc?: string,
   author?: string,
   author?: string,
 }
 }
 
 
-export type GrowiThemePluginMeta = GrowiPluginMeta & {
+export type IGrowiThemePluginMeta = IGrowiPluginMeta & {
   themes: GrowiThemeMetadata[]
   themes: GrowiThemeMetadata[]
 }
 }
 
 
-export type GrowiPluginHasId = GrowiPlugin & HasObjectId;
+export type IGrowiPluginHasId = IGrowiPlugin & HasObjectId;

+ 12 - 12
apps/app/src/features/growi-plugin/models/growi-plugin.ts

@@ -1,20 +1,20 @@
 import { GrowiThemeMetadata, GrowiThemeSchemeType } from '@growi/core';
 import { GrowiThemeMetadata, GrowiThemeSchemeType } from '@growi/core';
 import {
 import {
-  Schema, Model, Document, Types,
+  Schema, type Model, type Document, type Types,
 } from 'mongoose';
 } from 'mongoose';
 
 
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 
 
 import { GrowiPluginResourceType } from '../interfaces';
 import { GrowiPluginResourceType } from '../interfaces';
 import type {
 import type {
-  GrowiPlugin, GrowiPluginMeta, GrowiPluginOrigin, GrowiThemePluginMeta,
+  IGrowiPlugin, IGrowiPluginMeta, IGrowiPluginOrigin, IGrowiThemePluginMeta,
 } from '../interfaces';
 } from '../interfaces';
 
 
-export interface GrowiPluginDocument extends GrowiPlugin, Document {
+export interface IGrowiPluginDocument extends IGrowiPlugin, Document {
 }
 }
-export interface GrowiPluginModel extends Model<GrowiPluginDocument> {
-  findEnabledPlugins(): Promise<GrowiPlugin[]>
-  findEnabledPluginsIncludingAnyTypes(includingTypes: GrowiPluginResourceType[]): Promise<GrowiPlugin[]>
+export interface IGrowiPluginModel extends Model<IGrowiPluginDocument> {
+  findEnabledPlugins(): Promise<IGrowiPlugin[]>
+  findEnabledPluginsIncludingAnyTypes(includingTypes: GrowiPluginResourceType[]): Promise<IGrowiPlugin[]>
   activatePlugin(id: Types.ObjectId): Promise<string>
   activatePlugin(id: Types.ObjectId): Promise<string>
   deactivatePlugin(id: Types.ObjectId): Promise<string>
   deactivatePlugin(id: Types.ObjectId): Promise<string>
 }
 }
@@ -33,7 +33,7 @@ const growiThemeMetadataSchema = new Schema<GrowiThemeMetadata>({
   accent: { type: String, required: true },
   accent: { type: String, required: true },
 });
 });
 
 
-const growiPluginMetaSchema = new Schema<GrowiPluginMeta|GrowiThemePluginMeta>({
+const growiPluginMetaSchema = new Schema<IGrowiPluginMeta|IGrowiThemePluginMeta>({
   name: { type: String, required: true },
   name: { type: String, required: true },
   types: {
   types: {
     type: [String],
     type: [String],
@@ -45,13 +45,13 @@ const growiPluginMetaSchema = new Schema<GrowiPluginMeta|GrowiThemePluginMeta>({
   themes: [growiThemeMetadataSchema],
   themes: [growiThemeMetadataSchema],
 });
 });
 
 
-const growiPluginOriginSchema = new Schema<GrowiPluginOrigin>({
+const growiPluginOriginSchema = new Schema<IGrowiPluginOrigin>({
   url: { type: String },
   url: { type: String },
   ghBranch: { type: String },
   ghBranch: { type: String },
   ghTag: { type: String },
   ghTag: { type: String },
 });
 });
 
 
-const growiPluginSchema = new Schema<GrowiPluginDocument, GrowiPluginModel>({
+const growiPluginSchema = new Schema<IGrowiPluginDocument, IGrowiPluginModel>({
   isEnabled: { type: Boolean },
   isEnabled: { type: Boolean },
   installedPath: { type: String },
   installedPath: { type: String },
   organizationName: { type: String },
   organizationName: { type: String },
@@ -59,11 +59,11 @@ const growiPluginSchema = new Schema<GrowiPluginDocument, GrowiPluginModel>({
   meta: growiPluginMetaSchema,
   meta: growiPluginMetaSchema,
 });
 });
 
 
-growiPluginSchema.statics.findEnabledPlugins = async function(): Promise<GrowiPlugin[]> {
+growiPluginSchema.statics.findEnabledPlugins = async function(): Promise<IGrowiPlugin[]> {
   return this.find({ isEnabled: true });
   return this.find({ isEnabled: true });
 };
 };
 
 
-growiPluginSchema.statics.findEnabledPluginsIncludingAnyTypes = async function(types: GrowiPluginResourceType[]): Promise<GrowiPlugin[]> {
+growiPluginSchema.statics.findEnabledPluginsIncludingAnyTypes = async function(types: GrowiPluginResourceType[]): Promise<IGrowiPlugin[]> {
   return this.find({
   return this.find({
     isEnabled: true,
     isEnabled: true,
     'meta.types': { $in: types },
     'meta.types': { $in: types },
@@ -90,4 +90,4 @@ growiPluginSchema.statics.deactivatePlugin = async function(id: Types.ObjectId):
   return pluginName;
   return pluginName;
 };
 };
 
 
-export default getOrCreateModel<GrowiPluginDocument, GrowiPluginModel>('GrowiPlugin', growiPluginSchema);
+export const GrowiPlugin = getOrCreateModel<IGrowiPluginDocument, IGrowiPluginModel>('GrowiPlugin', growiPluginSchema);

+ 4 - 7
apps/app/src/features/growi-plugin/routes/growi-plugins.ts

@@ -5,7 +5,7 @@ import mongoose from 'mongoose';
 import Crowi from '~/server/crowi';
 import Crowi from '~/server/crowi';
 import { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 
 
-import type { GrowiPluginModel } from '../models/growi-plugin';
+import { GrowiPlugin } from '../models';
 import { growiPluginService } from '../services';
 import { growiPluginService } from '../services';
 
 
 
 
@@ -31,8 +31,7 @@ module.exports = (crowi: Crowi): Router => {
 
 
   router.get('/', loginRequiredStrictly, adminRequired, async(req: Request, res: ApiV3Response) => {
   router.get('/', loginRequiredStrictly, adminRequired, async(req: Request, res: ApiV3Response) => {
     try {
     try {
-      const GrowiPluginModel = mongoose.model('GrowiPlugin') as GrowiPluginModel;
-      const data = await GrowiPluginModel.find({});
+      const data = await GrowiPlugin.find({});
       return res.apiv3({ plugins: data });
       return res.apiv3({ plugins: data });
     }
     }
     catch (err) {
     catch (err) {
@@ -57,8 +56,7 @@ module.exports = (crowi: Crowi): Router => {
     const pluginId = new ObjectID(id);
     const pluginId = new ObjectID(id);
 
 
     try {
     try {
-      const GrowiPluginModel = mongoose.model('GrowiPlugin') as GrowiPluginModel;
-      const pluginName = await GrowiPluginModel.activatePlugin(pluginId);
+      const pluginName = await GrowiPlugin.activatePlugin(pluginId);
       return res.apiv3({ pluginName });
       return res.apiv3({ pluginName });
     }
     }
     catch (err) {
     catch (err) {
@@ -71,8 +69,7 @@ module.exports = (crowi: Crowi): Router => {
     const pluginId = new ObjectID(id);
     const pluginId = new ObjectID(id);
 
 
     try {
     try {
-      const GrowiPluginModel = mongoose.model('GrowiPlugin') as GrowiPluginModel;
-      const pluginName = await GrowiPluginModel.deactivatePlugin(pluginId);
+      const pluginName = await GrowiPlugin.deactivatePlugin(pluginId);
       return res.apiv3({ pluginName });
       return res.apiv3({ pluginName });
     }
     }
     catch (err) {
     catch (err) {

+ 13 - 21
apps/app/src/features/growi-plugin/services/growi-plugin.ts

@@ -13,9 +13,9 @@ import { resolveFromRoot } from '~/utils/project-dir-utils';
 
 
 import { GrowiPluginResourceType } from '../interfaces';
 import { GrowiPluginResourceType } from '../interfaces';
 import type {
 import type {
-  GrowiPlugin, GrowiPluginOrigin, GrowiThemePluginMeta, GrowiPluginMeta,
+  IGrowiPlugin, IGrowiPluginOrigin, IGrowiThemePluginMeta, IGrowiPluginMeta,
 } from '../interfaces';
 } from '../interfaces';
-import type { GrowiPluginModel } from '../models';
+import { GrowiPlugin } from '../models';
 
 
 const logger = loggerFactory('growi:plugins:plugin-utils');
 const logger = loggerFactory('growi:plugins:plugin-utils');
 
 
@@ -28,7 +28,7 @@ const PLUGINS_STATIC_DIR = '/static/plugins'; // configured by express.static
 
 
 export type GrowiPluginResourceEntries = [installedPath: string, href: string][];
 export type GrowiPluginResourceEntries = [installedPath: string, href: string][];
 
 
-function retrievePluginManifest(growiPlugin: GrowiPlugin): ViteManifest {
+function retrievePluginManifest(growiPlugin: IGrowiPlugin): ViteManifest {
   const manifestPath = resolveFromRoot(path.join('tmp/plugins', growiPlugin.installedPath, 'dist/manifest.json'));
   const manifestPath = resolveFromRoot(path.join('tmp/plugins', growiPlugin.installedPath, 'dist/manifest.json'));
   const manifestStr: string = readFileSync(manifestPath, 'utf-8');
   const manifestStr: string = readFileSync(manifestPath, 'utf-8');
   return JSON.parse(manifestStr);
   return JSON.parse(manifestStr);
@@ -36,13 +36,13 @@ function retrievePluginManifest(growiPlugin: GrowiPlugin): ViteManifest {
 
 
 
 
 type FindThemePluginResult = {
 type FindThemePluginResult = {
-  growiPlugin: GrowiPlugin,
+  growiPlugin: IGrowiPlugin,
   themeMetadata: GrowiThemeMetadata,
   themeMetadata: GrowiThemeMetadata,
   themeHref: string,
   themeHref: string,
 }
 }
 
 
 export interface IGrowiPluginService {
 export interface IGrowiPluginService {
-  install(origin: GrowiPluginOrigin): Promise<string>
+  install(origin: IGrowiPluginOrigin): Promise<string>
   findThemePlugin(theme: string): Promise<FindThemePluginResult | null>
   findThemePlugin(theme: string): Promise<FindThemePluginResult | null>
   retrieveAllPluginResourceEntries(): Promise<GrowiPluginResourceEntries>
   retrieveAllPluginResourceEntries(): Promise<GrowiPluginResourceEntries>
   downloadNotExistPluginRepositories(): Promise<void>
   downloadNotExistPluginRepositories(): Promise<void>
@@ -56,7 +56,6 @@ export class GrowiPluginService implements IGrowiPluginService {
   async downloadNotExistPluginRepositories(): Promise<void> {
   async downloadNotExistPluginRepositories(): Promise<void> {
     try {
     try {
       // find all growi plugin documents
       // find all growi plugin documents
-      const GrowiPlugin = mongoose.model<GrowiPlugin>('GrowiPlugin');
       const growiPlugins = await GrowiPlugin.find({});
       const growiPlugins = await GrowiPlugin.find({});
 
 
       // if not exists repository in file system, download latest plugin repository
       // if not exists repository in file system, download latest plugin repository
@@ -114,7 +113,7 @@ export class GrowiPluginService implements IGrowiPluginService {
   /*
   /*
   * Install a plugin from URL and save it in the DB and file system.
   * Install a plugin from URL and save it in the DB and file system.
   */
   */
-  async install(origin: GrowiPluginOrigin): Promise<string> {
+  async install(origin: IGrowiPluginOrigin): Promise<string> {
     const ghUrl = new URL(origin.url);
     const ghUrl = new URL(origin.url);
     const ghPathname = ghUrl.pathname;
     const ghPathname = ghUrl.pathname;
     // TODO: Branch names can be specified.
     // TODO: Branch names can be specified.
@@ -138,7 +137,7 @@ export class GrowiPluginService implements IGrowiPluginService {
     const organizationPath = path.join(pluginStoringPath, ghOrganizationName);
     const organizationPath = path.join(pluginStoringPath, ghOrganizationName);
 
 
 
 
-    let plugins: GrowiPlugin<GrowiPluginMeta>[];
+    let plugins: IGrowiPlugin<IGrowiPluginMeta>[];
 
 
     try {
     try {
       // download github repository to file system's temporary path
       // download github repository to file system's temporary path
@@ -185,7 +184,6 @@ export class GrowiPluginService implements IGrowiPluginService {
   }
   }
 
 
   private async deleteOldPluginDocument(path: string): Promise<void> {
   private async deleteOldPluginDocument(path: string): Promise<void> {
-    const GrowiPlugin = mongoose.model<GrowiPlugin>('GrowiPlugin');
     await GrowiPlugin.deleteMany({ installedPath: path });
     await GrowiPlugin.deleteMany({ installedPath: path });
   }
   }
 
 
@@ -231,13 +229,12 @@ export class GrowiPluginService implements IGrowiPluginService {
     }
     }
   }
   }
 
 
-  private async savePluginMetaData(plugins: GrowiPlugin[]): Promise<void> {
-    const GrowiPlugin = mongoose.model('GrowiPlugin');
+  private async savePluginMetaData(plugins: IGrowiPlugin[]): Promise<void> {
     await GrowiPlugin.insertMany(plugins);
     await GrowiPlugin.insertMany(plugins);
   }
   }
 
 
   // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, max-len
   // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, max-len
-  private static async detectPlugins(origin: GrowiPluginOrigin, ghOrganizationName: string, ghReposName: string, parentPackageJson?: any): Promise<GrowiPlugin[]> {
+  private static async detectPlugins(origin: IGrowiPluginOrigin, ghOrganizationName: string, ghReposName: string, parentPackageJson?: any): Promise<IGrowiPlugin[]> {
     const packageJsonPath = path.resolve(pluginStoringPath, ghReposName, 'package.json');
     const packageJsonPath = path.resolve(pluginStoringPath, ghReposName, 'package.json');
     const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
     const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
 
 
@@ -280,7 +277,7 @@ export class GrowiPluginService implements IGrowiPluginService {
 
 
     // add theme metadata
     // add theme metadata
     if (growiPlugin.types.includes(GrowiPluginResourceType.Theme)) {
     if (growiPlugin.types.includes(GrowiPluginResourceType.Theme)) {
-      (plugin as GrowiPlugin<GrowiThemePluginMeta>).meta = {
+      (plugin as IGrowiPlugin<IGrowiThemePluginMeta>).meta = {
         ...plugin.meta,
         ...plugin.meta,
         themes: growiPlugin.themes,
         themes: growiPlugin.themes,
       };
       };
@@ -291,7 +288,7 @@ export class GrowiPluginService implements IGrowiPluginService {
     return [plugin];
     return [plugin];
   }
   }
 
 
-  async listPlugins(): Promise<GrowiPlugin[]> {
+  async listPlugins(): Promise<IGrowiPlugin[]> {
     return [];
     return [];
   }
   }
 
 
@@ -303,7 +300,6 @@ export class GrowiPluginService implements IGrowiPluginService {
       return fs.promises.rm(path, { recursive: true });
       return fs.promises.rm(path, { recursive: true });
     };
     };
 
 
-    const GrowiPlugin = mongoose.model<GrowiPlugin>('GrowiPlugin');
     const growiPlugins = await GrowiPlugin.findById(pluginId);
     const growiPlugins = await GrowiPlugin.findById(pluginId);
 
 
     if (growiPlugins == null) {
     if (growiPlugins == null) {
@@ -331,14 +327,12 @@ export class GrowiPluginService implements IGrowiPluginService {
   }
   }
 
 
   async findThemePlugin(theme: string): Promise<FindThemePluginResult | null> {
   async findThemePlugin(theme: string): Promise<FindThemePluginResult | null> {
-    const GrowiPlugin = mongoose.model('GrowiPlugin') as GrowiPluginModel;
-
-    let matchedPlugin: GrowiPlugin | undefined;
+    let matchedPlugin: IGrowiPlugin | undefined;
     let matchedThemeMetadata: GrowiThemeMetadata | undefined;
     let matchedThemeMetadata: GrowiThemeMetadata | undefined;
 
 
     try {
     try {
       // retrieve plugin manifests
       // retrieve plugin manifests
-      const growiPlugins = await GrowiPlugin.findEnabledPluginsIncludingAnyTypes([GrowiPluginResourceType.Theme]) as GrowiPlugin<GrowiThemePluginMeta>[];
+      const growiPlugins = await GrowiPlugin.findEnabledPluginsIncludingAnyTypes([GrowiPluginResourceType.Theme]) as IGrowiPlugin<IGrowiThemePluginMeta>[];
 
 
       growiPlugins
       growiPlugins
         .forEach(async(growiPlugin) => {
         .forEach(async(growiPlugin) => {
@@ -374,8 +368,6 @@ export class GrowiPluginService implements IGrowiPluginService {
 
 
   async retrieveAllPluginResourceEntries(): Promise<GrowiPluginResourceEntries> {
   async retrieveAllPluginResourceEntries(): Promise<GrowiPluginResourceEntries> {
 
 
-    const GrowiPlugin = mongoose.model('GrowiPlugin') as GrowiPluginModel;
-
     const entries: GrowiPluginResourceEntries = [];
     const entries: GrowiPluginResourceEntries = [];
 
 
     try {
     try {

+ 2 - 2
apps/app/src/features/growi-plugin/stores/growi-plugin.tsx

@@ -2,10 +2,10 @@ import useSWR, { SWRResponse } from 'swr';
 
 
 import { apiv3Get } from '~/client/util/apiv3-client';
 import { apiv3Get } from '~/client/util/apiv3-client';
 
 
-import type { GrowiPluginHasId } from '../interfaces';
+import type { IGrowiPluginHasId } from '../interfaces';
 
 
 type Plugins = {
 type Plugins = {
-  plugins: GrowiPluginHasId[]
+  plugins: IGrowiPluginHasId[]
 }
 }
 
 
 const pluginsFetcher = () => {
 const pluginsFetcher = () => {

+ 5 - 8
apps/app/src/server/crowi/index.js

@@ -131,7 +131,6 @@ Crowi.prototype.init = async function() {
     this.scanRuntimeVersions(),
     this.scanRuntimeVersions(),
     this.setupPassport(),
     this.setupPassport(),
     this.setupSearcher(),
     this.setupSearcher(),
-    this.setupPluginer(),
     this.setupMailer(),
     this.setupMailer(),
     this.setupSlackIntegrationService(),
     this.setupSlackIntegrationService(),
     this.setupG2GTransferService(),
     this.setupG2GTransferService(),
@@ -143,7 +142,7 @@ Crowi.prototype.init = async function() {
     this.setupUserGroupService(),
     this.setupUserGroupService(),
     this.setupExport(),
     this.setupExport(),
     this.setupImport(),
     this.setupImport(),
-    this.setupPluginService(),
+    this.setupGrowiPluginService(),
     this.setupPageService(),
     this.setupPageService(),
     this.setupInAppNotificationService(),
     this.setupInAppNotificationService(),
     this.setupActivityService(),
     this.setupActivityService(),
@@ -706,14 +705,12 @@ Crowi.prototype.setupImport = async function() {
   }
   }
 };
 };
 
 
-Crowi.prototype.setupPluginService = async function() {
-  const { PluginService } = require('../../features/growi-plugin/services/growi-plugin');
-  if (this.pluginService == null) {
-    this.pluginService = new PluginService(this);
-  }
+Crowi.prototype.setupGrowiPluginService = async function() {
+  const { growiPluginService } = require('~/features/growi-plugin/services');
+
   // download plugin repositories, if document exists but there is no repository
   // download plugin repositories, if document exists but there is no repository
   // TODO: Cannot download unless connected to the Internet at setup.
   // TODO: Cannot download unless connected to the Internet at setup.
-  await this.pluginService.downloadNotExistPluginRepositories();
+  await growiPluginService.downloadNotExistPluginRepositories();
 };
 };
 
 
 Crowi.prototype.setupPageService = async function() {
 Crowi.prototype.setupPageService = async function() {

+ 2 - 2
apps/app/src/server/routes/apiv3/customize-setting.js

@@ -7,6 +7,7 @@ import mongoose from 'mongoose';
 import multer from 'multer';
 import multer from 'multer';
 
 
 import { GrowiPluginResourceType } from '~/features/growi-plugin/interfaces';
 import { GrowiPluginResourceType } from '~/features/growi-plugin/interfaces';
+import { GrowiPlugin } from '~/features/growi-plugin/models';
 import { SupportedAction } from '~/interfaces/activity';
 import { SupportedAction } from '~/interfaces/activity';
 import { AttachmentType } from '~/server/interfaces/attachment';
 import { AttachmentType } from '~/server/interfaces/attachment';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
@@ -274,8 +275,7 @@ module.exports = (crowi) => {
       const currentTheme = await crowi.configManager.getConfig('crowi', 'customize:theme');
       const currentTheme = await crowi.configManager.getConfig('crowi', 'customize:theme');
 
 
       // retrieve plugin manifests
       // retrieve plugin manifests
-      const GrowiPluginModel = mongoose.model('GrowiPlugin');
-      const themePlugins = await GrowiPluginModel.findEnabledPluginsIncludingAnyTypes([GrowiPluginResourceType.Theme]);
+      const themePlugins = await GrowiPlugin.findEnabledPluginsIncludingAnyTypes([GrowiPluginResourceType.Theme]);
 
 
       const pluginThemesMetadatas = themePlugins
       const pluginThemesMetadatas = themePlugins
         .map(themePlugin => themePlugin.meta.themes)
         .map(themePlugin => themePlugin.meta.themes)