@strapi/upload 5.60.0 → 5.61.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/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.js +29 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.js.map +1 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.mjs +27 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.mjs.map +1 -0
- package/dist/admin/components/Drawer.js +12 -7
- package/dist/admin/components/Drawer.js.map +1 -1
- package/dist/admin/components/Drawer.mjs +12 -7
- package/dist/admin/components/Drawer.mjs.map +1 -1
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.js +188 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.js.map +1 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.mjs +186 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +5 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +5 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +37 -27
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +37 -27
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.js +46 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.mjs +43 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.mjs.map +1 -0
- package/dist/admin/index.js +10 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +10 -1
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/pages/Assets/AssetsPage.js +1 -1
- package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/pages/Assets/AssetsPage.mjs +2 -2
- package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +2 -2
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +181 -65
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +184 -69
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetPreview.mjs +1 -1
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.js +2 -6
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.js.map +1 -1
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.mjs +2 -6
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.mjs.map +1 -1
- package/dist/admin/src/components/AssetPickerDialog/MediaLibraryPickerDialog.d.ts +19 -0
- package/dist/admin/src/components/Drawer.d.ts +8 -0
- package/dist/admin/src/components/EditorFileDropZone/EditorFileDropZone.d.ts +21 -0
- package/dist/admin/src/components/MediaLibraryInput/AddAssetMenu.d.ts +7 -1
- package/dist/admin/src/components/MediaLibraryInput/openAssetDetails.d.ts +10 -0
- package/dist/admin/src/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +41 -5
- package/dist/admin/src/pages/Assets/hooks/useIsAssetDetailsOpen.d.ts +2 -6
- package/dist/admin/translations/en.json.js +4 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +4 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/audit-logs.js +264 -0
- package/dist/server/audit-logs.js.map +1 -0
- package/dist/server/audit-logs.mjs +255 -0
- package/dist/server/audit-logs.mjs.map +1 -0
- package/dist/server/bootstrap.js +4 -0
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs +4 -0
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/controllers/admin-folder-file.js +23 -1
- package/dist/server/controllers/admin-folder-file.js.map +1 -1
- package/dist/server/controllers/admin-folder-file.mjs +23 -1
- package/dist/server/controllers/admin-folder-file.mjs.map +1 -1
- package/dist/server/services/folder.js +48 -1
- package/dist/server/services/folder.js.map +1 -1
- package/dist/server/services/folder.mjs +48 -1
- package/dist/server/services/folder.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +12 -5
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +12 -5
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/services/upload.js +100 -16
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +102 -18
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/audit-logs.d.ts +142 -0
- package/dist/server/src/audit-logs.d.ts.map +1 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-folder-file.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -3
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
- package/dist/server/src/services/folder.d.ts.map +1 -1
- package/dist/server/src/services/image-manipulation.d.ts +3 -3
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +3 -3
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/package.json +9 -16
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { emitAudit } from '@strapi/utils';
|
|
2
|
+
|
|
3
|
+
const AUDITED_EVENTS = {
|
|
4
|
+
UPLOAD_SETTINGS_UPDATE: 'upload-settings.update',
|
|
5
|
+
MEDIA_CREATE: 'media.create',
|
|
6
|
+
MEDIA_UPDATE: 'media.update',
|
|
7
|
+
MEDIA_DELETE: 'media.delete',
|
|
8
|
+
MEDIA_MOVE: 'media.move',
|
|
9
|
+
FOLDER_CREATE: 'media-folder.create',
|
|
10
|
+
FOLDER_UPDATE: 'media-folder.update',
|
|
11
|
+
// Audit-only events. media.update is a webhook event that carries neither the file as it was
|
|
12
|
+
// nor its folder; media-folder.delete carries every deleted folder in one event.
|
|
13
|
+
MEDIA_UPDATE_AUDIT: 'media.update.audit',
|
|
14
|
+
FOLDER_DELETE_AUDIT: 'media-folder.delete.audit'
|
|
15
|
+
};
|
|
16
|
+
const AUDITED_SETTINGS = [
|
|
17
|
+
'sizeOptimization',
|
|
18
|
+
'responsiveDimensions',
|
|
19
|
+
'autoOrientation',
|
|
20
|
+
'aiMetadata'
|
|
21
|
+
];
|
|
22
|
+
// The store replaces the whole value, so an option missing from the request is removed and recorded as null.
|
|
23
|
+
const getUploadSettingsChanges = (previous, next)=>{
|
|
24
|
+
const changes = {};
|
|
25
|
+
for (const setting of AUDITED_SETTINGS){
|
|
26
|
+
const before = previous?.[setting] ?? null;
|
|
27
|
+
const after = next[setting] ?? null;
|
|
28
|
+
if (before !== after) {
|
|
29
|
+
changes[setting] = {
|
|
30
|
+
before,
|
|
31
|
+
after
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return changes;
|
|
36
|
+
};
|
|
37
|
+
const toFolderRef = (folder)=>folder ? {
|
|
38
|
+
id: Number(folder.id),
|
|
39
|
+
name: folder.name ?? null
|
|
40
|
+
} : null;
|
|
41
|
+
/** Picks the fields the audit log compares. */ const toAuditedFile = (file)=>({
|
|
42
|
+
id: Number(file.id),
|
|
43
|
+
name: file.name,
|
|
44
|
+
mime: file.mime,
|
|
45
|
+
size: file.size,
|
|
46
|
+
alternativeText: file.alternativeText ?? null,
|
|
47
|
+
caption: file.caption ?? null,
|
|
48
|
+
focalPoint: file.focalPoint ?? null,
|
|
49
|
+
folder: toFolderRef(file.folder)
|
|
50
|
+
});
|
|
51
|
+
const summarizeFile = (file)=>({
|
|
52
|
+
name: file.name,
|
|
53
|
+
mime: file.mime ?? null,
|
|
54
|
+
size: file.size ?? null
|
|
55
|
+
});
|
|
56
|
+
const getMediaChanges = ({ file: media, previous, replaced })=>{
|
|
57
|
+
const changes = {};
|
|
58
|
+
if (previous.name !== media.name) {
|
|
59
|
+
changes.name = {
|
|
60
|
+
before: previous.name,
|
|
61
|
+
after: media.name
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// The admin sends '' for an empty field that is stored as null
|
|
65
|
+
const blankAsNull = (value)=>value || null;
|
|
66
|
+
for (const field of [
|
|
67
|
+
'alternativeText',
|
|
68
|
+
'caption'
|
|
69
|
+
]){
|
|
70
|
+
const before = previous[field] ?? null;
|
|
71
|
+
const after = media[field] ?? null;
|
|
72
|
+
if (blankAsNull(before) !== blankAsNull(after)) {
|
|
73
|
+
changes[field] = {
|
|
74
|
+
before,
|
|
75
|
+
after
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const focalBefore = previous.focalPoint ?? null;
|
|
80
|
+
const focalAfter = media.focalPoint ?? null;
|
|
81
|
+
if (JSON.stringify(focalBefore) !== JSON.stringify(focalAfter)) {
|
|
82
|
+
changes.focalPoint = {
|
|
83
|
+
before: focalBefore,
|
|
84
|
+
after: focalAfter
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const folderBefore = toFolderRef(previous.folder);
|
|
88
|
+
const folderAfter = toFolderRef(media.folder);
|
|
89
|
+
if ((folderBefore?.id ?? null) !== (folderAfter?.id ?? null)) {
|
|
90
|
+
changes.folder = {
|
|
91
|
+
before: folderBefore,
|
|
92
|
+
after: folderAfter
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (replaced) {
|
|
96
|
+
changes.file = {
|
|
97
|
+
before: summarizeFile(previous),
|
|
98
|
+
after: summarizeFile(media)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return changes;
|
|
102
|
+
};
|
|
103
|
+
const getFolderChanges = ({ folder, previous })=>{
|
|
104
|
+
if (!previous) {
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
const changes = {};
|
|
108
|
+
if (previous.name !== folder.name) {
|
|
109
|
+
changes.name = {
|
|
110
|
+
before: previous.name,
|
|
111
|
+
after: folder.name
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const parentBefore = toFolderRef(previous.parent);
|
|
115
|
+
const parentAfter = toFolderRef(folder.parent);
|
|
116
|
+
if ((parentBefore?.id ?? null) !== (parentAfter?.id ?? null)) {
|
|
117
|
+
changes.parent = {
|
|
118
|
+
before: parentBefore,
|
|
119
|
+
after: parentAfter
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return changes;
|
|
123
|
+
};
|
|
124
|
+
const readParents = async (read, joinTable, ids)=>{
|
|
125
|
+
if (ids.length === 0) {
|
|
126
|
+
return new Map();
|
|
127
|
+
}
|
|
128
|
+
const { joinColumn, inverseJoinColumn } = joinTable;
|
|
129
|
+
const rows = await read(joinTable.name).select(joinColumn.name, inverseJoinColumn.name).whereIn(joinColumn.name, ids);
|
|
130
|
+
return new Map(rows.map((row)=>[
|
|
131
|
+
Number(row[joinColumn.name]),
|
|
132
|
+
Number(row[inverseJoinColumn.name])
|
|
133
|
+
]));
|
|
134
|
+
};
|
|
135
|
+
const readMediaMoves = async (read, { files, folders, destinationFolderId, fileFolderJoinTable, folderParentJoinTable, folderTable })=>{
|
|
136
|
+
const fileParents = await readParents(read, fileFolderJoinTable, files.map((file)=>Number(file.id)));
|
|
137
|
+
const folderParents = await readParents(read, folderParentJoinTable, folders.map((folder)=>Number(folder.id)));
|
|
138
|
+
const destinationId = destinationFolderId === null ? null : Number(destinationFolderId);
|
|
139
|
+
const referencedIds = new Set([
|
|
140
|
+
...fileParents.values(),
|
|
141
|
+
...folderParents.values()
|
|
142
|
+
]);
|
|
143
|
+
if (destinationId !== null) {
|
|
144
|
+
referencedIds.add(destinationId);
|
|
145
|
+
}
|
|
146
|
+
const folderNames = new Map();
|
|
147
|
+
if (referencedIds.size > 0) {
|
|
148
|
+
const rows = await read(folderTable).select('id', 'name').whereIn('id', [
|
|
149
|
+
...referencedIds
|
|
150
|
+
]);
|
|
151
|
+
rows.forEach((row)=>folderNames.set(Number(row.id), row.name ?? null));
|
|
152
|
+
}
|
|
153
|
+
const toRef = (id)=>id == null ? null : {
|
|
154
|
+
id,
|
|
155
|
+
name: folderNames.get(id) ?? null
|
|
156
|
+
};
|
|
157
|
+
const to = toRef(destinationId);
|
|
158
|
+
return [
|
|
159
|
+
...files.map((file)=>({
|
|
160
|
+
kind: 'file',
|
|
161
|
+
id: Number(file.id),
|
|
162
|
+
name: file.name,
|
|
163
|
+
from: toRef(fileParents.get(Number(file.id))),
|
|
164
|
+
to
|
|
165
|
+
})),
|
|
166
|
+
...folders.map((folder)=>({
|
|
167
|
+
kind: 'folder',
|
|
168
|
+
id: Number(folder.id),
|
|
169
|
+
name: folder.name,
|
|
170
|
+
from: toRef(folderParents.get(Number(folder.id))),
|
|
171
|
+
to
|
|
172
|
+
}))
|
|
173
|
+
];
|
|
174
|
+
};
|
|
175
|
+
const emitMediaMoves = async ({ strapi }, moves)=>{
|
|
176
|
+
for (const move of moves){
|
|
177
|
+
if ((move.from?.id ?? null) !== (move.to?.id ?? null)) {
|
|
178
|
+
await emitAudit({
|
|
179
|
+
strapi
|
|
180
|
+
}, AUDITED_EVENTS.MEDIA_MOVE, move);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const registerAuditEvents = (auditLogsLifecycle)=>{
|
|
185
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.UPLOAD_SETTINGS_UPDATE, (event)=>({
|
|
186
|
+
resource: {
|
|
187
|
+
type: 'upload-settings'
|
|
188
|
+
},
|
|
189
|
+
details: {
|
|
190
|
+
changes: event.changes
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
193
|
+
const fileResource = (file)=>({
|
|
194
|
+
type: 'media',
|
|
195
|
+
id: Number(file.id),
|
|
196
|
+
name: file.name
|
|
197
|
+
});
|
|
198
|
+
const folderResource = (folder)=>({
|
|
199
|
+
type: 'media-folder',
|
|
200
|
+
id: Number(folder.id),
|
|
201
|
+
name: folder.name
|
|
202
|
+
});
|
|
203
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.MEDIA_CREATE, ({ media })=>({
|
|
204
|
+
resource: fileResource(media),
|
|
205
|
+
details: {
|
|
206
|
+
mime: media.mime ?? null,
|
|
207
|
+
size: media.size ?? null
|
|
208
|
+
}
|
|
209
|
+
}));
|
|
210
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.MEDIA_UPDATE_AUDIT, (event)=>({
|
|
211
|
+
resource: fileResource(event.file),
|
|
212
|
+
details: {
|
|
213
|
+
changes: getMediaChanges(event)
|
|
214
|
+
}
|
|
215
|
+
}), {
|
|
216
|
+
action: AUDITED_EVENTS.MEDIA_UPDATE,
|
|
217
|
+
shouldRecord: (event)=>Object.keys(getMediaChanges(event)).length > 0
|
|
218
|
+
});
|
|
219
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.MEDIA_DELETE, ({ media })=>({
|
|
220
|
+
resource: fileResource(media)
|
|
221
|
+
}));
|
|
222
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.FOLDER_CREATE, ({ folder })=>({
|
|
223
|
+
resource: folderResource(folder)
|
|
224
|
+
}), {
|
|
225
|
+
action: AUDITED_EVENTS.MEDIA_CREATE
|
|
226
|
+
});
|
|
227
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.FOLDER_UPDATE, (event)=>({
|
|
228
|
+
resource: folderResource(event.folder),
|
|
229
|
+
details: {
|
|
230
|
+
changes: getFolderChanges(event)
|
|
231
|
+
}
|
|
232
|
+
}), {
|
|
233
|
+
action: AUDITED_EVENTS.MEDIA_UPDATE,
|
|
234
|
+
shouldRecord: (event)=>Object.keys(getFolderChanges(event)).length > 0
|
|
235
|
+
});
|
|
236
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.FOLDER_DELETE_AUDIT, ({ folder })=>({
|
|
237
|
+
resource: folderResource(folder)
|
|
238
|
+
}), {
|
|
239
|
+
action: AUDITED_EVENTS.MEDIA_DELETE
|
|
240
|
+
});
|
|
241
|
+
auditLogsLifecycle.registerEvent(AUDITED_EVENTS.MEDIA_MOVE, (event)=>({
|
|
242
|
+
resource: {
|
|
243
|
+
type: event.kind === 'file' ? 'media' : 'media-folder',
|
|
244
|
+
id: event.id,
|
|
245
|
+
name: event.name
|
|
246
|
+
},
|
|
247
|
+
details: {
|
|
248
|
+
from: event.from,
|
|
249
|
+
to: event.to
|
|
250
|
+
}
|
|
251
|
+
}));
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export { AUDITED_EVENTS, emitMediaMoves, getFolderChanges, getMediaChanges, getUploadSettingsChanges, readMediaMoves, registerAuditEvents, toAuditedFile };
|
|
255
|
+
//# sourceMappingURL=audit-logs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logs.mjs","sources":["../../server/src/audit-logs.ts"],"sourcesContent":["import { emitAudit } from '@strapi/utils';\nimport type { Core, Modules } from '@strapi/types';\n\nimport type { Settings } from './controllers/validation/admin/settings';\n\nexport const AUDITED_EVENTS = {\n UPLOAD_SETTINGS_UPDATE: 'upload-settings.update',\n MEDIA_CREATE: 'media.create',\n MEDIA_UPDATE: 'media.update',\n MEDIA_DELETE: 'media.delete',\n MEDIA_MOVE: 'media.move',\n FOLDER_CREATE: 'media-folder.create',\n FOLDER_UPDATE: 'media-folder.update',\n // Audit-only events. media.update is a webhook event that carries neither the file as it was\n // nor its folder; media-folder.delete carries every deleted folder in one event.\n MEDIA_UPDATE_AUDIT: 'media.update.audit',\n FOLDER_DELETE_AUDIT: 'media-folder.delete.audit',\n} as const;\n\nconst AUDITED_SETTINGS = [\n 'sizeOptimization',\n 'responsiveDimensions',\n 'autoOrientation',\n 'aiMetadata',\n] as const;\n\nexport type UploadSettingsChanges = Partial<\n Record<(typeof AUDITED_SETTINGS)[number], Modules.AuditLogs.FieldChange<boolean | null>>\n>;\n\nexport interface SettingsUpdateDetails {\n changes: UploadSettingsChanges;\n}\n\n// The store replaces the whole value, so an option missing from the request is removed and recorded as null.\nexport const getUploadSettingsChanges = (\n previous: Partial<Settings> | null,\n next: Partial<Settings>\n): UploadSettingsChanges => {\n const changes: UploadSettingsChanges = {};\n\n for (const setting of AUDITED_SETTINGS) {\n const before = previous?.[setting] ?? null;\n const after = next[setting] ?? null;\n\n if (before !== after) {\n changes[setting] = { before, after };\n }\n }\n\n return changes;\n};\n\ninterface FolderRef {\n id: number;\n name: string | null;\n}\n\nexport interface MediaMoveEvent {\n kind: 'file' | 'folder';\n id: number;\n name: string;\n from: FolderRef | null;\n to: FolderRef | null;\n}\n\nexport interface MoveDetails {\n from: FolderRef | null;\n to: FolderRef | null;\n}\n\nconst toFolderRef = (folder: { id: number | string; name?: string | null } | null | undefined) =>\n folder ? { id: Number(folder.id), name: folder.name ?? null } : null;\n\ninterface MediaFile {\n id: number;\n name: string;\n mime?: string;\n size?: number;\n alternativeText?: string | null;\n caption?: string | null;\n focalPoint?: { x: number; y: number } | null;\n folder?: { id: number; name: string | null } | null;\n}\n\n/** The payload of media.create and media.delete, which are also webhook events. */\nexport interface MediaEvent {\n media: MediaFile;\n}\n\nexport interface MediaUpdateEvent {\n file: MediaFile;\n previous: MediaFile;\n /** The file's content was replaced. It keeps its hash and url, so no field shows it. */\n replaced?: boolean;\n}\n\n/** Picks the fields the audit log compares. */\nexport const toAuditedFile = (file: Record<string, any>): MediaFile => ({\n id: Number(file.id),\n name: file.name,\n mime: file.mime,\n size: file.size,\n alternativeText: file.alternativeText ?? null,\n caption: file.caption ?? null,\n focalPoint: file.focalPoint ?? null,\n folder: toFolderRef(file.folder),\n});\n\ninterface FileSummary {\n name: string;\n mime: string | null;\n size: number | null;\n}\n\nexport interface MediaChanges {\n name?: Modules.AuditLogs.FieldChange<string>;\n alternativeText?: Modules.AuditLogs.FieldChange<string | null>;\n caption?: Modules.AuditLogs.FieldChange<string | null>;\n focalPoint?: Modules.AuditLogs.FieldChange<{ x: number; y: number } | null>;\n folder?: Modules.AuditLogs.FieldChange<FolderRef | null>;\n file?: Modules.AuditLogs.FieldChange<FileSummary>;\n}\n\nconst summarizeFile = (file: MediaFile): FileSummary => ({\n name: file.name,\n mime: file.mime ?? null,\n size: file.size ?? null,\n});\n\nexport const getMediaChanges = ({\n file: media,\n previous,\n replaced,\n}: MediaUpdateEvent): MediaChanges => {\n const changes: MediaChanges = {};\n\n if (previous.name !== media.name) {\n changes.name = { before: previous.name, after: media.name };\n }\n\n // The admin sends '' for an empty field that is stored as null\n const blankAsNull = (value: string | null | undefined) => value || null;\n for (const field of ['alternativeText', 'caption'] as const) {\n const before = previous[field] ?? null;\n const after = media[field] ?? null;\n if (blankAsNull(before) !== blankAsNull(after)) {\n changes[field] = { before, after };\n }\n }\n\n const focalBefore = previous.focalPoint ?? null;\n const focalAfter = media.focalPoint ?? null;\n if (JSON.stringify(focalBefore) !== JSON.stringify(focalAfter)) {\n changes.focalPoint = { before: focalBefore, after: focalAfter };\n }\n\n const folderBefore = toFolderRef(previous.folder);\n const folderAfter = toFolderRef(media.folder);\n if ((folderBefore?.id ?? null) !== (folderAfter?.id ?? null)) {\n changes.folder = { before: folderBefore, after: folderAfter };\n }\n\n if (replaced) {\n changes.file = { before: summarizeFile(previous), after: summarizeFile(media) };\n }\n\n return changes;\n};\n\ninterface MediaFolder {\n id: number;\n name: string;\n parent?: { id: number; name: string | null } | null;\n}\n\n/** The payload of the media-folder.* events. They are not webhook events. */\nexport interface FolderEvent {\n folder: MediaFolder;\n previous?: MediaFolder;\n}\n\nexport interface FolderChanges {\n name?: Modules.AuditLogs.FieldChange<string>;\n parent?: Modules.AuditLogs.FieldChange<FolderRef | null>;\n}\n\nexport const getFolderChanges = ({ folder, previous }: FolderEvent): FolderChanges => {\n if (!previous) {\n return {};\n }\n\n const changes: FolderChanges = {};\n\n if (previous.name !== folder.name) {\n changes.name = { before: previous.name, after: folder.name };\n }\n\n const parentBefore = toFolderRef(previous.parent);\n const parentAfter = toFolderRef(folder.parent);\n if ((parentBefore?.id ?? null) !== (parentAfter?.id ?? null)) {\n changes.parent = { before: parentBefore, after: parentAfter };\n }\n\n return changes;\n};\n\ninterface JoinTable {\n name: string;\n joinColumn: { name: string };\n inverseJoinColumn: { name: string };\n}\n\n/** Reads rows of a table inside the move transaction. */\ntype ReadTable = (table: string | undefined) => {\n select(...columns: string[]): {\n whereIn(column: string, values: readonly number[]): PromiseLike<Record<string, any>[]>;\n };\n};\n\nconst readParents = async (read: ReadTable, joinTable: JoinTable, ids: number[]) => {\n if (ids.length === 0) {\n return new Map<number, number>();\n }\n\n const { joinColumn, inverseJoinColumn } = joinTable;\n const rows = await read(joinTable.name)\n .select(joinColumn.name, inverseJoinColumn.name)\n .whereIn(joinColumn.name, ids);\n\n return new Map(\n rows.map((row) => [Number(row[joinColumn.name]), Number(row[inverseJoinColumn.name])])\n );\n};\n\nexport const readMediaMoves = async (\n read: ReadTable,\n {\n files,\n folders,\n destinationFolderId,\n fileFolderJoinTable,\n folderParentJoinTable,\n folderTable,\n }: {\n files: Array<{ id: number | string; name: string }>;\n folders: Array<{ id: number | string; name: string }>;\n destinationFolderId: number | string | null;\n fileFolderJoinTable: JoinTable;\n folderParentJoinTable: JoinTable;\n folderTable: string | undefined;\n }\n): Promise<MediaMoveEvent[]> => {\n const fileParents = await readParents(\n read,\n fileFolderJoinTable,\n files.map((file) => Number(file.id))\n );\n const folderParents = await readParents(\n read,\n folderParentJoinTable,\n folders.map((folder) => Number(folder.id))\n );\n\n const destinationId = destinationFolderId === null ? null : Number(destinationFolderId);\n const referencedIds = new Set([...fileParents.values(), ...folderParents.values()]);\n if (destinationId !== null) {\n referencedIds.add(destinationId);\n }\n\n const folderNames = new Map<number, string | null>();\n if (referencedIds.size > 0) {\n const rows = await read(folderTable)\n .select('id', 'name')\n .whereIn('id', [...referencedIds]);\n rows.forEach((row) => folderNames.set(Number(row.id), row.name ?? null));\n }\n\n const toRef = (id: number | null | undefined): FolderRef | null =>\n id == null ? null : { id, name: folderNames.get(id) ?? null };\n\n const to = toRef(destinationId);\n\n return [\n ...files.map((file) => ({\n kind: 'file' as const,\n id: Number(file.id),\n name: file.name,\n from: toRef(fileParents.get(Number(file.id))),\n to,\n })),\n ...folders.map((folder) => ({\n kind: 'folder' as const,\n id: Number(folder.id),\n name: folder.name,\n from: toRef(folderParents.get(Number(folder.id))),\n to,\n })),\n ];\n};\n\nexport const emitMediaMoves = async (\n { strapi }: { strapi: Core.Strapi },\n moves: MediaMoveEvent[]\n) => {\n for (const move of moves) {\n if ((move.from?.id ?? null) !== (move.to?.id ?? null)) {\n await emitAudit({ strapi }, AUDITED_EVENTS.MEDIA_MOVE, move);\n }\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used by this plugin.\n * The full service type lives in the Admin EE package and cannot be imported here.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { action?: string; shouldRecord?: (...args: any[]) => boolean }\n ): void;\n}\n\nexport const registerAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n auditLogsLifecycle.registerEvent<SettingsUpdateDetails>(\n AUDITED_EVENTS.UPLOAD_SETTINGS_UPDATE,\n (event: SettingsUpdateDetails) => ({\n resource: { type: 'upload-settings' },\n details: { changes: event.changes },\n })\n );\n\n const fileResource = (file: MediaFile) => ({\n type: 'media',\n id: Number(file.id),\n name: file.name,\n });\n const folderResource = (folder: MediaFolder) => ({\n type: 'media-folder',\n id: Number(folder.id),\n name: folder.name,\n });\n\n auditLogsLifecycle.registerEvent<{ mime: string | null; size: number | null }>(\n AUDITED_EVENTS.MEDIA_CREATE,\n ({ media }: MediaEvent) => ({\n resource: fileResource(media),\n details: { mime: media.mime ?? null, size: media.size ?? null },\n })\n );\n\n auditLogsLifecycle.registerEvent<{ changes: MediaChanges }>(\n AUDITED_EVENTS.MEDIA_UPDATE_AUDIT,\n (event: MediaUpdateEvent) => ({\n resource: fileResource(event.file),\n details: { changes: getMediaChanges(event) },\n }),\n {\n action: AUDITED_EVENTS.MEDIA_UPDATE,\n shouldRecord: (event: MediaUpdateEvent) => Object.keys(getMediaChanges(event)).length > 0,\n }\n );\n\n auditLogsLifecycle.registerEvent(AUDITED_EVENTS.MEDIA_DELETE, ({ media }: MediaEvent) => ({\n resource: fileResource(media),\n }));\n\n auditLogsLifecycle.registerEvent(\n AUDITED_EVENTS.FOLDER_CREATE,\n ({ folder }: FolderEvent) => ({ resource: folderResource(folder) }),\n { action: AUDITED_EVENTS.MEDIA_CREATE }\n );\n\n auditLogsLifecycle.registerEvent<{ changes: FolderChanges }>(\n AUDITED_EVENTS.FOLDER_UPDATE,\n (event: FolderEvent) => ({\n resource: folderResource(event.folder),\n details: { changes: getFolderChanges(event) },\n }),\n {\n action: AUDITED_EVENTS.MEDIA_UPDATE,\n shouldRecord: (event: FolderEvent) => Object.keys(getFolderChanges(event)).length > 0,\n }\n );\n\n auditLogsLifecycle.registerEvent(\n AUDITED_EVENTS.FOLDER_DELETE_AUDIT,\n ({ folder }: FolderEvent) => ({ resource: folderResource(folder) }),\n { action: AUDITED_EVENTS.MEDIA_DELETE }\n );\n\n auditLogsLifecycle.registerEvent<MoveDetails>(\n AUDITED_EVENTS.MEDIA_MOVE,\n (event: MediaMoveEvent) => ({\n resource: {\n type: event.kind === 'file' ? 'media' : 'media-folder',\n id: event.id,\n name: event.name,\n },\n details: { from: event.from, to: event.to },\n })\n );\n};\n"],"names":["AUDITED_EVENTS","UPLOAD_SETTINGS_UPDATE","MEDIA_CREATE","MEDIA_UPDATE","MEDIA_DELETE","MEDIA_MOVE","FOLDER_CREATE","FOLDER_UPDATE","MEDIA_UPDATE_AUDIT","FOLDER_DELETE_AUDIT","AUDITED_SETTINGS","getUploadSettingsChanges","previous","next","changes","setting","before","after","toFolderRef","folder","id","Number","name","toAuditedFile","file","mime","size","alternativeText","caption","focalPoint","summarizeFile","getMediaChanges","media","replaced","blankAsNull","value","field","focalBefore","focalAfter","JSON","stringify","folderBefore","folderAfter","getFolderChanges","parentBefore","parent","parentAfter","readParents","read","joinTable","ids","length","Map","joinColumn","inverseJoinColumn","rows","select","whereIn","map","row","readMediaMoves","files","folders","destinationFolderId","fileFolderJoinTable","folderParentJoinTable","folderTable","fileParents","folderParents","destinationId","referencedIds","Set","values","add","folderNames","forEach","set","toRef","get","to","kind","from","emitMediaMoves","strapi","moves","move","emitAudit","registerAuditEvents","auditLogsLifecycle","registerEvent","event","resource","type","details","fileResource","folderResource","action","shouldRecord","Object","keys"],"mappings":"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"}
|
package/dist/server/bootstrap.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var index = require('./utils/index.js');
|
|
4
4
|
var constants = require('./constants.js');
|
|
5
5
|
var mediaLibraryDefaultNotice = require('./media-library-default-notice.js');
|
|
6
|
+
var auditLogs = require('./audit-logs.js');
|
|
6
7
|
|
|
7
8
|
async function bootstrap({ strapi: strapi1 }) {
|
|
8
9
|
const defaultConfig = {
|
|
@@ -46,6 +47,9 @@ async function bootstrap({ strapi: strapi1 }) {
|
|
|
46
47
|
});
|
|
47
48
|
await registerPermissionActions();
|
|
48
49
|
await registerWebhookEvents();
|
|
50
|
+
if (strapi1.has('audit-logs-lifecycle')) {
|
|
51
|
+
auditLogs.registerAuditEvents(strapi1.get('audit-logs-lifecycle'));
|
|
52
|
+
}
|
|
49
53
|
await index.getService('weeklyMetrics').registerCron();
|
|
50
54
|
// AI metadata
|
|
51
55
|
if (strapi1.ai.admin.isAvailable()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from './utils';\nimport { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } from './constants';\nimport { notifyMediaLibraryDefault } from './media-library-default-notice';\n\nexport async function bootstrap({ strapi }: { strapi: Core.Strapi }) {\n const defaultConfig = {\n settings: {\n sizeOptimization: true,\n responsiveDimensions: true,\n autoOrientation: false,\n aiMetadata: true,\n },\n view_configuration: {\n pageSize: 10,\n sort: ALLOWED_SORT_STRINGS[0],\n },\n };\n\n // Whether this plugin has stored settings from an earlier boot, which is what separates\n // an upgrading app from a fresh install for the Media Library default notice below.\n let isExistingApp = false;\n\n for (const [key, defaultValue] of Object.entries(defaultConfig)) {\n // set plugin store\n const configurator = strapi.store!({ type: 'plugin', name: 'upload', key });\n\n const config = await configurator.get({});\n\n if (config) {\n isExistingApp = true;\n }\n if (\n config &&\n Object.keys(defaultValue).every((key) => Object.prototype.hasOwnProperty.call(config, key))\n ) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // if the config does not exist or does not have all the required keys\n // set from the defaultValue ensuring all required settings are present\n await configurator.set({\n value: Object.assign(defaultValue, config || {}),\n });\n }\n\n await notifyMediaLibraryDefault({ strapi, isExistingApp });\n\n await registerPermissionActions();\n await registerWebhookEvents();\n\n await getService('weeklyMetrics').registerCron();\n\n // AI metadata\n if (strapi.ai.admin.isAvailable()) {\n const aiMetadataProvider = getService('aiMetadataProvider');\n\n if (!aiMetadataProvider.hasProvider() && strapi.ai.admin.isStrapiManagedAiEnabled()) {\n aiMetadataProvider.registerStrapiManagedProvider();\n }\n }\n\n getService('metrics').sendUploadPluginMetrics();\n\n getService('extensions').signFileUrlsOnDocumentService();\n}\n\nconst registerWebhookEvents = async () =>\n Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {\n strapi.get('webhookStore').addAllowedEvent(key, value);\n });\n\nconst registerPermissionActions = async () => {\n const actions = [\n {\n section: 'plugins',\n displayName: 'Access the Media Library',\n uid: 'read',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Create (upload)',\n uid: 'assets.create',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Update (crop, details, replace) + delete',\n uid: 'assets.update',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Download',\n uid: 'assets.download',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Copy link',\n uid: 'assets.copy-link',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Configure view',\n uid: 'configure-view',\n pluginName: 'upload',\n },\n {\n section: 'settings',\n displayName: 'Access the Media Library settings page',\n uid: 'settings.read',\n category: 'media library',\n pluginName: 'upload',\n },\n ];\n\n await strapi.service('admin::permission').actionProvider.registerMany(actions);\n};\n"],"names":["bootstrap","strapi","defaultConfig","settings","sizeOptimization","responsiveDimensions","autoOrientation","aiMetadata","view_configuration","pageSize","sort","ALLOWED_SORT_STRINGS","isExistingApp","key","defaultValue","Object","entries","configurator","store","type","name","config","get","keys","every","prototype","hasOwnProperty","call","set","value","assign","notifyMediaLibraryDefault","registerPermissionActions","registerWebhookEvents","getService","registerCron","ai","admin","isAvailable","aiMetadataProvider","hasProvider","isStrapiManagedAiEnabled","registerStrapiManagedProvider","sendUploadPluginMetrics","signFileUrlsOnDocumentService","ALLOWED_WEBHOOK_EVENTS","forEach","addAllowedEvent","actions","section","displayName","uid","pluginName","subCategory","category","service","actionProvider","registerMany"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from './utils';\nimport { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } from './constants';\nimport { notifyMediaLibraryDefault } from './media-library-default-notice';\nimport { registerAuditEvents } from './audit-logs';\n\nexport async function bootstrap({ strapi }: { strapi: Core.Strapi }) {\n const defaultConfig = {\n settings: {\n sizeOptimization: true,\n responsiveDimensions: true,\n autoOrientation: false,\n aiMetadata: true,\n },\n view_configuration: {\n pageSize: 10,\n sort: ALLOWED_SORT_STRINGS[0],\n },\n };\n\n // Whether this plugin has stored settings from an earlier boot, which is what separates\n // an upgrading app from a fresh install for the Media Library default notice below.\n let isExistingApp = false;\n\n for (const [key, defaultValue] of Object.entries(defaultConfig)) {\n // set plugin store\n const configurator = strapi.store!({ type: 'plugin', name: 'upload', key });\n\n const config = await configurator.get({});\n\n if (config) {\n isExistingApp = true;\n }\n if (\n config &&\n Object.keys(defaultValue).every((key) => Object.prototype.hasOwnProperty.call(config, key))\n ) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // if the config does not exist or does not have all the required keys\n // set from the defaultValue ensuring all required settings are present\n await configurator.set({\n value: Object.assign(defaultValue, config || {}),\n });\n }\n\n await notifyMediaLibraryDefault({ strapi, isExistingApp });\n\n await registerPermissionActions();\n await registerWebhookEvents();\n\n if (strapi.has('audit-logs-lifecycle')) {\n registerAuditEvents(strapi.get('audit-logs-lifecycle'));\n }\n\n await getService('weeklyMetrics').registerCron();\n\n // AI metadata\n if (strapi.ai.admin.isAvailable()) {\n const aiMetadataProvider = getService('aiMetadataProvider');\n\n if (!aiMetadataProvider.hasProvider() && strapi.ai.admin.isStrapiManagedAiEnabled()) {\n aiMetadataProvider.registerStrapiManagedProvider();\n }\n }\n\n getService('metrics').sendUploadPluginMetrics();\n\n getService('extensions').signFileUrlsOnDocumentService();\n}\n\nconst registerWebhookEvents = async () =>\n Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {\n strapi.get('webhookStore').addAllowedEvent(key, value);\n });\n\nconst registerPermissionActions = async () => {\n const actions = [\n {\n section: 'plugins',\n displayName: 'Access the Media Library',\n uid: 'read',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Create (upload)',\n uid: 'assets.create',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Update (crop, details, replace) + delete',\n uid: 'assets.update',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Download',\n uid: 'assets.download',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Copy link',\n uid: 'assets.copy-link',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Configure view',\n uid: 'configure-view',\n pluginName: 'upload',\n },\n {\n section: 'settings',\n displayName: 'Access the Media Library settings page',\n uid: 'settings.read',\n category: 'media library',\n pluginName: 'upload',\n },\n ];\n\n await strapi.service('admin::permission').actionProvider.registerMany(actions);\n};\n"],"names":["bootstrap","strapi","defaultConfig","settings","sizeOptimization","responsiveDimensions","autoOrientation","aiMetadata","view_configuration","pageSize","sort","ALLOWED_SORT_STRINGS","isExistingApp","key","defaultValue","Object","entries","configurator","store","type","name","config","get","keys","every","prototype","hasOwnProperty","call","set","value","assign","notifyMediaLibraryDefault","registerPermissionActions","registerWebhookEvents","has","registerAuditEvents","getService","registerCron","ai","admin","isAvailable","aiMetadataProvider","hasProvider","isStrapiManagedAiEnabled","registerStrapiManagedProvider","sendUploadPluginMetrics","signFileUrlsOnDocumentService","ALLOWED_WEBHOOK_EVENTS","forEach","addAllowedEvent","actions","section","displayName","uid","pluginName","subCategory","category","service","actionProvider","registerMany"],"mappings":";;;;;;;AAOO,eAAeA,SAAAA,CAAU,EAAEC,MAAAA,EAAAA,OAAM,EAA2B,EAAA;AACjE,IAAA,MAAMC,aAAAA,GAAgB;QACpBC,QAAAA,EAAU;YACRC,gBAAAA,EAAkB,IAAA;YAClBC,oBAAAA,EAAsB,IAAA;YACtBC,eAAAA,EAAiB,KAAA;YACjBC,UAAAA,EAAY;AACd,SAAA;QACAC,kBAAAA,EAAoB;YAClBC,QAAAA,EAAU,EAAA;YACVC,IAAAA,EAAMC,8BAAoB,CAAC,CAAA;AAC7B;AACF,KAAA;;;AAIA,IAAA,IAAIC,aAAAA,GAAgB,KAAA;IAEpB,KAAK,MAAM,CAACC,GAAAA,EAAKC,YAAAA,CAAa,IAAIC,MAAAA,CAAOC,OAAO,CAACd,aAAAA,CAAAA,CAAgB;;QAE/D,MAAMe,YAAAA,GAAehB,OAAAA,CAAOiB,KAAK,CAAE;YAAEC,IAAAA,EAAM,QAAA;YAAUC,IAAAA,EAAM,QAAA;AAAUP,YAAAA;AAAI,SAAA,CAAA;AAEzE,QAAA,MAAMQ,MAAAA,GAAS,MAAMJ,YAAAA,CAAaK,GAAG,CAAC,EAAC,CAAA;AAEvC,QAAA,IAAID,MAAAA,EAAQ;YACVT,aAAAA,GAAgB,IAAA;AAClB,QAAA;AACA,QAAA,IACES,UACAN,MAAAA,CAAOQ,IAAI,CAACT,YAAAA,CAAAA,CAAcU,KAAK,CAAC,CAACX,GAAAA,GAAQE,MAAAA,CAAOU,SAAS,CAACC,cAAc,CAACC,IAAI,CAACN,QAAQR,GAAAA,CAAAA,CAAAA,EACtF;AAEA,YAAA;AACF,QAAA;;;QAIA,MAAMI,YAAAA,CAAaW,GAAG,CAAC;AACrBC,YAAAA,KAAAA,EAAOd,MAAAA,CAAOe,MAAM,CAAChB,YAAAA,EAAcO,UAAU,EAAC;AAChD,SAAA,CAAA;AACF,IAAA;AAEA,IAAA,MAAMU,mDAAAA,CAA0B;QAAE9B,MAAAA,EAAAA,OAAAA;AAAQW,QAAAA;AAAc,KAAA,CAAA;IAExD,MAAMoB,yBAAAA,EAAAA;IACN,MAAMC,qBAAAA,EAAAA;IAEN,IAAIhC,OAAAA,CAAOiC,GAAG,CAAC,sBAAA,CAAA,EAAyB;QACtCC,6BAAAA,CAAoBlC,OAAAA,CAAOqB,GAAG,CAAC,sBAAA,CAAA,CAAA;AACjC,IAAA;IAEA,MAAMc,gBAAAA,CAAW,iBAAiBC,YAAY,EAAA;;AAG9C,IAAA,IAAIpC,QAAOqC,EAAE,CAACC,KAAK,CAACC,WAAW,EAAA,EAAI;AACjC,QAAA,MAAMC,qBAAqBL,gBAAAA,CAAW,oBAAA,CAAA;QAEtC,IAAI,CAACK,kBAAAA,CAAmBC,WAAW,EAAA,IAAMzC,OAAAA,CAAOqC,EAAE,CAACC,KAAK,CAACI,wBAAwB,EAAA,EAAI;AACnFF,YAAAA,kBAAAA,CAAmBG,6BAA6B,EAAA;AAClD,QAAA;AACF,IAAA;AAEAR,IAAAA,gBAAAA,CAAW,WAAWS,uBAAuB,EAAA;AAE7CT,IAAAA,gBAAAA,CAAW,cAAcU,6BAA6B,EAAA;AACxD;AAEA,MAAMb,qBAAAA,GAAwB,UAC5BlB,MAAAA,CAAOC,OAAO,CAAC+B,gCAAAA,CAAAA,CAAwBC,OAAO,CAAC,CAAC,CAACnC,GAAAA,EAAKgB,KAAAA,CAAM,GAAA;AAC1D5B,QAAAA,MAAAA,CAAOqB,GAAG,CAAC,cAAA,CAAA,CAAgB2B,eAAe,CAACpC,GAAAA,EAAKgB,KAAAA,CAAAA;AAClD,IAAA,CAAA,CAAA;AAEF,MAAMG,yBAAAA,GAA4B,UAAA;AAChC,IAAA,MAAMkB,OAAAA,GAAU;AACd,QAAA;YACEC,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,0BAAA;YACbC,GAAAA,EAAK,MAAA;YACLC,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,iBAAA;YACbC,GAAAA,EAAK,eAAA;YACLE,WAAAA,EAAa,QAAA;YACbD,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,0CAAA;YACbC,GAAAA,EAAK,eAAA;YACLE,WAAAA,EAAa,QAAA;YACbD,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,UAAA;YACbC,GAAAA,EAAK,iBAAA;YACLE,WAAAA,EAAa,QAAA;YACbD,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,WAAA;YACbC,GAAAA,EAAK,kBAAA;YACLE,WAAAA,EAAa,QAAA;YACbD,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,SAAA;YACTC,WAAAA,EAAa,gBAAA;YACbC,GAAAA,EAAK,gBAAA;YACLC,UAAAA,EAAY;AACd,SAAA;AACA,QAAA;YACEH,OAAAA,EAAS,UAAA;YACTC,WAAAA,EAAa,wCAAA;YACbC,GAAAA,EAAK,eAAA;YACLG,QAAAA,EAAU,eAAA;YACVF,UAAAA,EAAY;AACd;AACD,KAAA;AAED,IAAA,MAAMrD,OAAOwD,OAAO,CAAC,qBAAqBC,cAAc,CAACC,YAAY,CAACT,OAAAA,CAAAA;AACxE,CAAA;;;;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getService } from './utils/index.mjs';
|
|
2
2
|
import { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } from './constants.mjs';
|
|
3
3
|
import { notifyMediaLibraryDefault } from './media-library-default-notice.mjs';
|
|
4
|
+
import { registerAuditEvents } from './audit-logs.mjs';
|
|
4
5
|
|
|
5
6
|
async function bootstrap({ strapi: strapi1 }) {
|
|
6
7
|
const defaultConfig = {
|
|
@@ -44,6 +45,9 @@ async function bootstrap({ strapi: strapi1 }) {
|
|
|
44
45
|
});
|
|
45
46
|
await registerPermissionActions();
|
|
46
47
|
await registerWebhookEvents();
|
|
48
|
+
if (strapi1.has('audit-logs-lifecycle')) {
|
|
49
|
+
registerAuditEvents(strapi1.get('audit-logs-lifecycle'));
|
|
50
|
+
}
|
|
47
51
|
await getService('weeklyMetrics').registerCron();
|
|
48
52
|
// AI metadata
|
|
49
53
|
if (strapi1.ai.admin.isAvailable()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.mjs","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from './utils';\nimport { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } from './constants';\nimport { notifyMediaLibraryDefault } from './media-library-default-notice';\n\nexport async function bootstrap({ strapi }: { strapi: Core.Strapi }) {\n const defaultConfig = {\n settings: {\n sizeOptimization: true,\n responsiveDimensions: true,\n autoOrientation: false,\n aiMetadata: true,\n },\n view_configuration: {\n pageSize: 10,\n sort: ALLOWED_SORT_STRINGS[0],\n },\n };\n\n // Whether this plugin has stored settings from an earlier boot, which is what separates\n // an upgrading app from a fresh install for the Media Library default notice below.\n let isExistingApp = false;\n\n for (const [key, defaultValue] of Object.entries(defaultConfig)) {\n // set plugin store\n const configurator = strapi.store!({ type: 'plugin', name: 'upload', key });\n\n const config = await configurator.get({});\n\n if (config) {\n isExistingApp = true;\n }\n if (\n config &&\n Object.keys(defaultValue).every((key) => Object.prototype.hasOwnProperty.call(config, key))\n ) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // if the config does not exist or does not have all the required keys\n // set from the defaultValue ensuring all required settings are present\n await configurator.set({\n value: Object.assign(defaultValue, config || {}),\n });\n }\n\n await notifyMediaLibraryDefault({ strapi, isExistingApp });\n\n await registerPermissionActions();\n await registerWebhookEvents();\n\n await getService('weeklyMetrics').registerCron();\n\n // AI metadata\n if (strapi.ai.admin.isAvailable()) {\n const aiMetadataProvider = getService('aiMetadataProvider');\n\n if (!aiMetadataProvider.hasProvider() && strapi.ai.admin.isStrapiManagedAiEnabled()) {\n aiMetadataProvider.registerStrapiManagedProvider();\n }\n }\n\n getService('metrics').sendUploadPluginMetrics();\n\n getService('extensions').signFileUrlsOnDocumentService();\n}\n\nconst registerWebhookEvents = async () =>\n Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {\n strapi.get('webhookStore').addAllowedEvent(key, value);\n });\n\nconst registerPermissionActions = async () => {\n const actions = [\n {\n section: 'plugins',\n displayName: 'Access the Media Library',\n uid: 'read',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Create (upload)',\n uid: 'assets.create',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Update (crop, details, replace) + delete',\n uid: 'assets.update',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Download',\n uid: 'assets.download',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Copy link',\n uid: 'assets.copy-link',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Configure view',\n uid: 'configure-view',\n pluginName: 'upload',\n },\n {\n section: 'settings',\n displayName: 'Access the Media Library settings page',\n uid: 'settings.read',\n category: 'media library',\n pluginName: 'upload',\n },\n ];\n\n await strapi.service('admin::permission').actionProvider.registerMany(actions);\n};\n"],"names":["bootstrap","strapi","defaultConfig","settings","sizeOptimization","responsiveDimensions","autoOrientation","aiMetadata","view_configuration","pageSize","sort","ALLOWED_SORT_STRINGS","isExistingApp","key","defaultValue","Object","entries","configurator","store","type","name","config","get","keys","every","prototype","hasOwnProperty","call","set","value","assign","notifyMediaLibraryDefault","registerPermissionActions","registerWebhookEvents","getService","registerCron","ai","admin","isAvailable","aiMetadataProvider","hasProvider","isStrapiManagedAiEnabled","registerStrapiManagedProvider","sendUploadPluginMetrics","signFileUrlsOnDocumentService","ALLOWED_WEBHOOK_EVENTS","forEach","addAllowedEvent","actions","section","displayName","uid","pluginName","subCategory","category","service","actionProvider","registerMany"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bootstrap.mjs","sources":["../../server/src/bootstrap.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from './utils';\nimport { ALLOWED_SORT_STRINGS, ALLOWED_WEBHOOK_EVENTS } from './constants';\nimport { notifyMediaLibraryDefault } from './media-library-default-notice';\nimport { registerAuditEvents } from './audit-logs';\n\nexport async function bootstrap({ strapi }: { strapi: Core.Strapi }) {\n const defaultConfig = {\n settings: {\n sizeOptimization: true,\n responsiveDimensions: true,\n autoOrientation: false,\n aiMetadata: true,\n },\n view_configuration: {\n pageSize: 10,\n sort: ALLOWED_SORT_STRINGS[0],\n },\n };\n\n // Whether this plugin has stored settings from an earlier boot, which is what separates\n // an upgrading app from a fresh install for the Media Library default notice below.\n let isExistingApp = false;\n\n for (const [key, defaultValue] of Object.entries(defaultConfig)) {\n // set plugin store\n const configurator = strapi.store!({ type: 'plugin', name: 'upload', key });\n\n const config = await configurator.get({});\n\n if (config) {\n isExistingApp = true;\n }\n if (\n config &&\n Object.keys(defaultValue).every((key) => Object.prototype.hasOwnProperty.call(config, key))\n ) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n // if the config does not exist or does not have all the required keys\n // set from the defaultValue ensuring all required settings are present\n await configurator.set({\n value: Object.assign(defaultValue, config || {}),\n });\n }\n\n await notifyMediaLibraryDefault({ strapi, isExistingApp });\n\n await registerPermissionActions();\n await registerWebhookEvents();\n\n if (strapi.has('audit-logs-lifecycle')) {\n registerAuditEvents(strapi.get('audit-logs-lifecycle'));\n }\n\n await getService('weeklyMetrics').registerCron();\n\n // AI metadata\n if (strapi.ai.admin.isAvailable()) {\n const aiMetadataProvider = getService('aiMetadataProvider');\n\n if (!aiMetadataProvider.hasProvider() && strapi.ai.admin.isStrapiManagedAiEnabled()) {\n aiMetadataProvider.registerStrapiManagedProvider();\n }\n }\n\n getService('metrics').sendUploadPluginMetrics();\n\n getService('extensions').signFileUrlsOnDocumentService();\n}\n\nconst registerWebhookEvents = async () =>\n Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {\n strapi.get('webhookStore').addAllowedEvent(key, value);\n });\n\nconst registerPermissionActions = async () => {\n const actions = [\n {\n section: 'plugins',\n displayName: 'Access the Media Library',\n uid: 'read',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Create (upload)',\n uid: 'assets.create',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Update (crop, details, replace) + delete',\n uid: 'assets.update',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Download',\n uid: 'assets.download',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Copy link',\n uid: 'assets.copy-link',\n subCategory: 'assets',\n pluginName: 'upload',\n },\n {\n section: 'plugins',\n displayName: 'Configure view',\n uid: 'configure-view',\n pluginName: 'upload',\n },\n {\n section: 'settings',\n displayName: 'Access the Media Library settings page',\n uid: 'settings.read',\n category: 'media library',\n pluginName: 'upload',\n },\n ];\n\n await strapi.service('admin::permission').actionProvider.registerMany(actions);\n};\n"],"names":["bootstrap","strapi","defaultConfig","settings","sizeOptimization","responsiveDimensions","autoOrientation","aiMetadata","view_configuration","pageSize","sort","ALLOWED_SORT_STRINGS","isExistingApp","key","defaultValue","Object","entries","configurator","store","type","name","config","get","keys","every","prototype","hasOwnProperty","call","set","value","assign","notifyMediaLibraryDefault","registerPermissionActions","registerWebhookEvents","has","registerAuditEvents","getService","registerCron","ai","admin","isAvailable","aiMetadataProvider","hasProvider","isStrapiManagedAiEnabled","registerStrapiManagedProvider","sendUploadPluginMetrics","signFileUrlsOnDocumentService","ALLOWED_WEBHOOK_EVENTS","forEach","addAllowedEvent","actions","section","displayName","uid","pluginName","subCategory","category","service","actionProvider","registerMany"],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ var index = require('../utils/index.js');
|
|
|
5
5
|
var constants = require('../constants.js');
|
|
6
6
|
var errors = require('../errors.js');
|
|
7
7
|
var folderFile = require('./validation/admin/folder-file.js');
|
|
8
|
+
var auditLogs = require('../audit-logs.js');
|
|
8
9
|
|
|
9
10
|
var adminFolderFile = {
|
|
10
11
|
async deleteMany (ctx) {
|
|
@@ -103,11 +104,13 @@ var adminFolderFile = {
|
|
|
103
104
|
const { folderIds = [], fileIds = [], destinationFolderId } = body;
|
|
104
105
|
let totalFolderNumber = 0;
|
|
105
106
|
let totalFileNumber = 0;
|
|
107
|
+
let moves = [];
|
|
106
108
|
const trx = await strapi.db.transaction();
|
|
107
109
|
try {
|
|
108
110
|
// fetch folders
|
|
109
111
|
const existingFolders = await strapi.db.queryBuilder(constants.FOLDER_MODEL_UID).select([
|
|
110
112
|
'id',
|
|
113
|
+
'name',
|
|
111
114
|
'pathId',
|
|
112
115
|
'path'
|
|
113
116
|
]).where({
|
|
@@ -117,7 +120,8 @@ var adminFolderFile = {
|
|
|
117
120
|
}).transacting(trx.get()).forUpdate().execute();
|
|
118
121
|
// fetch files
|
|
119
122
|
const existingFiles = await strapi.db.queryBuilder(constants.FILE_MODEL_UID).select([
|
|
120
|
-
'id'
|
|
123
|
+
'id',
|
|
124
|
+
'name'
|
|
121
125
|
]).where({
|
|
122
126
|
id: {
|
|
123
127
|
$in: fileIds
|
|
@@ -137,6 +141,19 @@ var adminFolderFile = {
|
|
|
137
141
|
strapi.db.metadata.get(constants.FILE_MODEL_UID).attributes.folderPath.columnName;
|
|
138
142
|
// @ts-expect-error - no dynamic typings for the models
|
|
139
143
|
const pathColName = strapi.db.metadata.get(constants.FOLDER_MODEL_UID).attributes.path.columnName;
|
|
144
|
+
// Read before the write: the audit log records where each item was.
|
|
145
|
+
const fileFolderAttribute = strapi.db.metadata.get(constants.FILE_MODEL_UID).attributes.folder;
|
|
146
|
+
const folderParentAttribute = strapi.db.metadata.get(constants.FOLDER_MODEL_UID).attributes.parent;
|
|
147
|
+
moves = await auditLogs.readMediaMoves((table)=>strapi.db.getConnection(table).transacting(trx.get()), {
|
|
148
|
+
files: existingFiles,
|
|
149
|
+
folders: existingFolders,
|
|
150
|
+
destinationFolderId,
|
|
151
|
+
// @ts-expect-error - no dynamic typings for the models
|
|
152
|
+
fileFolderJoinTable: fileFolderAttribute.joinTable,
|
|
153
|
+
// @ts-expect-error - no dynamic typings for the models
|
|
154
|
+
folderParentJoinTable: folderParentAttribute.joinTable,
|
|
155
|
+
folderTable
|
|
156
|
+
});
|
|
140
157
|
if (existingFolders.length > 0) {
|
|
141
158
|
// update folders' parent relation
|
|
142
159
|
// @ts-expect-error - no dynamic typings for the models
|
|
@@ -201,6 +218,11 @@ var adminFolderFile = {
|
|
|
201
218
|
await trx.rollback();
|
|
202
219
|
throw e;
|
|
203
220
|
}
|
|
221
|
+
auditLogs.emitMediaMoves({
|
|
222
|
+
strapi
|
|
223
|
+
}, moves).catch((error)=>{
|
|
224
|
+
strapi.log.error(`Could not record media moves in audit logs: ${error?.message ?? error}`);
|
|
225
|
+
});
|
|
204
226
|
const updatedFolders = await strapi.db.query(constants.FOLDER_MODEL_UID).findMany({
|
|
205
227
|
where: {
|
|
206
228
|
id: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-folder-file.js","sources":["../../../server/src/controllers/admin-folder-file.ts"],"sourcesContent":["import { errors, strings } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { FolderContainsUnauthorizedAssetsError } from '../errors';\nimport {\n validateDeleteManyFoldersFiles,\n validateMoveManyFoldersFiles,\n} from './validation/admin/folder-file';\n\nimport type { File, Folder } from '../types';\n\nexport default {\n async deleteMany(ctx: Context) {\n const { body } = ctx.request;\n const {\n state: { userAbility },\n } = ctx;\n\n const pmFolder = strapi.service('admin::permission').createPermissionsManager({\n ability: ctx.state.userAbility,\n model: FOLDER_MODEL_UID,\n });\n\n const pmFile = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.update,\n model: FILE_MODEL_UID,\n });\n\n await validateDeleteManyFoldersFiles(body);\n\n const fileService = getService('file');\n const folderService = getService('folder');\n\n const { fileIds = [], folderIds = [] } = body;\n\n const canDeleteFiles = async (files: File[]) => {\n const ids = [...new Set(files.map(({ id }) => id))];\n\n if (ids.length === 0) {\n return true;\n }\n\n const query = pmFile.addPermissionsQueryTo({ filters: { id: { $in: ids } } });\n const permittedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n select: ['id'],\n where: query.filters,\n });\n\n return permittedFiles.length === ids.length;\n };\n\n // https://github.com/strapi/strapi/issues/27649\n // Validate explicitly selected files before deleting a folder. Otherwise a mixed request\n // could delete permitted files first and only then discover a forbidden file in the folder.\n if (fileIds.length > 0) {\n const selectedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: { id: { $in: fileIds } },\n });\n\n if (!(await canDeleteFiles(selectedFiles))) {\n throw new errors.ForbiddenError();\n }\n }\n\n const {\n folders: deletedFolders,\n totalFolderNumber,\n totalFileNumber,\n } = await folderService.deleteByIds(folderIds, {\n async validateFiles(files) {\n if (!(await canDeleteFiles(files))) {\n throw new FolderContainsUnauthorizedAssetsError();\n }\n },\n });\n const deletedFiles = await fileService.deleteByIds(fileIds);\n\n if (deletedFiles.length + deletedFolders.length > 1) {\n await getService('metrics').trackUsage('didBulkDeleteMediaLibraryElements', {\n eventProperties: {\n rootFolderNumber: deletedFolders.length,\n rootAssetNumber: deletedFiles.length,\n totalFolderNumber,\n totalAssetNumber: totalFileNumber + deletedFiles.length,\n },\n });\n }\n\n ctx.body = {\n data: {\n files: await pmFile.sanitizeOutput(deletedFiles, { action: ACTIONS.read }),\n folders: await pmFolder.sanitizeOutput(deletedFolders),\n },\n };\n },\n async moveMany(ctx: Context) {\n const { body } = ctx.request;\n const {\n state: { userAbility },\n } = ctx;\n\n const pmFolder = strapi.service('admin::permission').createPermissionsManager({\n ability: ctx.state.userAbility,\n model: FOLDER_MODEL_UID,\n });\n\n const pmFile = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n await validateMoveManyFoldersFiles(body);\n const { folderIds = [], fileIds = [], destinationFolderId } = body;\n\n let totalFolderNumber = 0;\n let totalFileNumber = 0;\n\n const trx = await strapi.db.transaction();\n try {\n // fetch folders\n const existingFolders = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select(['id', 'pathId', 'path'])\n .where({ id: { $in: folderIds } })\n .transacting(trx.get())\n .forUpdate()\n .execute<Folder[]>();\n\n // fetch files\n const existingFiles = await strapi.db\n .queryBuilder(FILE_MODEL_UID)\n .select(['id'])\n .where({ id: { $in: fileIds } })\n .transacting(trx.get())\n .forUpdate()\n .execute<File[]>();\n\n // fetch destinationFolder path\n let destinationFolderPath = '/';\n if (destinationFolderId !== null) {\n const destinationFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select('path')\n .where({ id: destinationFolderId })\n .transacting(trx.get())\n .first()\n .execute<Folder>();\n destinationFolderPath = destinationFolder.path;\n }\n\n const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;\n const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;\n const folderPathColName =\n // @ts-expect-error - no dynamic typings for the models\n strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName;\n // @ts-expect-error - no dynamic typings for the models\n const pathColName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;\n\n if (existingFolders.length > 0) {\n // update folders' parent relation\n // @ts-expect-error - no dynamic typings for the models\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [joinTable.joinColumn.name]: { $in: folderIds } })\n .execute();\n\n if (destinationFolderId !== null) {\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .insert(\n existingFolders.map((folder) => ({\n [joinTable.inverseJoinColumn.name]: destinationFolderId,\n [joinTable.joinColumn.name]: folder.id,\n }))\n )\n .execute();\n }\n\n for (const existingFolder of existingFolders) {\n let replaceQuery;\n switch (strapi.db.dialect.client) {\n case 'sqlite':\n replaceQuery = '? || SUBSTRING(??, ?)';\n break;\n case 'postgres':\n replaceQuery = 'CONCAT(?::TEXT, SUBSTRING(??, ?::INTEGER))';\n break;\n default:\n replaceQuery = 'CONCAT(?, SUBSTRING(??, ?))';\n }\n\n // update path for folders themselves & folders below\n totalFolderNumber = await strapi.db\n .getConnection(folderTable)\n .transacting(trx.get())\n .where(pathColName, existingFolder.path)\n .orWhere(pathColName, 'like', `${existingFolder.path}/%`)\n .update(\n pathColName,\n strapi.db.connection.raw(replaceQuery, [\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n pathColName,\n existingFolder.path.length + 1,\n ])\n );\n\n // update path of files below\n totalFileNumber = await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .where(folderPathColName, existingFolder.path)\n .orWhere(folderPathColName, 'like', `${existingFolder.path}/%`)\n .update(\n folderPathColName,\n strapi.db.connection.raw(replaceQuery, [\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n folderPathColName,\n existingFolder.path.length + 1,\n ])\n );\n }\n }\n\n if (existingFiles.length > 0) {\n // update files' folder relation (delete + insert; upsert not possible)\n // @ts-expect-error - no dynamic typings for the models\n const fileJoinTable = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folder.joinTable;\n await strapi.db\n .queryBuilder(fileJoinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [fileJoinTable.joinColumn.name]: { $in: fileIds } })\n .execute();\n\n if (destinationFolderId !== null) {\n await strapi.db\n .queryBuilder(fileJoinTable.name)\n .transacting(trx.get())\n .insert(\n existingFiles.map((file) => ({\n [fileJoinTable.inverseJoinColumn.name]: destinationFolderId,\n [fileJoinTable.joinColumn.name]: file.id,\n }))\n )\n .execute();\n }\n\n // update files main fields (path + updatedBy)\n await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .whereIn('id', fileIds)\n .update(folderPathColName, destinationFolderPath);\n }\n\n await trx.commit();\n } catch (e) {\n await trx.rollback();\n throw e;\n }\n\n const updatedFolders = await strapi.db.query(FOLDER_MODEL_UID).findMany({\n where: { id: { $in: folderIds } },\n });\n\n const updatedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: { id: { $in: fileIds } },\n });\n\n await getService('metrics').trackUsage('didBulkMoveMediaLibraryElements', {\n eventProperties: {\n rootFolderNumber: updatedFolders.length,\n rootAssetNumber: updatedFiles.length,\n totalFolderNumber,\n totalAssetNumber: totalFileNumber + updatedFiles.length,\n },\n });\n\n ctx.body = {\n data: {\n files: await pmFile.sanitizeOutput(updatedFiles),\n folders: await pmFolder.sanitizeOutput(updatedFolders),\n },\n };\n },\n};\n"],"names":["deleteMany","ctx","body","request","state","userAbility","pmFolder","strapi","service","createPermissionsManager","ability","model","FOLDER_MODEL_UID","pmFile","action","ACTIONS","update","FILE_MODEL_UID","validateDeleteManyFoldersFiles","fileService","getService","folderService","fileIds","folderIds","canDeleteFiles","files","ids","Set","map","id","length","query","addPermissionsQueryTo","filters","$in","permittedFiles","db","findMany","select","where","selectedFiles","errors","ForbiddenError","folders","deletedFolders","totalFolderNumber","totalFileNumber","deleteByIds","validateFiles","FolderContainsUnauthorizedAssetsError","deletedFiles","trackUsage","eventProperties","rootFolderNumber","rootAssetNumber","totalAssetNumber","data","sanitizeOutput","read","moveMany","validateMoveManyFoldersFiles","destinationFolderId","trx","transaction","existingFolders","queryBuilder","transacting","get","forUpdate","execute","existingFiles","destinationFolderPath","destinationFolder","first","path","fileTable","getModel","collectionName","folderTable","folderPathColName","metadata","attributes","folderPath","columnName","pathColName","joinTable","parent","name","delete","joinColumn","insert","folder","inverseJoinColumn","existingFolder","replaceQuery","dialect","client","getConnection","orWhere","connection","raw","strings","joinBy","pathId","fileJoinTable","file","whereIn","commit","e","rollback","updatedFolders","updatedFiles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-folder-file.js","sources":["../../../server/src/controllers/admin-folder-file.ts"],"sourcesContent":["import { errors, strings } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { FolderContainsUnauthorizedAssetsError } from '../errors';\nimport {\n validateDeleteManyFoldersFiles,\n validateMoveManyFoldersFiles,\n} from './validation/admin/folder-file';\nimport { emitMediaMoves, readMediaMoves, type MediaMoveEvent } from '../audit-logs';\n\nimport type { File, Folder } from '../types';\n\nexport default {\n async deleteMany(ctx: Context) {\n const { body } = ctx.request;\n const {\n state: { userAbility },\n } = ctx;\n\n const pmFolder = strapi.service('admin::permission').createPermissionsManager({\n ability: ctx.state.userAbility,\n model: FOLDER_MODEL_UID,\n });\n\n const pmFile = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.update,\n model: FILE_MODEL_UID,\n });\n\n await validateDeleteManyFoldersFiles(body);\n\n const fileService = getService('file');\n const folderService = getService('folder');\n\n const { fileIds = [], folderIds = [] } = body;\n\n const canDeleteFiles = async (files: File[]) => {\n const ids = [...new Set(files.map(({ id }) => id))];\n\n if (ids.length === 0) {\n return true;\n }\n\n const query = pmFile.addPermissionsQueryTo({ filters: { id: { $in: ids } } });\n const permittedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n select: ['id'],\n where: query.filters,\n });\n\n return permittedFiles.length === ids.length;\n };\n\n // https://github.com/strapi/strapi/issues/27649\n // Validate explicitly selected files before deleting a folder. Otherwise a mixed request\n // could delete permitted files first and only then discover a forbidden file in the folder.\n if (fileIds.length > 0) {\n const selectedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: { id: { $in: fileIds } },\n });\n\n if (!(await canDeleteFiles(selectedFiles))) {\n throw new errors.ForbiddenError();\n }\n }\n\n const {\n folders: deletedFolders,\n totalFolderNumber,\n totalFileNumber,\n } = await folderService.deleteByIds(folderIds, {\n async validateFiles(files) {\n if (!(await canDeleteFiles(files))) {\n throw new FolderContainsUnauthorizedAssetsError();\n }\n },\n });\n const deletedFiles = await fileService.deleteByIds(fileIds);\n\n if (deletedFiles.length + deletedFolders.length > 1) {\n await getService('metrics').trackUsage('didBulkDeleteMediaLibraryElements', {\n eventProperties: {\n rootFolderNumber: deletedFolders.length,\n rootAssetNumber: deletedFiles.length,\n totalFolderNumber,\n totalAssetNumber: totalFileNumber + deletedFiles.length,\n },\n });\n }\n\n ctx.body = {\n data: {\n files: await pmFile.sanitizeOutput(deletedFiles, { action: ACTIONS.read }),\n folders: await pmFolder.sanitizeOutput(deletedFolders),\n },\n };\n },\n async moveMany(ctx: Context) {\n const { body } = ctx.request;\n const {\n state: { userAbility },\n } = ctx;\n\n const pmFolder = strapi.service('admin::permission').createPermissionsManager({\n ability: ctx.state.userAbility,\n model: FOLDER_MODEL_UID,\n });\n\n const pmFile = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.read,\n model: FILE_MODEL_UID,\n });\n\n await validateMoveManyFoldersFiles(body);\n const { folderIds = [], fileIds = [], destinationFolderId } = body;\n\n let totalFolderNumber = 0;\n let totalFileNumber = 0;\n let moves: MediaMoveEvent[] = [];\n\n const trx = await strapi.db.transaction();\n try {\n // fetch folders\n const existingFolders = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select(['id', 'name', 'pathId', 'path'])\n .where({ id: { $in: folderIds } })\n .transacting(trx.get())\n .forUpdate()\n .execute<Folder[]>();\n\n // fetch files\n const existingFiles = await strapi.db\n .queryBuilder(FILE_MODEL_UID)\n .select(['id', 'name'])\n .where({ id: { $in: fileIds } })\n .transacting(trx.get())\n .forUpdate()\n .execute<File[]>();\n\n // fetch destinationFolder path\n let destinationFolderPath = '/';\n if (destinationFolderId !== null) {\n const destinationFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select('path')\n .where({ id: destinationFolderId })\n .transacting(trx.get())\n .first()\n .execute<Folder>();\n destinationFolderPath = destinationFolder.path;\n }\n\n const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;\n const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;\n const folderPathColName =\n // @ts-expect-error - no dynamic typings for the models\n strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName;\n // @ts-expect-error - no dynamic typings for the models\n const pathColName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;\n\n // Read before the write: the audit log records where each item was.\n const fileFolderAttribute = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folder;\n const folderParentAttribute = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n moves = await readMediaMoves(\n (table) => strapi.db.getConnection(table).transacting(trx.get()),\n {\n files: existingFiles,\n folders: existingFolders,\n destinationFolderId,\n // @ts-expect-error - no dynamic typings for the models\n fileFolderJoinTable: fileFolderAttribute.joinTable,\n // @ts-expect-error - no dynamic typings for the models\n folderParentJoinTable: folderParentAttribute.joinTable,\n folderTable,\n }\n );\n\n if (existingFolders.length > 0) {\n // update folders' parent relation\n // @ts-expect-error - no dynamic typings for the models\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [joinTable.joinColumn.name]: { $in: folderIds } })\n .execute();\n\n if (destinationFolderId !== null) {\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .insert(\n existingFolders.map((folder) => ({\n [joinTable.inverseJoinColumn.name]: destinationFolderId,\n [joinTable.joinColumn.name]: folder.id,\n }))\n )\n .execute();\n }\n\n for (const existingFolder of existingFolders) {\n let replaceQuery;\n switch (strapi.db.dialect.client) {\n case 'sqlite':\n replaceQuery = '? || SUBSTRING(??, ?)';\n break;\n case 'postgres':\n replaceQuery = 'CONCAT(?::TEXT, SUBSTRING(??, ?::INTEGER))';\n break;\n default:\n replaceQuery = 'CONCAT(?, SUBSTRING(??, ?))';\n }\n\n // update path for folders themselves & folders below\n totalFolderNumber = await strapi.db\n .getConnection(folderTable)\n .transacting(trx.get())\n .where(pathColName, existingFolder.path)\n .orWhere(pathColName, 'like', `${existingFolder.path}/%`)\n .update(\n pathColName,\n strapi.db.connection.raw(replaceQuery, [\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n pathColName,\n existingFolder.path.length + 1,\n ])\n );\n\n // update path of files below\n totalFileNumber = await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .where(folderPathColName, existingFolder.path)\n .orWhere(folderPathColName, 'like', `${existingFolder.path}/%`)\n .update(\n folderPathColName,\n strapi.db.connection.raw(replaceQuery, [\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n folderPathColName,\n existingFolder.path.length + 1,\n ])\n );\n }\n }\n\n if (existingFiles.length > 0) {\n // update files' folder relation (delete + insert; upsert not possible)\n // @ts-expect-error - no dynamic typings for the models\n const fileJoinTable = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folder.joinTable;\n await strapi.db\n .queryBuilder(fileJoinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [fileJoinTable.joinColumn.name]: { $in: fileIds } })\n .execute();\n\n if (destinationFolderId !== null) {\n await strapi.db\n .queryBuilder(fileJoinTable.name)\n .transacting(trx.get())\n .insert(\n existingFiles.map((file) => ({\n [fileJoinTable.inverseJoinColumn.name]: destinationFolderId,\n [fileJoinTable.joinColumn.name]: file.id,\n }))\n )\n .execute();\n }\n\n // update files main fields (path + updatedBy)\n await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .whereIn('id', fileIds)\n .update(folderPathColName, destinationFolderPath);\n }\n\n await trx.commit();\n } catch (e) {\n await trx.rollback();\n throw e;\n }\n\n emitMediaMoves({ strapi }, moves).catch((error) => {\n strapi.log.error(`Could not record media moves in audit logs: ${error?.message ?? error}`);\n });\n\n const updatedFolders = await strapi.db.query(FOLDER_MODEL_UID).findMany({\n where: { id: { $in: folderIds } },\n });\n\n const updatedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: { id: { $in: fileIds } },\n });\n\n await getService('metrics').trackUsage('didBulkMoveMediaLibraryElements', {\n eventProperties: {\n rootFolderNumber: updatedFolders.length,\n rootAssetNumber: updatedFiles.length,\n totalFolderNumber,\n totalAssetNumber: totalFileNumber + updatedFiles.length,\n },\n });\n\n ctx.body = {\n data: {\n files: await pmFile.sanitizeOutput(updatedFiles),\n folders: await pmFolder.sanitizeOutput(updatedFolders),\n },\n };\n },\n};\n"],"names":["deleteMany","ctx","body","request","state","userAbility","pmFolder","strapi","service","createPermissionsManager","ability","model","FOLDER_MODEL_UID","pmFile","action","ACTIONS","update","FILE_MODEL_UID","validateDeleteManyFoldersFiles","fileService","getService","folderService","fileIds","folderIds","canDeleteFiles","files","ids","Set","map","id","length","query","addPermissionsQueryTo","filters","$in","permittedFiles","db","findMany","select","where","selectedFiles","errors","ForbiddenError","folders","deletedFolders","totalFolderNumber","totalFileNumber","deleteByIds","validateFiles","FolderContainsUnauthorizedAssetsError","deletedFiles","trackUsage","eventProperties","rootFolderNumber","rootAssetNumber","totalAssetNumber","data","sanitizeOutput","read","moveMany","validateMoveManyFoldersFiles","destinationFolderId","moves","trx","transaction","existingFolders","queryBuilder","transacting","get","forUpdate","execute","existingFiles","destinationFolderPath","destinationFolder","first","path","fileTable","getModel","collectionName","folderTable","folderPathColName","metadata","attributes","folderPath","columnName","pathColName","fileFolderAttribute","folder","folderParentAttribute","parent","readMediaMoves","table","getConnection","fileFolderJoinTable","joinTable","folderParentJoinTable","name","delete","joinColumn","insert","inverseJoinColumn","existingFolder","replaceQuery","dialect","client","orWhere","connection","raw","strings","joinBy","pathId","fileJoinTable","file","whereIn","commit","e","rollback","emitMediaMoves","catch","error","log","message","updatedFolders","updatedFiles"],"mappings":"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"}
|