@adminforth/bulk-ai-flow 1.27.4 → 1.27.5
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/build.log +2 -2
- package/custom/VisionAction.vue +4 -6
- package/dist/custom/VisionAction.vue +4 -6
- package/dist/index.d.ts +14 -0
- package/dist/index.js +117 -25
- package/index.ts +134 -24
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -14,5 +14,5 @@ custom/package.json
|
|
|
14
14
|
custom/pnpm-lock.yaml
|
|
15
15
|
custom/tsconfig.json
|
|
16
16
|
|
|
17
|
-
sent 130,
|
|
18
|
-
total size is 129,
|
|
17
|
+
sent 130,414 bytes received 191 bytes 261,210.00 bytes/sec
|
|
18
|
+
total size is 129,691 speedup is 0.99
|
package/custom/VisionAction.vue
CHANGED
|
@@ -884,7 +884,7 @@ async function processOneRecord(recordId: string, sessionIds: string[]) {
|
|
|
884
884
|
record.label = oldDataResult._label || record.label;
|
|
885
885
|
initializeRecordData(record, oldDataResult);
|
|
886
886
|
if (props.meta.isAttachFiles) {
|
|
887
|
-
await fetchImages(record,
|
|
887
|
+
await fetchImages(record, recordId);
|
|
888
888
|
if (!checkIfDialogOpen()) {
|
|
889
889
|
return;
|
|
890
890
|
}
|
|
@@ -1162,16 +1162,14 @@ function normalizeEnumValue(key: string, value: any) {
|
|
|
1162
1162
|
return match ? value : null;
|
|
1163
1163
|
}
|
|
1164
1164
|
|
|
1165
|
-
async function fetchImages(record: RecordState,
|
|
1165
|
+
async function fetchImages(record: RecordState, recordId: string) {
|
|
1166
1166
|
try {
|
|
1167
1167
|
const res = await callAdminForthApi({
|
|
1168
1168
|
path: `/plugin/${props.meta.pluginInstanceId}/get_images`,
|
|
1169
1169
|
method: 'POST',
|
|
1170
|
-
body: {
|
|
1171
|
-
record: [oldRecord],
|
|
1172
|
-
},
|
|
1170
|
+
body: { recordId },
|
|
1173
1171
|
});
|
|
1174
|
-
record.images = res.images
|
|
1172
|
+
record.images = res.images || [];
|
|
1175
1173
|
touchRecords();
|
|
1176
1174
|
} catch (error) {
|
|
1177
1175
|
console.error('Failed to get images:', error);
|
|
@@ -884,7 +884,7 @@ async function processOneRecord(recordId: string, sessionIds: string[]) {
|
|
|
884
884
|
record.label = oldDataResult._label || record.label;
|
|
885
885
|
initializeRecordData(record, oldDataResult);
|
|
886
886
|
if (props.meta.isAttachFiles) {
|
|
887
|
-
await fetchImages(record,
|
|
887
|
+
await fetchImages(record, recordId);
|
|
888
888
|
if (!checkIfDialogOpen()) {
|
|
889
889
|
return;
|
|
890
890
|
}
|
|
@@ -1162,16 +1162,14 @@ function normalizeEnumValue(key: string, value: any) {
|
|
|
1162
1162
|
return match ? value : null;
|
|
1163
1163
|
}
|
|
1164
1164
|
|
|
1165
|
-
async function fetchImages(record: RecordState,
|
|
1165
|
+
async function fetchImages(record: RecordState, recordId: string) {
|
|
1166
1166
|
try {
|
|
1167
1167
|
const res = await callAdminForthApi({
|
|
1168
1168
|
path: `/plugin/${props.meta.pluginInstanceId}/get_images`,
|
|
1169
1169
|
method: 'POST',
|
|
1170
|
-
body: {
|
|
1171
|
-
record: [oldRecord],
|
|
1172
|
-
},
|
|
1170
|
+
body: { recordId },
|
|
1173
1171
|
});
|
|
1174
|
-
record.images = res.images
|
|
1172
|
+
record.images = res.images || [];
|
|
1175
1173
|
touchRecords();
|
|
1176
1174
|
} catch (error) {
|
|
1177
1175
|
console.error('Failed to get images:', error);
|
package/dist/index.d.ts
CHANGED
|
@@ -34,5 +34,19 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
34
34
|
oldRecord: any;
|
|
35
35
|
fields: Record<string, any>;
|
|
36
36
|
}): Promise<string | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Reads one record the way the core show route does: the resource-level `show` permission first,
|
|
39
|
+
* then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
|
|
40
|
+
* filters before the query runs.
|
|
41
|
+
* The returned record is the raw row, so callers which send it to the browser must pass it
|
|
42
|
+
* through `scopeRecordForFrontend` first.
|
|
43
|
+
*/
|
|
44
|
+
private getRecordForShow;
|
|
45
|
+
/**
|
|
46
|
+
* The action dialog only ever renders the fields this plugin generates, so only those leave the
|
|
47
|
+
* backend, next to the primary key and the record label. backendOnly columns are dropped the same
|
|
48
|
+
* way the core show route drops them.
|
|
49
|
+
*/
|
|
50
|
+
private scopeRecordForFrontend;
|
|
37
51
|
setupEndpoints(server: IHttpServer): void;
|
|
38
52
|
}
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const getRecordsBodySchema = z.object({
|
|
|
17
17
|
record: z.array(z.any()).nullish(),
|
|
18
18
|
}).strict();
|
|
19
19
|
const getImagesBodySchema = z.object({
|
|
20
|
-
|
|
20
|
+
recordId: z.union([z.string(), z.number()]),
|
|
21
21
|
}).strict();
|
|
22
22
|
const getOldDataBodySchema = z.object({
|
|
23
23
|
recordId: z.union([z.string(), z.number()]).nullish(),
|
|
@@ -28,7 +28,7 @@ const updateFieldsBodySchema = z.object({
|
|
|
28
28
|
saveImages: z.boolean().nullish(),
|
|
29
29
|
}).strict();
|
|
30
30
|
const getImageGenerationPromptsBodySchema = z.object({
|
|
31
|
-
recordId: z.union([z.string(), z.number()])
|
|
31
|
+
recordId: z.union([z.string(), z.number()]),
|
|
32
32
|
customPrompt: z.string().nullish(),
|
|
33
33
|
}).strict();
|
|
34
34
|
const createJobBodySchema = z.object({
|
|
@@ -907,44 +907,126 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
907
907
|
return null;
|
|
908
908
|
});
|
|
909
909
|
}
|
|
910
|
+
/**
|
|
911
|
+
* Reads one record the way the core show route does: the resource-level `show` permission first,
|
|
912
|
+
* then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
|
|
913
|
+
* filters before the query runs.
|
|
914
|
+
* The returned record is the raw row, so callers which send it to the browser must pass it
|
|
915
|
+
* through `scopeRecordForFrontend` first.
|
|
916
|
+
*/
|
|
917
|
+
getRecordForShow(_a) {
|
|
918
|
+
return __awaiter(this, arguments, void 0, function* ({ adminUser, recordId, extra }) {
|
|
919
|
+
var _b, _c;
|
|
920
|
+
const meta = { requestBody: extra.body, pk: recordId };
|
|
921
|
+
const ctx = {
|
|
922
|
+
adminUser,
|
|
923
|
+
resource: this.resourceConfig,
|
|
924
|
+
meta,
|
|
925
|
+
source: ActionCheckSource.ShowRequest,
|
|
926
|
+
adminforth: this.adminforth,
|
|
927
|
+
};
|
|
928
|
+
const { allowedActions } = yield interpretResource(adminUser, this.resourceConfig, meta, ActionCheckSource.ShowRequest, this.adminforth);
|
|
929
|
+
const showAllowed = allowedActions[AllowedActionsEnum.show];
|
|
930
|
+
if (showAllowed !== true) {
|
|
931
|
+
return { error: typeof showAllowed === 'string' ? showAllowed : 'You are not allowed to view records in this resource' };
|
|
932
|
+
}
|
|
933
|
+
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
934
|
+
const hookQuery = {
|
|
935
|
+
resourceId: this.resourceConfig.resourceId,
|
|
936
|
+
source: 'show',
|
|
937
|
+
filters: [Filters.EQ(primaryKeyColumn.name, recordId)],
|
|
938
|
+
limit: 1,
|
|
939
|
+
offset: 0,
|
|
940
|
+
sort: [],
|
|
941
|
+
};
|
|
942
|
+
for (const hook of ((_c = (_b = this.resourceConfig.hooks) === null || _b === void 0 ? void 0 : _b.show) === null || _c === void 0 ? void 0 : _c.beforeDatasourceRequest) || []) {
|
|
943
|
+
const filterTools = filtersTools.get(hookQuery);
|
|
944
|
+
hookQuery.filtersTools = filterTools;
|
|
945
|
+
const resp = yield hook({
|
|
946
|
+
resource: this.resourceConfig,
|
|
947
|
+
query: hookQuery,
|
|
948
|
+
adminUser,
|
|
949
|
+
//@ts-ignore
|
|
950
|
+
filtersTools: filterTools,
|
|
951
|
+
extra,
|
|
952
|
+
adminforth: this.adminforth,
|
|
953
|
+
});
|
|
954
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
955
|
+
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
956
|
+
}
|
|
957
|
+
if (resp.error) {
|
|
958
|
+
return { error: resp.error };
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get(hookQuery.filters);
|
|
962
|
+
if (!record) {
|
|
963
|
+
return { error: 'Record not found' };
|
|
964
|
+
}
|
|
965
|
+
return { record, ctx };
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* The action dialog only ever renders the fields this plugin generates, so only those leave the
|
|
970
|
+
* backend, next to the primary key and the record label. backendOnly columns are dropped the same
|
|
971
|
+
* way the core show route drops them.
|
|
972
|
+
*/
|
|
973
|
+
scopeRecordForFrontend(record, ctx) {
|
|
974
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
975
|
+
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
976
|
+
const managedFields = this.pluginManagedFields();
|
|
977
|
+
const scoped = {
|
|
978
|
+
[primaryKeyColumn.name]: record[primaryKeyColumn.name],
|
|
979
|
+
_label: this.resourceConfig.recordLabel(record),
|
|
980
|
+
};
|
|
981
|
+
for (const column of this.resourceConfig.columns.filter((col) => managedFields.has(col.name))) {
|
|
982
|
+
if (yield resolveBoolOrFn(column.backendOnly, ctx)) {
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
scoped[column.name] = record[column.name];
|
|
986
|
+
}
|
|
987
|
+
return scoped;
|
|
988
|
+
});
|
|
989
|
+
}
|
|
910
990
|
setupEndpoints(server) {
|
|
911
991
|
server.endpoint({
|
|
912
992
|
method: 'POST',
|
|
913
993
|
path: `/plugin/${this.pluginInstanceId}/get_old_data`,
|
|
914
994
|
request_schema: getOldDataBodySchema,
|
|
915
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body,
|
|
995
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
|
|
916
996
|
const data = body;
|
|
917
997
|
const recordId = data.recordId;
|
|
918
998
|
if (recordId === undefined || recordId === null) {
|
|
919
999
|
return { ok: false, error: "Missing recordId" };
|
|
920
1000
|
}
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1001
|
+
const { record, ctx, error } = yield this.getRecordForShow({
|
|
1002
|
+
adminUser,
|
|
1003
|
+
recordId,
|
|
1004
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1005
|
+
});
|
|
1006
|
+
if (error) {
|
|
1007
|
+
return { ok: false, error };
|
|
926
1008
|
}
|
|
927
|
-
record
|
|
928
|
-
return { ok: true, record };
|
|
1009
|
+
return { ok: true, record: yield this.scopeRecordForFrontend(record, ctx) };
|
|
929
1010
|
})
|
|
930
1011
|
});
|
|
931
1012
|
server.endpoint({
|
|
932
1013
|
method: 'POST',
|
|
933
1014
|
path: `/plugin/${this.pluginInstanceId}/get_images`,
|
|
934
1015
|
request_schema: getImagesBodySchema,
|
|
935
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body,
|
|
1016
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
|
|
936
1017
|
const data = body;
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1018
|
+
// attachFiles runs with server privileges and usually mints download URLs, so it is only
|
|
1019
|
+
// ever given a record loaded here after the show check, never one supplied by the client
|
|
1020
|
+
const { record, error } = yield this.getRecordForShow({
|
|
1021
|
+
adminUser,
|
|
1022
|
+
recordId: data.recordId,
|
|
1023
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1024
|
+
});
|
|
1025
|
+
if (error) {
|
|
1026
|
+
return { ok: false, error };
|
|
944
1027
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
};
|
|
1028
|
+
const images = this.options.attachFiles ? yield this.options.attachFiles({ record }) : [];
|
|
1029
|
+
return { ok: true, images };
|
|
948
1030
|
})
|
|
949
1031
|
});
|
|
950
1032
|
server.endpoint({
|
|
@@ -1074,12 +1156,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
1074
1156
|
method: 'POST',
|
|
1075
1157
|
path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
|
|
1076
1158
|
request_schema: getImageGenerationPromptsBodySchema,
|
|
1077
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, headers,
|
|
1078
|
-
var _b;
|
|
1159
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl }) {
|
|
1079
1160
|
const data = body;
|
|
1080
|
-
const Id = data.recordId || [];
|
|
1081
1161
|
const customPrompt = data.customPrompt || null;
|
|
1082
|
-
const record = yield this.
|
|
1162
|
+
const { record, error } = yield this.getRecordForShow({
|
|
1163
|
+
adminUser,
|
|
1164
|
+
recordId: data.recordId,
|
|
1165
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1166
|
+
});
|
|
1167
|
+
if (error) {
|
|
1168
|
+
return { ok: false, error };
|
|
1169
|
+
}
|
|
1083
1170
|
const compiledGenerationOptions = yield this.compileGenerationFieldTemplates(record, JSON.stringify({ "prompt": customPrompt }));
|
|
1084
1171
|
return compiledGenerationOptions;
|
|
1085
1172
|
})
|
|
@@ -1258,6 +1345,11 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
1258
1345
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers, query, cookies, requestUrl, response }) {
|
|
1259
1346
|
var _b, _c;
|
|
1260
1347
|
const resource = this.resourceConfig;
|
|
1348
|
+
const { allowedActions } = yield interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.ListRequest, this.adminforth);
|
|
1349
|
+
const listAllowed = allowedActions[AllowedActionsEnum.list];
|
|
1350
|
+
if (listAllowed !== true) {
|
|
1351
|
+
return { ok: false, error: typeof listAllowed === 'string' ? listAllowed : 'You are not allowed to list records in this resource' };
|
|
1352
|
+
}
|
|
1261
1353
|
for (const hook of ((_c = (_b = resource.hooks) === null || _b === void 0 ? void 0 : _b.list) === null || _c === void 0 ? void 0 : _c.beforeDatasourceRequest) || []) {
|
|
1262
1354
|
const filterTools = filtersTools.get(body);
|
|
1263
1355
|
body.filtersTools = filterTools;
|
package/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ const getRecordsBodySchema = z.object({
|
|
|
12
12
|
}).strict();
|
|
13
13
|
|
|
14
14
|
const getImagesBodySchema = z.object({
|
|
15
|
-
|
|
15
|
+
recordId: z.union([z.string(), z.number()]),
|
|
16
16
|
}).strict();
|
|
17
17
|
|
|
18
18
|
const getOldDataBodySchema = z.object({
|
|
@@ -26,7 +26,7 @@ const updateFieldsBodySchema = z.object({
|
|
|
26
26
|
}).strict();
|
|
27
27
|
|
|
28
28
|
const getImageGenerationPromptsBodySchema = z.object({
|
|
29
|
-
recordId: z.union([z.string(), z.number()])
|
|
29
|
+
recordId: z.union([z.string(), z.number()]),
|
|
30
30
|
customPrompt: z.string().nullish(),
|
|
31
31
|
}).strict();
|
|
32
32
|
|
|
@@ -949,25 +949,116 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
949
949
|
return null;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
/**
|
|
953
|
+
* Reads one record the way the core show route does: the resource-level `show` permission first,
|
|
954
|
+
* then the resource's own `show.beforeDatasourceRequest` hooks so row-level scoping narrows the
|
|
955
|
+
* filters before the query runs.
|
|
956
|
+
* The returned record is the raw row, so callers which send it to the browser must pass it
|
|
957
|
+
* through `scopeRecordForFrontend` first.
|
|
958
|
+
*/
|
|
959
|
+
private async getRecordForShow({ adminUser, recordId, extra }: {
|
|
960
|
+
adminUser: AdminUser,
|
|
961
|
+
recordId: any,
|
|
962
|
+
extra: { body: any, query: any, headers: any, cookies: any, requestUrl: string },
|
|
963
|
+
}): Promise<{ record?: any, ctx?: AccessCheckContext, error?: string }> {
|
|
964
|
+
const meta = { requestBody: extra.body, pk: recordId };
|
|
965
|
+
const ctx: AccessCheckContext = {
|
|
966
|
+
adminUser,
|
|
967
|
+
resource: this.resourceConfig,
|
|
968
|
+
meta,
|
|
969
|
+
source: ActionCheckSource.ShowRequest,
|
|
970
|
+
adminforth: this.adminforth,
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
const { allowedActions } = await interpretResource(
|
|
974
|
+
adminUser,
|
|
975
|
+
this.resourceConfig,
|
|
976
|
+
meta,
|
|
977
|
+
ActionCheckSource.ShowRequest,
|
|
978
|
+
this.adminforth,
|
|
979
|
+
);
|
|
980
|
+
const showAllowed = allowedActions[AllowedActionsEnum.show] as boolean | string | undefined;
|
|
981
|
+
if (showAllowed !== true) {
|
|
982
|
+
return { error: typeof showAllowed === 'string' ? showAllowed : 'You are not allowed to view records in this resource' };
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
986
|
+
const hookQuery: any = {
|
|
987
|
+
resourceId: this.resourceConfig.resourceId,
|
|
988
|
+
source: 'show',
|
|
989
|
+
filters: [Filters.EQ(primaryKeyColumn.name, recordId)],
|
|
990
|
+
limit: 1,
|
|
991
|
+
offset: 0,
|
|
992
|
+
sort: [],
|
|
993
|
+
};
|
|
994
|
+
for (const hook of this.resourceConfig.hooks?.show?.beforeDatasourceRequest || []) {
|
|
995
|
+
const filterTools = filtersTools.get(hookQuery);
|
|
996
|
+
hookQuery.filtersTools = filterTools;
|
|
997
|
+
const resp = await hook({
|
|
998
|
+
resource: this.resourceConfig,
|
|
999
|
+
query: hookQuery,
|
|
1000
|
+
adminUser,
|
|
1001
|
+
//@ts-ignore
|
|
1002
|
+
filtersTools: filterTools,
|
|
1003
|
+
extra,
|
|
1004
|
+
adminforth: this.adminforth,
|
|
1005
|
+
});
|
|
1006
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
1007
|
+
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
1008
|
+
}
|
|
1009
|
+
if (resp.error) {
|
|
1010
|
+
return { error: resp.error };
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get(hookQuery.filters);
|
|
1015
|
+
if (!record) {
|
|
1016
|
+
return { error: 'Record not found' };
|
|
1017
|
+
}
|
|
1018
|
+
return { record, ctx };
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* The action dialog only ever renders the fields this plugin generates, so only those leave the
|
|
1023
|
+
* backend, next to the primary key and the record label. backendOnly columns are dropped the same
|
|
1024
|
+
* way the core show route drops them.
|
|
1025
|
+
*/
|
|
1026
|
+
private async scopeRecordForFrontend(record: any, ctx: AccessCheckContext): Promise<Record<string, any>> {
|
|
1027
|
+
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
1028
|
+
const managedFields = this.pluginManagedFields();
|
|
1029
|
+
const scoped: Record<string, any> = {
|
|
1030
|
+
[primaryKeyColumn.name]: record[primaryKeyColumn.name],
|
|
1031
|
+
_label: this.resourceConfig.recordLabel(record),
|
|
1032
|
+
};
|
|
1033
|
+
for (const column of this.resourceConfig.columns.filter((col) => managedFields.has(col.name))) {
|
|
1034
|
+
if (await resolveBoolOrFn(column.backendOnly, ctx)) {
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
scoped[column.name] = record[column.name];
|
|
1038
|
+
}
|
|
1039
|
+
return scoped;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
952
1042
|
setupEndpoints(server: IHttpServer) {
|
|
953
1043
|
server.endpoint({
|
|
954
1044
|
method: 'POST',
|
|
955
1045
|
path: `/plugin/${this.pluginInstanceId}/get_old_data`,
|
|
956
1046
|
request_schema: getOldDataBodySchema,
|
|
957
|
-
handler: async ({ body,
|
|
1047
|
+
handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
|
|
958
1048
|
const data = body as z.infer<typeof getOldDataBodySchema>;
|
|
959
1049
|
const recordId = data.recordId;
|
|
960
1050
|
if (recordId === undefined || recordId === null) {
|
|
961
1051
|
return { ok: false, error: "Missing recordId" };
|
|
962
1052
|
}
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1053
|
+
const { record, ctx, error } = await this.getRecordForShow({
|
|
1054
|
+
adminUser,
|
|
1055
|
+
recordId,
|
|
1056
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1057
|
+
});
|
|
1058
|
+
if (error) {
|
|
1059
|
+
return { ok: false, error };
|
|
968
1060
|
}
|
|
969
|
-
record
|
|
970
|
-
return { ok: true, record };
|
|
1061
|
+
return { ok: true, record: await this.scopeRecordForFrontend(record, ctx) };
|
|
971
1062
|
}
|
|
972
1063
|
});
|
|
973
1064
|
|
|
@@ -976,19 +1067,20 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
976
1067
|
method: 'POST',
|
|
977
1068
|
path: `/plugin/${this.pluginInstanceId}/get_images`,
|
|
978
1069
|
request_schema: getImagesBodySchema,
|
|
979
|
-
handler: async ({ body,
|
|
1070
|
+
handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
|
|
980
1071
|
const data = body as z.infer<typeof getImagesBodySchema>;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1072
|
+
// attachFiles runs with server privileges and usually mints download URLs, so it is only
|
|
1073
|
+
// ever given a record loaded here after the show check, never one supplied by the client
|
|
1074
|
+
const { record, error } = await this.getRecordForShow({
|
|
1075
|
+
adminUser,
|
|
1076
|
+
recordId: data.recordId,
|
|
1077
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1078
|
+
});
|
|
1079
|
+
if (error) {
|
|
1080
|
+
return { ok: false, error };
|
|
988
1081
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
};
|
|
1082
|
+
const images = this.options.attachFiles ? await this.options.attachFiles({ record }) : [];
|
|
1083
|
+
return { ok: true, images };
|
|
992
1084
|
}
|
|
993
1085
|
});
|
|
994
1086
|
|
|
@@ -1130,11 +1222,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
1130
1222
|
method: 'POST',
|
|
1131
1223
|
path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
|
|
1132
1224
|
request_schema: getImageGenerationPromptsBodySchema,
|
|
1133
|
-
handler: async ({ body, headers,
|
|
1225
|
+
handler: async ({ body, adminUser, headers, query, cookies, requestUrl }) => {
|
|
1134
1226
|
const data = body as z.infer<typeof getImageGenerationPromptsBodySchema>;
|
|
1135
|
-
const Id = data.recordId || [];
|
|
1136
1227
|
const customPrompt = data.customPrompt || null;
|
|
1137
|
-
const record = await this.
|
|
1228
|
+
const { record, error } = await this.getRecordForShow({
|
|
1229
|
+
adminUser,
|
|
1230
|
+
recordId: data.recordId,
|
|
1231
|
+
extra: { body, query, headers, cookies, requestUrl },
|
|
1232
|
+
});
|
|
1233
|
+
if (error) {
|
|
1234
|
+
return { ok: false, error };
|
|
1235
|
+
}
|
|
1138
1236
|
const compiledGenerationOptions = await this.compileGenerationFieldTemplates(record, JSON.stringify({"prompt": customPrompt}));
|
|
1139
1237
|
return compiledGenerationOptions;
|
|
1140
1238
|
}
|
|
@@ -1324,6 +1422,18 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
1324
1422
|
handler: async ({ body, adminUser, headers, query, cookies, requestUrl, response }) => {
|
|
1325
1423
|
const resource = this.resourceConfig;
|
|
1326
1424
|
|
|
1425
|
+
const { allowedActions } = await interpretResource(
|
|
1426
|
+
adminUser,
|
|
1427
|
+
resource,
|
|
1428
|
+
{ requestBody: body },
|
|
1429
|
+
ActionCheckSource.ListRequest,
|
|
1430
|
+
this.adminforth,
|
|
1431
|
+
);
|
|
1432
|
+
const listAllowed = allowedActions[AllowedActionsEnum.list] as boolean | string | undefined;
|
|
1433
|
+
if (listAllowed !== true) {
|
|
1434
|
+
return { ok: false, error: typeof listAllowed === 'string' ? listAllowed : 'You are not allowed to list records in this resource' };
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1327
1437
|
for (const hook of resource.hooks?.list?.beforeDatasourceRequest || []) {
|
|
1328
1438
|
const filterTools = filtersTools.get(body);
|
|
1329
1439
|
body.filtersTools = filterTools;
|