فهرست منبع

Merge pull request #9616 from weseek/fix/middlewares-abount-installation

fix: Middlewares about installation
mergify[bot] 1 سال پیش
والد
کامیت
b7b899f112

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

@@ -46,6 +46,9 @@ describe('convertToLegacyFormat', () => {
   });
   });
 
 
   test('should convert new format to legacy format', () => {
   test('should convert new format to legacy format', () => {
+    const installedAt = new Date();
+    const installedAtByOldestUser = new Date();
+
     const growiInfo: IGrowiInfo<IGrowiAppAdditionalInfo> = {
     const growiInfo: IGrowiInfo<IGrowiAppAdditionalInfo> = {
       version: '1.0.0',
       version: '1.0.0',
       appSiteUrl: 'https://example.com',
       appSiteUrl: 'https://example.com',
@@ -60,8 +63,8 @@ describe('convertToLegacyFormat', () => {
         totalmem: 8589934592,
         totalmem: 8589934592,
       },
       },
       additionalInfo: {
       additionalInfo: {
-        installedAt: new Date(),
-        installedAtByOldestUser: new Date(),
+        installedAt,
+        installedAtByOldestUser,
         currentUsersCount: 1,
         currentUsersCount: 1,
         currentActiveUsersCount: 1,
         currentActiveUsersCount: 1,
         attachmentType: AttachmentMethodType.local,
         attachmentType: AttachmentMethodType.local,
@@ -88,8 +91,8 @@ describe('convertToLegacyFormat', () => {
       },
       },
 
 
       // legacy properties
       // legacy properties
-      installedAt: new Date(),
-      installedAtByOldestUser: new Date(),
+      installedAt,
+      installedAtByOldestUser,
       currentUsersCount: 1,
       currentUsersCount: 1,
       currentActiveUsersCount: 1,
       currentActiveUsersCount: 1,
       attachmentType: AttachmentMethodType.local,
       attachmentType: AttachmentMethodType.local,

+ 0 - 0
apps/app/src/server/middlewares/application-installed.js → apps/app/src/server/middlewares/application-installed.ts


+ 0 - 14
apps/app/src/server/middlewares/application-not-installed.js

@@ -1,14 +0,0 @@
-/** @param {import('~/server/crowi').default} crowi Crowi instance */
-module.exports = (crowi) => {
-  const { appService } = crowi;
-
-  return async(req, res, next) => {
-    const isDBInitialized = await appService.isDBInitialized(true);
-
-    if (isDBInitialized) {
-      return res.redirect('/');
-    }
-
-    return next();
-  };
-};

+ 53 - 0
apps/app/src/server/middlewares/application-not-installed.ts

@@ -0,0 +1,53 @@
+import type { NextFunction, Request, Response } from 'express';
+import createError, { isHttpError } from 'http-errors';
+
+import type Crowi from '../crowi';
+
+/**
+ * Middleware factory to check if the application is already installed
+ */
+export const generateCheckerMiddleware = (crowi: Crowi) => async(req: Request, res: Response, next: NextFunction): Promise<void> => {
+  const { appService } = crowi;
+
+  const isDBInitialized = await appService.isDBInitialized(true);
+
+  if (isDBInitialized) {
+    return next(createError(409, 'Application is already installed'));
+  }
+
+  return next();
+};
+
+/**
+ * Middleware to return HttpError 409 if the application is already installed
+ */
+export const allreadyInstalledMiddleware = async(req: Request, res: Response, next: NextFunction): Promise<void> => {
+  return next(createError(409, 'Application is already installed'));
+};
+
+/**
+ * Error handler to handle errors as API errors
+ */
+export const handleAsApiError = (error: Error, req: Request, res: Response, next: NextFunction): void => {
+  if (error == null) {
+    return next();
+  }
+
+  if (isHttpError(error)) {
+    const httpError = error as createError.HttpError;
+    res.status(httpError.status).json({ message: httpError.message });
+    return;
+  }
+
+  next();
+};
+
+/**
+ * Error handler to redirect to top page on error
+ */
+export const redirectToTopOnError = (error: Error, req: Request, res: Response, next: NextFunction): void => {
+  if (error != null) {
+    return res.redirect('/');
+  }
+  return next();
+};

+ 5 - 1
apps/app/src/server/routes/apiv3/index.js

@@ -1,5 +1,6 @@
 import growiPlugin from '~/features/growi-plugin/server/routes/apiv3/admin';
 import growiPlugin from '~/features/growi-plugin/server/routes/apiv3/admin';
 import { factory as openaiRouteFactory } from '~/features/openai/server/routes';
 import { factory as openaiRouteFactory } from '~/features/openai/server/routes';
+import { allreadyInstalledMiddleware } from '~/server/middlewares/application-not-installed';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
@@ -71,8 +72,11 @@ module.exports = (crowi, app) => {
     userActivation.validateRegisterForm, userActivation.registerAction(crowi));
     userActivation.validateRegisterForm, userActivation.registerAction(crowi));
 
 
   // installer
   // installer
+  routerForAdmin.use('/installer', isInstalled
+    ? allreadyInstalledMiddleware
+    : require('./installer')(crowi));
+
   if (!isInstalled) {
   if (!isInstalled) {
-    routerForAdmin.use('/installer', require('./installer')(crowi));
     return [router, routerForAdmin, routerForAuth];
     return [router, routerForAdmin, routerForAuth];
   }
   }
 
 

+ 8 - 5
apps/app/src/server/routes/apiv3/installer.ts

@@ -8,6 +8,7 @@ import loggerFactory from '~/utils/logger';
 
 
 import type Crowi from '../../crowi';
 import type Crowi from '../../crowi';
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
 import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
+import * as applicationNotInstalled from '../../middlewares/application-not-installed';
 import { registerRules, registerValidation } from '../../middlewares/register-form-validator';
 import { registerRules, registerValidation } from '../../middlewares/register-form-validator';
 import { InstallerService, FailedToCreateAdminUserError } from '../../service/installer';
 import { InstallerService, FailedToCreateAdminUserError } from '../../service/installer';
 
 
@@ -27,6 +28,12 @@ module.exports = (crowi: Crowi): Router => {
 
 
   const router = express.Router();
   const router = express.Router();
 
 
+  // check application is not installed yet
+  router.use(
+    applicationNotInstalled.generateCheckerMiddleware(crowi),
+    applicationNotInstalled.handleAsApiError,
+  );
+
   const minPasswordLength = configManager.getConfig('app:minPasswordLength');
   const minPasswordLength = configManager.getConfig('app:minPasswordLength');
 
 
   /**
   /**
@@ -73,10 +80,6 @@ module.exports = (crowi: Crowi): Router => {
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
   router.post('/', registerRules(minPasswordLength), registerValidation, addActivity, async(req: FormRequest, res: ApiV3Response) => {
   router.post('/', registerRules(minPasswordLength), registerValidation, addActivity, async(req: FormRequest, res: ApiV3Response) => {
-    const appService = crowi.appService;
-    if (appService == null) {
-      return res.apiv3Err(new ErrorV3('GROWI cannot be installed due to an internal error', 'app_service_not_setup'), 500);
-    }
 
 
     if (!req.form.isValid) {
     if (!req.form.isValid) {
       const errors = req.form.errors;
       const errors = req.form.errors;
@@ -109,7 +112,7 @@ module.exports = (crowi: Crowi): Router => {
       return res.apiv3Err(new ErrorV3(err, 'failed_to_install'));
       return res.apiv3Err(new ErrorV3(err, 'failed_to_install'));
     }
     }
 
 
-    await appService.setupAfterInstall();
+    await crowi.appService.setupAfterInstall();
 
 
     const parameters = { action: SupportedAction.ACTION_USER_REGISTRATION_SUCCESS };
     const parameters = { action: SupportedAction.ACTION_USER_REGISTRATION_SUCCESS };
     activityEvent.emit('update', res.locals.activity._id, parameters);
     activityEvent.emit('update', res.locals.activity._id, parameters);

+ 5 - 2
apps/app/src/server/routes/index.js

@@ -6,6 +6,7 @@ import { middlewareFactory as rateLimiterFactory } from '~/features/rate-limiter
 import { accessTokenParser } from '../middlewares/access-token-parser';
 import { accessTokenParser } from '../middlewares/access-token-parser';
 import { generateAddActivityMiddleware } from '../middlewares/add-activity';
 import { generateAddActivityMiddleware } from '../middlewares/add-activity';
 import apiV1FormValidator from '../middlewares/apiv1-form-validator';
 import apiV1FormValidator from '../middlewares/apiv1-form-validator';
+import * as applicationNotInstalled from '../middlewares/application-not-installed';
 import { excludeReadOnlyUser, excludeReadOnlyUserIfCommentNotAllowed } from '../middlewares/exclude-read-only-user';
 import { excludeReadOnlyUser, excludeReadOnlyUserIfCommentNotAllowed } from '../middlewares/exclude-read-only-user';
 import injectResetOrderByTokenMiddleware from '../middlewares/inject-reset-order-by-token-middleware';
 import injectResetOrderByTokenMiddleware from '../middlewares/inject-reset-order-by-token-middleware';
 import injectUserRegistrationOrderByTokenMiddleware from '../middlewares/inject-user-registration-order-by-token-middleware';
 import injectUserRegistrationOrderByTokenMiddleware from '../middlewares/inject-user-registration-order-by-token-middleware';
@@ -30,7 +31,6 @@ autoReap.options.reapOnError = true; // continue reaping the file even if an err
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
   const autoReconnectToSearch = require('../middlewares/auto-reconnect-to-search')(crowi);
   const autoReconnectToSearch = require('../middlewares/auto-reconnect-to-search')(crowi);
-  const applicationNotInstalled = require('../middlewares/application-not-installed')(crowi);
   const applicationInstalled = require('../middlewares/application-installed')(crowi);
   const applicationInstalled = require('../middlewares/application-installed')(crowi);
   const loginRequiredStrictly = require('../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../middlewares/login-required')(crowi);
   const loginRequired = require('../middlewares/login-required')(crowi, true);
   const loginRequired = require('../middlewares/login-required')(crowi, true);
@@ -83,7 +83,10 @@ module.exports = function(crowi, app) {
   app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , next.delegateToNext);
   app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , next.delegateToNext);
 
 
   // installer
   // installer
-  app.get('/installer'                , applicationNotInstalled, next.delegateToNext);
+  app.get('/installer',
+    applicationNotInstalled.generateCheckerMiddleware(crowi),
+    next.delegateToNext,
+    applicationNotInstalled.redirectToTopOnError);
 
 
   // OAuth
   // OAuth
   app.get('/passport/google'                      , loginPassport.loginWithGoogle, loginPassport.loginFailureForExternalAccount);
   app.get('/passport/google'                      , loginPassport.loginWithGoogle, loginPassport.loginFailureForExternalAccount);