@autofleet/shtinker 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +97 -0
- package/dist/index.d.ts +97 -12
- package/dist/index.js +2 -122
- package/dist/index.js.map +1 -0
- package/package.json +39 -20
- package/readme.md +9 -0
- package/dist/audit-api.d.ts +0 -6
- package/dist/audit-api.js +0 -36
- package/dist/audit-logger.d.ts +0 -12
- package/dist/audit-logger.js +0 -133
- package/dist/audit-ms.d.ts +0 -4
- package/dist/audit-ms.js +0 -14
- package/dist/const.d.ts +0 -5
- package/dist/const.js +0 -8
- package/dist/logger.d.ts +0 -2
- package/dist/logger.js +0 -7
- package/dist/types.d.ts +0 -55
- package/dist/types.js +0 -30
- package/src/audit-api.ts +0 -30
- package/src/audit-logger.ts +0 -131
- package/src/audit-ms.ts +0 -12
- package/src/const.ts +0 -5
- package/src/index.ts +0 -90
- package/src/logger.ts +0 -3
- package/src/types.ts +0 -63
- package/tsconfig.json +0 -13
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,`__esModule`,{value:!0});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`@autofleet/zehut`)),l=s(require(`lodash`)),u=s(require(`@autofleet/logger`)),d=s(require(`@autofleet/errors`)),f=s(require(`@autofleet/network`));let p=/* @__PURE__ */ function(e){return e.CREATE=`create`,e.BULK_CREATE=`bulk-create`,e.BULK_EDIT=`bulk-edit`,e.DELETE=`delete`,e.UPDATE=`update`,e.CANCEL=`cancel`,e.FAIL=`fail`,e.UNASSIGN=`unassign`,e.BULK_ASSIGN=`bulk-assign`,e.REASSIGN=`reassign`,e.DISPATCH=`dispatch`,e.BULK_DISPATCH=`bulk-dispatch`,e.BULK_UPSERT=`bulk-upsert`,e.UPSERT=`upsert`,e.JOIN=`join`,e.MOVE=`move`,e.REOPTIMIZATION=`reoptimization`,e}({}),m=/* @__PURE__ */ function(e){return e.RIDE=`Ride`,e.VEHICLE=`Vehicle`,e.DRIVER=`Driver`,e.PRICE_CALCULATION=`PriceCalculation`,e}({}),h=/* @__PURE__ */ function(e){return e.USER=`user`,e.AUTOMATION=`automation`,e}({});const g=`audit-log-context`,_=`audit-log-rows`,v=`auditLogContext`,y=`x-af-automation-id`,b=(0,u.default)(null);var x=b;const S=`customFields`,C=()=>{let e=(0,c.getCurrentPayload)(),t=e?.nonHeaderContext?.get(v);return t},w={[p.BULK_CREATE]:p.BULK_CREATE,[p.BULK_EDIT]:p.BULK_EDIT,[p.BULK_ASSIGN]:p.BULK_ASSIGN,[p.BULK_DISPATCH]:p.BULK_DISPATCH,[p.BULK_UPSERT]:p.BULK_UPSERT},T=e=>[null,void 0].includes(e)?!0:Array.isArray(e)?e.length===0:typeof e==`object`&&!(e instanceof Date)?Object.keys(e).length===0:!1,E=e=>!w[e],D=(e,t)=>e.filter(e=>!T(t.get(e))||!T(t.previous(e))),O=(e,t)=>{let n=t.returning?t.fields:e.changed(),r=D(n.filter(e=>e!==S),e);return r.map(t=>({property:t,previousValue:e.previous(t),newValue:e.get(t)}))},k=e=>{let t=e.changed(),n=t&&t.includes(S);if(!n)return[];let r=e.get(S),i=e.previous(S),a=Object.keys(r).filter(e=>{let t=r?.[e],n=i?.[e];return(!T(t)||!T(n))&&!(0,l.isEqual)(t,n)});return a.map(e=>({property:`${S}.${e}`,previousValue:i?.[e],newValue:r?.[e]}))};var A=class{constructor(e){this.rabbit=e.rabbit,this.sequelize=e.sequelize,this.logger=e.logger||x}registerHooks(){Object.entries(this.sequelize.models).forEach(([e,t])=>{t.addHook(`afterSave`,async(t,n)=>{try{let r=C();if(!r)return;r?.entityType?.toLowerCase()===e?.toLowerCase()&&E(r.action)&&(r.entityId=t.id);let i=O(t,n),a=k(t),o={entityType:e,entityId:t.id,rows:[...i,...a]};this.sendAuditLogRows(o)}catch(e){this.logger.error(`Failed to send audit log rows`,e)}})})}async sendAuditLogContext(e){try{await this.rabbit.sendToQueue(g,e)}catch(e){this.logger.error(`Failed to send audit log context`,e)}}async sendAuditLogRows(e){try{await this.rabbit.sendToQueue(_,e)}catch(e){this.logger.error(`Failed to send audit log rows`,e)}}},j=A;const M=new f.default({serviceName:`AUDIT_MS`,timeout:6e4,logger:x}),N=async e=>{let{data:t}=await M.get(`api/v1/audit-logs/${e}`);return t},P={getByEntityId:N};var F=P,I=async({router:e,logger:t,entityScopedModelMap:n})=>{!n||!e||Object.entries(n).forEach(([n,r])=>{e.get(`${n}/:id/audit`,async(e,i)=>{try{let{id:a}=e.params,o=await r.findByPk(a);if(!o)return(0,d.handleError)(new d.ResourceNotFoundError,i,{logger:t,message:`Entity ${n} with id ${a} not found`});let s=F.getByEntityId(a);return i.json(s)}catch(e){return(0,d.handleError)(new d.UnexpectedError(e),i,{logger:t})}})})};let L;const R=e=>{process.env.DISABLE_AUDIT_LOGS!==`true`&&(L=new j(e),I(e),L.registerHooks())},z=(e,t)=>async(n,r,i)=>{try{if(process.env.DISABLE_AUDIT_LOGS===`true`||!L)return i();let a=(0,c.getUser)(),o=n.headers[y],{performedBy:s,actionOrigin:l}=a?.id?{performedBy:a.id,actionOrigin:h.USER}:{performedBy:o??null,actionOrigin:o?h.AUTOMATION:null},u={entityType:e,action:t,endpoint:n.url,method:n.method,performedBy:s,actionOrigin:l},d=(0,c.getCurrentPayload)();d.nonHeaderContext.set(v,u);let f=async()=>{r.off(`finish`,f),r.off(`close`,f),r.off(`error`,f),await L.sendAuditLogContext(u)};E(t)?(r.once(`finish`,f),r.once(`close`,f),r.once(`error`,f)):await L.sendAuditLogContext(u)}catch(e){x.error(`coudln't set audit context`,e)}return i()},B=(e,t)=>async(n,{userId:r,automationId:i})=>{if(process.env.DISABLE_AUDIT_LOGS===`true`||!L)return;let a=(0,c.getCurrentPayload)();if(a?.context?.get){let{performedBy:o,actionOrigin:s}=r?{performedBy:r,actionOrigin:h.USER}:{performedBy:i??null,actionOrigin:i?h.AUTOMATION:null},c={entityType:e,action:t,endpoint:n,method:`rabbit`,performedBy:o,actionOrigin:s};a.nonHeaderContext.set(v,c),await L.sendAuditLogContext(c)}};var V=j;exports.AUDIT_LOG_CONTEXT_KEY=v,exports.AUDIT_LOG_CONTEXT_QUEUE=g,exports.AUDIT_LOG_ROWS_QUEUE=_,exports.AUTOMATION_ID_HEADER=y,exports.Action=p,exports.ActionOrigin=h,exports.EntityType=m,exports.default=V,exports.enableAuditing=R,exports.setAuditContext=z,exports.setRabbitAuditContext=B;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["logger: LoggerInstanceManager","action: string","fields: string[]","instance: Model","options: CreateOptions<any> | InstanceUpdateOptions<any>","changedFields: string[]","property: string","options: AuditLoggerOptions","payload: AuditLogPayload","context: AuditLogContext","entityId: string","exportObj: { getByEntityId: typeof getByEntityId }","auditLogger: AuditLogger | undefined","options: AuditLoggerOptions","entityType: string","action: string","req: Request","res: Response","next: NextFunction","auditLogContext: AuditLogContext","endpoint: string"],"sources":["../src/types.ts","../src/const.ts","../src/logger.ts","../src/audit-logger.ts","../src/audit-ms.ts","../src/audit-api.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable no-shadow */\nimport type { ModelStatic, Model } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport type RabbitMq from '@autofleet/rabbit';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { IRouter } from 'express';\n\nexport type AuditLoggerOptions = {\n rabbit: RabbitMq;\n sequelize: Sequelize;\n logger: LoggerInstanceManager;\n router?: IRouter;\n entityScopedModelMap?: { [modelName: string]: ModelStatic<Model> };\n};\n\nexport interface AuditLogContext {\n entityType: string;\n entityId?: string;\n action: string;\n performedBy: string;\n endpoint: string;\n method: string;\n actionOrigin?: string;\n}\n\nexport interface AuditLogRow {\n property: string;\n previousValue: any;\n newValue: any;\n}\n\nexport interface AuditLogPayload {\n entityType: string;\n entityId: string;\n rows: AuditLogRow[];\n}\n\nexport enum Action {\n CREATE = 'create',\n BULK_CREATE = 'bulk-create',\n BULK_EDIT = 'bulk-edit',\n DELETE = 'delete',\n UPDATE = 'update',\n CANCEL = 'cancel',\n FAIL = 'fail',\n UNASSIGN = 'unassign',\n BULK_ASSIGN = 'bulk-assign',\n REASSIGN = 'reassign',\n DISPATCH = 'dispatch',\n BULK_DISPATCH = 'bulk-dispatch',\n BULK_UPSERT = 'bulk-upsert',\n UPSERT = 'upsert',\n JOIN = 'join',\n MOVE = 'move',\n REOPTIMIZATION = 'reoptimization',\n}\n\nexport enum EntityType {\n RIDE = 'Ride',\n VEHICLE = 'Vehicle',\n DRIVER = 'Driver',\n PRICE_CALCULATION = 'PriceCalculation',\n}\n\nexport const enum ActionOrigin {\n USER = 'user',\n AUTOMATION = 'automation',\n}\n","export const AUDIT_LOG_CONTEXT_QUEUE = 'audit-log-context';\nexport const AUDIT_LOG_ROWS_QUEUE = 'audit-log-rows';\nexport const AUDIT_LOG_CONTEXT_KEY = 'auditLogContext';\nexport const AUTOMATION_ID_HEADER = 'x-af-automation-id';\n","import Logger, { type LoggerInstanceManager } from '@autofleet/logger';\n\nconst logger: LoggerInstanceManager = Logger(null);\nexport default logger;\n","import type RabbitMq from '@autofleet/rabbit';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { getCurrentPayload as getCurrentTrace } from '@autofleet/zehut';\nimport type {\n CreateOptions, InstanceUpdateOptions, Model, Sequelize,\n} from 'sequelize';\nimport { isEqual } from 'lodash';\nimport {\n type AuditLogPayload, type AuditLoggerOptions, type AuditLogContext, Action,\n} from './types';\nimport { AUDIT_LOG_CONTEXT_QUEUE, AUDIT_LOG_ROWS_QUEUE, AUDIT_LOG_CONTEXT_KEY } from './const';\nimport logger from './logger';\n\nconst CUSTOM_FIELDS_PROPERTY = 'customFields';\n\nconst getAuditContext = () => {\n const currentTrace = getCurrentTrace();\n const auditContext = currentTrace?.nonHeaderContext?.get(AUDIT_LOG_CONTEXT_KEY);\n return auditContext as AuditLogContext;\n};\n\nconst ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT = {\n [Action.BULK_CREATE]: Action.BULK_CREATE,\n [Action.BULK_EDIT]: Action.BULK_EDIT,\n [Action.BULK_ASSIGN]: Action.BULK_ASSIGN,\n [Action.BULK_DISPATCH]: Action.BULK_DISPATCH,\n [Action.BULK_UPSERT]: Action.BULK_UPSERT,\n};\n\nconst isEmpty = (field) => {\n if ([null, undefined].includes(field)) {\n return true;\n }\n if (Array.isArray(field)) {\n return field.length === 0;\n }\n if (typeof field === 'object' && !(field instanceof Date)) {\n return Object.keys(field).length === 0;\n }\n return false;\n};\n\nexport const isEntityIdRequired = (action: string): boolean => !ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT[action];\n\nconst filterOutEmptyFields = (fields: string[], instance) => fields.filter((field) => !isEmpty(instance.get(field)) || !isEmpty(instance.previous(field)));\n\nconst getChangedFieldsRows = (instance: Model, options: CreateOptions<any> | InstanceUpdateOptions<any>) => {\n // When bulk updating in sequelize using the \"returning\" option, the instance.changed() stops working.\n // It's a known issue with sequelize.\n const changedFields: string[] = options.returning ? options.fields as string[] : instance.changed() as string[];\n // Filter customFields - we'll handle them later\n const filteredChangedFields = filterOutEmptyFields(changedFields.filter((field) => field !== CUSTOM_FIELDS_PROPERTY), instance);\n return filteredChangedFields.map((property: string) => ({\n property,\n previousValue: instance.previous(property),\n newValue: instance.get(property),\n }));\n};\n\nconst getChangedCustomFieldsRows = (instance: Model) => {\n const changed = instance.changed();\n const customFieldsChanged = changed && changed.includes(CUSTOM_FIELDS_PROPERTY);\n if (!customFieldsChanged) {\n return [];\n }\n\n const customFields = instance.get(CUSTOM_FIELDS_PROPERTY);\n const previousCustomFields = instance.previous(CUSTOM_FIELDS_PROPERTY);\n const changedCustomFields = Object.keys(customFields).filter((field) => {\n const newValue = customFields?.[field];\n const oldValue = previousCustomFields?.[field];\n return (!isEmpty(newValue) || !isEmpty(oldValue)) && !isEqual(newValue, oldValue);\n });\n return changedCustomFields.map((changedCustomField) => ({\n property: `${CUSTOM_FIELDS_PROPERTY}.${changedCustomField}`,\n previousValue: previousCustomFields?.[changedCustomField],\n newValue: customFields?.[changedCustomField],\n }));\n};\n\nclass AuditLogger {\n private rabbit: RabbitMq;\n\n private sequelize: Sequelize;\n\n private logger: LoggerInstanceManager;\n\n constructor(options: AuditLoggerOptions) {\n this.rabbit = options.rabbit;\n this.sequelize = options.sequelize;\n this.logger = options.logger || logger;\n }\n\n public registerHooks(): void {\n Object.entries(this.sequelize.models).forEach(([modelName, modelType]) => {\n modelType.addHook('afterSave', async (instance, options) => {\n try {\n const auditContext = getAuditContext();\n if (!auditContext) {\n return;\n }\n if (auditContext?.entityType?.toLowerCase() === modelName?.toLowerCase() && isEntityIdRequired(auditContext.action)) {\n auditContext.entityId = (instance as any).id;\n }\n const changedFieldsRows = getChangedFieldsRows(instance, options);\n const changedCustomFieldsRows = getChangedCustomFieldsRows(instance);\n const payload: AuditLogPayload = {\n entityType: modelName,\n entityId: (instance as any).id,\n rows: [...changedFieldsRows, ...changedCustomFieldsRows],\n };\n this.sendAuditLogRows(payload);\n } catch (error) {\n this.logger.error('Failed to send audit log rows', error);\n }\n });\n });\n }\n\n public async sendAuditLogContext(context: AuditLogContext): Promise<void> {\n try {\n await this.rabbit.sendToQueue(AUDIT_LOG_CONTEXT_QUEUE, context);\n } catch (err) {\n this.logger.error('Failed to send audit log context', err);\n }\n }\n\n private async sendAuditLogRows(payload: AuditLogPayload): Promise<void> {\n try {\n await this.rabbit.sendToQueue(AUDIT_LOG_ROWS_QUEUE, payload);\n } catch (err) {\n this.logger.error('Failed to send audit log rows', err);\n }\n }\n}\n\nexport default AuditLogger;\n","import Network from '@autofleet/network';\nimport logger from './logger';\n\nconst auditMs = new Network({ serviceName: 'AUDIT_MS', timeout: 60_000, logger });\n\nconst getByEntityId = async (entityId: string): Promise<any> => {\n const { data } = await auditMs.get(`api/v1/audit-logs/${entityId}`);\n return data;\n};\n\nconst exportObj: { getByEntityId: typeof getByEntityId } = { getByEntityId };\n\nexport default exportObj;\n","import { handleError, ResourceNotFoundError, UnexpectedError } from '@autofleet/errors';\nimport auditMs from './audit-ms';\nimport { AuditLoggerOptions } from './types';\n\nexport default async ({\n router,\n logger,\n entityScopedModelMap,\n}: AuditLoggerOptions): Promise<void> => {\n if (!entityScopedModelMap || !router) {\n return;\n }\n Object.entries(entityScopedModelMap).forEach(([entity, ScopedModel]) => {\n router.get(`${entity}/:id/audit`, async (req, res) => {\n try {\n const { id } = req.params;\n const entityData = await ScopedModel.findByPk(id);\n if (!entityData) {\n return handleError(new ResourceNotFoundError(), res, { logger, message: `Entity ${entity} with id ${id} not found` });\n }\n const auditData = auditMs.getByEntityId(id);\n return res.json(auditData);\n } catch (err) {\n return handleError(new UnexpectedError(err as Error), res, { logger });\n }\n });\n });\n};\n","import { getCurrentPayload as getCurrentTrace, getUser } from '@autofleet/zehut';\nimport type { Request, Response, NextFunction } from 'express';\nimport AuditLogger, { isEntityIdRequired } from './audit-logger';\nimport { ActionOrigin, type AuditLogContext, type AuditLoggerOptions } from './types';\nimport { AUDIT_LOG_CONTEXT_KEY, AUTOMATION_ID_HEADER } from './const';\nimport addAuditApi from './audit-api';\nimport logger from './logger';\n\nlet auditLogger: AuditLogger | undefined;\n\nexport const enableAuditing = (options: AuditLoggerOptions): void => {\n if (process.env.DISABLE_AUDIT_LOGS === 'true') {\n return;\n }\n auditLogger = new AuditLogger(options);\n addAuditApi(options);\n auditLogger.registerHooks();\n};\n\nexport const setAuditContext = (\n entityType: string,\n action: string,\n) => async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n if (process.env.DISABLE_AUDIT_LOGS === 'true' || !auditLogger) {\n return next();\n }\n const user = getUser();\n const automationId = req.headers[AUTOMATION_ID_HEADER] as string | undefined;\n const { performedBy, actionOrigin } = user?.id\n ? { performedBy: user.id, actionOrigin: ActionOrigin.USER }\n : { performedBy: automationId ?? null, actionOrigin: automationId ? ActionOrigin.AUTOMATION : null };\n const auditLogContext: AuditLogContext = {\n entityType,\n action,\n endpoint: req.url,\n method: req.method,\n performedBy,\n actionOrigin,\n };\n\n const currentTrace = getCurrentTrace();\n currentTrace.nonHeaderContext.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);\n\n const sendAuditLogContextEvent = async () => {\n res.off('finish', sendAuditLogContextEvent);\n res.off('close', sendAuditLogContextEvent);\n res.off('error', sendAuditLogContextEvent);\n await auditLogger.sendAuditLogContext(auditLogContext);\n };\n if (!isEntityIdRequired(action)) { // if it's a bulk action, we don't want to wait for the response to add the entity id\n await auditLogger.sendAuditLogContext(auditLogContext);\n } else {\n res.once('finish', sendAuditLogContextEvent);\n res.once('close', sendAuditLogContextEvent);\n res.once('error', sendAuditLogContextEvent);\n }\n } catch (err) {\n logger.error('coudln\\'t set audit context', err);\n }\n return next();\n};\n\nexport const setRabbitAuditContext = (\n entityType: string,\n action: string,\n) => async (endpoint: string, { userId, automationId }: { userId:string; automationId:string; }): Promise<void> => {\n if (process.env.DISABLE_AUDIT_LOGS === 'true' || !auditLogger) {\n return;\n }\n const currentTrace = getCurrentTrace();\n if (currentTrace?.context?.get) {\n const { performedBy, actionOrigin } = userId\n ? { performedBy: userId, actionOrigin: ActionOrigin.USER }\n : { performedBy: automationId ?? null, actionOrigin: automationId ? ActionOrigin.AUTOMATION : null };\n const auditLogContext: AuditLogContext = {\n entityType,\n action,\n endpoint,\n method: 'rabbit',\n performedBy,\n actionOrigin,\n };\n currentTrace.nonHeaderContext.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);\n await auditLogger.sendAuditLogContext(auditLogContext);\n }\n};\n\nexport * from './types';\nexport * from './const';\n\nexport default AuditLogger;\n"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { IRouter, NextFunction, Request, Response } from "express";
|
|
2
|
+
import { Model, ModelStatic } from "sequelize";
|
|
3
|
+
import { Sequelize } from "sequelize-typescript";
|
|
4
|
+
import RabbitMq from "@autofleet/rabbit";
|
|
5
|
+
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
6
|
+
|
|
7
|
+
//#region src/types.d.ts
|
|
8
|
+
type AuditLoggerOptions = {
|
|
9
|
+
rabbit: RabbitMq;
|
|
10
|
+
sequelize: Sequelize;
|
|
11
|
+
logger: LoggerInstanceManager;
|
|
12
|
+
router?: IRouter;
|
|
13
|
+
entityScopedModelMap?: {
|
|
14
|
+
[modelName: string]: ModelStatic<Model>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
interface AuditLogContext {
|
|
18
|
+
entityType: string;
|
|
19
|
+
entityId?: string;
|
|
20
|
+
action: string;
|
|
21
|
+
performedBy: string;
|
|
22
|
+
endpoint: string;
|
|
23
|
+
method: string;
|
|
24
|
+
actionOrigin?: string;
|
|
25
|
+
}
|
|
26
|
+
interface AuditLogRow {
|
|
27
|
+
property: string;
|
|
28
|
+
previousValue: any;
|
|
29
|
+
newValue: any;
|
|
30
|
+
}
|
|
31
|
+
interface AuditLogPayload {
|
|
32
|
+
entityType: string;
|
|
33
|
+
entityId: string;
|
|
34
|
+
rows: AuditLogRow[];
|
|
35
|
+
}
|
|
36
|
+
declare enum Action {
|
|
37
|
+
CREATE = "create",
|
|
38
|
+
BULK_CREATE = "bulk-create",
|
|
39
|
+
BULK_EDIT = "bulk-edit",
|
|
40
|
+
DELETE = "delete",
|
|
41
|
+
UPDATE = "update",
|
|
42
|
+
CANCEL = "cancel",
|
|
43
|
+
FAIL = "fail",
|
|
44
|
+
UNASSIGN = "unassign",
|
|
45
|
+
BULK_ASSIGN = "bulk-assign",
|
|
46
|
+
REASSIGN = "reassign",
|
|
47
|
+
DISPATCH = "dispatch",
|
|
48
|
+
BULK_DISPATCH = "bulk-dispatch",
|
|
49
|
+
BULK_UPSERT = "bulk-upsert",
|
|
50
|
+
UPSERT = "upsert",
|
|
51
|
+
JOIN = "join",
|
|
52
|
+
MOVE = "move",
|
|
53
|
+
REOPTIMIZATION = "reoptimization",
|
|
54
|
+
}
|
|
55
|
+
declare enum EntityType {
|
|
56
|
+
RIDE = "Ride",
|
|
57
|
+
VEHICLE = "Vehicle",
|
|
58
|
+
DRIVER = "Driver",
|
|
59
|
+
PRICE_CALCULATION = "PriceCalculation",
|
|
60
|
+
}
|
|
61
|
+
declare const enum ActionOrigin {
|
|
62
|
+
USER = "user",
|
|
63
|
+
AUTOMATION = "automation",
|
|
64
|
+
} //#endregion
|
|
65
|
+
//#region src/audit-logger.d.ts
|
|
66
|
+
declare class AuditLogger {
|
|
67
|
+
private rabbit;
|
|
68
|
+
private sequelize;
|
|
69
|
+
private logger;
|
|
70
|
+
constructor(options: AuditLoggerOptions);
|
|
71
|
+
registerHooks(): void;
|
|
72
|
+
sendAuditLogContext(context: AuditLogContext): Promise<void>;
|
|
73
|
+
private sendAuditLogRows;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/const.d.ts
|
|
78
|
+
declare const AUDIT_LOG_CONTEXT_QUEUE = "audit-log-context";
|
|
79
|
+
declare const AUDIT_LOG_ROWS_QUEUE = "audit-log-rows";
|
|
80
|
+
declare const AUDIT_LOG_CONTEXT_KEY = "auditLogContext";
|
|
81
|
+
declare const AUTOMATION_ID_HEADER = "x-af-automation-id";
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/index.d.ts
|
|
85
|
+
declare const enableAuditing: (options: AuditLoggerOptions) => void;
|
|
86
|
+
declare const setAuditContext: (entityType: string, action: string) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
87
|
+
declare const setRabbitAuditContext: (entityType: string, action: string) => (endpoint: string, {
|
|
88
|
+
userId,
|
|
89
|
+
automationId
|
|
90
|
+
}: {
|
|
91
|
+
userId: string;
|
|
92
|
+
automationId: string;
|
|
93
|
+
}) => Promise<void>;
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { AUDIT_LOG_CONTEXT_KEY, AUDIT_LOG_CONTEXT_QUEUE, AUDIT_LOG_ROWS_QUEUE, AUTOMATION_ID_HEADER, Action, ActionOrigin, AuditLogContext, AuditLogPayload, AuditLogRow, AuditLoggerOptions, EntityType, AuditLogger as default, enableAuditing, setAuditContext, setRabbitAuditContext };
|
|
97
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,97 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
2
|
+
import { IRouter, NextFunction, Request, Response } from "express";
|
|
3
|
+
import { Model, ModelStatic } from "sequelize";
|
|
4
|
+
import { Sequelize } from "sequelize-typescript";
|
|
5
|
+
import RabbitMq from "@autofleet/rabbit";
|
|
6
|
+
|
|
7
|
+
//#region src/types.d.ts
|
|
8
|
+
type AuditLoggerOptions = {
|
|
9
|
+
rabbit: RabbitMq;
|
|
10
|
+
sequelize: Sequelize;
|
|
11
|
+
logger: LoggerInstanceManager;
|
|
12
|
+
router?: IRouter;
|
|
13
|
+
entityScopedModelMap?: {
|
|
14
|
+
[modelName: string]: ModelStatic<Model>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
interface AuditLogContext {
|
|
18
|
+
entityType: string;
|
|
19
|
+
entityId?: string;
|
|
20
|
+
action: string;
|
|
21
|
+
performedBy: string;
|
|
22
|
+
endpoint: string;
|
|
23
|
+
method: string;
|
|
24
|
+
actionOrigin?: string;
|
|
25
|
+
}
|
|
26
|
+
interface AuditLogRow {
|
|
27
|
+
property: string;
|
|
28
|
+
previousValue: any;
|
|
29
|
+
newValue: any;
|
|
30
|
+
}
|
|
31
|
+
interface AuditLogPayload {
|
|
32
|
+
entityType: string;
|
|
33
|
+
entityId: string;
|
|
34
|
+
rows: AuditLogRow[];
|
|
35
|
+
}
|
|
36
|
+
declare enum Action {
|
|
37
|
+
CREATE = "create",
|
|
38
|
+
BULK_CREATE = "bulk-create",
|
|
39
|
+
BULK_EDIT = "bulk-edit",
|
|
40
|
+
DELETE = "delete",
|
|
41
|
+
UPDATE = "update",
|
|
42
|
+
CANCEL = "cancel",
|
|
43
|
+
FAIL = "fail",
|
|
44
|
+
UNASSIGN = "unassign",
|
|
45
|
+
BULK_ASSIGN = "bulk-assign",
|
|
46
|
+
REASSIGN = "reassign",
|
|
47
|
+
DISPATCH = "dispatch",
|
|
48
|
+
BULK_DISPATCH = "bulk-dispatch",
|
|
49
|
+
BULK_UPSERT = "bulk-upsert",
|
|
50
|
+
UPSERT = "upsert",
|
|
51
|
+
JOIN = "join",
|
|
52
|
+
MOVE = "move",
|
|
53
|
+
REOPTIMIZATION = "reoptimization",
|
|
54
|
+
}
|
|
55
|
+
declare enum EntityType {
|
|
56
|
+
RIDE = "Ride",
|
|
57
|
+
VEHICLE = "Vehicle",
|
|
58
|
+
DRIVER = "Driver",
|
|
59
|
+
PRICE_CALCULATION = "PriceCalculation",
|
|
60
|
+
}
|
|
61
|
+
declare const enum ActionOrigin {
|
|
62
|
+
USER = "user",
|
|
63
|
+
AUTOMATION = "automation",
|
|
64
|
+
} //#endregion
|
|
65
|
+
//#region src/audit-logger.d.ts
|
|
66
|
+
declare class AuditLogger {
|
|
67
|
+
private rabbit;
|
|
68
|
+
private sequelize;
|
|
69
|
+
private logger;
|
|
70
|
+
constructor(options: AuditLoggerOptions);
|
|
71
|
+
registerHooks(): void;
|
|
72
|
+
sendAuditLogContext(context: AuditLogContext): Promise<void>;
|
|
73
|
+
private sendAuditLogRows;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/const.d.ts
|
|
78
|
+
declare const AUDIT_LOG_CONTEXT_QUEUE = "audit-log-context";
|
|
79
|
+
declare const AUDIT_LOG_ROWS_QUEUE = "audit-log-rows";
|
|
80
|
+
declare const AUDIT_LOG_CONTEXT_KEY = "auditLogContext";
|
|
81
|
+
declare const AUTOMATION_ID_HEADER = "x-af-automation-id";
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/index.d.ts
|
|
85
|
+
declare const enableAuditing: (options: AuditLoggerOptions) => void;
|
|
86
|
+
declare const setAuditContext: (entityType: string, action: string) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
87
|
+
declare const setRabbitAuditContext: (entityType: string, action: string) => (endpoint: string, {
|
|
88
|
+
userId,
|
|
89
|
+
automationId
|
|
90
|
+
}: {
|
|
91
|
+
userId: string;
|
|
92
|
+
automationId: string;
|
|
93
|
+
}) => Promise<void>;
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { AUDIT_LOG_CONTEXT_KEY, AUDIT_LOG_CONTEXT_QUEUE, AUDIT_LOG_ROWS_QUEUE, AUTOMATION_ID_HEADER, Action, ActionOrigin, AuditLogContext, AuditLogPayload, AuditLogRow, AuditLoggerOptions, EntityType, AuditLogger as default, enableAuditing, setAuditContext, setRabbitAuditContext };
|
|
97
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,122 +1,2 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
26
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
27
|
-
};
|
|
28
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
29
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
30
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
31
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
32
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
33
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
34
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
|
-
};
|
|
40
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
exports.setRabbitAuditContext = exports.setAuditContext = exports.enableAuditing = void 0;
|
|
42
|
-
const zehut_1 = require("@autofleet/zehut");
|
|
43
|
-
const audit_logger_1 = __importStar(require("./audit-logger"));
|
|
44
|
-
const const_1 = require("./const");
|
|
45
|
-
const audit_api_1 = __importDefault(require("./audit-api"));
|
|
46
|
-
const logger_1 = __importDefault(require("./logger"));
|
|
47
|
-
let auditLogger;
|
|
48
|
-
const enableAuditing = (options) => {
|
|
49
|
-
if (process.env.DISABLE_AUDIT_LOGS !== 'true') {
|
|
50
|
-
auditLogger = new audit_logger_1.default(options);
|
|
51
|
-
(0, audit_api_1.default)(options);
|
|
52
|
-
auditLogger.registerHooks();
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
exports.enableAuditing = enableAuditing;
|
|
56
|
-
const setAuditContext = (entityType, action) => (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
-
var _a, _b;
|
|
58
|
-
try {
|
|
59
|
-
const currentTrace = (0, zehut_1.getCurrentPayload)();
|
|
60
|
-
if (process.env.DISABLE_AUDIT_LOGS === 'true' || !((_a = currentTrace === null || currentTrace === void 0 ? void 0 : currentTrace.context) === null || _a === void 0 ? void 0 : _a.get)) {
|
|
61
|
-
return next();
|
|
62
|
-
}
|
|
63
|
-
const user = currentTrace.context.get(const_1.USER_CONTEXT_KEY);
|
|
64
|
-
const { performedBy, actionOrigin } = (user === null || user === void 0 ? void 0 : user.id)
|
|
65
|
-
? { performedBy: user.id, actionOrigin: "user" /* ActionOrigin.USER */ }
|
|
66
|
-
: { performedBy: (_b = req.headers[const_1.AUTOMATION_ID_HEADER]) !== null && _b !== void 0 ? _b : null, actionOrigin: req.headers[const_1.AUTOMATION_ID_HEADER] ? "automation" /* ActionOrigin.AUTOMATION */ : null };
|
|
67
|
-
const auditLogContext = {
|
|
68
|
-
entityType,
|
|
69
|
-
action,
|
|
70
|
-
endpoint: req.url,
|
|
71
|
-
method: req.method,
|
|
72
|
-
performedBy,
|
|
73
|
-
actionOrigin,
|
|
74
|
-
};
|
|
75
|
-
currentTrace.context.set(const_1.AUDIT_LOG_CONTEXT_KEY, auditLogContext);
|
|
76
|
-
const sendAuditLogContextEvent = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
77
|
-
res.off('finish', sendAuditLogContextEvent);
|
|
78
|
-
res.off('close', sendAuditLogContextEvent);
|
|
79
|
-
res.off('error', sendAuditLogContextEvent);
|
|
80
|
-
yield auditLogger.sendAuditLogContext(auditLogContext);
|
|
81
|
-
});
|
|
82
|
-
if (!(0, audit_logger_1.isEntityIdRequired)(action)) { // if it's a bulk action, we don't want to wait for the response to add the entity id
|
|
83
|
-
yield auditLogger.sendAuditLogContext(auditLogContext);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
res.once('finish', sendAuditLogContextEvent);
|
|
87
|
-
res.once('close', sendAuditLogContextEvent);
|
|
88
|
-
res.once('error', sendAuditLogContextEvent);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (err) {
|
|
92
|
-
logger_1.default.error('coudln\'t set audit context', err);
|
|
93
|
-
}
|
|
94
|
-
return next();
|
|
95
|
-
});
|
|
96
|
-
exports.setAuditContext = setAuditContext;
|
|
97
|
-
const setRabbitAuditContext = (entityType, action) => (endpoint, { userId, automationId }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
-
var _c;
|
|
99
|
-
if (process.env.DISABLE_AUDIT_LOGS === 'true') {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const currentTrace = (0, zehut_1.getCurrentPayload)();
|
|
103
|
-
if ((_c = currentTrace === null || currentTrace === void 0 ? void 0 : currentTrace.context) === null || _c === void 0 ? void 0 : _c.get) {
|
|
104
|
-
const { performedBy, actionOrigin } = userId
|
|
105
|
-
? { performedBy: userId, actionOrigin: "user" /* ActionOrigin.USER */ }
|
|
106
|
-
: { performedBy: automationId !== null && automationId !== void 0 ? automationId : null, actionOrigin: automationId ? "automation" /* ActionOrigin.AUTOMATION */ : null };
|
|
107
|
-
const auditLogContext = {
|
|
108
|
-
entityType,
|
|
109
|
-
action,
|
|
110
|
-
endpoint,
|
|
111
|
-
method: 'rabbit',
|
|
112
|
-
performedBy,
|
|
113
|
-
actionOrigin,
|
|
114
|
-
};
|
|
115
|
-
currentTrace.context.set(const_1.AUDIT_LOG_CONTEXT_KEY, auditLogContext);
|
|
116
|
-
yield auditLogger.sendAuditLogContext(auditLogContext);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
exports.setRabbitAuditContext = setRabbitAuditContext;
|
|
120
|
-
__exportStar(require("./types"), exports);
|
|
121
|
-
__exportStar(require("./const"), exports);
|
|
122
|
-
exports.default = audit_logger_1.default;
|
|
1
|
+
import{getCurrentPayload as e,getUser as t}from"@autofleet/zehut";import{isEqual as n}from"lodash";import r from"@autofleet/logger";import{ResourceNotFoundError as i,UnexpectedError as a,handleError as o}from"@autofleet/errors";import s from"@autofleet/network";let c=/* @__PURE__ */ function(e){return e.CREATE=`create`,e.BULK_CREATE=`bulk-create`,e.BULK_EDIT=`bulk-edit`,e.DELETE=`delete`,e.UPDATE=`update`,e.CANCEL=`cancel`,e.FAIL=`fail`,e.UNASSIGN=`unassign`,e.BULK_ASSIGN=`bulk-assign`,e.REASSIGN=`reassign`,e.DISPATCH=`dispatch`,e.BULK_DISPATCH=`bulk-dispatch`,e.BULK_UPSERT=`bulk-upsert`,e.UPSERT=`upsert`,e.JOIN=`join`,e.MOVE=`move`,e.REOPTIMIZATION=`reoptimization`,e}({}),l=/* @__PURE__ */ function(e){return e.RIDE=`Ride`,e.VEHICLE=`Vehicle`,e.DRIVER=`Driver`,e.PRICE_CALCULATION=`PriceCalculation`,e}({}),u=/* @__PURE__ */ function(e){return e.USER=`user`,e.AUTOMATION=`automation`,e}({});const d=`audit-log-context`,f=`audit-log-rows`,p=`auditLogContext`,m=`x-af-automation-id`,h=r(null);var g=h;const _=`customFields`,v=()=>{let t=e(),n=t?.nonHeaderContext?.get(p);return n},y={[c.BULK_CREATE]:c.BULK_CREATE,[c.BULK_EDIT]:c.BULK_EDIT,[c.BULK_ASSIGN]:c.BULK_ASSIGN,[c.BULK_DISPATCH]:c.BULK_DISPATCH,[c.BULK_UPSERT]:c.BULK_UPSERT},b=e=>[null,void 0].includes(e)?!0:Array.isArray(e)?e.length===0:typeof e==`object`&&!(e instanceof Date)?Object.keys(e).length===0:!1,x=e=>!y[e],S=(e,t)=>e.filter(e=>!b(t.get(e))||!b(t.previous(e))),C=(e,t)=>{let n=t.returning?t.fields:e.changed(),r=S(n.filter(e=>e!==_),e);return r.map(t=>({property:t,previousValue:e.previous(t),newValue:e.get(t)}))},w=e=>{let t=e.changed(),r=t&&t.includes(_);if(!r)return[];let i=e.get(_),a=e.previous(_),o=Object.keys(i).filter(e=>{let t=i?.[e],r=a?.[e];return(!b(t)||!b(r))&&!n(t,r)});return o.map(e=>({property:`${_}.${e}`,previousValue:a?.[e],newValue:i?.[e]}))};var T=class{constructor(e){this.rabbit=e.rabbit,this.sequelize=e.sequelize,this.logger=e.logger||g}registerHooks(){Object.entries(this.sequelize.models).forEach(([e,t])=>{t.addHook(`afterSave`,async(t,n)=>{try{let r=v();if(!r)return;r?.entityType?.toLowerCase()===e?.toLowerCase()&&x(r.action)&&(r.entityId=t.id);let i=C(t,n),a=w(t),o={entityType:e,entityId:t.id,rows:[...i,...a]};this.sendAuditLogRows(o)}catch(e){this.logger.error(`Failed to send audit log rows`,e)}})})}async sendAuditLogContext(e){try{await this.rabbit.sendToQueue(d,e)}catch(e){this.logger.error(`Failed to send audit log context`,e)}}async sendAuditLogRows(e){try{await this.rabbit.sendToQueue(f,e)}catch(e){this.logger.error(`Failed to send audit log rows`,e)}}},E=T;const D=new s({serviceName:`AUDIT_MS`,timeout:6e4,logger:g}),O=async e=>{let{data:t}=await D.get(`api/v1/audit-logs/${e}`);return t},k={getByEntityId:O};var A=k,j=async({router:e,logger:t,entityScopedModelMap:n})=>{!n||!e||Object.entries(n).forEach(([n,r])=>{e.get(`${n}/:id/audit`,async(e,s)=>{try{let{id:a}=e.params,c=await r.findByPk(a);if(!c)return o(new i,s,{logger:t,message:`Entity ${n} with id ${a} not found`});let l=A.getByEntityId(a);return s.json(l)}catch(e){return o(new a(e),s,{logger:t})}})})};let M;const N=e=>{process.env.DISABLE_AUDIT_LOGS!==`true`&&(M=new E(e),j(e),M.registerHooks())},P=(n,r)=>async(i,a,o)=>{try{if(process.env.DISABLE_AUDIT_LOGS===`true`||!M)return o();let s=t(),c=i.headers[m],{performedBy:l,actionOrigin:d}=s?.id?{performedBy:s.id,actionOrigin:u.USER}:{performedBy:c??null,actionOrigin:c?u.AUTOMATION:null},f={entityType:n,action:r,endpoint:i.url,method:i.method,performedBy:l,actionOrigin:d},h=e();h.nonHeaderContext.set(p,f);let g=async()=>{a.off(`finish`,g),a.off(`close`,g),a.off(`error`,g),await M.sendAuditLogContext(f)};x(r)?(a.once(`finish`,g),a.once(`close`,g),a.once(`error`,g)):await M.sendAuditLogContext(f)}catch(e){g.error(`coudln't set audit context`,e)}return o()},F=(t,n)=>async(r,{userId:i,automationId:a})=>{if(process.env.DISABLE_AUDIT_LOGS===`true`||!M)return;let o=e();if(o?.context?.get){let{performedBy:e,actionOrigin:s}=i?{performedBy:i,actionOrigin:u.USER}:{performedBy:a??null,actionOrigin:a?u.AUTOMATION:null},c={entityType:t,action:n,endpoint:r,method:`rabbit`,performedBy:e,actionOrigin:s};o.nonHeaderContext.set(p,c),await M.sendAuditLogContext(c)}};var I=E;export{p as AUDIT_LOG_CONTEXT_KEY,d as AUDIT_LOG_CONTEXT_QUEUE,f as AUDIT_LOG_ROWS_QUEUE,m as AUTOMATION_ID_HEADER,c as Action,u as ActionOrigin,l as EntityType,I as default,N as enableAuditing,P as setAuditContext,F as setRabbitAuditContext};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["logger: LoggerInstanceManager","action: string","fields: string[]","instance: Model","options: CreateOptions<any> | InstanceUpdateOptions<any>","changedFields: string[]","property: string","options: AuditLoggerOptions","payload: AuditLogPayload","context: AuditLogContext","entityId: string","exportObj: { getByEntityId: typeof getByEntityId }","auditLogger: AuditLogger | undefined","options: AuditLoggerOptions","entityType: string","action: string","req: Request","res: Response","next: NextFunction","auditLogContext: AuditLogContext","endpoint: string"],"sources":["../src/types.ts","../src/const.ts","../src/logger.ts","../src/audit-logger.ts","../src/audit-ms.ts","../src/audit-api.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable no-shadow */\nimport type { ModelStatic, Model } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport type RabbitMq from '@autofleet/rabbit';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport type { IRouter } from 'express';\n\nexport type AuditLoggerOptions = {\n rabbit: RabbitMq;\n sequelize: Sequelize;\n logger: LoggerInstanceManager;\n router?: IRouter;\n entityScopedModelMap?: { [modelName: string]: ModelStatic<Model> };\n};\n\nexport interface AuditLogContext {\n entityType: string;\n entityId?: string;\n action: string;\n performedBy: string;\n endpoint: string;\n method: string;\n actionOrigin?: string;\n}\n\nexport interface AuditLogRow {\n property: string;\n previousValue: any;\n newValue: any;\n}\n\nexport interface AuditLogPayload {\n entityType: string;\n entityId: string;\n rows: AuditLogRow[];\n}\n\nexport enum Action {\n CREATE = 'create',\n BULK_CREATE = 'bulk-create',\n BULK_EDIT = 'bulk-edit',\n DELETE = 'delete',\n UPDATE = 'update',\n CANCEL = 'cancel',\n FAIL = 'fail',\n UNASSIGN = 'unassign',\n BULK_ASSIGN = 'bulk-assign',\n REASSIGN = 'reassign',\n DISPATCH = 'dispatch',\n BULK_DISPATCH = 'bulk-dispatch',\n BULK_UPSERT = 'bulk-upsert',\n UPSERT = 'upsert',\n JOIN = 'join',\n MOVE = 'move',\n REOPTIMIZATION = 'reoptimization',\n}\n\nexport enum EntityType {\n RIDE = 'Ride',\n VEHICLE = 'Vehicle',\n DRIVER = 'Driver',\n PRICE_CALCULATION = 'PriceCalculation',\n}\n\nexport const enum ActionOrigin {\n USER = 'user',\n AUTOMATION = 'automation',\n}\n","export const AUDIT_LOG_CONTEXT_QUEUE = 'audit-log-context';\nexport const AUDIT_LOG_ROWS_QUEUE = 'audit-log-rows';\nexport const AUDIT_LOG_CONTEXT_KEY = 'auditLogContext';\nexport const AUTOMATION_ID_HEADER = 'x-af-automation-id';\n","import Logger, { type LoggerInstanceManager } from '@autofleet/logger';\n\nconst logger: LoggerInstanceManager = Logger(null);\nexport default logger;\n","import type RabbitMq from '@autofleet/rabbit';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport { getCurrentPayload as getCurrentTrace } from '@autofleet/zehut';\nimport type {\n CreateOptions, InstanceUpdateOptions, Model, Sequelize,\n} from 'sequelize';\nimport { isEqual } from 'lodash';\nimport {\n type AuditLogPayload, type AuditLoggerOptions, type AuditLogContext, Action,\n} from './types';\nimport { AUDIT_LOG_CONTEXT_QUEUE, AUDIT_LOG_ROWS_QUEUE, AUDIT_LOG_CONTEXT_KEY } from './const';\nimport logger from './logger';\n\nconst CUSTOM_FIELDS_PROPERTY = 'customFields';\n\nconst getAuditContext = () => {\n const currentTrace = getCurrentTrace();\n const auditContext = currentTrace?.nonHeaderContext?.get(AUDIT_LOG_CONTEXT_KEY);\n return auditContext as AuditLogContext;\n};\n\nconst ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT = {\n [Action.BULK_CREATE]: Action.BULK_CREATE,\n [Action.BULK_EDIT]: Action.BULK_EDIT,\n [Action.BULK_ASSIGN]: Action.BULK_ASSIGN,\n [Action.BULK_DISPATCH]: Action.BULK_DISPATCH,\n [Action.BULK_UPSERT]: Action.BULK_UPSERT,\n};\n\nconst isEmpty = (field) => {\n if ([null, undefined].includes(field)) {\n return true;\n }\n if (Array.isArray(field)) {\n return field.length === 0;\n }\n if (typeof field === 'object' && !(field instanceof Date)) {\n return Object.keys(field).length === 0;\n }\n return false;\n};\n\nexport const isEntityIdRequired = (action: string): boolean => !ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT[action];\n\nconst filterOutEmptyFields = (fields: string[], instance) => fields.filter((field) => !isEmpty(instance.get(field)) || !isEmpty(instance.previous(field)));\n\nconst getChangedFieldsRows = (instance: Model, options: CreateOptions<any> | InstanceUpdateOptions<any>) => {\n // When bulk updating in sequelize using the \"returning\" option, the instance.changed() stops working.\n // It's a known issue with sequelize.\n const changedFields: string[] = options.returning ? options.fields as string[] : instance.changed() as string[];\n // Filter customFields - we'll handle them later\n const filteredChangedFields = filterOutEmptyFields(changedFields.filter((field) => field !== CUSTOM_FIELDS_PROPERTY), instance);\n return filteredChangedFields.map((property: string) => ({\n property,\n previousValue: instance.previous(property),\n newValue: instance.get(property),\n }));\n};\n\nconst getChangedCustomFieldsRows = (instance: Model) => {\n const changed = instance.changed();\n const customFieldsChanged = changed && changed.includes(CUSTOM_FIELDS_PROPERTY);\n if (!customFieldsChanged) {\n return [];\n }\n\n const customFields = instance.get(CUSTOM_FIELDS_PROPERTY);\n const previousCustomFields = instance.previous(CUSTOM_FIELDS_PROPERTY);\n const changedCustomFields = Object.keys(customFields).filter((field) => {\n const newValue = customFields?.[field];\n const oldValue = previousCustomFields?.[field];\n return (!isEmpty(newValue) || !isEmpty(oldValue)) && !isEqual(newValue, oldValue);\n });\n return changedCustomFields.map((changedCustomField) => ({\n property: `${CUSTOM_FIELDS_PROPERTY}.${changedCustomField}`,\n previousValue: previousCustomFields?.[changedCustomField],\n newValue: customFields?.[changedCustomField],\n }));\n};\n\nclass AuditLogger {\n private rabbit: RabbitMq;\n\n private sequelize: Sequelize;\n\n private logger: LoggerInstanceManager;\n\n constructor(options: AuditLoggerOptions) {\n this.rabbit = options.rabbit;\n this.sequelize = options.sequelize;\n this.logger = options.logger || logger;\n }\n\n public registerHooks(): void {\n Object.entries(this.sequelize.models).forEach(([modelName, modelType]) => {\n modelType.addHook('afterSave', async (instance, options) => {\n try {\n const auditContext = getAuditContext();\n if (!auditContext) {\n return;\n }\n if (auditContext?.entityType?.toLowerCase() === modelName?.toLowerCase() && isEntityIdRequired(auditContext.action)) {\n auditContext.entityId = (instance as any).id;\n }\n const changedFieldsRows = getChangedFieldsRows(instance, options);\n const changedCustomFieldsRows = getChangedCustomFieldsRows(instance);\n const payload: AuditLogPayload = {\n entityType: modelName,\n entityId: (instance as any).id,\n rows: [...changedFieldsRows, ...changedCustomFieldsRows],\n };\n this.sendAuditLogRows(payload);\n } catch (error) {\n this.logger.error('Failed to send audit log rows', error);\n }\n });\n });\n }\n\n public async sendAuditLogContext(context: AuditLogContext): Promise<void> {\n try {\n await this.rabbit.sendToQueue(AUDIT_LOG_CONTEXT_QUEUE, context);\n } catch (err) {\n this.logger.error('Failed to send audit log context', err);\n }\n }\n\n private async sendAuditLogRows(payload: AuditLogPayload): Promise<void> {\n try {\n await this.rabbit.sendToQueue(AUDIT_LOG_ROWS_QUEUE, payload);\n } catch (err) {\n this.logger.error('Failed to send audit log rows', err);\n }\n }\n}\n\nexport default AuditLogger;\n","import Network from '@autofleet/network';\nimport logger from './logger';\n\nconst auditMs = new Network({ serviceName: 'AUDIT_MS', timeout: 60_000, logger });\n\nconst getByEntityId = async (entityId: string): Promise<any> => {\n const { data } = await auditMs.get(`api/v1/audit-logs/${entityId}`);\n return data;\n};\n\nconst exportObj: { getByEntityId: typeof getByEntityId } = { getByEntityId };\n\nexport default exportObj;\n","import { handleError, ResourceNotFoundError, UnexpectedError } from '@autofleet/errors';\nimport auditMs from './audit-ms';\nimport { AuditLoggerOptions } from './types';\n\nexport default async ({\n router,\n logger,\n entityScopedModelMap,\n}: AuditLoggerOptions): Promise<void> => {\n if (!entityScopedModelMap || !router) {\n return;\n }\n Object.entries(entityScopedModelMap).forEach(([entity, ScopedModel]) => {\n router.get(`${entity}/:id/audit`, async (req, res) => {\n try {\n const { id } = req.params;\n const entityData = await ScopedModel.findByPk(id);\n if (!entityData) {\n return handleError(new ResourceNotFoundError(), res, { logger, message: `Entity ${entity} with id ${id} not found` });\n }\n const auditData = auditMs.getByEntityId(id);\n return res.json(auditData);\n } catch (err) {\n return handleError(new UnexpectedError(err as Error), res, { logger });\n }\n });\n });\n};\n","import { getCurrentPayload as getCurrentTrace, getUser } from '@autofleet/zehut';\nimport type { Request, Response, NextFunction } from 'express';\nimport AuditLogger, { isEntityIdRequired } from './audit-logger';\nimport { ActionOrigin, type AuditLogContext, type AuditLoggerOptions } from './types';\nimport { AUDIT_LOG_CONTEXT_KEY, AUTOMATION_ID_HEADER } from './const';\nimport addAuditApi from './audit-api';\nimport logger from './logger';\n\nlet auditLogger: AuditLogger | undefined;\n\nexport const enableAuditing = (options: AuditLoggerOptions): void => {\n if (process.env.DISABLE_AUDIT_LOGS === 'true') {\n return;\n }\n auditLogger = new AuditLogger(options);\n addAuditApi(options);\n auditLogger.registerHooks();\n};\n\nexport const setAuditContext = (\n entityType: string,\n action: string,\n) => async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n if (process.env.DISABLE_AUDIT_LOGS === 'true' || !auditLogger) {\n return next();\n }\n const user = getUser();\n const automationId = req.headers[AUTOMATION_ID_HEADER] as string | undefined;\n const { performedBy, actionOrigin } = user?.id\n ? { performedBy: user.id, actionOrigin: ActionOrigin.USER }\n : { performedBy: automationId ?? null, actionOrigin: automationId ? ActionOrigin.AUTOMATION : null };\n const auditLogContext: AuditLogContext = {\n entityType,\n action,\n endpoint: req.url,\n method: req.method,\n performedBy,\n actionOrigin,\n };\n\n const currentTrace = getCurrentTrace();\n currentTrace.nonHeaderContext.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);\n\n const sendAuditLogContextEvent = async () => {\n res.off('finish', sendAuditLogContextEvent);\n res.off('close', sendAuditLogContextEvent);\n res.off('error', sendAuditLogContextEvent);\n await auditLogger.sendAuditLogContext(auditLogContext);\n };\n if (!isEntityIdRequired(action)) { // if it's a bulk action, we don't want to wait for the response to add the entity id\n await auditLogger.sendAuditLogContext(auditLogContext);\n } else {\n res.once('finish', sendAuditLogContextEvent);\n res.once('close', sendAuditLogContextEvent);\n res.once('error', sendAuditLogContextEvent);\n }\n } catch (err) {\n logger.error('coudln\\'t set audit context', err);\n }\n return next();\n};\n\nexport const setRabbitAuditContext = (\n entityType: string,\n action: string,\n) => async (endpoint: string, { userId, automationId }: { userId:string; automationId:string; }): Promise<void> => {\n if (process.env.DISABLE_AUDIT_LOGS === 'true' || !auditLogger) {\n return;\n }\n const currentTrace = getCurrentTrace();\n if (currentTrace?.context?.get) {\n const { performedBy, actionOrigin } = userId\n ? { performedBy: userId, actionOrigin: ActionOrigin.USER }\n : { performedBy: automationId ?? null, actionOrigin: automationId ? ActionOrigin.AUTOMATION : null };\n const auditLogContext: AuditLogContext = {\n entityType,\n action,\n endpoint,\n method: 'rabbit',\n performedBy,\n actionOrigin,\n };\n currentTrace.nonHeaderContext.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);\n await auditLogger.sendAuditLogContext(auditLogContext);\n }\n};\n\nexport * from './types';\nexport * from './const';\n\nexport default AuditLogger;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,42 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/shtinker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.cjs.d.ts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
6
20
|
"scripts": {
|
|
7
21
|
"start": "ts-node src/index.ts",
|
|
8
|
-
"build": "
|
|
9
|
-
"linter": "
|
|
10
|
-
"test": "
|
|
11
|
-
"coverage": "
|
|
12
|
-
|
|
22
|
+
"build": "tsdown",
|
|
23
|
+
"linter": "eslint .",
|
|
24
|
+
"test": "vitest",
|
|
25
|
+
"coverage": "vitest --coverage"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
13
29
|
},
|
|
14
30
|
"dependencies": {
|
|
15
|
-
"@autofleet/
|
|
16
|
-
"
|
|
17
|
-
"@autofleet/network": "^1.4.7",
|
|
18
|
-
"@autofleet/rabbit": "^4.0.0",
|
|
19
|
-
"lodash": "^4.17.21",
|
|
20
|
-
"sequelize-typescript": "^2.1.5"
|
|
31
|
+
"@autofleet/network": "^1.7.5",
|
|
32
|
+
"lodash": "^4.17.21"
|
|
21
33
|
},
|
|
22
34
|
"devDependencies": {
|
|
23
|
-
"@autofleet/zehut": "^
|
|
35
|
+
"@autofleet/zehut": "^4.0.1",
|
|
24
36
|
"@types/express": "^4.17.17",
|
|
25
|
-
"@types/jest": "^27.0.9",
|
|
26
37
|
"@types/node": "^18.11.19",
|
|
27
|
-
"@types/sequelize": "^4.28.14",
|
|
28
38
|
"@typescript-eslint/eslint-plugin": "^4.8.1",
|
|
39
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
29
40
|
"eslint": "^7.13.0",
|
|
30
41
|
"eslint-config-airbnb-typescript": "^12.0.0",
|
|
31
42
|
"eslint-plugin-import": "^2.22.1",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
43
|
+
"sequelize": "^6.37.6",
|
|
44
|
+
"sequelize-typescript": "^2.1.6",
|
|
34
45
|
"ts-node": "^10.9.1",
|
|
35
|
-
"
|
|
46
|
+
"tsdown": "^0.11.3",
|
|
47
|
+
"typescript": "^5.8.3",
|
|
48
|
+
"vitest": "^3.1.3"
|
|
36
49
|
},
|
|
37
50
|
"peerDependencies": {
|
|
38
|
-
"@autofleet/
|
|
51
|
+
"@autofleet/errors": "^3",
|
|
52
|
+
"@autofleet/logger": "^4.2.1",
|
|
53
|
+
"@autofleet/rabbit": ">=3.2.25",
|
|
54
|
+
"@autofleet/zehut": "^4"
|
|
39
55
|
},
|
|
40
56
|
"author": "Autofleet",
|
|
41
|
-
"license": "
|
|
57
|
+
"license": "Proprietary",
|
|
58
|
+
"files": [
|
|
59
|
+
"dist/"
|
|
60
|
+
]
|
|
42
61
|
}
|
package/readme.md
CHANGED
|
@@ -3,3 +3,12 @@
|
|
|
3
3
|
## Breaking Changes in V2
|
|
4
4
|
- No code changes are required for services using this package.
|
|
5
5
|
- Fixed a bug where the context entity ID was incorrectly set to the ID of the last entity saved to the database under the same context. Now, the entity ID will only change when the entity type of the context matches the model name during the save operation to the database.
|
|
6
|
+
|
|
7
|
+
# V3 migration
|
|
8
|
+
|
|
9
|
+
The breaking change in this version is the removal of `zehut` from dependencies and usage as a peer-dependency.
|
|
10
|
+
The required version of zehut is now `^4.0.0`.
|
|
11
|
+
|
|
12
|
+
This was moved to being a peer-dependency in order to ensure that the version of `zehut` used here is the same as used in the MS, and not risk the package using v4 while the service is using v3, which would cause `zehut` to have multiple traces, which will not all hold the correct data.
|
|
13
|
+
|
|
14
|
+
Additionally, the minimum node version is now 18, due to the minimum version of node defined in `zehut`.
|
package/dist/audit-api.d.ts
DELETED
package/dist/audit-api.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const errors_1 = require("@autofleet/errors");
|
|
16
|
-
const audit_ms_1 = __importDefault(require("./audit-ms"));
|
|
17
|
-
exports.default = ({ router, entiyScopedModelMap, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
-
if (entiyScopedModelMap) {
|
|
19
|
-
Object.entries(entiyScopedModelMap).forEach(([entity, ScopedModel]) => {
|
|
20
|
-
router.get(`${entity}/:id/audit`, (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
-
try {
|
|
22
|
-
const { id } = req.params;
|
|
23
|
-
const entityData = yield ScopedModel.findByPk(id);
|
|
24
|
-
if (!entityData) {
|
|
25
|
-
return (0, errors_1.handleError)(new errors_1.ResourceNotFoundError(), res);
|
|
26
|
-
}
|
|
27
|
-
const auditData = audit_ms_1.default.getByEntityId(id);
|
|
28
|
-
return res.json(auditData);
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
return (0, errors_1.handleError)(new errors_1.UnexpectedError(err), res);
|
|
32
|
-
}
|
|
33
|
-
}));
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
});
|
package/dist/audit-logger.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { AuditLogPayload, AuditLoggerOptions, AuditLogContext } from './types';
|
|
2
|
-
export declare const isEntityIdRequired: (action: string) => boolean;
|
|
3
|
-
declare class AuditLogger {
|
|
4
|
-
private rabbit;
|
|
5
|
-
private sequelize;
|
|
6
|
-
private logger;
|
|
7
|
-
constructor(options: AuditLoggerOptions);
|
|
8
|
-
registerHooks(): void;
|
|
9
|
-
sendAuditLogContext(context: AuditLogContext): Promise<void>;
|
|
10
|
-
sendAuditLogRows(payload: AuditLogPayload): Promise<void>;
|
|
11
|
-
}
|
|
12
|
-
export default AuditLogger;
|
package/dist/audit-logger.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.isEntityIdRequired = void 0;
|
|
16
|
-
const zehut_1 = require("@autofleet/zehut");
|
|
17
|
-
const lodash_1 = require("lodash");
|
|
18
|
-
const types_1 = require("./types");
|
|
19
|
-
const const_1 = require("./const");
|
|
20
|
-
const logger_1 = __importDefault(require("./logger"));
|
|
21
|
-
const CUSTOM_FIELDS_PROPERTY = 'customFields';
|
|
22
|
-
const getAuditContext = () => {
|
|
23
|
-
var _a;
|
|
24
|
-
const currentTrace = (0, zehut_1.getCurrentPayload)();
|
|
25
|
-
const auditContext = (_a = currentTrace === null || currentTrace === void 0 ? void 0 : currentTrace.context) === null || _a === void 0 ? void 0 : _a.get(const_1.AUDIT_LOG_CONTEXT_KEY);
|
|
26
|
-
return auditContext;
|
|
27
|
-
};
|
|
28
|
-
const ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT = {
|
|
29
|
-
[types_1.Action.BULK_CREATE]: types_1.Action.BULK_CREATE,
|
|
30
|
-
[types_1.Action.BULK_EDIT]: types_1.Action.BULK_EDIT,
|
|
31
|
-
[types_1.Action.BULK_ASSIGN]: types_1.Action.BULK_ASSIGN,
|
|
32
|
-
[types_1.Action.BULK_DISPATCH]: types_1.Action.BULK_DISPATCH,
|
|
33
|
-
[types_1.Action.BULK_UPSERT]: types_1.Action.BULK_UPSERT,
|
|
34
|
-
};
|
|
35
|
-
const isEmpty = (field) => {
|
|
36
|
-
if ([null, undefined].includes(field)) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
if (Array.isArray(field)) {
|
|
40
|
-
return field.length === 0;
|
|
41
|
-
}
|
|
42
|
-
if (typeof field === 'object' && !(field instanceof Date)) {
|
|
43
|
-
return Object.keys(field).length === 0;
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
};
|
|
47
|
-
const isEntityIdRequired = (action) => !ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT[action];
|
|
48
|
-
exports.isEntityIdRequired = isEntityIdRequired;
|
|
49
|
-
const filterOutEmptyFields = (fields, instance) => fields.filter((field) => !isEmpty(instance.get(field)) || !isEmpty(instance.previous(field)));
|
|
50
|
-
const getChangedFieldsRows = (instance, options) => {
|
|
51
|
-
// When bulk updating in sequelize using the "returning" option, the instance.changed() stops working.
|
|
52
|
-
// It's a known issue with sequelize.
|
|
53
|
-
const changedFields = options.returning ? options.fields : instance.changed();
|
|
54
|
-
// Filter customFields - we'll handle them later
|
|
55
|
-
const filteredChangedFields = filterOutEmptyFields(changedFields.filter((field) => field !== CUSTOM_FIELDS_PROPERTY), instance);
|
|
56
|
-
return filteredChangedFields.map((property) => ({
|
|
57
|
-
property,
|
|
58
|
-
previousValue: instance.previous(property),
|
|
59
|
-
newValue: instance.get(property),
|
|
60
|
-
}));
|
|
61
|
-
};
|
|
62
|
-
const getChangedCustomFieldsRows = (instance) => {
|
|
63
|
-
const customFieldsChanged = instance.changed().includes(CUSTOM_FIELDS_PROPERTY);
|
|
64
|
-
if (!customFieldsChanged) {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
const customFields = instance.get(CUSTOM_FIELDS_PROPERTY);
|
|
68
|
-
const previousCustomFields = instance.previous(CUSTOM_FIELDS_PROPERTY);
|
|
69
|
-
const changedCustomFields = Object.keys(customFields).filter((field) => {
|
|
70
|
-
const newValue = customFields === null || customFields === void 0 ? void 0 : customFields[field];
|
|
71
|
-
const oldValue = previousCustomFields === null || previousCustomFields === void 0 ? void 0 : previousCustomFields[field];
|
|
72
|
-
return (!isEmpty(newValue) || !isEmpty(oldValue)) && !(0, lodash_1.isEqual)(newValue, oldValue);
|
|
73
|
-
});
|
|
74
|
-
return changedCustomFields.map((changedCustomField) => ({
|
|
75
|
-
property: `customFields.${changedCustomField}`,
|
|
76
|
-
previousValue: previousCustomFields === null || previousCustomFields === void 0 ? void 0 : previousCustomFields[changedCustomField],
|
|
77
|
-
newValue: customFields === null || customFields === void 0 ? void 0 : customFields[changedCustomField],
|
|
78
|
-
}));
|
|
79
|
-
};
|
|
80
|
-
class AuditLogger {
|
|
81
|
-
constructor(options) {
|
|
82
|
-
this.rabbit = options.rabbit;
|
|
83
|
-
this.sequelize = options.sequelize;
|
|
84
|
-
this.logger = options.logger || logger_1.default;
|
|
85
|
-
}
|
|
86
|
-
registerHooks() {
|
|
87
|
-
Object.entries(this.sequelize.models).forEach(([modelName, modelType]) => {
|
|
88
|
-
modelType.addHook('afterSave', (instance, options) => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
var _a;
|
|
90
|
-
try {
|
|
91
|
-
const auditContext = getAuditContext();
|
|
92
|
-
if (auditContext) {
|
|
93
|
-
if (((_a = auditContext === null || auditContext === void 0 ? void 0 : auditContext.entityType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (modelName === null || modelName === void 0 ? void 0 : modelName.toLowerCase()) && (0, exports.isEntityIdRequired)(auditContext.action)) {
|
|
94
|
-
auditContext.entityId = instance.id;
|
|
95
|
-
}
|
|
96
|
-
const changedFieldsRows = getChangedFieldsRows(instance, options);
|
|
97
|
-
const changedCustomFieldsRows = getChangedCustomFieldsRows(instance);
|
|
98
|
-
const payload = {
|
|
99
|
-
entityType: modelName,
|
|
100
|
-
entityId: instance.id,
|
|
101
|
-
rows: [...changedFieldsRows, ...changedCustomFieldsRows],
|
|
102
|
-
};
|
|
103
|
-
this.sendAuditLogRows(payload);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
this.logger.error('Failed to send audit log rows', error);
|
|
108
|
-
}
|
|
109
|
-
}));
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
sendAuditLogContext(context) {
|
|
113
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
-
try {
|
|
115
|
-
yield this.rabbit.sendToQueue(const_1.AUDIT_LOG_CONTEXT_QUEUE, context);
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
this.logger.error('Failed to send audit log context', err);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
sendAuditLogRows(payload) {
|
|
123
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
-
try {
|
|
125
|
-
yield this.rabbit.sendToQueue(const_1.AUDIT_LOG_ROWS_QUEUE, payload);
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
this.logger.error('Failed to send audit log rows', err);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
exports.default = AuditLogger;
|
package/dist/audit-ms.d.ts
DELETED
package/dist/audit-ms.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const network_1 = __importDefault(require("@autofleet/network"));
|
|
7
|
-
const auditMs = new network_1.default({ serviceName: 'AUDIT_MS', timeout: 1000 * 60 });
|
|
8
|
-
const getByEntityId = (entityId) => {
|
|
9
|
-
const { data } = auditMs.get(`api/v1/audit-logs/${entityId}`);
|
|
10
|
-
return data;
|
|
11
|
-
};
|
|
12
|
-
exports.default = {
|
|
13
|
-
getByEntityId,
|
|
14
|
-
};
|
package/dist/const.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare const AUDIT_LOG_CONTEXT_QUEUE = "audit-log-context";
|
|
2
|
-
export declare const AUDIT_LOG_ROWS_QUEUE = "audit-log-rows";
|
|
3
|
-
export declare const AUDIT_LOG_CONTEXT_KEY = "auditLogContext";
|
|
4
|
-
export declare const USER_CONTEXT_KEY = "userObject";
|
|
5
|
-
export declare const AUTOMATION_ID_HEADER = "x-af-automation-id";
|
package/dist/const.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AUTOMATION_ID_HEADER = exports.USER_CONTEXT_KEY = exports.AUDIT_LOG_CONTEXT_KEY = exports.AUDIT_LOG_ROWS_QUEUE = exports.AUDIT_LOG_CONTEXT_QUEUE = void 0;
|
|
4
|
-
exports.AUDIT_LOG_CONTEXT_QUEUE = 'audit-log-context';
|
|
5
|
-
exports.AUDIT_LOG_ROWS_QUEUE = 'audit-log-rows';
|
|
6
|
-
exports.AUDIT_LOG_CONTEXT_KEY = 'auditLogContext';
|
|
7
|
-
exports.USER_CONTEXT_KEY = 'userObject';
|
|
8
|
-
exports.AUTOMATION_ID_HEADER = 'x-af-automation-id';
|
package/dist/logger.d.ts
DELETED
package/dist/logger.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const logger_1 = __importDefault(require("@autofleet/logger"));
|
|
7
|
-
exports.default = (0, logger_1.default)(null);
|
package/dist/types.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Sequelize } from 'sequelize-typescript';
|
|
2
|
-
import RabbitMq from '@autofleet/rabbit';
|
|
3
|
-
export type AuditLoggerOptions = {
|
|
4
|
-
rabbit: RabbitMq;
|
|
5
|
-
sequelize: Sequelize;
|
|
6
|
-
logger: any;
|
|
7
|
-
};
|
|
8
|
-
export interface AuditLogContext {
|
|
9
|
-
entityType: string;
|
|
10
|
-
entityId?: string;
|
|
11
|
-
action: string;
|
|
12
|
-
performedBy: string;
|
|
13
|
-
endpoint: string;
|
|
14
|
-
method: string;
|
|
15
|
-
actionOrigin?: string;
|
|
16
|
-
}
|
|
17
|
-
export interface AuditLogRow {
|
|
18
|
-
property: string;
|
|
19
|
-
previousValue: any;
|
|
20
|
-
newValue: any;
|
|
21
|
-
}
|
|
22
|
-
export interface AuditLogPayload {
|
|
23
|
-
entityType: string;
|
|
24
|
-
entityId: string;
|
|
25
|
-
rows: AuditLogRow[];
|
|
26
|
-
}
|
|
27
|
-
export declare enum Action {
|
|
28
|
-
CREATE = "create",
|
|
29
|
-
BULK_CREATE = "bulk-create",
|
|
30
|
-
BULK_EDIT = "bulk-edit",
|
|
31
|
-
DELETE = "delete",
|
|
32
|
-
UPDATE = "update",
|
|
33
|
-
CANCEL = "cancel",
|
|
34
|
-
FAIL = "fail",
|
|
35
|
-
UNASSIGN = "unassign",
|
|
36
|
-
BULK_ASSIGN = "bulk-assign",
|
|
37
|
-
REASSIGN = "reassign",
|
|
38
|
-
DISPATCH = "dispatch",
|
|
39
|
-
BULK_DISPATCH = "bulk-dispatch",
|
|
40
|
-
BULK_UPSERT = "bulk-upsert",
|
|
41
|
-
UPSERT = "upsert",
|
|
42
|
-
JOIN = "join",
|
|
43
|
-
MOVE = "move",
|
|
44
|
-
REOPTIMIZATION = "reoptimization"
|
|
45
|
-
}
|
|
46
|
-
export declare enum EntityType {
|
|
47
|
-
RIDE = "Ride",
|
|
48
|
-
VEHICLE = "Vehicle",
|
|
49
|
-
DRIVER = "Driver",
|
|
50
|
-
PRICE_CALCULATION = "PriceCalculation"
|
|
51
|
-
}
|
|
52
|
-
export declare const enum ActionOrigin {
|
|
53
|
-
USER = "user",
|
|
54
|
-
AUTOMATION = "automation"
|
|
55
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EntityType = exports.Action = void 0;
|
|
4
|
-
var Action;
|
|
5
|
-
(function (Action) {
|
|
6
|
-
Action["CREATE"] = "create";
|
|
7
|
-
Action["BULK_CREATE"] = "bulk-create";
|
|
8
|
-
Action["BULK_EDIT"] = "bulk-edit";
|
|
9
|
-
Action["DELETE"] = "delete";
|
|
10
|
-
Action["UPDATE"] = "update";
|
|
11
|
-
Action["CANCEL"] = "cancel";
|
|
12
|
-
Action["FAIL"] = "fail";
|
|
13
|
-
Action["UNASSIGN"] = "unassign";
|
|
14
|
-
Action["BULK_ASSIGN"] = "bulk-assign";
|
|
15
|
-
Action["REASSIGN"] = "reassign";
|
|
16
|
-
Action["DISPATCH"] = "dispatch";
|
|
17
|
-
Action["BULK_DISPATCH"] = "bulk-dispatch";
|
|
18
|
-
Action["BULK_UPSERT"] = "bulk-upsert";
|
|
19
|
-
Action["UPSERT"] = "upsert";
|
|
20
|
-
Action["JOIN"] = "join";
|
|
21
|
-
Action["MOVE"] = "move";
|
|
22
|
-
Action["REOPTIMIZATION"] = "reoptimization";
|
|
23
|
-
})(Action = exports.Action || (exports.Action = {}));
|
|
24
|
-
var EntityType;
|
|
25
|
-
(function (EntityType) {
|
|
26
|
-
EntityType["RIDE"] = "Ride";
|
|
27
|
-
EntityType["VEHICLE"] = "Vehicle";
|
|
28
|
-
EntityType["DRIVER"] = "Driver";
|
|
29
|
-
EntityType["PRICE_CALCULATION"] = "PriceCalculation";
|
|
30
|
-
})(EntityType = exports.EntityType || (exports.EntityType = {}));
|
package/src/audit-api.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
|
-
import { handleError, ResourceNotFoundError, UnexpectedError } from '@autofleet/errors';
|
|
3
|
-
|
|
4
|
-
import auditMs from './audit-ms';
|
|
5
|
-
|
|
6
|
-
export default async ({
|
|
7
|
-
router,
|
|
8
|
-
entiyScopedModelMap,
|
|
9
|
-
} : {
|
|
10
|
-
router: Router,
|
|
11
|
-
entiyScopedModelMap: Array<any>,
|
|
12
|
-
}): Promise<void> => {
|
|
13
|
-
if (entiyScopedModelMap) {
|
|
14
|
-
Object.entries(entiyScopedModelMap).forEach(([entity, ScopedModel]) => {
|
|
15
|
-
router.get(`${entity}/:id/audit`, async (req, res) => {
|
|
16
|
-
try {
|
|
17
|
-
const { id } = req.params;
|
|
18
|
-
const entityData = await ScopedModel.findByPk(id);
|
|
19
|
-
if (!entityData) {
|
|
20
|
-
return handleError(new ResourceNotFoundError(), res);
|
|
21
|
-
}
|
|
22
|
-
const auditData = auditMs.getByEntityId(id);
|
|
23
|
-
return res.json(auditData);
|
|
24
|
-
} catch (err) {
|
|
25
|
-
return handleError(new UnexpectedError(err as Error), res);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
};
|
package/src/audit-logger.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { getCurrentPayload as getCurrentTrace } from '@autofleet/zehut';
|
|
2
|
-
import { Sequelize } from 'sequelize';
|
|
3
|
-
import { isEqual } from 'lodash';
|
|
4
|
-
import {
|
|
5
|
-
AuditLogPayload, AuditLoggerOptions, AuditLogContext, Action,
|
|
6
|
-
} from './types';
|
|
7
|
-
import { AUDIT_LOG_CONTEXT_QUEUE, AUDIT_LOG_ROWS_QUEUE, AUDIT_LOG_CONTEXT_KEY } from './const';
|
|
8
|
-
import logger from './logger';
|
|
9
|
-
|
|
10
|
-
const CUSTOM_FIELDS_PROPERTY = 'customFields';
|
|
11
|
-
|
|
12
|
-
const getAuditContext = () => {
|
|
13
|
-
const currentTrace = getCurrentTrace();
|
|
14
|
-
const auditContext = currentTrace?.context?.get(AUDIT_LOG_CONTEXT_KEY);
|
|
15
|
-
return auditContext;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT = {
|
|
19
|
-
[Action.BULK_CREATE]: Action.BULK_CREATE,
|
|
20
|
-
[Action.BULK_EDIT]: Action.BULK_EDIT,
|
|
21
|
-
[Action.BULK_ASSIGN]: Action.BULK_ASSIGN,
|
|
22
|
-
[Action.BULK_DISPATCH]: Action.BULK_DISPATCH,
|
|
23
|
-
[Action.BULK_UPSERT]: Action.BULK_UPSERT,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const isEmpty = (field) => {
|
|
27
|
-
if ([null, undefined].includes(field)) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
if (Array.isArray(field)) {
|
|
31
|
-
return field.length === 0;
|
|
32
|
-
}
|
|
33
|
-
if (typeof field === 'object' && !(field instanceof Date)) {
|
|
34
|
-
return Object.keys(field).length === 0;
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const isEntityIdRequired = (action: string): boolean => !ACTIONS_TO_OMIT_ENTITY_ID_FROM_CONTEXT[action];
|
|
40
|
-
|
|
41
|
-
const filterOutEmptyFields = (fields: string[], instance) => fields.filter((field) => !isEmpty(instance.get(field)) || !isEmpty(instance.previous(field)));
|
|
42
|
-
|
|
43
|
-
const getChangedFieldsRows = (instance, options) => {
|
|
44
|
-
// When bulk updating in sequelize using the "returning" option, the instance.changed() stops working.
|
|
45
|
-
// It's a known issue with sequelize.
|
|
46
|
-
const changedFields: string[] = options.returning ? options.fields : instance.changed();
|
|
47
|
-
// Filter customFields - we'll handle them later
|
|
48
|
-
const filteredChangedFields = filterOutEmptyFields(changedFields.filter((field) => field !== CUSTOM_FIELDS_PROPERTY), instance);
|
|
49
|
-
return filteredChangedFields.map((property: string) => ({
|
|
50
|
-
property,
|
|
51
|
-
previousValue: instance.previous(property),
|
|
52
|
-
newValue: instance.get(property),
|
|
53
|
-
}));
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const getChangedCustomFieldsRows = (instance) => {
|
|
57
|
-
const customFieldsChanged = instance.changed().includes(CUSTOM_FIELDS_PROPERTY);
|
|
58
|
-
if (!customFieldsChanged) {
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const customFields = instance.get(CUSTOM_FIELDS_PROPERTY);
|
|
63
|
-
const previousCustomFields = instance.previous(CUSTOM_FIELDS_PROPERTY);
|
|
64
|
-
const changedCustomFields = Object.keys(customFields).filter((field) => {
|
|
65
|
-
const newValue = customFields?.[field];
|
|
66
|
-
const oldValue = previousCustomFields?.[field];
|
|
67
|
-
return (!isEmpty(newValue) || !isEmpty(oldValue)) && !isEqual(newValue, oldValue);
|
|
68
|
-
});
|
|
69
|
-
return changedCustomFields.map((changedCustomField) => ({
|
|
70
|
-
property: `customFields.${changedCustomField}`,
|
|
71
|
-
previousValue: previousCustomFields?.[changedCustomField],
|
|
72
|
-
newValue: customFields?.[changedCustomField],
|
|
73
|
-
}));
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
class AuditLogger {
|
|
77
|
-
private rabbit;
|
|
78
|
-
|
|
79
|
-
private sequelize: Sequelize;
|
|
80
|
-
|
|
81
|
-
private logger;
|
|
82
|
-
|
|
83
|
-
constructor(options: AuditLoggerOptions) {
|
|
84
|
-
this.rabbit = options.rabbit;
|
|
85
|
-
this.sequelize = options.sequelize;
|
|
86
|
-
this.logger = options.logger || logger;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
registerHooks(): void {
|
|
90
|
-
Object.entries(this.sequelize.models).forEach(([modelName, modelType]) => {
|
|
91
|
-
modelType.addHook('afterSave', async (instance: any, options: any) => {
|
|
92
|
-
try {
|
|
93
|
-
const auditContext = getAuditContext();
|
|
94
|
-
if (auditContext) {
|
|
95
|
-
if (auditContext?.entityType?.toLowerCase() === modelName?.toLowerCase() && isEntityIdRequired(auditContext.action)) {
|
|
96
|
-
auditContext.entityId = instance.id;
|
|
97
|
-
}
|
|
98
|
-
const changedFieldsRows = getChangedFieldsRows(instance, options);
|
|
99
|
-
const changedCustomFieldsRows = getChangedCustomFieldsRows(instance);
|
|
100
|
-
const payload: AuditLogPayload = {
|
|
101
|
-
entityType: modelName,
|
|
102
|
-
entityId: instance.id,
|
|
103
|
-
rows: [...changedFieldsRows, ...changedCustomFieldsRows],
|
|
104
|
-
};
|
|
105
|
-
this.sendAuditLogRows(payload);
|
|
106
|
-
}
|
|
107
|
-
} catch (error) {
|
|
108
|
-
this.logger.error('Failed to send audit log rows', error);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async sendAuditLogContext(context: AuditLogContext): Promise<void> {
|
|
115
|
-
try {
|
|
116
|
-
await this.rabbit.sendToQueue(AUDIT_LOG_CONTEXT_QUEUE, context);
|
|
117
|
-
} catch (err) {
|
|
118
|
-
this.logger.error('Failed to send audit log context', err);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async sendAuditLogRows(payload: AuditLogPayload): Promise<void> {
|
|
123
|
-
try {
|
|
124
|
-
await this.rabbit.sendToQueue(AUDIT_LOG_ROWS_QUEUE, payload);
|
|
125
|
-
} catch (err) {
|
|
126
|
-
this.logger.error('Failed to send audit log rows', err);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export default AuditLogger;
|
package/src/audit-ms.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import Network from '@autofleet/network';
|
|
2
|
-
|
|
3
|
-
const auditMs = new Network({ serviceName: 'AUDIT_MS', timeout: 1000 * 60 });
|
|
4
|
-
|
|
5
|
-
const getByEntityId = (entityId: string): any => {
|
|
6
|
-
const { data } = auditMs.get(`api/v1/audit-logs/${entityId}`);
|
|
7
|
-
return data;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
getByEntityId,
|
|
12
|
-
};
|
package/src/const.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export const AUDIT_LOG_CONTEXT_QUEUE = 'audit-log-context';
|
|
2
|
-
export const AUDIT_LOG_ROWS_QUEUE = 'audit-log-rows';
|
|
3
|
-
export const AUDIT_LOG_CONTEXT_KEY = 'auditLogContext';
|
|
4
|
-
export const USER_CONTEXT_KEY = 'userObject';
|
|
5
|
-
export const AUTOMATION_ID_HEADER = 'x-af-automation-id';
|
package/src/index.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { getCurrentPayload as getCurrentTrace } from '@autofleet/zehut';
|
|
2
|
-
import type { Request, Response, NextFunction } from 'express';
|
|
3
|
-
import AuditLogger, { isEntityIdRequired } from './audit-logger';
|
|
4
|
-
import { ActionOrigin, AuditLogContext, AuditLoggerOptions } from './types';
|
|
5
|
-
import { AUDIT_LOG_CONTEXT_KEY, AUTOMATION_ID_HEADER, USER_CONTEXT_KEY } from './const';
|
|
6
|
-
import addAuditApi from './audit-api';
|
|
7
|
-
import logger from './logger';
|
|
8
|
-
|
|
9
|
-
let auditLogger: AuditLogger;
|
|
10
|
-
|
|
11
|
-
export const enableAuditing = (options: AuditLoggerOptions) => {
|
|
12
|
-
if (process.env.DISABLE_AUDIT_LOGS !== 'true') {
|
|
13
|
-
auditLogger = new AuditLogger(options);
|
|
14
|
-
addAuditApi(options as any);
|
|
15
|
-
auditLogger.registerHooks();
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const setAuditContext = (
|
|
20
|
-
entityType: string,
|
|
21
|
-
action: string,
|
|
22
|
-
) => async (req: Request, res: Response, next: NextFunction): Promise<any> => {
|
|
23
|
-
try {
|
|
24
|
-
const currentTrace = getCurrentTrace();
|
|
25
|
-
if (process.env.DISABLE_AUDIT_LOGS === 'true' || !currentTrace?.context?.get) {
|
|
26
|
-
return next();
|
|
27
|
-
}
|
|
28
|
-
const user = currentTrace.context.get(USER_CONTEXT_KEY);
|
|
29
|
-
const { performedBy, actionOrigin } = user?.id
|
|
30
|
-
? { performedBy: user.id, actionOrigin: ActionOrigin.USER }
|
|
31
|
-
: { performedBy: req.headers[AUTOMATION_ID_HEADER] ?? null, actionOrigin: req.headers[AUTOMATION_ID_HEADER] ? ActionOrigin.AUTOMATION : null };
|
|
32
|
-
const auditLogContext: AuditLogContext = {
|
|
33
|
-
entityType,
|
|
34
|
-
action,
|
|
35
|
-
endpoint: req.url,
|
|
36
|
-
method: req.method,
|
|
37
|
-
performedBy,
|
|
38
|
-
actionOrigin,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
currentTrace.context.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);
|
|
42
|
-
|
|
43
|
-
const sendAuditLogContextEvent = async () => {
|
|
44
|
-
res.off('finish', sendAuditLogContextEvent);
|
|
45
|
-
res.off('close', sendAuditLogContextEvent);
|
|
46
|
-
res.off('error', sendAuditLogContextEvent);
|
|
47
|
-
await auditLogger.sendAuditLogContext(auditLogContext);
|
|
48
|
-
};
|
|
49
|
-
if (!isEntityIdRequired(action)) { // if it's a bulk action, we don't want to wait for the response to add the entity id
|
|
50
|
-
await auditLogger.sendAuditLogContext(auditLogContext);
|
|
51
|
-
} else {
|
|
52
|
-
res.once('finish', sendAuditLogContextEvent);
|
|
53
|
-
res.once('close', sendAuditLogContextEvent);
|
|
54
|
-
res.once('error', sendAuditLogContextEvent);
|
|
55
|
-
}
|
|
56
|
-
} catch (err) {
|
|
57
|
-
logger.error('coudln\'t set audit context', err);
|
|
58
|
-
}
|
|
59
|
-
return next();
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const setRabbitAuditContext = (
|
|
63
|
-
entityType: string,
|
|
64
|
-
action: string,
|
|
65
|
-
) => async (endpoint: string, { userId, automationId }:{ userId:string; automationId:string; }): Promise<any> => {
|
|
66
|
-
if (process.env.DISABLE_AUDIT_LOGS === 'true') {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
const currentTrace = getCurrentTrace();
|
|
70
|
-
if (currentTrace?.context?.get) {
|
|
71
|
-
const { performedBy, actionOrigin } = userId
|
|
72
|
-
? { performedBy: userId, actionOrigin: ActionOrigin.USER }
|
|
73
|
-
: { performedBy: automationId ?? null, actionOrigin: automationId ? ActionOrigin.AUTOMATION : null };
|
|
74
|
-
const auditLogContext: AuditLogContext = {
|
|
75
|
-
entityType,
|
|
76
|
-
action,
|
|
77
|
-
endpoint,
|
|
78
|
-
method: 'rabbit',
|
|
79
|
-
performedBy,
|
|
80
|
-
actionOrigin,
|
|
81
|
-
};
|
|
82
|
-
currentTrace.context.set(AUDIT_LOG_CONTEXT_KEY, auditLogContext);
|
|
83
|
-
await auditLogger.sendAuditLogContext(auditLogContext);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export * from './types';
|
|
88
|
-
export * from './const';
|
|
89
|
-
|
|
90
|
-
export default AuditLogger;
|
package/src/logger.ts
DELETED
package/src/types.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-shadow */
|
|
2
|
-
import { Sequelize } from 'sequelize-typescript';
|
|
3
|
-
import RabbitMq from '@autofleet/rabbit';
|
|
4
|
-
|
|
5
|
-
export type AuditLoggerOptions = {
|
|
6
|
-
rabbit: RabbitMq;
|
|
7
|
-
sequelize: Sequelize;
|
|
8
|
-
logger: any;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export interface AuditLogContext {
|
|
12
|
-
entityType: string;
|
|
13
|
-
entityId?: string;
|
|
14
|
-
action: string;
|
|
15
|
-
performedBy: string;
|
|
16
|
-
endpoint: string;
|
|
17
|
-
method: string;
|
|
18
|
-
actionOrigin?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface AuditLogRow {
|
|
22
|
-
property: string;
|
|
23
|
-
previousValue: any;
|
|
24
|
-
newValue: any;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface AuditLogPayload {
|
|
28
|
-
entityType: string;
|
|
29
|
-
entityId: string;
|
|
30
|
-
rows: AuditLogRow[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export enum Action {
|
|
34
|
-
CREATE = 'create',
|
|
35
|
-
BULK_CREATE = 'bulk-create',
|
|
36
|
-
BULK_EDIT = 'bulk-edit',
|
|
37
|
-
DELETE = 'delete',
|
|
38
|
-
UPDATE = 'update',
|
|
39
|
-
CANCEL = 'cancel',
|
|
40
|
-
FAIL = 'fail',
|
|
41
|
-
UNASSIGN = 'unassign',
|
|
42
|
-
BULK_ASSIGN = 'bulk-assign',
|
|
43
|
-
REASSIGN = 'reassign',
|
|
44
|
-
DISPATCH = 'dispatch',
|
|
45
|
-
BULK_DISPATCH = 'bulk-dispatch',
|
|
46
|
-
BULK_UPSERT = 'bulk-upsert',
|
|
47
|
-
UPSERT = 'upsert',
|
|
48
|
-
JOIN = 'join',
|
|
49
|
-
MOVE = 'move',
|
|
50
|
-
REOPTIMIZATION = 'reoptimization',
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export enum EntityType {
|
|
54
|
-
RIDE = 'Ride',
|
|
55
|
-
VEHICLE = 'Vehicle',
|
|
56
|
-
DRIVER = 'Driver',
|
|
57
|
-
PRICE_CALCULATION = 'PriceCalculation',
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const enum ActionOrigin {
|
|
61
|
-
USER = 'user',
|
|
62
|
-
AUTOMATION = 'automation',
|
|
63
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es6",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"experimentalDecorators": true,
|
|
9
|
-
"emitDecoratorMetadata": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
},
|
|
12
|
-
"exclude": ["node_modules", "**/*.test.ts", "dist"]
|
|
13
|
-
}
|