directus 9.13.0 → 9.14.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/app.js +9 -4
- package/dist/auth/drivers/openid.js +4 -1
- package/dist/controllers/files.js +1 -1
- package/dist/emitter.js +12 -7
- package/dist/operations/item-read/index.d.ts +1 -0
- package/dist/operations/item-read/index.js +3 -3
- package/dist/services/import-export.js +6 -1
- package/dist/services/items.d.ts +1 -0
- package/dist/services/items.js +21 -17
- package/dist/services/notifications.js +22 -11
- package/dist/services/payload.js +11 -8
- package/package.json +12 -12
package/dist/app.js
CHANGED
|
@@ -173,13 +173,18 @@ async function createApp() {
|
|
|
173
173
|
// Set the App's base path according to the APIs public URL
|
|
174
174
|
const html = await fs_extra_1.default.readFile(adminPath, 'utf8');
|
|
175
175
|
const htmlWithBase = html.replace(/<base \/>/, `<base href="${adminUrl.toString({ rootRelative: true })}/" />`);
|
|
176
|
-
const
|
|
176
|
+
const sendHtml = (_req, res) => {
|
|
177
177
|
res.setHeader('Cache-Control', 'no-cache');
|
|
178
|
+
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
178
179
|
res.send(htmlWithBase);
|
|
179
180
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
const setStaticHeaders = (res) => {
|
|
182
|
+
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
|
|
183
|
+
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
184
|
+
};
|
|
185
|
+
app.get('/admin', sendHtml);
|
|
186
|
+
app.use('/admin', express_1.default.static(path_1.default.join(adminPath, '..'), { setHeaders: setStaticHeaders }));
|
|
187
|
+
app.use('/admin/*', sendHtml);
|
|
183
188
|
}
|
|
184
189
|
// use the rate limiter - all routes for now
|
|
185
190
|
if (env_1.default.RATE_LIMITER_ENABLED === true) {
|
|
@@ -51,7 +51,10 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
51
51
|
...clientOptionsOverrides,
|
|
52
52
|
}));
|
|
53
53
|
})
|
|
54
|
-
.catch(
|
|
54
|
+
.catch((e) => {
|
|
55
|
+
logger_1.default.error(e, '[OpenID] Failed to fetch provider config');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
55
58
|
});
|
|
56
59
|
}
|
|
57
60
|
generateCodeVerifier() {
|
|
@@ -32,7 +32,7 @@ const multipartHandler = (req, res, next) => {
|
|
|
32
32
|
'content-type': 'application/octet-stream',
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
const busboy = (0, busboy_1.default)({ headers });
|
|
35
|
+
const busboy = (0, busboy_1.default)({ headers, defParamCharset: 'utf8' });
|
|
36
36
|
const savedFiles = [];
|
|
37
37
|
const service = new services_1.FilesService({ accountability: req.accountability, schema: req.schema });
|
|
38
38
|
const existingPrimaryKey = req.params.pk || undefined;
|
package/dist/emitter.js
CHANGED
|
@@ -21,12 +21,17 @@ class Emitter {
|
|
|
21
21
|
}
|
|
22
22
|
async emitFilter(event, payload, meta, context) {
|
|
23
23
|
const events = Array.isArray(event) ? event : [event];
|
|
24
|
-
const
|
|
24
|
+
const eventListeners = events.map((event) => ({
|
|
25
|
+
event,
|
|
26
|
+
listeners: this.filterEmitter.listeners(event),
|
|
27
|
+
}));
|
|
25
28
|
let updatedPayload = payload;
|
|
26
|
-
for (const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
for (const { event, listeners } of eventListeners) {
|
|
30
|
+
for (const listener of listeners) {
|
|
31
|
+
const result = await listener(updatedPayload, { event, ...meta }, context);
|
|
32
|
+
if (result !== undefined) {
|
|
33
|
+
updatedPayload = result;
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
return updatedPayload;
|
|
@@ -34,7 +39,7 @@ class Emitter {
|
|
|
34
39
|
emitAction(event, meta, context) {
|
|
35
40
|
const events = Array.isArray(event) ? event : [event];
|
|
36
41
|
for (const event of events) {
|
|
37
|
-
this.actionEmitter.emitAsync(event, meta, context).catch((err) => {
|
|
42
|
+
this.actionEmitter.emitAsync(event, { event, ...meta }, context).catch((err) => {
|
|
38
43
|
logger_1.default.warn(`An error was thrown while executing action "${event}"`);
|
|
39
44
|
logger_1.default.warn(err);
|
|
40
45
|
});
|
|
@@ -42,7 +47,7 @@ class Emitter {
|
|
|
42
47
|
}
|
|
43
48
|
async emitInit(event, meta) {
|
|
44
49
|
try {
|
|
45
|
-
await this.initEmitter.emitAsync(event, meta);
|
|
50
|
+
await this.initEmitter.emitAsync(event, { event, ...meta });
|
|
46
51
|
}
|
|
47
52
|
catch (err) {
|
|
48
53
|
logger_1.default.warn(`An error was thrown while executing init "${event}"`);
|
|
@@ -3,6 +3,7 @@ declare type Options = {
|
|
|
3
3
|
collection: string;
|
|
4
4
|
key?: PrimaryKey | PrimaryKey[] | null;
|
|
5
5
|
query?: Record<string, any> | string | null;
|
|
6
|
+
emitEvents: boolean;
|
|
6
7
|
permissions: string;
|
|
7
8
|
};
|
|
8
9
|
declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
|
|
@@ -6,7 +6,7 @@ const get_accountability_for_role_1 = require("../../utils/get-accountability-fo
|
|
|
6
6
|
const sanitize_query_1 = require("../../utils/sanitize-query");
|
|
7
7
|
exports.default = (0, utils_1.defineOperationApi)({
|
|
8
8
|
id: 'item-read',
|
|
9
|
-
handler: async ({ collection, key, query, permissions }, { accountability, database, getSchema }) => {
|
|
9
|
+
handler: async ({ collection, key, query, emitEvents, permissions }, { accountability, database, getSchema }) => {
|
|
10
10
|
const schema = await getSchema({ database });
|
|
11
11
|
let customAccountability;
|
|
12
12
|
if (!permissions || permissions === '$trigger') {
|
|
@@ -35,10 +35,10 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
35
35
|
else {
|
|
36
36
|
const keys = (0, utils_1.toArray)(key);
|
|
37
37
|
if (keys.length === 1) {
|
|
38
|
-
result = await itemsService.readOne(keys[0], sanitizedQueryObject);
|
|
38
|
+
result = await itemsService.readOne(keys[0], sanitizedQueryObject, { emitEvents });
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
result = await itemsService.readMany(keys, sanitizedQueryObject);
|
|
41
|
+
result = await itemsService.readMany(keys, sanitizedQueryObject, { emitEvents });
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
return result;
|
|
@@ -102,7 +102,12 @@ class ImportService {
|
|
|
102
102
|
else {
|
|
103
103
|
try {
|
|
104
104
|
const parsedJson = (0, utils_1.parseJSON)(value);
|
|
105
|
-
|
|
105
|
+
if (typeof parsedJson === 'number') {
|
|
106
|
+
(0, lodash_1.set)(result, key, value);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
(0, lodash_1.set)(result, key, parsedJson);
|
|
110
|
+
}
|
|
106
111
|
}
|
|
107
112
|
catch {
|
|
108
113
|
(0, lodash_1.set)(result, key, value);
|
package/dist/services/items.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { AbstractService, AbstractServiceOptions, Item as AnyItem, MutationOptio
|
|
|
5
5
|
export declare type QueryOptions = {
|
|
6
6
|
stripNonRequested?: boolean;
|
|
7
7
|
permissionsAction?: PermissionsAction;
|
|
8
|
+
emitEvents?: boolean;
|
|
8
9
|
};
|
|
9
10
|
export declare class ItemsService<Item extends AnyItem = AnyItem> implements AbstractService {
|
|
10
11
|
collection: string;
|
package/dist/services/items.js
CHANGED
|
@@ -221,23 +221,27 @@ class ItemsService {
|
|
|
221
221
|
if (records === null) {
|
|
222
222
|
throw new exceptions_1.ForbiddenException();
|
|
223
223
|
}
|
|
224
|
-
const filteredRecords =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
collection: this.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
224
|
+
const filteredRecords = (opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false
|
|
225
|
+
? await emitter_1.default.emitFilter(this.eventScope === 'items' ? ['items.read', `${this.collection}.items.read`] : `${this.eventScope}.read`, records, {
|
|
226
|
+
query,
|
|
227
|
+
collection: this.collection,
|
|
228
|
+
}, {
|
|
229
|
+
database: this.knex,
|
|
230
|
+
schema: this.schema,
|
|
231
|
+
accountability: this.accountability,
|
|
232
|
+
})
|
|
233
|
+
: records;
|
|
234
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
|
|
235
|
+
emitter_1.default.emitAction(this.eventScope === 'items' ? ['items.read', `${this.collection}.items.read`] : `${this.eventScope}.read`, {
|
|
236
|
+
payload: filteredRecords,
|
|
237
|
+
query,
|
|
238
|
+
collection: this.collection,
|
|
239
|
+
}, {
|
|
240
|
+
database: this.knex || (0, database_1.default)(),
|
|
241
|
+
schema: this.schema,
|
|
242
|
+
accountability: this.accountability,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
241
245
|
return filteredRecords;
|
|
242
246
|
}
|
|
243
247
|
/**
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.NotificationsService = void 0;
|
|
4
7
|
const items_1 = require("./items");
|
|
5
8
|
const md_1 = require("../utils/md");
|
|
6
9
|
const users_1 = require("./users");
|
|
7
10
|
const mail_1 = require("./mail");
|
|
11
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
8
12
|
class NotificationsService extends items_1.ItemsService {
|
|
9
13
|
constructor(options) {
|
|
10
14
|
super('directus_notifications', options);
|
|
@@ -12,29 +16,36 @@ class NotificationsService extends items_1.ItemsService {
|
|
|
12
16
|
this.mailService = new mail_1.MailService({ schema: this.schema, accountability: this.accountability });
|
|
13
17
|
}
|
|
14
18
|
async createOne(data, opts) {
|
|
19
|
+
const response = await super.createOne(data, opts);
|
|
15
20
|
await this.sendEmail(data);
|
|
16
|
-
return
|
|
21
|
+
return response;
|
|
17
22
|
}
|
|
18
23
|
async createMany(data, opts) {
|
|
24
|
+
const response = await super.createMany(data, opts);
|
|
19
25
|
for (const notification of data) {
|
|
20
26
|
await this.sendEmail(notification);
|
|
21
27
|
}
|
|
22
|
-
return
|
|
28
|
+
return response;
|
|
23
29
|
}
|
|
24
30
|
async sendEmail(data) {
|
|
25
31
|
if (data.recipient) {
|
|
26
32
|
const user = await this.usersService.readOne(data.recipient, { fields: ['email', 'email_notifications'] });
|
|
27
33
|
if (user.email && user.email_notifications === true) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
try {
|
|
35
|
+
await this.mailService.send({
|
|
36
|
+
template: {
|
|
37
|
+
name: 'base',
|
|
38
|
+
data: {
|
|
39
|
+
html: data.message ? (0, md_1.md)(data.message) : '',
|
|
40
|
+
},
|
|
33
41
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
42
|
+
to: user.email,
|
|
43
|
+
subject: data.subject,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger_1.default.error(error.message);
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
}
|
|
40
51
|
}
|
package/dist/services/payload.js
CHANGED
|
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PayloadService = void 0;
|
|
7
|
-
const utils_1 = require("@directus/shared/utils");
|
|
8
7
|
const date_fns_1 = require("date-fns");
|
|
8
|
+
const utils_1 = require("@directus/shared/utils");
|
|
9
9
|
const flat_1 = require("flat");
|
|
10
10
|
const joi_1 = __importDefault(require("joi"));
|
|
11
11
|
const lodash_1 = require("lodash");
|
|
@@ -259,15 +259,18 @@ class PayloadService {
|
|
|
259
259
|
else {
|
|
260
260
|
if (value instanceof Date === false && typeof value === 'string') {
|
|
261
261
|
if (dateColumn.type === 'date') {
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
const parsedDate = (0, date_fns_1.parseISO)(value);
|
|
263
|
+
if (!(0, date_fns_1.isValid)(parsedDate)) {
|
|
264
|
+
throw new exceptions_1.InvalidPayloadException(`Invalid Date format in field "${dateColumn.field}"`);
|
|
265
|
+
}
|
|
266
|
+
payload[name] = parsedDate;
|
|
265
267
|
}
|
|
266
268
|
if (dateColumn.type === 'dateTime') {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
const parsedDate = (0, date_fns_1.parseISO)(value);
|
|
270
|
+
if (!(0, date_fns_1.isValid)(parsedDate)) {
|
|
271
|
+
throw new exceptions_1.InvalidPayloadException(`Invalid DateTime format in field "${dateColumn.field}"`);
|
|
272
|
+
}
|
|
273
|
+
payload[name] = parsedDate;
|
|
271
274
|
}
|
|
272
275
|
if (dateColumn.type === 'timestamp') {
|
|
273
276
|
const newValue = this.helpers.date.writeTimestamp(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "directus",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.14.0",
|
|
4
4
|
"license": "GPL-3.0-only",
|
|
5
5
|
"homepage": "https://github.com/directus/directus#readme",
|
|
6
6
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content.",
|
|
@@ -77,16 +77,16 @@
|
|
|
77
77
|
],
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@aws-sdk/client-ses": "^3.107.0",
|
|
80
|
-
"@directus/app": "9.
|
|
81
|
-
"@directus/drive": "9.
|
|
82
|
-
"@directus/drive-azure": "9.
|
|
83
|
-
"@directus/drive-gcs": "9.
|
|
84
|
-
"@directus/drive-s3": "9.
|
|
85
|
-
"@directus/extensions-sdk": "9.
|
|
86
|
-
"@directus/format-title": "9.
|
|
87
|
-
"@directus/schema": "9.
|
|
88
|
-
"@directus/shared": "9.
|
|
89
|
-
"@directus/specs": "9.
|
|
80
|
+
"@directus/app": "9.14.0",
|
|
81
|
+
"@directus/drive": "9.14.0",
|
|
82
|
+
"@directus/drive-azure": "9.14.0",
|
|
83
|
+
"@directus/drive-gcs": "9.14.0",
|
|
84
|
+
"@directus/drive-s3": "9.14.0",
|
|
85
|
+
"@directus/extensions-sdk": "9.14.0",
|
|
86
|
+
"@directus/format-title": "9.14.0",
|
|
87
|
+
"@directus/schema": "9.14.0",
|
|
88
|
+
"@directus/shared": "9.14.0",
|
|
89
|
+
"@directus/specs": "9.14.0",
|
|
90
90
|
"@godaddy/terminus": "^4.10.2",
|
|
91
91
|
"@rollup/plugin-alias": "^3.1.9",
|
|
92
92
|
"@rollup/plugin-virtual": "^2.1.0",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"sqlite3": "^5.0.8",
|
|
175
175
|
"tedious": "^13.0.0"
|
|
176
176
|
},
|
|
177
|
-
"gitHead": "
|
|
177
|
+
"gitHead": "d952222058dca96cf823b3e91dc146266ff89bd0",
|
|
178
178
|
"devDependencies": {
|
|
179
179
|
"@types/async": "3.2.13",
|
|
180
180
|
"@types/body-parser": "1.19.2",
|