2
0
Эх сурвалжийг харах

add actions validation etc

Naoki427 6 сар өмнө
parent
commit
2fac68efee

+ 2 - 1
apps/app/src/features/audit-log-bulk-export/interfaces/audit-log-bulk-export.ts

@@ -1,4 +1,5 @@
 import type { HasObjectId, IUser, Ref } from '@growi/core';
 import type { HasObjectId, IUser, Ref } from '@growi/core';
+import type { SupportedActionType } from '~/interfaces/activity';
 
 
 export const AuditLogBulkExportFormat = {
 export const AuditLogBulkExportFormat = {
   json: 'json',
   json: 'json',
@@ -23,7 +24,7 @@ export type AuditLogBulkExportJobStatus =
 
 
 export interface IAuditLogBulkExportFilters {
 export interface IAuditLogBulkExportFilters {
   users?: Array<Ref<IUser>>;
   users?: Array<Ref<IUser>>;
-  actions?: string[];
+  actions?: SupportedActionType[];
   dateFrom?: Date;
   dateFrom?: Date;
   dateTo?: Date;
   dateTo?: Date;
 }
 }

+ 10 - 1
apps/app/src/features/audit-log-bulk-export/server/models/audit-log-bulk-export-job.ts

@@ -2,6 +2,7 @@ import type { HydratedDocument } from 'mongoose';
 import { type Model, Schema } from 'mongoose';
 import { type Model, Schema } from 'mongoose';
 
 
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
 import { getOrCreateModel } from '~/server/util/mongoose-utils';
+import { AllSupportedActions } from '~/interfaces/activity';
 
 
 import type { IAuditLogBulkExportJob } from '../../interfaces/audit-log-bulk-export';
 import type { IAuditLogBulkExportJob } from '../../interfaces/audit-log-bulk-export';
 import {
 import {
@@ -17,7 +18,15 @@ export type AuditLogBulkExportJobModel = Model<AuditLogBulkExportJobDocument>;
 const auditLogBulkExportJobSchema = new Schema<IAuditLogBulkExportJob>(
 const auditLogBulkExportJobSchema = new Schema<IAuditLogBulkExportJob>(
   {
   {
     user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
     user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
-    filters: { type: Schema.Types.Mixed, required: true },
+    filters: {
+      type: {
+        users: [{ type: Schema.Types.ObjectId, ref: 'User' }],
+        actions: [{ type: String, enum: AllSupportedActions }],
+        dateFrom: { type: Date },
+        dateTo: { type: Date },
+      },
+      required: true,
+    },
     filterHash: { type: String, required: true, index: true },
     filterHash: { type: String, required: true, index: true },
     format: {
     format: {
       type: String,
       type: String,

+ 23 - 19
apps/app/src/features/audit-log-bulk-export/server/routes/apiv3/audit-log-bulk-export.ts

@@ -2,10 +2,13 @@ import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request } from 'express';
 import type { Request } from 'express';
 import { Router } from 'express';
 import { Router } from 'express';
-import { body, validationResult } from 'express-validator';
+import { body } from 'express-validator';
 
 
 import { AuditLogBulkExportFormat } from '~/features/audit-log-bulk-export/interfaces/audit-log-bulk-export';
 import { AuditLogBulkExportFormat } from '~/features/audit-log-bulk-export/interfaces/audit-log-bulk-export';
+import type { SupportedActionType } from '~/interfaces/activity';
+import { AllSupportedActions } from '~/interfaces/activity';
 import type Crowi from '~/server/crowi';
 import type Crowi from '~/server/crowi';
+import { apiV3FormValidator } from '~/server/middlewares/apiv3-form-validator';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -18,7 +21,18 @@ const logger = loggerFactory('growi:routes:apiv3:audit-log-bulk-export');
 
 
 const router = Router();
 const router = Router();
 
 
-interface AuthorizedRequest extends Request {
+interface AuditLogExportReqBody {
+  filters: {
+    users?: string[];
+    actions?: SupportedActionType[];
+    dateFrom?: Date;
+    dateTo?: Date;
+  };
+  format?: (typeof AuditLogBulkExportFormat)[keyof typeof AuditLogBulkExportFormat];
+  restartJob?: boolean;
+}
+interface AuthorizedRequest
+  extends Request<undefined, ApiV3Response, AuditLogExportReqBody> {
   user?: any;
   user?: any;
 }
 }
 
 
@@ -32,9 +46,12 @@ module.exports = (crowi: Crowi): Router => {
     auditLogBulkExport: [
     auditLogBulkExport: [
       body('filters').exists({ checkFalsy: true }).isObject(),
       body('filters').exists({ checkFalsy: true }).isObject(),
       body('filters.users').optional({ nullable: true }).isArray(),
       body('filters.users').optional({ nullable: true }).isArray(),
-      body('filters.users.*').optional({ nullable: true }).isString(),
+      body('filters.users.*').optional({ nullable: true }).isMongoId(),
       body('filters.actions').optional({ nullable: true }).isArray(),
       body('filters.actions').optional({ nullable: true }).isArray(),
-      body('filters.actions.*').optional({ nullable: true }).isString(),
+      body('filters.actions.*')
+        .optional({ nullable: true })
+        .isString()
+        .isIn(AllSupportedActions),
       body('filters.dateFrom')
       body('filters.dateFrom')
         .optional({ nullable: true })
         .optional({ nullable: true })
         .isISO8601()
         .isISO8601()
@@ -52,26 +69,13 @@ module.exports = (crowi: Crowi): Router => {
     accessTokenParser([SCOPE.WRITE.ADMIN.AUDIT_LOG]),
     accessTokenParser([SCOPE.WRITE.ADMIN.AUDIT_LOG]),
     loginRequiredStrictly,
     loginRequiredStrictly,
     validators.auditLogBulkExport,
     validators.auditLogBulkExport,
+    apiV3FormValidator,
     async (req: AuthorizedRequest, res: ApiV3Response) => {
     async (req: AuthorizedRequest, res: ApiV3Response) => {
-      const errors = validationResult(req);
-      if (!errors.isEmpty()) {
-        return res.status(400).json({ errors: errors.array() });
-      }
-
       const {
       const {
         filters,
         filters,
         format = AuditLogBulkExportFormat.json,
         format = AuditLogBulkExportFormat.json,
         restartJob,
         restartJob,
-      } = req.body as {
-        filters: {
-          users?: string[];
-          actions?: string[];
-          dateFrom?: Date;
-          dateTo?: Date;
-        };
-        format?: (typeof AuditLogBulkExportFormat)[keyof typeof AuditLogBulkExportFormat];
-        restartJob?: boolean;
-      };
+      } = req.body;
 
 
       try {
       try {
         await auditLogBulkExportService.createOrResetExportJob(
         await auditLogBulkExportService.createOrResetExportJob(

+ 2 - 4
apps/app/src/features/audit-log-bulk-export/server/service/audit-log-bulk-export.ts

@@ -1,7 +1,5 @@
 import { createHash } from 'node:crypto';
 import { createHash } from 'node:crypto';
 
 
-import type { IUserHasId } from '@growi/core';
-
 import type {
 import type {
   AuditLogBulkExportFormat,
   AuditLogBulkExportFormat,
   IAuditLogBulkExportFilters,
   IAuditLogBulkExportFilters,
@@ -17,7 +15,7 @@ export interface IAuditLogBulkExportService {
   createOrResetExportJob: (
   createOrResetExportJob: (
     filters: IAuditLogBulkExportFilters,
     filters: IAuditLogBulkExportFilters,
     format: AuditLogBulkExportFormat,
     format: AuditLogBulkExportFormat,
-    currentUser: IUserHasId,
+    currentUser,
     restartJob?: boolean,
     restartJob?: boolean,
   ) => Promise<void>;
   ) => Promise<void>;
   resetExportJob: (job: AuditLogBulkExportJobDocument) => Promise<void>;
   resetExportJob: (job: AuditLogBulkExportJobDocument) => Promise<void>;
@@ -76,7 +74,7 @@ class AuditLogBulkExportService implements IAuditLogBulkExportService {
   async createOrResetExportJob(
   async createOrResetExportJob(
     filters: IAuditLogBulkExportFilters,
     filters: IAuditLogBulkExportFilters,
     format: AuditLogBulkExportFormat,
     format: AuditLogBulkExportFormat,
-    currentUser: IUserHasId,
+    currentUser,
     restartJob?: boolean,
     restartJob?: boolean,
   ): Promise<void> {
   ): Promise<void> {
     const normalizedFilters = canonicalizeFilters(filters);
     const normalizedFilters = canonicalizeFilters(filters);