@adminforth/crud-approve-plugin 1.0.12 → 1.0.14
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/.woodpecker/buildSlackNotify.sh +3 -1
- package/.woodpecker/release.yml +27 -9
- package/05-CRUDApprove.md +0 -130
- package/build.log +15 -0
- package/custom/ListPageDiffView.vue +1 -1
- package/custom/pnpm-lock.yaml +308 -0
- package/dist/custom/ListPageDiffView.vue +86 -0
- package/dist/custom/ShowPageDiffView.vue +95 -0
- package/dist/custom/package-lock.json +420 -0
- package/dist/custom/package.json +6 -1
- package/dist/custom/pnpm-lock.yaml +308 -0
- package/dist/index.js +364 -19
- package/dist/types.js +10 -3
- package/index.ts +13 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -7,11 +7,242 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { AdminForthPlugin } from "adminforth";
|
|
11
|
-
import {
|
|
10
|
+
import { ActionCheckSource, AdminForthPlugin, AdminForthSortDirections, Filters } from "adminforth";
|
|
11
|
+
import { AdminForthDataTypes, AllowedActionsEnum } from "adminforth";
|
|
12
|
+
import { AllowedForReviewActionsEnum, ApprovalStatusEnum } from './types.js';
|
|
13
|
+
import dayjs from "dayjs";
|
|
14
|
+
import utc from "dayjs/plugin/utc.js";
|
|
15
|
+
import { randomUUID } from "crypto";
|
|
16
|
+
dayjs.extend(utc);
|
|
12
17
|
export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
13
18
|
constructor(options) {
|
|
14
19
|
super(options, import.meta.url);
|
|
20
|
+
this.createApprovalRequest = (_a) => __awaiter(this, [_a], void 0, function* ({ resource, action, data, user, oldRecord, updates, extra, record }) {
|
|
21
|
+
var _b;
|
|
22
|
+
//@ts-ignore
|
|
23
|
+
if (extra && extra.adminforth_plugin_crud_approve && extra.adminforth_plugin_crud_approve.callingFromApprovalPlugin) {
|
|
24
|
+
return { ok: true, error: 'Approval request creation aborted to avoid infinite loop' };
|
|
25
|
+
}
|
|
26
|
+
const recordIdFieldName = (_b = resource.columns.find((c) => c.primaryKey === true)) === null || _b === void 0 ? void 0 : _b.name;
|
|
27
|
+
const recordId = (data === null || data === void 0 ? void 0 : data[recordIdFieldName]) || (oldRecord === null || oldRecord === void 0 ? void 0 : oldRecord[recordIdFieldName]);
|
|
28
|
+
let newRecord = {};
|
|
29
|
+
const connector = this.adminforth.connectors[resource.dataSource];
|
|
30
|
+
if (action === AllowedForReviewActionsEnum.create) {
|
|
31
|
+
oldRecord = {};
|
|
32
|
+
newRecord = updates || record;
|
|
33
|
+
}
|
|
34
|
+
else if (action === AllowedForReviewActionsEnum.edit) {
|
|
35
|
+
newRecord = yield connector.getRecordByPrimaryKey(resource, recordId);
|
|
36
|
+
for (const key in updates) {
|
|
37
|
+
newRecord[key] = updates[key];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (action === AllowedForReviewActionsEnum.delete) {
|
|
41
|
+
oldRecord = yield connector.getRecordByPrimaryKey(resource, recordId);
|
|
42
|
+
}
|
|
43
|
+
const checks = yield Promise.all(resource.columns.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
var _a;
|
|
45
|
+
if (typeof c.backendOnly === "function") {
|
|
46
|
+
const result = yield c.backendOnly({
|
|
47
|
+
adminUser: user,
|
|
48
|
+
resource,
|
|
49
|
+
meta: {},
|
|
50
|
+
source: ActionCheckSource.ShowRequest,
|
|
51
|
+
adminforth: this.adminforth,
|
|
52
|
+
});
|
|
53
|
+
return { col: c, result };
|
|
54
|
+
}
|
|
55
|
+
return { col: c, result: (_a = c.backendOnly) !== null && _a !== void 0 ? _a : false };
|
|
56
|
+
})));
|
|
57
|
+
const backendOnlyColumns = checks
|
|
58
|
+
.filter(({ result }) => result === true)
|
|
59
|
+
.map(({ col }) => col);
|
|
60
|
+
backendOnlyColumns.forEach((c) => {
|
|
61
|
+
if (JSON.stringify(oldRecord[c.name]) != JSON.stringify(newRecord[c.name])) {
|
|
62
|
+
if (action !== AllowedForReviewActionsEnum.delete) {
|
|
63
|
+
newRecord[c.name] = '<hidden value after>';
|
|
64
|
+
}
|
|
65
|
+
if (action !== AllowedForReviewActionsEnum.create) {
|
|
66
|
+
oldRecord[c.name] = '<hidden value before>';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
delete oldRecord[c.name];
|
|
71
|
+
delete newRecord[c.name];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (action === AllowedForReviewActionsEnum.edit) {
|
|
75
|
+
for (const key in oldRecord) {
|
|
76
|
+
if (JSON.stringify(oldRecord[key]) === JSON.stringify(newRecord[key])) {
|
|
77
|
+
delete oldRecord[key];
|
|
78
|
+
delete newRecord[key];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const createdAt = dayjs.utc().format();
|
|
83
|
+
const diffRecord = {
|
|
84
|
+
[this.options.resourceColumns.idColumnName]: randomUUID(),
|
|
85
|
+
[this.options.resourceColumns.resourceIdColumnName]: resource.resourceId,
|
|
86
|
+
[this.options.resourceColumns.actionColumnName]: action,
|
|
87
|
+
[this.options.resourceColumns.statusColumnName]: ApprovalStatusEnum.pending,
|
|
88
|
+
[this.options.resourceColumns.dataColumnName]: { 'oldRecord': oldRecord, 'newRecord': newRecord },
|
|
89
|
+
[this.options.resourceColumns.userIdColumnName]: user.pk,
|
|
90
|
+
[this.options.resourceColumns.recordIdColumnName]: recordId,
|
|
91
|
+
[this.options.resourceColumns.createdAtColumnName]: createdAt,
|
|
92
|
+
[this.options.resourceColumns.extraColumnName]: extra || {},
|
|
93
|
+
};
|
|
94
|
+
const diffResource = this.adminforth.config.resources.find((r) => r.resourceId === this.diffResource.resourceId);
|
|
95
|
+
yield this.adminforth.createResourceRecord({ resource: diffResource, record: diffRecord, adminUser: user });
|
|
96
|
+
return { ok: true, error: null };
|
|
97
|
+
});
|
|
98
|
+
this.callBeforeSaveHooks = (
|
|
99
|
+
// resource: AdminForthResource, action: AllowedActionsEnum, record: any,
|
|
100
|
+
// adminUser: AdminUser, recordId?: any, extra?: HttpExtra
|
|
101
|
+
resource, action, record, adminUser, recordId, updates, oldRecord, adminforth, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
let hooks = [];
|
|
103
|
+
if (action === AllowedActionsEnum.create) {
|
|
104
|
+
hooks = resource.hooks.create.beforeSave;
|
|
105
|
+
}
|
|
106
|
+
else if (action === AllowedActionsEnum.edit) {
|
|
107
|
+
hooks = resource.hooks.edit.beforeSave;
|
|
108
|
+
}
|
|
109
|
+
else if (action === AllowedActionsEnum.delete) {
|
|
110
|
+
hooks = resource.hooks.delete.beforeSave;
|
|
111
|
+
}
|
|
112
|
+
if (extra === undefined) {
|
|
113
|
+
extra = {};
|
|
114
|
+
}
|
|
115
|
+
//@ts-ignore
|
|
116
|
+
extra.adminforth_plugin_crud_approve = {
|
|
117
|
+
//@ts-ignore
|
|
118
|
+
callingFromApprovalPlugin: true
|
|
119
|
+
//@ts-ignore
|
|
120
|
+
};
|
|
121
|
+
for (const hook of hooks) {
|
|
122
|
+
const resp = yield hook({
|
|
123
|
+
resource,
|
|
124
|
+
record,
|
|
125
|
+
adminUser,
|
|
126
|
+
recordId,
|
|
127
|
+
adminforth: this.adminforth,
|
|
128
|
+
extra,
|
|
129
|
+
updates,
|
|
130
|
+
oldRecord,
|
|
131
|
+
});
|
|
132
|
+
if (!resp || (typeof resp.ok !== 'boolean' && (!resp.error && !resp.newRecordId))) {
|
|
133
|
+
throw new Error(`Invalid return value from beforeSave hook. Expected: { ok: boolean, error?: string | null, newRecordId?: any }.\n` +
|
|
134
|
+
`Note: Return { ok: false, error: null, newRecordId } to stop creation and redirect to an existing record.`);
|
|
135
|
+
}
|
|
136
|
+
if (resp.ok === false && !resp.error) {
|
|
137
|
+
const { error, ok, newRecordId } = resp;
|
|
138
|
+
return {
|
|
139
|
+
error: error !== null && error !== void 0 ? error : 'Operation aborted by hook',
|
|
140
|
+
newRecordId: newRecordId
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (resp.error) {
|
|
144
|
+
return { error: resp.error };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { ok: true, error: null };
|
|
148
|
+
});
|
|
149
|
+
this.callAfterSaveHooks = (
|
|
150
|
+
// resource: AdminForthResource, action: AllowedActionsEnum, record: any,
|
|
151
|
+
// adminUser: AdminUser, recordId: any, extra?: HttpExtra
|
|
152
|
+
resource, action, record, adminUser, recordId, updates, oldRecord, adminforth, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
153
|
+
let hooks = [];
|
|
154
|
+
if (action === AllowedActionsEnum.create) {
|
|
155
|
+
hooks = resource.hooks.create.afterSave;
|
|
156
|
+
}
|
|
157
|
+
else if (action === AllowedActionsEnum.edit) {
|
|
158
|
+
hooks = resource.hooks.edit.afterSave;
|
|
159
|
+
}
|
|
160
|
+
else if (action === AllowedActionsEnum.delete) {
|
|
161
|
+
hooks = resource.hooks.delete.afterSave;
|
|
162
|
+
}
|
|
163
|
+
for (const hook of hooks) {
|
|
164
|
+
const resp = yield hook({
|
|
165
|
+
resource,
|
|
166
|
+
record,
|
|
167
|
+
adminUser,
|
|
168
|
+
recordId,
|
|
169
|
+
adminforth: this.adminforth,
|
|
170
|
+
extra,
|
|
171
|
+
updates,
|
|
172
|
+
oldRecord,
|
|
173
|
+
});
|
|
174
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
175
|
+
throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
|
|
176
|
+
}
|
|
177
|
+
if (resp.error) {
|
|
178
|
+
return { error: resp.error };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
this.verifyAuth = (cookies) => __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
let authCookie;
|
|
184
|
+
for (const i in cookies) {
|
|
185
|
+
if (cookies[i].key === `adminforth_${this.adminforth.config.customization.brandNameSlug}_jwt`) {
|
|
186
|
+
authCookie = cookies[i].value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const authRes = yield this.adminforth.auth.verify(authCookie, 'auth', true);
|
|
190
|
+
if ('error' in authRes) {
|
|
191
|
+
return { error: authRes.error, authRes: null };
|
|
192
|
+
}
|
|
193
|
+
return { error: null, authRes: authRes };
|
|
194
|
+
});
|
|
195
|
+
this.createRecord = (resource, diffData, adminUser) => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
const connector = this.adminforth.connectors[resource.dataSource];
|
|
197
|
+
//@ts-ignore
|
|
198
|
+
const err = this.adminforth.validateRecordValues(resource, diffData['newRecord'], 'create');
|
|
199
|
+
if (err) {
|
|
200
|
+
return { ok: false, error: err, createdRecord: null };
|
|
201
|
+
}
|
|
202
|
+
// remove virtual columns from record
|
|
203
|
+
for (const column of resource.columns.filter((col) => col.virtual)) {
|
|
204
|
+
if (diffData['newRecord'][column.name]) {
|
|
205
|
+
delete diffData['newRecord'][column.name];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return yield connector.createRecord({ resource, record: diffData['newRecord'], adminUser });
|
|
209
|
+
});
|
|
210
|
+
this.editRecord = (resource, diffData, targetRecordId, connector) => __awaiter(this, void 0, void 0, function* () {
|
|
211
|
+
let oldRecord;
|
|
212
|
+
const dataToUse = diffData['newRecord'];
|
|
213
|
+
//@ts-ignore
|
|
214
|
+
const err = this.adminforth.validateRecordValues(resource, dataToUse, 'edit', targetRecordId);
|
|
215
|
+
if (err) {
|
|
216
|
+
return { error: err };
|
|
217
|
+
}
|
|
218
|
+
// remove editReadonly columns from record
|
|
219
|
+
oldRecord = yield connector.getRecordByPrimaryKey(resource, targetRecordId);
|
|
220
|
+
for (const column of resource.columns.filter((col) => col.editReadonly)) {
|
|
221
|
+
if (column.name in dataToUse)
|
|
222
|
+
delete dataToUse[column.name];
|
|
223
|
+
}
|
|
224
|
+
const newValues = {};
|
|
225
|
+
for (const recordField in dataToUse) {
|
|
226
|
+
if (dataToUse[recordField] !== oldRecord[recordField]) {
|
|
227
|
+
// leave only changed fields to reduce data transfer/modifications in db
|
|
228
|
+
const column = resource.columns.find((col) => col.name === recordField);
|
|
229
|
+
if (!column || !column.virtual) {
|
|
230
|
+
// exclude virtual columns
|
|
231
|
+
newValues[recordField] = dataToUse[recordField];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (Object.keys(newValues).length > 0) {
|
|
236
|
+
const { error } = yield connector.updateRecord({ resource, recordId: targetRecordId, newValues });
|
|
237
|
+
if (error) {
|
|
238
|
+
return { ok: false, error };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { ok: true, error: null };
|
|
242
|
+
});
|
|
243
|
+
this.deleteRecord = (resource, targetRecordId, connector) => __awaiter(this, void 0, void 0, function* () {
|
|
244
|
+
return yield connector.deleteRecord({ resource, recordId: targetRecordId });
|
|
245
|
+
});
|
|
15
246
|
this.options = options;
|
|
16
247
|
}
|
|
17
248
|
modifyResourceConfig(adminforth, resourceConfig) {
|
|
@@ -19,25 +250,31 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
19
250
|
modifyResourceConfig: { get: () => super.modifyResourceConfig }
|
|
20
251
|
});
|
|
21
252
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
_super.modifyResourceConfig.call(this, adminforth, resourceConfig);
|
|
23
253
|
// simply modify resourceConfig or adminforth.config. You can get access to plugin options via this.options;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
254
|
+
_super.modifyResourceConfig.call(this, adminforth, resourceConfig);
|
|
255
|
+
this.adminforth = adminforth;
|
|
256
|
+
this.diffResource = this.resourceConfig;
|
|
257
|
+
let diffColumn = resourceConfig.columns.find((c) => c.name === this.options.resourceColumns.dataColumnName);
|
|
258
|
+
if (!diffColumn) {
|
|
259
|
+
throw new Error(`Column ${this.options.resourceColumns.dataColumnName} not found in ${resourceConfig.label}`);
|
|
260
|
+
}
|
|
261
|
+
if (diffColumn.type !== AdminForthDataTypes.JSON) {
|
|
262
|
+
// throw new Error(`Column ${this.options.resourceColumns.dataColumnName} must be of type 'json'`)
|
|
263
|
+
}
|
|
264
|
+
diffColumn.components = {
|
|
265
|
+
show: {
|
|
266
|
+
file: this.componentPath('ShowPageDiffView.vue'),
|
|
267
|
+
meta: Object.assign(Object.assign({}, this.options), { pluginInstanceId: this.pluginInstanceId })
|
|
268
|
+
},
|
|
269
|
+
list: {
|
|
270
|
+
file: this.componentPath('ListPageDiffView.vue'),
|
|
271
|
+
meta: Object.assign(Object.assign({}, this.options), { pluginInstanceId: this.pluginInstanceId })
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
resourceConfig.options.defaultSort = {
|
|
275
|
+
columnName: this.options.resourceColumns.createdAtColumnName,
|
|
276
|
+
direction: AdminForthSortDirections.desc
|
|
38
277
|
};
|
|
39
|
-
const approvalResource = this.adminforth.config.resources.find(r => r.resourceId === this.options.diffTableName);
|
|
40
|
-
yield this.adminforth.createResourceRecord({ resource: approvalResource, record, adminUser: user });
|
|
41
278
|
});
|
|
42
279
|
}
|
|
43
280
|
validateConfigAfterDiscover(adminforth, resourceConfig) {
|
|
@@ -48,4 +285,112 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
48
285
|
// Needed if plugin can have multiple instances on one resource
|
|
49
286
|
return `single`;
|
|
50
287
|
}
|
|
288
|
+
setupEndpoints(server) {
|
|
289
|
+
server.endpoint({
|
|
290
|
+
method: 'POST',
|
|
291
|
+
path: `/plugin/crud-approve/update-status`,
|
|
292
|
+
noAuth: true,
|
|
293
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, response, cookies }) {
|
|
294
|
+
const authRes = yield this.verifyAuth(cookies);
|
|
295
|
+
if (authRes.error) {
|
|
296
|
+
response.status = 403;
|
|
297
|
+
return { error: authRes.error };
|
|
298
|
+
}
|
|
299
|
+
const adminUser = authRes.authRes;
|
|
300
|
+
const { resourceId, diffId, recordId, action, approved, code } = body;
|
|
301
|
+
const diffRecord = yield this.adminforth.resource(this.diffResource.resourceId).get(Filters.EQ(this.options.resourceColumns.idColumnName, diffId));
|
|
302
|
+
if (!diffRecord) {
|
|
303
|
+
response.status = 404;
|
|
304
|
+
return { error: 'Diff record not found' };
|
|
305
|
+
}
|
|
306
|
+
if (diffRecord[this.options.resourceColumns.statusColumnName] !== ApprovalStatusEnum.pending) {
|
|
307
|
+
response.status = 400;
|
|
308
|
+
return { error: 'Diff record is not pending' };
|
|
309
|
+
}
|
|
310
|
+
let beforeSaveResp;
|
|
311
|
+
if (approved === true) {
|
|
312
|
+
const resource = this.adminforth.config.resources.find((res) => res.resourceId == diffRecord[this.options.resourceColumns.resourceIdColumnName]);
|
|
313
|
+
const diffData = diffRecord[this.options.resourceColumns.dataColumnName];
|
|
314
|
+
const extra = diffRecord[this.options.resourceColumns.extraColumnName] || {};
|
|
315
|
+
extra.body = body;
|
|
316
|
+
extra.cookies = cookies;
|
|
317
|
+
let oldRecord = undefined;
|
|
318
|
+
if (action !== AllowedActionsEnum.create) {
|
|
319
|
+
oldRecord = yield this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, diffRecord[this.options.resourceColumns.recordIdColumnName]);
|
|
320
|
+
}
|
|
321
|
+
beforeSaveResp = yield this.callBeforeSaveHooks(resource, action, diffData['newRecord'], adminUser, diffRecord[this.options.resourceColumns.recordIdColumnName], diffData['newRecord'], oldRecord, this.adminforth, extra);
|
|
322
|
+
if (beforeSaveResp.error && beforeSaveResp.error !== 'Operation aborted by hook') {
|
|
323
|
+
response.status = 500;
|
|
324
|
+
return { error: `Failed to apply approved changes: ${beforeSaveResp.error}` };
|
|
325
|
+
}
|
|
326
|
+
if (beforeSaveResp.error !== 'Operation aborted by hook') {
|
|
327
|
+
let recordUpdateResult;
|
|
328
|
+
const connector = this.adminforth.connectors[resource.dataSource];
|
|
329
|
+
if (action === AllowedActionsEnum.create) {
|
|
330
|
+
recordUpdateResult = yield this.createRecord(resource, diffData, adminUser);
|
|
331
|
+
}
|
|
332
|
+
else if (action === AllowedActionsEnum.edit) {
|
|
333
|
+
recordUpdateResult = yield this.editRecord(resource, diffData, diffRecord[this.options.resourceColumns.recordIdColumnName], connector);
|
|
334
|
+
}
|
|
335
|
+
else if (action === AllowedActionsEnum.delete) {
|
|
336
|
+
recordUpdateResult = yield this.deleteRecord(resource, diffRecord[this.options.resourceColumns.recordIdColumnName], connector);
|
|
337
|
+
}
|
|
338
|
+
if (recordUpdateResult === null || recordUpdateResult === void 0 ? void 0 : recordUpdateResult.error) {
|
|
339
|
+
response.status = 500;
|
|
340
|
+
console.error('Error applying approved changes:', recordUpdateResult);
|
|
341
|
+
return { error: `Failed to apply approved changes: ${recordUpdateResult.error}` };
|
|
342
|
+
}
|
|
343
|
+
let afterSaveResp;
|
|
344
|
+
if (action === AllowedActionsEnum.create) {
|
|
345
|
+
const newRecord = recordUpdateResult.createdRecord;
|
|
346
|
+
afterSaveResp = yield this.callAfterSaveHooks(resource, action, newRecord, adminUser, diffRecord[this.options.resourceColumns.recordIdColumnName],
|
|
347
|
+
//@ts-ignore
|
|
348
|
+
newRecord, {}, this.adminforth, { body });
|
|
349
|
+
}
|
|
350
|
+
else if (action === AllowedActionsEnum.edit) {
|
|
351
|
+
const newRecord = diffData['newRecord'];
|
|
352
|
+
const oldRecord = yield this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, diffRecord[this.options.resourceColumns.recordIdColumnName]);
|
|
353
|
+
afterSaveResp = yield this.callAfterSaveHooks(resource, action, newRecord, adminUser,
|
|
354
|
+
//@ts-ignore
|
|
355
|
+
recordId, newRecord, oldRecord, this.adminforth, { body });
|
|
356
|
+
}
|
|
357
|
+
else if (action === AllowedActionsEnum.delete) {
|
|
358
|
+
const newRecord = diffData['newRecord'];
|
|
359
|
+
afterSaveResp = yield this.callAfterSaveHooks(resource, action, newRecord, adminUser, diffRecord[this.options.resourceColumns.recordIdColumnName],
|
|
360
|
+
//@ts-ignore
|
|
361
|
+
{}, diffData['oldRecord'], this.adminforth, { body });
|
|
362
|
+
}
|
|
363
|
+
if (afterSaveResp === null || afterSaveResp === void 0 ? void 0 : afterSaveResp.error) {
|
|
364
|
+
response.status = 500;
|
|
365
|
+
return { error: `Failed to apply approved changes: ${afterSaveResp.error}` };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const r = yield this.adminforth.updateResourceRecord({
|
|
370
|
+
resource: this.diffResource, recordId: diffId,
|
|
371
|
+
adminUser: adminUser, oldRecord: diffRecord,
|
|
372
|
+
updates: {
|
|
373
|
+
[this.options.resourceColumns.statusColumnName]: approved ? ApprovalStatusEnum.approved : ApprovalStatusEnum.rejected,
|
|
374
|
+
[this.options.resourceColumns.responserIdColumnName]: authRes.authRes.pk,
|
|
375
|
+
},
|
|
376
|
+
extra: {
|
|
377
|
+
//@ts-ignore
|
|
378
|
+
adminforth_plugin_crud_approve: {
|
|
379
|
+
//@ts-ignore
|
|
380
|
+
callingFromApprovalPlugin: true
|
|
381
|
+
//@ts-ignore
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
if (r.error) {
|
|
386
|
+
response.status = 500;
|
|
387
|
+
return { error: `Failed to update diff record status: ${r.error}` };
|
|
388
|
+
}
|
|
389
|
+
if ((beforeSaveResp === null || beforeSaveResp === void 0 ? void 0 : beforeSaveResp.error) === 'Operation aborted by hook') {
|
|
390
|
+
return beforeSaveResp;
|
|
391
|
+
}
|
|
392
|
+
return { ok: true };
|
|
393
|
+
})
|
|
394
|
+
});
|
|
395
|
+
}
|
|
51
396
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
export var AllowedForReviewActionsEnum;
|
|
2
|
+
(function (AllowedForReviewActionsEnum) {
|
|
3
|
+
AllowedForReviewActionsEnum["create"] = "create";
|
|
4
|
+
AllowedForReviewActionsEnum["edit"] = "edit";
|
|
5
|
+
AllowedForReviewActionsEnum["delete"] = "delete";
|
|
6
|
+
AllowedForReviewActionsEnum["custom"] = "custom";
|
|
7
|
+
})(AllowedForReviewActionsEnum || (AllowedForReviewActionsEnum = {}));
|
|
1
8
|
export var ApprovalStatusEnum;
|
|
2
9
|
(function (ApprovalStatusEnum) {
|
|
3
|
-
ApprovalStatusEnum["
|
|
4
|
-
ApprovalStatusEnum["
|
|
5
|
-
ApprovalStatusEnum["
|
|
10
|
+
ApprovalStatusEnum[ApprovalStatusEnum["pending"] = 1] = "pending";
|
|
11
|
+
ApprovalStatusEnum[ApprovalStatusEnum["approved"] = 2] = "approved";
|
|
12
|
+
ApprovalStatusEnum[ApprovalStatusEnum["rejected"] = 3] = "rejected";
|
|
6
13
|
})(ApprovalStatusEnum || (ApprovalStatusEnum = {}));
|
package/index.ts
CHANGED
|
@@ -58,6 +58,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
58
58
|
{resource, action, data, user, oldRecord, updates, extra, record}:
|
|
59
59
|
{resource: AdminForthResource, action: AllowedForReviewActionsEnum, data: Object, user: AdminUser, record?: Object, oldRecord?: Object, updates?: Object, extra?: HttpExtra}
|
|
60
60
|
) => {
|
|
61
|
+
//@ts-ignore
|
|
61
62
|
if (extra && extra.adminforth_plugin_crud_approve && extra.adminforth_plugin_crud_approve.callingFromApprovalPlugin) {
|
|
62
63
|
return { ok: true, error: 'Approval request creation aborted to avoid infinite loop' };
|
|
63
64
|
}
|
|
@@ -168,8 +169,11 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
168
169
|
if (extra === undefined) {
|
|
169
170
|
extra = {};
|
|
170
171
|
}
|
|
172
|
+
//@ts-ignore
|
|
171
173
|
extra.adminforth_plugin_crud_approve = {
|
|
174
|
+
//@ts-ignore
|
|
172
175
|
callingFromApprovalPlugin: true
|
|
176
|
+
//@ts-ignore
|
|
173
177
|
}
|
|
174
178
|
for (const hook of hooks) {
|
|
175
179
|
const resp = await hook({
|
|
@@ -263,6 +267,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
263
267
|
|
|
264
268
|
createRecord = async (resource: AdminForthResource, diffData: any, adminUser: AdminUser) => {
|
|
265
269
|
const connector = this.adminforth.connectors[resource.dataSource];
|
|
270
|
+
//@ts-ignore
|
|
266
271
|
const err = this.adminforth.validateRecordValues(resource, diffData['newRecord'], 'create');
|
|
267
272
|
if (err) {
|
|
268
273
|
return { ok: false, error: err, createdRecord: null };
|
|
@@ -280,6 +285,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
280
285
|
editRecord = async (resource: AdminForthResource, diffData: any, targetRecordId: any, connector: IAdminForthDataSourceConnectorBase) => {
|
|
281
286
|
let oldRecord;
|
|
282
287
|
const dataToUse = diffData['newRecord'];
|
|
288
|
+
//@ts-ignore
|
|
283
289
|
const err = this.adminforth.validateRecordValues(resource, dataToUse, 'edit', targetRecordId);
|
|
284
290
|
if (err) {
|
|
285
291
|
return { error: err };
|
|
@@ -393,6 +399,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
393
399
|
afterSaveResp = await this.callAfterSaveHooks(
|
|
394
400
|
resource, action as AllowedActionsEnum, newRecord, adminUser,
|
|
395
401
|
diffRecord[this.options.resourceColumns.recordIdColumnName],
|
|
402
|
+
//@ts-ignore
|
|
396
403
|
newRecord, {}, this.adminforth, { body }
|
|
397
404
|
);
|
|
398
405
|
} else if (action === AllowedActionsEnum.edit) {
|
|
@@ -402,6 +409,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
402
409
|
);
|
|
403
410
|
afterSaveResp = await this.callAfterSaveHooks(
|
|
404
411
|
resource, action as AllowedActionsEnum, newRecord, adminUser,
|
|
412
|
+
//@ts-ignore
|
|
405
413
|
recordId, newRecord, oldRecord, this.adminforth, { body }
|
|
406
414
|
);
|
|
407
415
|
} else if (action === AllowedActionsEnum.delete) {
|
|
@@ -409,6 +417,7 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
409
417
|
afterSaveResp = await this.callAfterSaveHooks(
|
|
410
418
|
resource, action as AllowedActionsEnum, newRecord, adminUser,
|
|
411
419
|
diffRecord[this.options.resourceColumns.recordIdColumnName],
|
|
420
|
+
//@ts-ignore
|
|
412
421
|
{}, diffData['oldRecord'], this.adminforth, { body }
|
|
413
422
|
);
|
|
414
423
|
}
|
|
@@ -427,8 +436,11 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
427
436
|
[this.options.resourceColumns.responserIdColumnName]: authRes.authRes.pk,
|
|
428
437
|
},
|
|
429
438
|
extra: {
|
|
439
|
+
//@ts-ignore
|
|
430
440
|
adminforth_plugin_crud_approve: {
|
|
441
|
+
//@ts-ignore
|
|
431
442
|
callingFromApprovalPlugin: true
|
|
443
|
+
//@ts-ignore
|
|
432
444
|
}
|
|
433
445
|
}
|
|
434
446
|
});
|
|
@@ -443,4 +455,4 @@ export default class CRUDApprovePlugin extends AdminForthPlugin {
|
|
|
443
455
|
}
|
|
444
456
|
})
|
|
445
457
|
}
|
|
446
|
-
}
|
|
458
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/crud-approve-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -14,18 +14,17 @@
|
|
|
14
14
|
"url": "https://github.com/devforth/af-crud-approve-plugin.git"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsc && rsync -av --exclude 'node_modules' custom dist/"
|
|
18
|
-
"prepare": "npm link adminforth"
|
|
17
|
+
"build": "tsc && rsync -av --exclude 'node_modules' custom dist/"
|
|
19
18
|
},
|
|
20
19
|
"author": "devforth",
|
|
21
20
|
"license": "ISC",
|
|
22
21
|
"dependencies": {
|
|
23
|
-
"@adminforth/two-factors-auth": "^2.10.
|
|
24
|
-
"adminforth": "
|
|
22
|
+
"@adminforth/two-factors-auth": "^2.10.4",
|
|
23
|
+
"adminforth": "next",
|
|
25
24
|
"dayjs": "^1.11.11"
|
|
26
25
|
},
|
|
27
26
|
"peerDependencies": {
|
|
28
|
-
"adminforth": "^2.
|
|
27
|
+
"adminforth": "^2.24.0"
|
|
29
28
|
},
|
|
30
29
|
"release": {
|
|
31
30
|
"plugins": [
|
|
@@ -36,6 +35,7 @@
|
|
|
36
35
|
[
|
|
37
36
|
"semantic-release-slack-bot",
|
|
38
37
|
{
|
|
38
|
+
"packageName": "@adminforth/crud-approve-plugin",
|
|
39
39
|
"notifyOnSuccess": true,
|
|
40
40
|
"notifyOnFail": true,
|
|
41
41
|
"slackIcon": ":package:",
|