Просмотр исходного кода

Merge pull request #10500 from growilabs/support/156162-174081-app-apiv3-routes-biome-1

support: Configure biome for app apiv3 routes
Yuki Takei 4 месяцев назад
Родитель
Сommit
ba2b2cda6d

+ 5 - 0
apps/app/.eslintrc.js

@@ -64,6 +64,11 @@ module.exports = {
     'src/server/routes/*.js',
     'src/server/routes/*.ts',
     'src/server/routes/attachment/**',
+    'src/server/routes/apiv3/interfaces/**',
+    'src/server/routes/apiv3/pages/**',
+    'src/server/routes/apiv3/user/**',
+    'src/server/routes/apiv3/personal-setting/**',
+    'src/server/routes/apiv3/security-settings/**',
   ],
   settings: {
     // resolve path aliases by eslint-import-resolver-typescript

+ 2 - 2
apps/app/src/server/routes/apiv3/interfaces/apiv3-response.ts

@@ -1,6 +1,6 @@
 import type { Response } from 'express';
 
 export interface ApiV3Response extends Response {
-  apiv3(obj?: any, status?: number): any
-  apiv3Err(_err: any, status?: number, info?: any): any
+  apiv3(obj?: any, status?: number): any;
+  apiv3Err(_err: any, status?: number, info?: any): any;
 }

Разница между файлами не показана из-за своего большого размера
+ 458 - 234
apps/app/src/server/routes/apiv3/pages/index.js


+ 44 - 32
apps/app/src/server/routes/apiv3/personal-setting/delete-access-token.ts

@@ -1,9 +1,9 @@
+import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, RequestHandler } from 'express';
 import { query } from 'express-validator';
 
 import { SupportedAction } from '~/interfaces/activity';
-import { SCOPE } from '@growi/core/dist/interfaces';
 import type Crowi from '~/server/crowi';
 import { accessTokenParser } from '~/server/middlewares/access-token-parser';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
@@ -14,13 +14,20 @@ import loggerFactory from '~/utils/logger';
 
 import type { ApiV3Response } from '../interfaces/apiv3-response';
 
-const logger = loggerFactory('growi:routes:apiv3:personal-setting:generate-access-tokens');
+const logger = loggerFactory(
+  'growi:routes:apiv3:personal-setting:generate-access-tokens',
+);
 
 type ReqQuery = {
-  tokenId: string,
-}
+  tokenId: string;
+};
 
-type DeleteAccessTokenRequest = Request<undefined, ApiV3Response, undefined, ReqQuery>;
+type DeleteAccessTokenRequest = Request<
+  undefined,
+  ApiV3Response,
+  undefined,
+  ReqQuery
+>;
 
 type DeleteAccessTokenHandlersFactory = (crowi: Crowi) => RequestHandler[];
 
@@ -32,34 +39,39 @@ const validator = [
     .withMessage('tokenId must be a string'),
 ];
 
-export const deleteAccessTokenHandlersFactory: DeleteAccessTokenHandlersFactory = (crowi) => {
+export const deleteAccessTokenHandlersFactory: DeleteAccessTokenHandlersFactory =
+  (crowi) => {
+    const loginRequiredStrictly =
+      require('../../../middlewares/login-required')(crowi);
+    const addActivity = generateAddActivityMiddleware();
+    const activityEvent = crowi.event('activity');
 
-  const loginRequiredStrictly = require('../../../middlewares/login-required')(crowi);
-  const addActivity = generateAddActivityMiddleware();
-  const activityEvent = crowi.event('activity');
+    return [
+      accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
+      loginRequiredStrictly,
+      excludeReadOnlyUser,
+      addActivity,
+      validator,
+      apiV3FormValidator,
+      async (req: DeleteAccessTokenRequest, res: ApiV3Response) => {
+        const { query } = req;
+        const { tokenId } = query;
 
-  return [
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
-    loginRequiredStrictly,
-    excludeReadOnlyUser,
-    addActivity,
-    validator,
-    apiV3FormValidator,
-    async(req: DeleteAccessTokenRequest, res: ApiV3Response) => {
-      const { query } = req;
-      const { tokenId } = query;
+        try {
+          await AccessToken.deleteTokenById(tokenId);
 
-      try {
-        await AccessToken.deleteTokenById(tokenId);
+          const parameters = {
+            action: SupportedAction.ACTION_USER_ACCESS_TOKEN_DELETE,
+          };
+          activityEvent.emit('update', res.locals.activity._id, parameters);
 
-        const parameters = { action: SupportedAction.ACTION_USER_ACCESS_TOKEN_DELETE };
-        activityEvent.emit('update', res.locals.activity._id, parameters);
-
-        return res.apiv3({});
-      }
-      catch (err) {
-        logger.error(err);
-        return res.apiv3Err(new ErrorV3(err.toString(), 'delete-access-token-failed'));
-      }
-    }];
-};
+          return res.apiv3({});
+        } catch (err) {
+          logger.error(err);
+          return res.apiv3Err(
+            new ErrorV3(err.toString(), 'delete-access-token-failed'),
+          );
+        }
+      },
+    ];
+  };

+ 40 - 32
apps/app/src/server/routes/apiv3/personal-setting/delete-all-access-tokens.ts

@@ -1,9 +1,9 @@
 import type { IUserHasId } from '@growi/core/dist/interfaces';
+import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, RequestHandler } from 'express';
 
 import { SupportedAction } from '~/interfaces/activity';
-import { SCOPE } from '@growi/core/dist/interfaces';
 import type Crowi from '~/server/crowi';
 import { accessTokenParser } from '~/server/middlewares/access-token-parser';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
@@ -13,39 +13,47 @@ import loggerFactory from '~/utils/logger';
 
 import type { ApiV3Response } from '../interfaces/apiv3-response';
 
-const logger = loggerFactory('growi:routes:apiv3:personal-setting:generate-access-tokens');
+const logger = loggerFactory(
+  'growi:routes:apiv3:personal-setting:generate-access-tokens',
+);
 
-interface DeleteAllAccessTokensRequest extends Request<undefined, ApiV3Response, undefined> {
-  user: IUserHasId,
+interface DeleteAllAccessTokensRequest
+  extends Request<undefined, ApiV3Response, undefined> {
+  user: IUserHasId;
 }
 
 type DeleteAllAccessTokensHandlersFactory = (crowi: Crowi) => RequestHandler[];
 
-export const deleteAllAccessTokensHandlersFactory: DeleteAllAccessTokensHandlersFactory = (crowi) => {
-
-  const loginRequiredStrictly = require('../../../middlewares/login-required')(crowi);
-  const addActivity = generateAddActivityMiddleware();
-  const activityEvent = crowi.event('activity');
-
-  return [
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
-    loginRequiredStrictly,
-    excludeReadOnlyUser,
-    addActivity,
-    async(req: DeleteAllAccessTokensRequest, res: ApiV3Response) => {
-      const { user } = req;
-
-      try {
-        await AccessToken.deleteAllTokensByUserId(user._id);
-
-        const parameters = { action: SupportedAction.ACTION_USER_ACCESS_TOKEN_DELETE };
-        activityEvent.emit('update', res.locals.activity._id, parameters);
-
-        return res.apiv3({});
-      }
-      catch (err) {
-        logger.error(err);
-        return res.apiv3Err(new ErrorV3(err.toString(), 'delete-all-access-token-failed'));
-      }
-    }];
-};
+export const deleteAllAccessTokensHandlersFactory: DeleteAllAccessTokensHandlersFactory =
+  (crowi) => {
+    const loginRequiredStrictly =
+      require('../../../middlewares/login-required')(crowi);
+    const addActivity = generateAddActivityMiddleware();
+    const activityEvent = crowi.event('activity');
+
+    return [
+      accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
+      loginRequiredStrictly,
+      excludeReadOnlyUser,
+      addActivity,
+      async (req: DeleteAllAccessTokensRequest, res: ApiV3Response) => {
+        const { user } = req;
+
+        try {
+          await AccessToken.deleteAllTokensByUserId(user._id);
+
+          const parameters = {
+            action: SupportedAction.ACTION_USER_ACCESS_TOKEN_DELETE,
+          };
+          activityEvent.emit('update', res.locals.activity._id, parameters);
+
+          return res.apiv3({});
+        } catch (err) {
+          logger.error(err);
+          return res.apiv3Err(
+            new ErrorV3(err.toString(), 'delete-all-access-token-failed'),
+          );
+        }
+      },
+    ];
+  };

+ 51 - 42
apps/app/src/server/routes/apiv3/personal-setting/generate-access-token.ts

@@ -1,6 +1,4 @@
-import type {
-  IUserHasId, Scope,
-} from '@growi/core/dist/interfaces';
+import type { IUserHasId, Scope } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, RequestHandler } from 'express';
 import { body } from 'express-validator';
@@ -16,16 +14,19 @@ import loggerFactory from '~/utils/logger';
 import { apiV3FormValidator } from '../../../middlewares/apiv3-form-validator';
 import type { ApiV3Response } from '../interfaces/apiv3-response';
 
-const logger = loggerFactory('growi:routes:apiv3:personal-setting:generate-access-tokens');
+const logger = loggerFactory(
+  'growi:routes:apiv3:personal-setting:generate-access-tokens',
+);
 
 type ReqBody = {
-  expiredAt: Date,
-  description?: string,
-  scopes?: Scope[],
-}
+  expiredAt: Date;
+  description?: string;
+  scopes?: Scope[];
+};
 
-interface GenerateAccessTokenRequest extends Request<undefined, ApiV3Response, ReqBody> {
-  user: IUserHasId,
+interface GenerateAccessTokenRequest
+  extends Request<undefined, ApiV3Response, ReqBody> {
+  user: IUserHasId;
 }
 
 type GenerateAccessTokenHandlerFactory = (crowi: Crowi) => RequestHandler[];
@@ -73,35 +74,43 @@ const validator = [
     .withMessage('Invalid scope'),
 ];
 
-export const generateAccessTokenHandlerFactory: GenerateAccessTokenHandlerFactory = (crowi) => {
-
-  const loginRequiredStrictly = require('../../../middlewares/login-required')(crowi);
-  const activityEvent = crowi.event('activity');
-  const addActivity = generateAddActivityMiddleware();
-
-  return [
-    loginRequiredStrictly,
-    excludeReadOnlyUser,
-    addActivity,
-    validator,
-    apiV3FormValidator,
-    async(req: GenerateAccessTokenRequest, res: ApiV3Response) => {
-
-      const { user, body } = req;
-      const { expiredAt, description, scopes } = body;
-
-      try {
-        const tokenData = await AccessToken.generateToken(user._id, expiredAt, scopes, description);
-
-        const parameters = { action: SupportedAction.ACTION_USER_ACCESS_TOKEN_CREATE };
-        activityEvent.emit('update', res.locals.activity._id, parameters);
-
-        return res.apiv3(tokenData);
-      }
-      catch (err) {
-        logger.error(err);
-        return res.apiv3Err(new ErrorV3(err.toString(), 'generate-access-token-failed'));
-      }
-    },
-  ];
-};
+export const generateAccessTokenHandlerFactory: GenerateAccessTokenHandlerFactory =
+  (crowi) => {
+    const loginRequiredStrictly =
+      require('../../../middlewares/login-required')(crowi);
+    const activityEvent = crowi.event('activity');
+    const addActivity = generateAddActivityMiddleware();
+
+    return [
+      loginRequiredStrictly,
+      excludeReadOnlyUser,
+      addActivity,
+      validator,
+      apiV3FormValidator,
+      async (req: GenerateAccessTokenRequest, res: ApiV3Response) => {
+        const { user, body } = req;
+        const { expiredAt, description, scopes } = body;
+
+        try {
+          const tokenData = await AccessToken.generateToken(
+            user._id,
+            expiredAt,
+            scopes,
+            description,
+          );
+
+          const parameters = {
+            action: SupportedAction.ACTION_USER_ACCESS_TOKEN_CREATE,
+          };
+          activityEvent.emit('update', res.locals.activity._id, parameters);
+
+          return res.apiv3(tokenData);
+        } catch (err) {
+          logger.error(err);
+          return res.apiv3Err(
+            new ErrorV3(err.toString(), 'generate-access-token-failed'),
+          );
+        }
+      },
+    ];
+  };

+ 18 - 11
apps/app/src/server/routes/apiv3/personal-setting/get-access-tokens.ts

@@ -1,8 +1,8 @@
 import type { IUserHasId } from '@growi/core/dist/interfaces';
+import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, RequestHandler } from 'express';
 
-import { SCOPE } from '@growi/core/dist/interfaces';
 import type Crowi from '~/server/crowi';
 import { accessTokenParser } from '~/server/middlewares/access-token-parser';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
@@ -12,17 +12,23 @@ import loggerFactory from '~/utils/logger';
 
 import type { ApiV3Response } from '../interfaces/apiv3-response';
 
-const logger = loggerFactory('growi:routes:apiv3:personal-setting:get-access-tokens');
+const logger = loggerFactory(
+  'growi:routes:apiv3:personal-setting:get-access-tokens',
+);
 
-interface GetAccessTokenRequest extends Request<undefined, ApiV3Response, undefined> {
-  user: IUserHasId,
+interface GetAccessTokenRequest
+  extends Request<undefined, ApiV3Response, undefined> {
+  user: IUserHasId;
 }
 
 type GetAccessTokenHandlerFactory = (crowi: Crowi) => RequestHandler[];
 
-export const getAccessTokenHandlerFactory: GetAccessTokenHandlerFactory = (crowi) => {
-
-  const loginRequiredStrictly = require('../../../middlewares/login-required')(crowi);
+export const getAccessTokenHandlerFactory: GetAccessTokenHandlerFactory = (
+  crowi,
+) => {
+  const loginRequiredStrictly = require('../../../middlewares/login-required')(
+    crowi,
+  );
   const addActivity = generateAddActivityMiddleware();
 
   return [
@@ -30,16 +36,17 @@ export const getAccessTokenHandlerFactory: GetAccessTokenHandlerFactory = (crowi
     loginRequiredStrictly,
     excludeReadOnlyUser,
     addActivity,
-    async(req: GetAccessTokenRequest, res: ApiV3Response) => {
+    async (req: GetAccessTokenRequest, res: ApiV3Response) => {
       const { user } = req;
 
       try {
         const accessTokens = await AccessToken.findTokenByUserId(user._id);
         return res.apiv3({ accessTokens });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
-        return res.apiv3Err(new ErrorV3(err.toString(), 'colud_not_get_access_token'));
+        return res.apiv3Err(
+          new ErrorV3(err.toString(), 'colud_not_get_access_token'),
+        );
       }
     },
   ];

+ 277 - 157
apps/app/src/server/routes/apiv3/personal-setting/index.js

@@ -2,7 +2,6 @@ import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import { body } from 'express-validator';
 
-
 import { i18n } from '^/config/next-i18next.config';
 
 import { SupportedAction } from '~/interfaces/activity';
@@ -14,13 +13,11 @@ import { apiV3FormValidator } from '../../../middlewares/apiv3-form-validator';
 import EditorSettings from '../../../models/editor-settings';
 import ExternalAccount from '../../../models/external-account';
 import InAppNotificationSettings from '../../../models/in-app-notification-settings';
-
 import { deleteAccessTokenHandlersFactory } from './delete-access-token';
 import { deleteAllAccessTokensHandlersFactory } from './delete-all-access-tokens';
 import { generateAccessTokenHandlerFactory } from './generate-access-token';
 import { getAccessTokenHandlerFactory } from './get-access-tokens';
 
-
 const logger = loggerFactory('growi:routes:apiv3:personal-setting');
 
 const express = require('express');
@@ -76,14 +73,18 @@ const router = express.Router();
  */
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 module.exports = (crowi) => {
-  const loginRequiredStrictly = require('../../../middlewares/login-required')(crowi);
+  const loginRequiredStrictly = require('../../../middlewares/login-required')(
+    crowi,
+  );
   const addActivity = generateAddActivityMiddleware(crowi);
 
   const { User } = crowi.models;
 
   const activityEvent = crowi.event('activity');
 
-  const minPasswordLength = crowi.configManager.getConfig('app:minPasswordLength');
+  const minPasswordLength = crowi.configManager.getConfig(
+    'app:minPasswordLength',
+  );
 
   const validator = {
     personal: [
@@ -91,24 +92,31 @@ module.exports = (crowi) => {
       body('email')
         .isEmail()
         .custom((email) => {
-          if (!User.isEmailValid(email)) throw new Error('email is not included in whitelist');
+          if (!User.isEmailValid(email))
+            throw new Error('email is not included in whitelist');
           return true;
         }),
       body('lang').isString().isIn(i18n.locales),
       body('isEmailPublished').isBoolean(),
       body('slackMemberId').optional().isString(),
     ],
-    imageType: [
-      body('isGravatarEnabled').isBoolean(),
-    ],
+    imageType: [body('isGravatarEnabled').isBoolean()],
     password: [
       body('oldPassword').isString(),
-      body('newPassword').isString().not().isEmpty()
+      body('newPassword')
+        .isString()
+        .not()
+        .isEmpty()
         .isLength({ min: minPasswordLength })
-        .withMessage(`password must be at least ${minPasswordLength} characters long`),
-      body('newPasswordConfirm').isString().not().isEmpty()
+        .withMessage(
+          `password must be at least ${minPasswordLength} characters long`,
+        ),
+      body('newPasswordConfirm')
+        .isString()
+        .not()
+        .isEmpty()
         .custom((value, { req }) => {
-          return (value === req.body.newPassword);
+          return value === req.body.newPassword;
         }),
     ],
     associateLdap: [
@@ -150,24 +158,28 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: personal params
    */
-  router.get('/', accessTokenParser([SCOPE.READ.USER_SETTINGS.INFO], { acceptLegacy: true }), loginRequiredStrictly, async(req, res) => {
-    const { username } = req.user;
-    try {
-      const user = await User.findUserByUsername(username);
-
-      // return email and apiToken
-      const { email, apiToken } = user;
-      const currentUser = user.toObject();
-      currentUser.email = email;
-      currentUser.apiToken = apiToken;
-
-      return res.apiv3({ currentUser });
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err('update-personal-settings-failed');
-    }
-  });
+  router.get(
+    '/',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.INFO], { acceptLegacy: true }),
+    loginRequiredStrictly,
+    async (req, res) => {
+      const { username } = req.user;
+      try {
+        const user = await User.findUserByUsername(username);
+
+        // return email and apiToken
+        const { email, apiToken } = user;
+        const currentUser = user.toObject();
+        currentUser.email = email;
+        currentUser.apiToken = apiToken;
+
+        return res.apiv3({ currentUser });
+      } catch (err) {
+        logger.error(err);
+        return res.apiv3Err('update-personal-settings-failed');
+      }
+    },
+  );
 
   /**
    * @swagger
@@ -191,21 +203,28 @@ module.exports = (crowi) => {
    *                      type: number
    *                      description: Minimum password length
    */
-  router.get('/is-password-set', accessTokenParser([SCOPE.READ.USER_SETTINGS.PASSWORD], { acceptLegacy: true }), loginRequiredStrictly, async(req, res) => {
-    const { username } = req.user;
-
-    try {
-      const user = await User.findUserByUsername(username);
-      const isPasswordSet = user.isPasswordSet();
-      const minPasswordLength = crowi.configManager.getConfig('app:minPasswordLength');
-      return res.apiv3({ isPasswordSet, minPasswordLength });
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err('fail-to-get-whether-password-is-set');
-    }
-
-  });
+  router.get(
+    '/is-password-set',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.PASSWORD], {
+      acceptLegacy: true,
+    }),
+    loginRequiredStrictly,
+    async (req, res) => {
+      const { username } = req.user;
+
+      try {
+        const user = await User.findUserByUsername(username);
+        const isPasswordSet = user.isPasswordSet();
+        const minPasswordLength = crowi.configManager.getConfig(
+          'app:minPasswordLength',
+        );
+        return res.apiv3({ isPasswordSet, minPasswordLength });
+      } catch (err) {
+        logger.error(err);
+        return res.apiv3Err('fail-to-get-whether-password-is-set');
+      }
+    },
+  );
 
   /**
    * @swagger
@@ -232,10 +251,14 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: personal params
    */
-  router.put('/',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.INFO], { acceptLegacy: true }), loginRequiredStrictly, addActivity, validator.personal, apiV3FormValidator,
-    async(req, res) => {
-
+  router.put(
+    '/',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.INFO], { acceptLegacy: true }),
+    loginRequiredStrictly,
+    addActivity,
+    validator.personal,
+    apiV3FormValidator,
+    async (req, res) => {
       try {
         const user = await User.findOne({ _id: req.user.id });
         user.name = req.body.name;
@@ -248,22 +271,28 @@ module.exports = (crowi) => {
 
         if (!isUniqueEmail) {
           logger.error('email-is-not-unique');
-          return res.apiv3Err(new ErrorV3('The email is already in use', 'email-is-already-in-use'));
+          return res.apiv3Err(
+            new ErrorV3(
+              'The email is already in use',
+              'email-is-already-in-use',
+            ),
+          );
         }
 
         const updatedUser = await user.save();
 
-        const parameters = { action: SupportedAction.ACTION_USER_PERSONAL_SETTINGS_UPDATE };
+        const parameters = {
+          action: SupportedAction.ACTION_USER_PERSONAL_SETTINGS_UPDATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3({ updatedUser });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('update-personal-settings-failed');
       }
-
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -293,24 +322,32 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: user data
    */
-  router.put('/image-type', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.INFO], { acceptLegacy: true }), loginRequiredStrictly, addActivity,
-    validator.imageType, apiV3FormValidator,
-    async(req, res) => {
+  router.put(
+    '/image-type',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.INFO], { acceptLegacy: true }),
+    loginRequiredStrictly,
+    addActivity,
+    validator.imageType,
+    apiV3FormValidator,
+    async (req, res) => {
       const { isGravatarEnabled } = req.body;
 
       try {
-        const userData = await req.user.updateIsGravatarEnabled(isGravatarEnabled);
+        const userData =
+          await req.user.updateIsGravatarEnabled(isGravatarEnabled);
 
-        const parameters = { action: SupportedAction.ACTION_USER_IMAGE_TYPE_UPDATE };
+        const parameters = {
+          action: SupportedAction.ACTION_USER_IMAGE_TYPE_UPDATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3({ userData });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('update-personal-settings-failed');
       }
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -331,20 +368,24 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: array of external accounts
    */
-  router.get('/external-accounts',
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.EXTERNAL_ACCOUNT], { acceptLegacy: true }), loginRequiredStrictly, async(req, res) => {
+  router.get(
+    '/external-accounts',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.EXTERNAL_ACCOUNT], {
+      acceptLegacy: true,
+    }),
+    loginRequiredStrictly,
+    async (req, res) => {
       const userData = req.user;
 
       try {
         const externalAccounts = await ExternalAccount.find({ user: userData });
         return res.apiv3({ externalAccounts });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('get-external-accounts-failed');
       }
-
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -376,9 +417,16 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: user data updated
    */
-  router.put('/password',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.PASSWORD], { acceptLegacy: true }), loginRequiredStrictly, addActivity, validator.password, apiV3FormValidator,
-    async(req, res) => {
+  router.put(
+    '/password',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.PASSWORD], {
+      acceptLegacy: true,
+    }),
+    loginRequiredStrictly,
+    addActivity,
+    validator.password,
+    apiV3FormValidator,
+    async (req, res) => {
       const { body, user } = req;
       const { oldPassword, newPassword } = body;
 
@@ -388,17 +436,18 @@ module.exports = (crowi) => {
       try {
         const userData = await user.updatePassword(newPassword);
 
-        const parameters = { action: SupportedAction.ACTION_USER_PASSWORD_UPDATE };
+        const parameters = {
+          action: SupportedAction.ACTION_USER_PASSWORD_UPDATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3({ userData });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('update-password-failed');
       }
-
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -421,23 +470,29 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: user data
    */
-  router.put('/api-token', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.API_TOKEN]), loginRequiredStrictly, addActivity, async(req, res) => {
-    const { user } = req;
-
-    try {
-      const userData = await user.updateApiToken();
+  router.put(
+    '/api-token',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.API_TOKEN]),
+    loginRequiredStrictly,
+    addActivity,
+    async (req, res) => {
+      const { user } = req;
 
-      const parameters = { action: SupportedAction.ACTION_USER_API_TOKEN_UPDATE };
-      activityEvent.emit('update', res.locals.activity._id, parameters);
+      try {
+        const userData = await user.updateApiToken();
 
-      return res.apiv3({ userData });
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err('update-api-token-failed');
-    }
+        const parameters = {
+          action: SupportedAction.ACTION_USER_API_TOKEN_UPDATE,
+        };
+        activityEvent.emit('update', res.locals.activity._id, parameters);
 
-  });
+        return res.apiv3({ userData });
+      } catch (err) {
+        logger.error(err);
+        return res.apiv3Err('update-api-token-failed');
+      }
+    },
+  );
 
   /**
    * @swagger
@@ -458,7 +513,11 @@ module.exports = (crowi) => {
    *                     type: object
    *                     description: array of access tokens
    */
-  router.get('/access-token', accessTokenParser([SCOPE.READ.USER_SETTINGS.API.ACCESS_TOKEN]), getAccessTokenHandlerFactory(crowi));
+  router.get(
+    '/access-token',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.API.ACCESS_TOKEN]),
+    getAccessTokenHandlerFactory(crowi),
+  );
 
   /**
    * @swagger
@@ -493,7 +552,11 @@ module.exports = (crowi) => {
    *                     items:
    *                      type: string
    */
-  router.post('/access-token', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]), generateAccessTokenHandlerFactory(crowi));
+  router.post(
+    '/access-token',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
+    generateAccessTokenHandlerFactory(crowi),
+  );
 
   /**
    * @swagger
@@ -508,7 +571,11 @@ module.exports = (crowi) => {
    *           description: succeded to delete access token
    *
    */
-  router.delete('/access-token', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]), deleteAccessTokenHandlersFactory(crowi));
+  router.delete(
+    '/access-token',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
+    deleteAccessTokenHandlersFactory(crowi),
+  );
 
   /**
    * @swagger
@@ -522,7 +589,11 @@ module.exports = (crowi) => {
    *         200:
    *           description: succeded to delete all access tokens
    */
-  router.delete('/access-token/all', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]), deleteAllAccessTokensHandlersFactory(crowi));
+  router.delete(
+    '/access-token/all',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.API.ACCESS_TOKEN]),
+    deleteAllAccessTokensHandlersFactory(crowi),
+  );
 
   /**
    * @swagger
@@ -552,9 +623,14 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: Ldap account associate to me
    */
-  router.put('/associate-ldap', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.EXTERNAL_ACCOUNT]), loginRequiredStrictly, addActivity,
-    validator.associateLdap, apiV3FormValidator,
-    async(req, res) => {
+  router.put(
+    '/associate-ldap',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.EXTERNAL_ACCOUNT]),
+    loginRequiredStrictly,
+    addActivity,
+    validator.associateLdap,
+    apiV3FormValidator,
+    async (req, res) => {
       const { passportService } = crowi;
       const { user, body } = req;
       const { username } = body;
@@ -566,19 +642,24 @@ module.exports = (crowi) => {
 
       try {
         await passport.authenticate('ldapauth');
-        const associateUser = await ExternalAccount.associate('ldap', username, user);
+        const associateUser = await ExternalAccount.associate(
+          'ldap',
+          username,
+          user,
+        );
 
-        const parameters = { action: SupportedAction.ACTION_USER_LDAP_ACCOUNT_ASSOCIATE };
+        const parameters = {
+          action: SupportedAction.ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3({ associateUser });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('associate-ldap-account-failed');
       }
-
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -605,9 +686,14 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: Ldap account disassociate to me
    */
-  router.put('/disassociate-ldap',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.EXTERNAL_ACCOUNT]), loginRequiredStrictly, addActivity, validator.disassociateLdap, apiV3FormValidator,
-    async(req, res) => {
+  router.put(
+    '/disassociate-ldap',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.EXTERNAL_ACCOUNT]),
+    loginRequiredStrictly,
+    addActivity,
+    validator.disassociateLdap,
+    apiV3FormValidator,
+    async (req, res) => {
       const { user, body } = req;
       const { providerType, accountId } = body;
 
@@ -623,17 +709,18 @@ module.exports = (crowi) => {
           user,
         });
 
-        const parameters = { action: SupportedAction.ACTION_USER_LDAP_ACCOUNT_DISCONNECT };
+        const parameters = {
+          action: SupportedAction.ACTION_USER_LDAP_ACCOUNT_DISCONNECT,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3({ disassociateUser });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('disassociate-ldap-account-failed');
       }
-
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -666,37 +753,49 @@ module.exports = (crowi) => {
    *                  type: object
    *                  description: editor settings
    */
-  router.put('/editor-settings', accessTokenParser([SCOPE.WRITE.USER_SETTINGS.OTHER]), loginRequiredStrictly,
-    addActivity, validator.editorSettings, apiV3FormValidator,
-    async(req, res) => {
+  router.put(
+    '/editor-settings',
+    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.OTHER]),
+    loginRequiredStrictly,
+    addActivity,
+    validator.editorSettings,
+    apiV3FormValidator,
+    async (req, res) => {
       const query = { userId: req.user.id };
       const { body } = req;
 
-      const {
-        theme, keymapMode, styleActiveLine, autoFormatMarkdownTable,
-      } = body;
+      const { theme, keymapMode, styleActiveLine, autoFormatMarkdownTable } =
+        body;
 
       const document = {
-        theme, keymapMode, styleActiveLine, autoFormatMarkdownTable,
+        theme,
+        keymapMode,
+        styleActiveLine,
+        autoFormatMarkdownTable,
       };
 
       // Insert if document does not exist, and return new values
       // See: https://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
       const options = { upsert: true, new: true };
       try {
-        const response = await EditorSettings.findOneAndUpdate(query, { $set: document }, options);
-
-        const parameters = { action: SupportedAction.ACTION_USER_EDITOR_SETTINGS_UPDATE };
+        const response = await EditorSettings.findOneAndUpdate(
+          query,
+          { $set: document },
+          options,
+        );
+
+        const parameters = {
+          action: SupportedAction.ACTION_USER_EDITOR_SETTINGS_UPDATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3(response);
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('updating-editor-settings-failed');
       }
-    });
-
+    },
+  );
 
   /**
    * @swagger
@@ -715,17 +814,22 @@ module.exports = (crowi) => {
    *                  type: object
    *                  description: editor settings
    */
-  router.get('/editor-settings', accessTokenParser([SCOPE.READ.USER_SETTINGS.OTHER]), loginRequiredStrictly, async(req, res) => {
-    try {
-      const query = { userId: req.user.id };
-      const editorSettings = await EditorSettings.findOne(query) ?? new EditorSettings();
-      return res.apiv3(editorSettings);
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err('getting-editor-settings-failed');
-    }
-  });
+  router.get(
+    '/editor-settings',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.OTHER]),
+    loginRequiredStrictly,
+    async (req, res) => {
+      try {
+        const query = { userId: req.user.id };
+        const editorSettings =
+          (await EditorSettings.findOne(query)) ?? new EditorSettings();
+        return res.apiv3(editorSettings);
+      } catch (err) {
+        logger.error(err);
+        return res.apiv3Err('getting-editor-settings-failed');
+      }
+    },
+  );
 
   /**
    * @swagger
@@ -758,9 +862,14 @@ module.exports = (crowi) => {
    *                schema:
    *                 type: object
    */
-  router.put('/in-app-notification-settings',
+  router.put(
+    '/in-app-notification-settings',
     accessTokenParser([SCOPE.WRITE.USER_SETTINGS.IN_APP_NOTIFICATION]),
-    loginRequiredStrictly, addActivity, validator.inAppNotificationSettings, apiV3FormValidator, async(req, res) => {
+    loginRequiredStrictly,
+    addActivity,
+    validator.inAppNotificationSettings,
+    apiV3FormValidator,
+    async (req, res) => {
       const query = { userId: req.user.id };
       const subscribeRules = req.body.subscribeRules;
 
@@ -770,18 +879,25 @@ module.exports = (crowi) => {
 
       const options = { upsert: true, new: true, runValidators: true };
       try {
-        const response = await InAppNotificationSettings.findOneAndUpdate(query, { $set: { subscribeRules } }, options);
-
-        const parameters = { action: SupportedAction.ACTION_USER_IN_APP_NOTIFICATION_SETTINGS_UPDATE };
+        const response = await InAppNotificationSettings.findOneAndUpdate(
+          query,
+          { $set: { subscribeRules } },
+          options,
+        );
+
+        const parameters = {
+          action:
+            SupportedAction.ACTION_USER_IN_APP_NOTIFICATION_SETTINGS_UPDATE,
+        };
         activityEvent.emit('update', res.locals.activity._id, parameters);
 
         return res.apiv3(response);
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
         return res.apiv3Err('updating-in-app-notification-settings-failed');
       }
-    });
+    },
+  );
 
   /**
    * @swagger
@@ -802,17 +918,21 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: InAppNotificationSettings
    */
-  router.get('/in-app-notification-settings', accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION]), loginRequiredStrictly, async(req, res) => {
-    const query = { userId: req.user.id };
-    try {
-      const response = await InAppNotificationSettings.findOne(query);
-      return res.apiv3(response);
-    }
-    catch (err) {
-      logger.error(err);
-      return res.apiv3Err('getting-in-app-notification-settings-failed');
-    }
-  });
+  router.get(
+    '/in-app-notification-settings',
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION]),
+    loginRequiredStrictly,
+    async (req, res) => {
+      const query = { userId: req.user.id };
+      try {
+        const response = await InAppNotificationSettings.findOne(query);
+        return res.apiv3(response);
+      } catch (err) {
+        logger.error(err);
+        return res.apiv3Err('getting-in-app-notification-settings-failed');
+      }
+    },
+  );
 
   return router;
 };

+ 13 - 5
apps/app/src/server/routes/apiv3/security-settings/checkSetupStrategiesHasAdmin.ts

@@ -6,7 +6,7 @@ interface AggregateResult {
   count: number;
 }
 
-const checkLocalStrategyHasAdmin = async(): Promise<boolean> => {
+const checkLocalStrategyHasAdmin = async (): Promise<boolean> => {
   const User = mongoose.model('User') as any;
 
   const localAdmins: AggregateResult[] = await User.aggregate([
@@ -23,7 +23,9 @@ const checkLocalStrategyHasAdmin = async(): Promise<boolean> => {
   return localAdmins.length > 0 && localAdmins[0].count > 0;
 };
 
-const checkExternalStrategiesHasAdmin = async(setupExternalStrategies: IExternalAuthProviderType[]): Promise<boolean> => {
+const checkExternalStrategiesHasAdmin = async (
+  setupExternalStrategies: IExternalAuthProviderType[],
+): Promise<boolean> => {
   const User = mongoose.model('User') as any;
 
   const externalAdmins: AggregateResult[] = await User.aggregate([
@@ -47,7 +49,9 @@ const checkExternalStrategiesHasAdmin = async(setupExternalStrategies: IExternal
   return externalAdmins.length > 0 && externalAdmins[0].count > 0;
 };
 
-export const checkSetupStrategiesHasAdmin = async(setupStrategies: (IExternalAuthProviderType | 'local')[]): Promise<boolean> => {
+export const checkSetupStrategiesHasAdmin = async (
+  setupStrategies: (IExternalAuthProviderType | 'local')[],
+): Promise<boolean> => {
   if (setupStrategies.includes('local')) {
     const isLocalStrategyHasAdmin = await checkLocalStrategyHasAdmin();
     if (isLocalStrategyHasAdmin) {
@@ -55,12 +59,16 @@ export const checkSetupStrategiesHasAdmin = async(setupStrategies: (IExternalAut
     }
   }
 
-  const setupExternalStrategies = setupStrategies.filter(strategy => strategy !== 'local') as IExternalAuthProviderType[];
+  const setupExternalStrategies = setupStrategies.filter(
+    (strategy) => strategy !== 'local',
+  ) as IExternalAuthProviderType[];
   if (setupExternalStrategies.length === 0) {
     return false;
   }
 
-  const isExternalStrategiesHasAdmin = await checkExternalStrategiesHasAdmin(setupExternalStrategies);
+  const isExternalStrategiesHasAdmin = await checkExternalStrategiesHasAdmin(
+    setupExternalStrategies,
+  );
 
   return isExternalStrategiesHasAdmin;
 };

Разница между файлами не показана из-за своего большого размера
+ 687 - 291
apps/app/src/server/routes/apiv3/security-settings/index.js


+ 17 - 10
apps/app/src/server/routes/apiv3/user/get-related-groups.ts

@@ -1,8 +1,8 @@
 import type { IUserHasId } from '@growi/core';
+import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, RequestHandler } from 'express';
 
-import { SCOPE } from '@growi/core/dist/interfaces';
 import type Crowi from '~/server/crowi';
 import { accessTokenParser } from '~/server/middlewares/access-token-parser';
 import loggerFactory from '~/utils/logger';
@@ -14,22 +14,29 @@ const logger = loggerFactory('growi:routes:apiv3:user:get-related-groups');
 type GetRelatedGroupsHandlerFactory = (crowi: Crowi) => RequestHandler[];
 
 interface Req extends Request {
-  user: IUserHasId,
+  user: IUserHasId;
 }
 
-export const getRelatedGroupsHandlerFactory: GetRelatedGroupsHandlerFactory = (crowi) => {
-  const loginRequiredStrictly = require('~/server/middlewares/login-required')(crowi);
+export const getRelatedGroupsHandlerFactory: GetRelatedGroupsHandlerFactory = (
+  crowi,
+) => {
+  const loginRequiredStrictly = require('~/server/middlewares/login-required')(
+    crowi,
+  );
 
   return [
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.INFO], { acceptLegacy: true }), loginRequiredStrictly,
-    async(req: Req, res: ApiV3Response) => {
+    accessTokenParser([SCOPE.READ.USER_SETTINGS.INFO], { acceptLegacy: true }),
+    loginRequiredStrictly,
+    async (req: Req, res: ApiV3Response) => {
       try {
-        const relatedGroups = await crowi.pageGrantService?.getUserRelatedGroups(req.user);
+        const relatedGroups =
+          await crowi.pageGrantService?.getUserRelatedGroups(req.user);
         return res.apiv3({ relatedGroups });
-      }
-      catch (err) {
+      } catch (err) {
         logger.error(err);
-        return res.apiv3Err(new ErrorV3('Error occurred while getting user related groups'));
+        return res.apiv3Err(
+          new ErrorV3('Error occurred while getting user related groups'),
+        );
       }
     },
   ];

+ 4 - 1
biome.json

@@ -30,7 +30,10 @@
       "!packages/pdf-converter-client/specs",
       "!apps/app/src/client",
       "!apps/app/src/server/middlewares",
-      "!apps/app/src/server/routes/apiv3",
+      "!apps/app/src/server/routes/apiv3/app-settings",
+      "!apps/app/src/server/routes/apiv3/page",
+      "!apps/app/src/server/routes/apiv3/*.js",
+      "!apps/app/src/server/routes/apiv3/*.ts",
       "!apps/app/src/server/service"
     ]
   },

Некоторые файлы не были показаны из-за большого количества измененных файлов