directus 9.12.1 → 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 +20 -5
- package/dist/auth/drivers/index.js +5 -1
- package/dist/auth/drivers/ldap.js +5 -1
- package/dist/auth/drivers/oauth2.js +15 -23
- package/dist/auth/drivers/openid.js +20 -25
- package/dist/cli/commands/bootstrap/index.js +5 -1
- package/dist/cli/commands/schema/apply.js +7 -3
- package/dist/cli/commands/schema/snapshot.d.ts +1 -1
- package/dist/cli/commands/schema/snapshot.js +33 -25
- package/dist/cli/index.js +1 -1
- package/dist/cli/utils/create-env/env-stub.liquid +11 -11
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +5 -1
- package/dist/controllers/assets.js +5 -5
- package/dist/controllers/dashboards.js +4 -1
- package/dist/controllers/files.js +8 -5
- package/dist/controllers/flows.js +4 -1
- package/dist/controllers/folders.js +4 -1
- package/dist/controllers/items.js +4 -1
- package/dist/controllers/notifications.js +4 -1
- package/dist/controllers/operations.js +4 -1
- package/dist/controllers/panels.js +4 -1
- package/dist/controllers/permissions.js +4 -1
- package/dist/controllers/presets.js +4 -1
- package/dist/controllers/roles.js +4 -1
- package/dist/controllers/shares.js +4 -1
- package/dist/controllers/users.js +75 -3
- package/dist/controllers/utils.js +3 -3
- package/dist/database/helpers/date/dialects/sqlite.js +3 -0
- package/dist/database/helpers/fn/dialects/oracle.d.ts +9 -9
- package/dist/database/helpers/fn/dialects/oracle.js +22 -16
- package/dist/database/helpers/fn/dialects/sqlite.d.ts +9 -9
- package/dist/database/helpers/fn/dialects/sqlite.js +46 -16
- package/dist/database/helpers/fn/types.d.ts +12 -9
- package/dist/database/helpers/index.js +5 -1
- package/dist/database/index.js +2 -0
- package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -2
- package/dist/database/migrations/20210506A-rename-interfaces.js +2 -2
- package/dist/database/migrations/20210802A-replace-groups.js +2 -2
- package/dist/database/migrations/20210805A-update-groups.js +2 -2
- package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -3
- package/dist/database/migrations/20211007A-update-presets.js +5 -5
- package/dist/database/migrations/20220429A-add-flows.js +1 -2
- package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.d.ts +3 -0
- package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.js +11 -0
- package/dist/database/system-data/fields/dashboards.yaml +1 -0
- package/dist/database/system-data/fields/flows.yaml +1 -1
- package/dist/emitter.js +12 -7
- package/dist/env.d.ts +1 -1
- package/dist/env.js +8 -3
- package/dist/exceptions/database/translate.js +5 -1
- package/dist/exceptions/index.js +5 -1
- package/dist/extensions.d.ts +2 -1
- package/dist/extensions.js +28 -20
- package/dist/flows.d.ts +5 -0
- package/dist/flows.js +66 -40
- package/dist/index.js +5 -1
- package/dist/logger.js +5 -1
- package/dist/messenger.js +2 -2
- package/dist/middleware/graphql.js +2 -2
- package/dist/middleware/respond.js +10 -1
- package/dist/middleware/validate-batch.js +3 -1
- package/dist/operations/item-create/index.js +1 -2
- package/dist/operations/item-delete/index.d.ts +1 -0
- package/dist/operations/item-delete/index.js +8 -7
- package/dist/operations/item-read/index.d.ts +1 -0
- package/dist/operations/item-read/index.js +8 -7
- package/dist/operations/item-update/index.d.ts +1 -0
- package/dist/operations/item-update/index.js +9 -8
- package/dist/operations/log/index.js +1 -2
- package/dist/operations/notification/index.js +1 -2
- package/dist/operations/request/index.d.ts +4 -1
- package/dist/operations/request/index.js +5 -1
- package/dist/operations/transform/index.js +1 -2
- package/dist/operations/trigger/index.js +1 -2
- package/dist/server.js +5 -1
- package/dist/services/assets.js +5 -1
- package/dist/services/collections.js +5 -1
- package/dist/services/fields.d.ts +3 -3
- package/dist/services/fields.js +25 -17
- package/dist/services/files.js +5 -1
- package/dist/services/flows.d.ts +1 -2
- package/dist/services/flows.js +19 -8
- package/dist/services/{graphql.d.ts → graphql/index.d.ts} +3 -5
- package/dist/services/{graphql.js → graphql/index.js} +109 -101
- package/dist/services/graphql/types/date.d.ts +2 -0
- package/dist/services/graphql/types/date.js +9 -0
- package/dist/services/graphql/types/geojson.d.ts +2 -0
- package/dist/services/graphql/types/geojson.js +10 -0
- package/dist/services/graphql/types/string-or-float.d.ts +5 -0
- package/dist/services/graphql/types/string-or-float.js +34 -0
- package/dist/services/graphql/types/void.d.ts +2 -0
- package/dist/services/graphql/types/void.js +17 -0
- package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
- package/dist/services/graphql/utils/add-path-to-validation-error.js +20 -0
- package/dist/services/import-export.js +12 -8
- package/dist/services/index.js +5 -1
- package/dist/services/items.d.ts +6 -1
- package/dist/services/items.js +43 -19
- package/dist/services/mail/index.js +8 -6
- package/dist/services/notifications.js +22 -11
- package/dist/services/operations.d.ts +1 -2
- package/dist/services/operations.js +19 -8
- package/dist/services/payload.js +13 -11
- package/dist/services/permissions.d.ts +1 -0
- package/dist/services/permissions.js +5 -0
- package/dist/services/relations.js +5 -1
- package/dist/services/roles.d.ts +1 -0
- package/dist/services/roles.js +9 -0
- package/dist/services/server.js +5 -1
- package/dist/services/users.d.ts +1 -0
- package/dist/services/users.js +22 -0
- package/dist/types/index.js +5 -1
- package/dist/utils/apply-query.js +24 -15
- package/dist/utils/apply-snapshot.js +3 -0
- package/dist/utils/calculate-field-depth.d.ts +33 -0
- package/dist/utils/calculate-field-depth.js +75 -0
- package/dist/utils/get-column.js +1 -1
- package/dist/utils/get-default-value.js +3 -13
- package/dist/utils/get-graphql-type.js +4 -3
- package/dist/utils/get-local-type.d.ts +6 -3
- package/dist/utils/get-permissions.js +3 -4
- package/dist/utils/get-schema.js +1 -2
- package/dist/utils/get-string-byte-size.d.ts +4 -0
- package/dist/utils/get-string-byte-size.js +10 -0
- package/dist/utils/job-queue.d.ts +9 -0
- package/dist/utils/job-queue.js +24 -0
- package/dist/utils/jwt.js +5 -1
- package/dist/utils/sanitize-query.js +4 -5
- package/dist/utils/validate-query.js +50 -0
- package/dist/webhooks.js +5 -1
- package/package.json +74 -73
- package/dist/utils/operation-options.d.ts +0 -3
- package/dist/utils/operation-options.js +0 -45
- package/dist/utils/parse-json.d.ts +0 -5
- package/dist/utils/parse-json.js +0 -19
package/dist/services/items.js
CHANGED
|
@@ -14,10 +14,10 @@ const env_1 = __importDefault(require("../env"));
|
|
|
14
14
|
const exceptions_1 = require("../exceptions");
|
|
15
15
|
const translate_1 = require("../exceptions/database/translate");
|
|
16
16
|
const get_ast_from_query_1 = __importDefault(require("../utils/get-ast-from-query"));
|
|
17
|
+
const validate_keys_1 = require("../utils/validate-keys");
|
|
17
18
|
const authorization_1 = require("./authorization");
|
|
18
19
|
const index_1 = require("./index");
|
|
19
20
|
const payload_1 = require("./payload");
|
|
20
|
-
const validate_keys_1 = require("../utils/validate-keys");
|
|
21
21
|
class ItemsService {
|
|
22
22
|
constructor(collection, options) {
|
|
23
23
|
this.collection = collection;
|
|
@@ -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
|
/**
|
|
@@ -289,7 +293,27 @@ class ItemsService {
|
|
|
289
293
|
return key;
|
|
290
294
|
}
|
|
291
295
|
/**
|
|
292
|
-
* Update
|
|
296
|
+
* Update multiple items in a single transaction
|
|
297
|
+
*/
|
|
298
|
+
async updateBatch(data, opts) {
|
|
299
|
+
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
300
|
+
const keys = [];
|
|
301
|
+
await this.knex.transaction(async (trx) => {
|
|
302
|
+
const service = new ItemsService(this.collection, {
|
|
303
|
+
accountability: this.accountability,
|
|
304
|
+
knex: trx,
|
|
305
|
+
schema: this.schema,
|
|
306
|
+
});
|
|
307
|
+
for (const item of data) {
|
|
308
|
+
if (!item[primaryKeyField])
|
|
309
|
+
throw new exceptions_1.InvalidPayloadException(`Item in update misses primary key.`);
|
|
310
|
+
keys.push(await service.updateOne(item[primaryKeyField], (0, lodash_1.omit)(item, primaryKeyField), opts));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
return keys;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Update many items by primary key, setting all items to the same change
|
|
293
317
|
*/
|
|
294
318
|
async updateMany(keys, data, opts) {
|
|
295
319
|
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
@@ -23,12 +23,14 @@ class MailService {
|
|
|
23
23
|
this.accountability = opts.accountability || null;
|
|
24
24
|
this.knex = (opts === null || opts === void 0 ? void 0 : opts.knex) || (0, database_1.default)();
|
|
25
25
|
this.mailer = (0, mailer_1.default)();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
if (env_1.default.EMAIL_VERIFY_SETUP) {
|
|
27
|
+
this.mailer.verify((error) => {
|
|
28
|
+
if (error) {
|
|
29
|
+
logger_1.default.warn(`Email connection failed:`);
|
|
30
|
+
logger_1.default.warn(error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
async send(options) {
|
|
34
36
|
const { template, ...emailOptions } = options;
|
|
@@ -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
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { OperationRaw } from '@directus/shared/types';
|
|
2
|
-
import { Messenger } from '../messenger';
|
|
3
2
|
import { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types';
|
|
4
3
|
import { ItemsService } from './items';
|
|
5
4
|
export declare class OperationsService extends ItemsService<OperationRaw> {
|
|
6
|
-
messenger: Messenger;
|
|
7
5
|
constructor(options: AbstractServiceOptions);
|
|
8
6
|
createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
9
7
|
createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
10
8
|
updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
9
|
+
updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
11
10
|
updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
12
11
|
deleteOne(key: PrimaryKey, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
13
12
|
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
@@ -1,41 +1,52 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OperationsService = void 0;
|
|
4
|
-
const
|
|
4
|
+
const flows_1 = require("../flows");
|
|
5
5
|
const items_1 = require("./items");
|
|
6
6
|
class OperationsService extends items_1.ItemsService {
|
|
7
7
|
constructor(options) {
|
|
8
8
|
super('directus_operations', options);
|
|
9
|
-
this.messenger = (0, messenger_1.getMessenger)();
|
|
10
9
|
}
|
|
11
10
|
async createOne(data, opts) {
|
|
11
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
12
12
|
const result = await super.createOne(data, opts);
|
|
13
|
-
|
|
13
|
+
await flowManager.reload();
|
|
14
14
|
return result;
|
|
15
15
|
}
|
|
16
16
|
async createMany(data, opts) {
|
|
17
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
17
18
|
const result = await super.createMany(data, opts);
|
|
18
|
-
|
|
19
|
+
await flowManager.reload();
|
|
19
20
|
return result;
|
|
20
21
|
}
|
|
21
22
|
async updateOne(key, data, opts) {
|
|
23
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
22
24
|
const result = await super.updateOne(key, data, opts);
|
|
23
|
-
|
|
25
|
+
await flowManager.reload();
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
async updateBatch(data, opts) {
|
|
29
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
30
|
+
const result = await super.updateBatch(data, opts);
|
|
31
|
+
await flowManager.reload();
|
|
24
32
|
return result;
|
|
25
33
|
}
|
|
26
34
|
async updateMany(keys, data, opts) {
|
|
35
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
27
36
|
const result = await super.updateMany(keys, data, opts);
|
|
28
|
-
|
|
37
|
+
await flowManager.reload();
|
|
29
38
|
return result;
|
|
30
39
|
}
|
|
31
40
|
async deleteOne(key, opts) {
|
|
41
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
32
42
|
const result = await super.deleteOne(key, opts);
|
|
33
|
-
|
|
43
|
+
await flowManager.reload();
|
|
34
44
|
return result;
|
|
35
45
|
}
|
|
36
46
|
async deleteMany(keys, opts) {
|
|
47
|
+
const flowManager = (0, flows_1.getFlowManager)();
|
|
37
48
|
const result = await super.deleteMany(keys, opts);
|
|
38
|
-
|
|
49
|
+
await flowManager.reload();
|
|
39
50
|
return result;
|
|
40
51
|
}
|
|
41
52
|
}
|
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");
|
|
@@ -15,7 +15,6 @@ const database_1 = __importDefault(require("../database"));
|
|
|
15
15
|
const helpers_1 = require("../database/helpers");
|
|
16
16
|
const exceptions_1 = require("../exceptions");
|
|
17
17
|
const generate_hash_1 = require("../utils/generate-hash");
|
|
18
|
-
const parse_json_1 = require("../utils/parse-json");
|
|
19
18
|
const items_1 = require("./items");
|
|
20
19
|
/**
|
|
21
20
|
* Process a given payload for a collection to ensure the special fields (hash, uuid, date etc) are
|
|
@@ -56,7 +55,7 @@ class PayloadService {
|
|
|
56
55
|
if (action === 'read') {
|
|
57
56
|
if (typeof value === 'string') {
|
|
58
57
|
try {
|
|
59
|
-
return (0,
|
|
58
|
+
return (0, utils_1.parseJSON)(value);
|
|
60
59
|
}
|
|
61
60
|
catch {
|
|
62
61
|
return value;
|
|
@@ -197,7 +196,7 @@ class PayloadService {
|
|
|
197
196
|
processGeometries(payloads, action) {
|
|
198
197
|
const process = action == 'read'
|
|
199
198
|
? (value) => (typeof value === 'string' ? (0, wellknown_1.parse)(value) : value)
|
|
200
|
-
: (value) => this.helpers.st.fromGeoJSON(typeof value == 'string' ? (0,
|
|
199
|
+
: (value) => this.helpers.st.fromGeoJSON(typeof value == 'string' ? (0, utils_1.parseJSON)(value) : value);
|
|
201
200
|
const fieldsInCollection = Object.entries(this.schema.collections[this.collection].fields);
|
|
202
201
|
const geometryColumns = fieldsInCollection.filter(([_, field]) => field.type.startsWith('geometry'));
|
|
203
202
|
for (const [name] of geometryColumns) {
|
|
@@ -260,15 +259,18 @@ class PayloadService {
|
|
|
260
259
|
else {
|
|
261
260
|
if (value instanceof Date === false && typeof value === 'string') {
|
|
262
261
|
if (dateColumn.type === 'date') {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
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;
|
|
266
267
|
}
|
|
267
268
|
if (dateColumn.type === 'dateTime') {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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;
|
|
272
274
|
}
|
|
273
275
|
if (dateColumn.type === 'timestamp') {
|
|
274
276
|
const newValue = this.helpers.date.writeTimestamp(value);
|
|
@@ -12,6 +12,7 @@ export declare class PermissionsService extends ItemsService {
|
|
|
12
12
|
createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
13
13
|
updateByQuery(query: Query, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
14
14
|
updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
15
|
+
updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
15
16
|
updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
16
17
|
upsertOne(payload: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
17
18
|
upsertMany(payloads: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
@@ -70,6 +70,11 @@ class PermissionsService extends items_1.ItemsService {
|
|
|
70
70
|
await (0, cache_1.clearSystemCache)();
|
|
71
71
|
return res;
|
|
72
72
|
}
|
|
73
|
+
async updateBatch(data, opts) {
|
|
74
|
+
const res = await super.updateBatch(data, opts);
|
|
75
|
+
await (0, cache_1.clearSystemCache)();
|
|
76
|
+
return res;
|
|
77
|
+
}
|
|
73
78
|
async updateMany(keys, data, opts) {
|
|
74
79
|
const res = await super.updateMany(keys, data, opts);
|
|
75
80
|
await (0, cache_1.clearSystemCache)();
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/services/roles.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class RolesService extends ItemsService {
|
|
|
6
6
|
private checkForOtherAdminRoles;
|
|
7
7
|
private checkForOtherAdminUsers;
|
|
8
8
|
updateOne(key: PrimaryKey, data: Record<string, any>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
9
|
+
updateBatch(data: Record<string, any>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
9
10
|
updateMany(keys: PrimaryKey[], data: Record<string, any>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
10
11
|
deleteOne(key: PrimaryKey): Promise<PrimaryKey>;
|
|
11
12
|
deleteMany(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
package/dist/services/roles.js
CHANGED
|
@@ -64,6 +64,15 @@ class RolesService extends items_1.ItemsService {
|
|
|
64
64
|
}
|
|
65
65
|
return super.updateOne(key, data, opts);
|
|
66
66
|
}
|
|
67
|
+
async updateBatch(data, opts) {
|
|
68
|
+
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
69
|
+
const keys = data.map((item) => item[primaryKeyField]);
|
|
70
|
+
const setsToNoAdmin = data.some((item) => item.admin_access === false);
|
|
71
|
+
if (setsToNoAdmin) {
|
|
72
|
+
await this.checkForOtherAdminRoles(keys);
|
|
73
|
+
}
|
|
74
|
+
return super.updateBatch(data, opts);
|
|
75
|
+
}
|
|
67
76
|
async updateMany(keys, data, opts) {
|
|
68
77
|
if ('admin_access' in data && data.admin_access === false) {
|
|
69
78
|
await this.checkForOtherAdminRoles(keys);
|
package/dist/services/server.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/services/users.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class UsersService extends ItemsService {
|
|
|
38
38
|
* Update a single user by primary key
|
|
39
39
|
*/
|
|
40
40
|
updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
41
|
+
updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
41
42
|
/**
|
|
42
43
|
* Update many users by primary key
|
|
43
44
|
*/
|
package/dist/services/users.js
CHANGED
|
@@ -153,6 +153,23 @@ class UsersService extends items_1.ItemsService {
|
|
|
153
153
|
await this.updateMany([key], data, opts);
|
|
154
154
|
return key;
|
|
155
155
|
}
|
|
156
|
+
async updateBatch(data, opts) {
|
|
157
|
+
const primaryKeyField = this.schema.collections[this.collection].primary;
|
|
158
|
+
const keys = [];
|
|
159
|
+
await this.knex.transaction(async (trx) => {
|
|
160
|
+
const service = new UsersService({
|
|
161
|
+
accountability: this.accountability,
|
|
162
|
+
knex: trx,
|
|
163
|
+
schema: this.schema,
|
|
164
|
+
});
|
|
165
|
+
for (const item of data) {
|
|
166
|
+
if (!item[primaryKeyField])
|
|
167
|
+
throw new exceptions_2.InvalidPayloadException(`User in update misses primary key.`);
|
|
168
|
+
keys.push(await service.updateOne(item[primaryKeyField], item, opts));
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return keys;
|
|
172
|
+
}
|
|
156
173
|
/**
|
|
157
174
|
* Update many users by primary key
|
|
158
175
|
*/
|
|
@@ -305,6 +322,7 @@ class UsersService extends items_1.ItemsService {
|
|
|
305
322
|
await (0, stall_1.stall)(STALL_TIME, timeStart);
|
|
306
323
|
}
|
|
307
324
|
async resetPassword(token, password) {
|
|
325
|
+
var _a;
|
|
308
326
|
const { email, scope, hash } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
|
|
309
327
|
if (scope !== 'password-reset' || !hash)
|
|
310
328
|
throw new exceptions_2.ForbiddenException();
|
|
@@ -317,6 +335,10 @@ class UsersService extends items_1.ItemsService {
|
|
|
317
335
|
const service = new UsersService({
|
|
318
336
|
knex: this.knex,
|
|
319
337
|
schema: this.schema,
|
|
338
|
+
accountability: {
|
|
339
|
+
...((_a = this.accountability) !== null && _a !== void 0 ? _a : { role: null }),
|
|
340
|
+
admin: true, // We need to skip permissions checks for the update call below
|
|
341
|
+
},
|
|
320
342
|
});
|
|
321
343
|
await service.updateOne(user.id, { password, status: 'active' });
|
|
322
344
|
}
|
package/dist/types/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -211,7 +211,15 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
211
211
|
const columnName = (0, get_column_path_1.getColumnPath)({ path: filterPath, collection, relations, aliasMap });
|
|
212
212
|
if (!columnName)
|
|
213
213
|
continue;
|
|
214
|
-
|
|
214
|
+
if (relation === null || relation === void 0 ? void 0 : relation.related_collection) {
|
|
215
|
+
applyFilterToQuery(columnName, filterOperator, filterValue, logical, relation.related_collection); // m2o
|
|
216
|
+
}
|
|
217
|
+
else if (filterPath[0].includes(':')) {
|
|
218
|
+
applyFilterToQuery(columnName, filterOperator, filterValue, logical, filterPath[0].split(':')[1]); // a2o
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
applyFilterToQuery(columnName, filterOperator, filterValue, logical);
|
|
222
|
+
}
|
|
215
223
|
}
|
|
216
224
|
else {
|
|
217
225
|
applyFilterToQuery(`${collection}.${filterPath[0]}`, filterOperator, filterValue, logical);
|
|
@@ -245,7 +253,7 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
245
253
|
}
|
|
246
254
|
}
|
|
247
255
|
}
|
|
248
|
-
function applyFilterToQuery(key, operator, compareValue, logical = 'and') {
|
|
256
|
+
function applyFilterToQuery(key, operator, compareValue, logical = 'and', originalCollectionName) {
|
|
249
257
|
const [table, column] = key.split('.');
|
|
250
258
|
// Is processed through Knex.Raw, so should be safe to string-inject into these where queries
|
|
251
259
|
const selectionRaw = (0, get_column_1.getColumn)(knex, table, column, false, schema);
|
|
@@ -268,6 +276,17 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
268
276
|
query.where(key, '!=', '');
|
|
269
277
|
});
|
|
270
278
|
}
|
|
279
|
+
// The following fields however, require a value to be run. If no value is passed, we
|
|
280
|
+
// ignore them. This allows easier use in GraphQL, where you wouldn't be able to
|
|
281
|
+
// conditionally build out your filter structure (#4471)
|
|
282
|
+
if (compareValue === undefined)
|
|
283
|
+
return;
|
|
284
|
+
if (Array.isArray(compareValue)) {
|
|
285
|
+
// Tip: when using a `[Type]` type in GraphQL, but don't provide the variable, it'll be
|
|
286
|
+
// reported as [undefined].
|
|
287
|
+
// We need to remove any undefined values, as they are useless
|
|
288
|
+
compareValue = compareValue.filter((val) => val !== undefined);
|
|
289
|
+
}
|
|
271
290
|
// Cast filter value (compareValue) based on function used
|
|
272
291
|
if (column.includes('(') && column.includes(')')) {
|
|
273
292
|
const functionName = column.split('(')[0];
|
|
@@ -278,8 +297,9 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
278
297
|
}
|
|
279
298
|
// Cast filter value (compareValue) based on type of field being filtered against
|
|
280
299
|
const [collection, field] = key.split('.');
|
|
281
|
-
|
|
282
|
-
|
|
300
|
+
const mappedCollection = originalCollectionName || collection;
|
|
301
|
+
if (mappedCollection in schema.collections && field in schema.collections[mappedCollection].fields) {
|
|
302
|
+
const type = schema.collections[mappedCollection].fields[field].type;
|
|
283
303
|
if (['date', 'dateTime', 'time', 'timestamp'].includes(type)) {
|
|
284
304
|
if (Array.isArray(compareValue)) {
|
|
285
305
|
compareValue = compareValue.map((val) => helpers.date.parse(val));
|
|
@@ -297,17 +317,6 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
297
317
|
}
|
|
298
318
|
}
|
|
299
319
|
}
|
|
300
|
-
// The following fields however, require a value to be run. If no value is passed, we
|
|
301
|
-
// ignore them. This allows easier use in GraphQL, where you wouldn't be able to
|
|
302
|
-
// conditionally build out your filter structure (#4471)
|
|
303
|
-
if (compareValue === undefined)
|
|
304
|
-
return;
|
|
305
|
-
if (Array.isArray(compareValue)) {
|
|
306
|
-
// Tip: when using a `[Type]` type in GraphQL, but don't provide the variable, it'll be
|
|
307
|
-
// reported as [undefined].
|
|
308
|
-
// We need to remove any undefined values, as they are useless
|
|
309
|
-
compareValue = compareValue.filter((val) => val !== undefined);
|
|
310
|
-
}
|
|
311
320
|
if (operator === '_eq') {
|
|
312
321
|
dbQuery[logical].where(selectionRaw, '=', compareValue);
|
|
313
322
|
}
|
|
@@ -11,10 +11,12 @@ const services_1 = require("../services");
|
|
|
11
11
|
const get_schema_1 = require("./get-schema");
|
|
12
12
|
const get_snapshot_1 = require("./get-snapshot");
|
|
13
13
|
const get_snapshot_diff_1 = require("./get-snapshot-diff");
|
|
14
|
+
const cache_1 = require("../cache");
|
|
14
15
|
async function applySnapshot(snapshot, options) {
|
|
15
16
|
var _a, _b, _c, _d;
|
|
16
17
|
const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
|
|
17
18
|
const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database }));
|
|
19
|
+
const { systemCache } = (0, cache_1.getCache)();
|
|
18
20
|
const current = (_c = options === null || options === void 0 ? void 0 : options.current) !== null && _c !== void 0 ? _c : (await (0, get_snapshot_1.getSnapshot)({ database, schema }));
|
|
19
21
|
const snapshotDiff = (_d = options === null || options === void 0 ? void 0 : options.diff) !== null && _d !== void 0 ? _d : (0, get_snapshot_diff_1.getSnapshotDiff)(current, snapshot);
|
|
20
22
|
await database.transaction(async (trx) => {
|
|
@@ -178,6 +180,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
});
|
|
183
|
+
await (systemCache === null || systemCache === void 0 ? void 0 : systemCache.clear());
|
|
181
184
|
}
|
|
182
185
|
exports.applySnapshot = applySnapshot;
|
|
183
186
|
function isNestedMetaUpdate(diff) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the depth of a given JSON structure, not counting any _ prefixed properties
|
|
3
|
+
*
|
|
4
|
+
* Used to calculate the field depth in a filter or deep query structure
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
*
|
|
8
|
+
* ```js
|
|
9
|
+
* const deep = {
|
|
10
|
+
* translations: {
|
|
11
|
+
* _filter: {
|
|
12
|
+
* _and: [
|
|
13
|
+
* {
|
|
14
|
+
* language_id: {
|
|
15
|
+
* name: {
|
|
16
|
+
* _eq: 'English'
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* },
|
|
20
|
+
* {
|
|
21
|
+
* status: {
|
|
22
|
+
* _eq: 'Published'
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ]
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* };
|
|
29
|
+
*
|
|
30
|
+
* const result = calculateFieldDepth(deep); // => 3
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function calculateFieldDepth(obj?: Record<string, any> | null, dotNotationKeys?: string[]): number;
|