directus 9.21.0 → 9.22.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 -5
- package/dist/app.test.d.ts +1 -0
- package/dist/auth/drivers/openid.js +3 -1
- package/dist/cli/commands/bootstrap/index.js +2 -2
- package/dist/cli/commands/schema/apply.js +0 -2
- package/dist/cli/commands/schema/snapshot.js +0 -2
- package/dist/cli/commands/security/secret.js +2 -2
- package/dist/cli/utils/create-env/env-stub.liquid +3 -3
- package/dist/cli/utils/create-env/index.js +5 -8
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/controllers/assets.js +9 -7
- package/dist/controllers/files.js +2 -1
- package/dist/controllers/utils.js +2 -2
- package/dist/database/helpers/fn/dialects/mssql.js +2 -1
- package/dist/database/helpers/fn/dialects/mysql.js +3 -2
- package/dist/database/helpers/fn/dialects/oracle.js +2 -1
- package/dist/database/helpers/fn/dialects/postgres.js +2 -1
- package/dist/database/helpers/fn/dialects/sqlite.js +2 -1
- package/dist/database/helpers/fn/types.d.ts +1 -0
- package/dist/database/helpers/fn/types.js +5 -4
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/mssql.d.ts +6 -0
- package/dist/database/helpers/schema/dialects/mssql.js +14 -0
- package/dist/database/helpers/schema/dialects/mysql.d.ts +5 -0
- package/dist/database/helpers/schema/dialects/mysql.js +19 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/oracle.js +3 -0
- package/dist/database/helpers/schema/index.d.ts +2 -2
- package/dist/database/helpers/schema/index.js +4 -4
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +13 -0
- package/dist/database/index.d.ts +6 -0
- package/dist/database/index.js +20 -1
- package/dist/database/migrations/20211007A-update-presets.js +2 -2
- package/dist/database/migrations/run.js +7 -31
- package/dist/database/run-ast.js +132 -6
- package/dist/database/system-data/fields/index.js +2 -1
- package/dist/env.js +3 -2
- package/dist/exceptions/range-not-satisfiable.d.ts +1 -1
- package/dist/extensions.d.ts +7 -1
- package/dist/extensions.js +41 -15
- package/dist/logger.js +27 -1
- package/dist/middleware/schema.js +1 -1
- package/dist/operations/request/index.d.ts +1 -2
- package/dist/operations/request/index.js +2 -2
- package/dist/services/assets.d.ts +4 -3
- package/dist/services/assets.js +13 -11
- package/dist/services/authentication.js +4 -3
- package/dist/services/authorization.js +1 -1
- package/dist/services/collections.js +7 -7
- package/dist/services/fields.d.ts +3 -2
- package/dist/services/fields.js +40 -20
- package/dist/services/files.d.ts +4 -3
- package/dist/services/files.js +92 -68
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +0 -14
- package/dist/services/flows.test.d.ts +1 -0
- package/dist/services/graphql/index.d.ts +5 -1
- package/dist/services/graphql/index.js +29 -31
- package/dist/services/import-export.d.ts +4 -3
- package/dist/services/items.js +7 -1
- package/dist/services/meta.js +2 -2
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +0 -12
- package/dist/services/operations.test.d.ts +1 -0
- package/dist/services/permissions.d.ts +0 -5
- package/dist/services/permissions.js +0 -25
- package/dist/services/permissions.test.d.ts +1 -0
- package/dist/services/relations.d.ts +2 -2
- package/dist/services/relations.js +24 -16
- package/dist/services/roles.js +0 -3
- package/dist/services/roles.test.d.ts +1 -0
- package/dist/services/server.js +8 -6
- package/dist/services/shares.js +2 -2
- package/dist/services/specifications.js +12 -1
- package/dist/services/users.js +10 -4
- package/dist/services/webhooks.d.ts +0 -2
- package/dist/services/webhooks.js +0 -10
- package/dist/services/webhooks.test.d.ts +1 -0
- package/dist/storage/get-storage-driver.d.ts +3 -0
- package/dist/storage/get-storage-driver.js +20 -0
- package/dist/storage/get-storage-driver.test.d.ts +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +20 -0
- package/dist/storage/index.test.d.ts +1 -0
- package/dist/storage/register-drivers.d.ts +2 -0
- package/dist/storage/register-drivers.js +22 -0
- package/dist/storage/register-drivers.test.d.ts +1 -0
- package/dist/storage/register-locations.d.ts +2 -0
- package/dist/storage/register-locations.js +17 -0
- package/dist/storage/register-locations.test.d.ts +1 -0
- package/dist/utils/apply-query.d.ts +27 -3
- package/dist/utils/apply-query.js +180 -127
- package/dist/utils/apply-snapshot.js +32 -13
- package/dist/utils/dynamic-import.d.ts +1 -0
- package/dist/utils/dynamic-import.js +7 -0
- package/dist/utils/get-collection-from-alias.d.ts +6 -0
- package/dist/utils/get-collection-from-alias.js +15 -0
- package/dist/utils/get-collection-from-alias.test.d.ts +1 -0
- package/dist/utils/get-column-path.d.ts +14 -8
- package/dist/utils/get-column-path.js +24 -7
- package/dist/utils/get-column.d.ts +8 -1
- package/dist/utils/get-column.js +10 -3
- package/dist/utils/get-config-from-env.js +3 -2
- package/dist/utils/get-default-value.d.ts +1 -1
- package/dist/utils/get-schema.d.ts +6 -2
- package/dist/utils/get-schema.js +1 -1
- package/dist/utils/get-snapshot.js +1 -1
- package/dist/utils/parse-image-metadata.d.ts +3 -0
- package/dist/utils/parse-image-metadata.js +73 -0
- package/dist/utils/track.js +2 -2
- package/dist/utils/validate-env.js +3 -2
- package/dist/webhooks.js +2 -2
- package/package.json +18 -22
- package/dist/storage.d.ts +0 -3
- package/dist/storage.js +0 -61
|
@@ -12,13 +12,19 @@ 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
14
|
const cache_1 = require("../cache");
|
|
15
|
+
const emitter_1 = __importDefault(require("../emitter"));
|
|
15
16
|
async function applySnapshot(snapshot, options) {
|
|
16
17
|
var _a, _b, _c, _d;
|
|
17
18
|
const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
|
|
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 schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database, bypassCache: true }));
|
|
19
20
|
const { systemCache } = (0, cache_1.getCache)();
|
|
20
21
|
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 }));
|
|
21
22
|
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);
|
|
23
|
+
const nestedActionEvents = [];
|
|
24
|
+
const mutationOptions = {
|
|
25
|
+
autoPurgeSystemCache: false,
|
|
26
|
+
bypassEmitAction: (params) => nestedActionEvents.push(params),
|
|
27
|
+
};
|
|
22
28
|
await database.transaction(async (trx) => {
|
|
23
29
|
const collectionsService = new services_1.CollectionsService({ knex: trx, schema });
|
|
24
30
|
const getNestedCollectionsToCreate = (currentLevelCollection) => snapshotDiff.collections.filter(({ diff }) => { var _a, _b; return ((_b = (_a = diff[0].rhs) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.group) === currentLevelCollection; });
|
|
@@ -49,7 +55,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
49
55
|
await collectionsService.createOne({
|
|
50
56
|
...diff[0].rhs,
|
|
51
57
|
fields,
|
|
52
|
-
});
|
|
58
|
+
}, mutationOptions);
|
|
53
59
|
}
|
|
54
60
|
catch (err) {
|
|
55
61
|
logger_1.default.error(`Failed to create collection "${collection}"`);
|
|
@@ -69,7 +75,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
69
75
|
const relationsService = new services_1.RelationsService({ knex: trx, schema });
|
|
70
76
|
for (const relation of relations) {
|
|
71
77
|
try {
|
|
72
|
-
await relationsService.deleteOne(relation.collection, relation.field);
|
|
78
|
+
await relationsService.deleteOne(relation.collection, relation.field, mutationOptions);
|
|
73
79
|
}
|
|
74
80
|
catch (err) {
|
|
75
81
|
logger_1.default.error(`Failed to delete collection "${collection}" due to relation "${relation.collection}.${relation.field}"`);
|
|
@@ -81,7 +87,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
81
87
|
}
|
|
82
88
|
await deleteCollections(getNestedCollectionsToDelete(collection));
|
|
83
89
|
try {
|
|
84
|
-
await collectionsService.deleteOne(collection);
|
|
90
|
+
await collectionsService.deleteOne(collection, mutationOptions);
|
|
85
91
|
}
|
|
86
92
|
catch (err) {
|
|
87
93
|
logger_1.default.error(`Failed to delete collection "${collection}"`);
|
|
@@ -130,7 +136,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
130
136
|
});
|
|
131
137
|
if (newValues) {
|
|
132
138
|
try {
|
|
133
|
-
await collectionsService.updateOne(collection, newValues);
|
|
139
|
+
await collectionsService.updateOne(collection, newValues, mutationOptions);
|
|
134
140
|
}
|
|
135
141
|
catch (err) {
|
|
136
142
|
logger_1.default.error(`Failed to update collection "${collection}"`);
|
|
@@ -139,11 +145,14 @@ async function applySnapshot(snapshot, options) {
|
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
|
-
const fieldsService = new services_1.FieldsService({
|
|
148
|
+
const fieldsService = new services_1.FieldsService({
|
|
149
|
+
knex: trx,
|
|
150
|
+
schema: await (0, get_schema_1.getSchema)({ database: trx, bypassCache: true }),
|
|
151
|
+
});
|
|
143
152
|
for (const { collection, field, diff } of snapshotDiff.fields) {
|
|
144
153
|
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N' && !isNestedMetaUpdate(diff === null || diff === void 0 ? void 0 : diff[0])) {
|
|
145
154
|
try {
|
|
146
|
-
await fieldsService.createField(collection, diff[0].rhs);
|
|
155
|
+
await fieldsService.createField(collection, diff[0].rhs, undefined, mutationOptions);
|
|
147
156
|
}
|
|
148
157
|
catch (err) {
|
|
149
158
|
logger_1.default.error(`Failed to create field "${collection}.${field}"`);
|
|
@@ -158,7 +167,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
158
167
|
try {
|
|
159
168
|
await fieldsService.updateField(collection, {
|
|
160
169
|
...newValues,
|
|
161
|
-
});
|
|
170
|
+
}, mutationOptions);
|
|
162
171
|
}
|
|
163
172
|
catch (err) {
|
|
164
173
|
logger_1.default.error(`Failed to update field "${collection}.${field}"`);
|
|
@@ -168,7 +177,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
168
177
|
}
|
|
169
178
|
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D' && !isNestedMetaUpdate(diff === null || diff === void 0 ? void 0 : diff[0])) {
|
|
170
179
|
try {
|
|
171
|
-
await fieldsService.deleteField(collection, field);
|
|
180
|
+
await fieldsService.deleteField(collection, field, mutationOptions);
|
|
172
181
|
}
|
|
173
182
|
catch (err) {
|
|
174
183
|
logger_1.default.error(`Failed to delete field "${collection}.${field}"`);
|
|
@@ -179,7 +188,10 @@ async function applySnapshot(snapshot, options) {
|
|
|
179
188
|
snapshotDiff.relations = snapshotDiff.relations.filter((relation) => (relation.collection === collection && relation.field === field) === false);
|
|
180
189
|
}
|
|
181
190
|
}
|
|
182
|
-
const relationsService = new services_1.RelationsService({
|
|
191
|
+
const relationsService = new services_1.RelationsService({
|
|
192
|
+
knex: trx,
|
|
193
|
+
schema: await (0, get_schema_1.getSchema)({ database: trx, bypassCache: true }),
|
|
194
|
+
});
|
|
183
195
|
for (const { collection, field, diff } of snapshotDiff.relations) {
|
|
184
196
|
const structure = {};
|
|
185
197
|
for (const diffEdit of diff) {
|
|
@@ -187,7 +199,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
187
199
|
}
|
|
188
200
|
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
|
|
189
201
|
try {
|
|
190
|
-
await relationsService.createOne(diff[0].rhs);
|
|
202
|
+
await relationsService.createOne(diff[0].rhs, mutationOptions);
|
|
191
203
|
}
|
|
192
204
|
catch (err) {
|
|
193
205
|
logger_1.default.error(`Failed to create relation "${collection}.${field}"`);
|
|
@@ -200,7 +212,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
200
212
|
});
|
|
201
213
|
if (newValues) {
|
|
202
214
|
try {
|
|
203
|
-
await relationsService.updateOne(collection, field, newValues);
|
|
215
|
+
await relationsService.updateOne(collection, field, newValues, mutationOptions);
|
|
204
216
|
}
|
|
205
217
|
catch (err) {
|
|
206
218
|
logger_1.default.error(`Failed to update relation "${collection}.${field}"`);
|
|
@@ -210,7 +222,7 @@ async function applySnapshot(snapshot, options) {
|
|
|
210
222
|
}
|
|
211
223
|
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
|
|
212
224
|
try {
|
|
213
|
-
await relationsService.deleteOne(collection, field);
|
|
225
|
+
await relationsService.deleteOne(collection, field, mutationOptions);
|
|
214
226
|
}
|
|
215
227
|
catch (err) {
|
|
216
228
|
logger_1.default.error(`Failed to delete relation "${collection}.${field}"`);
|
|
@@ -220,6 +232,13 @@ async function applySnapshot(snapshot, options) {
|
|
|
220
232
|
}
|
|
221
233
|
});
|
|
222
234
|
await (systemCache === null || systemCache === void 0 ? void 0 : systemCache.clear());
|
|
235
|
+
if (nestedActionEvents.length > 0) {
|
|
236
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ database, bypassCache: true });
|
|
237
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
238
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
239
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
223
242
|
}
|
|
224
243
|
exports.applySnapshot = applySnapshot;
|
|
225
244
|
function isNestedMetaUpdate(diff) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const dynamicImport: (mod: string) => Promise<any>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCollectionFromAlias = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Extract the collection of an alias within an aliasMap
|
|
6
|
+
* For example: 'ljnsv.name' -> 'authors'
|
|
7
|
+
*/
|
|
8
|
+
function getCollectionFromAlias(alias, aliasMap) {
|
|
9
|
+
for (const aliasValue of Object.values(aliasMap)) {
|
|
10
|
+
if (aliasValue.alias === alias) {
|
|
11
|
+
return aliasValue.collection;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.getCollectionFromAlias = getCollectionFromAlias;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import { Relation } from '@directus/shared/types';
|
|
2
|
-
type AliasMap =
|
|
3
|
-
[key: string]:
|
|
1
|
+
import { Relation, SchemaOverview } from '@directus/shared/types';
|
|
2
|
+
export type AliasMap = {
|
|
3
|
+
[key: string]: {
|
|
4
|
+
alias: string;
|
|
5
|
+
collection: string;
|
|
6
|
+
};
|
|
4
7
|
};
|
|
5
8
|
export type ColPathProps = {
|
|
6
9
|
path: string[];
|
|
7
10
|
collection: string;
|
|
8
11
|
aliasMap: AliasMap;
|
|
9
12
|
relations: Relation[];
|
|
13
|
+
schema?: SchemaOverview;
|
|
14
|
+
};
|
|
15
|
+
export type ColPathResult = {
|
|
16
|
+
columnPath: string;
|
|
17
|
+
targetCollection: string;
|
|
18
|
+
addNestedPkField?: string;
|
|
10
19
|
};
|
|
11
20
|
/**
|
|
12
21
|
* Converts a Directus field list path to the correct SQL names based on the constructed alias map.
|
|
13
22
|
* For example: ['author', 'role', 'name'] -> 'ljnsv.name'
|
|
14
23
|
* Also returns the target collection of the column: 'directus_roles'
|
|
24
|
+
* If the last filter path is an alias field, a nested PK is appended to the path
|
|
15
25
|
*/
|
|
16
|
-
export declare function getColumnPath({ path, collection, aliasMap, relations }: ColPathProps):
|
|
17
|
-
columnPath: string;
|
|
18
|
-
targetCollection: string;
|
|
19
|
-
};
|
|
20
|
-
export {};
|
|
26
|
+
export declare function getColumnPath({ path, collection, aliasMap, relations, schema }: ColPathProps): ColPathResult;
|
|
@@ -3,15 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getColumnPath = void 0;
|
|
4
4
|
const get_relation_info_1 = require("./get-relation-info");
|
|
5
5
|
const exceptions_1 = require("../exceptions");
|
|
6
|
-
const lodash_1 = require("lodash");
|
|
7
6
|
/**
|
|
8
7
|
* Converts a Directus field list path to the correct SQL names based on the constructed alias map.
|
|
9
8
|
* For example: ['author', 'role', 'name'] -> 'ljnsv.name'
|
|
10
9
|
* Also returns the target collection of the column: 'directus_roles'
|
|
10
|
+
* If the last filter path is an alias field, a nested PK is appended to the path
|
|
11
11
|
*/
|
|
12
|
-
function getColumnPath({ path, collection, aliasMap, relations }) {
|
|
12
|
+
function getColumnPath({ path, collection, aliasMap, relations, schema }) {
|
|
13
13
|
return followRelation(path);
|
|
14
|
-
function followRelation(pathParts, parentCollection = collection,
|
|
14
|
+
function followRelation(pathParts, parentCollection = collection, parentFields, addNestedPkField) {
|
|
15
|
+
var _a, _b, _c, _d;
|
|
15
16
|
/**
|
|
16
17
|
* For A2M fields, the path can contain an optional collection scope <field>:<scope>
|
|
17
18
|
*/
|
|
@@ -20,7 +21,7 @@ function getColumnPath({ path, collection, aliasMap, relations }) {
|
|
|
20
21
|
if (!relation) {
|
|
21
22
|
throw new exceptions_1.InvalidQueryException(`"${parentCollection}.${pathRoot}" is not a relational field`);
|
|
22
23
|
}
|
|
23
|
-
const alias = (0
|
|
24
|
+
const alias = parentFields ? (_a = aliasMap[`${parentFields}.${pathParts[0]}`]) === null || _a === void 0 ? void 0 : _a.alias : (_b = aliasMap[pathParts[0]]) === null || _b === void 0 ? void 0 : _b.alias;
|
|
24
25
|
const remainingParts = pathParts.slice(1);
|
|
25
26
|
let parent;
|
|
26
27
|
if (relationType === 'a2o') {
|
|
@@ -36,13 +37,29 @@ function getColumnPath({ path, collection, aliasMap, relations }) {
|
|
|
36
37
|
else {
|
|
37
38
|
parent = relation.collection;
|
|
38
39
|
}
|
|
40
|
+
// Top level alias field
|
|
41
|
+
if (schema && !(((_c = remainingParts[0]) !== null && _c !== void 0 ? _c : parent).includes('(') && ((_d = remainingParts[0]) !== null && _d !== void 0 ? _d : parent).includes(')'))) {
|
|
42
|
+
if (remainingParts.length === 0) {
|
|
43
|
+
remainingParts.push(schema.collections[parent].primary);
|
|
44
|
+
addNestedPkField = schema.collections[parent].primary;
|
|
45
|
+
}
|
|
46
|
+
// Nested level alias field
|
|
47
|
+
else if (remainingParts.length === 1 && schema.collections[parent].fields[remainingParts[0]].type === 'alias') {
|
|
48
|
+
remainingParts.push(schema.collections[relation.related_collection].primary);
|
|
49
|
+
addNestedPkField = schema.collections[relation.related_collection].primary;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
39
52
|
if (remainingParts.length === 1) {
|
|
40
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
columnPath: `${alias || parent}.${remainingParts[0]}`,
|
|
55
|
+
targetCollection: parent,
|
|
56
|
+
addNestedPkField,
|
|
57
|
+
};
|
|
41
58
|
}
|
|
42
59
|
if (remainingParts.length) {
|
|
43
|
-
return followRelation(remainingParts, parent,
|
|
60
|
+
return followRelation(remainingParts, parent, `${parentFields ? parentFields + '.' : ''}${pathParts[0]}`, addNestedPkField);
|
|
44
61
|
}
|
|
45
|
-
return { columnPath: '', targetCollection: '' };
|
|
62
|
+
return { columnPath: '', targetCollection: '', addNestedPkField };
|
|
46
63
|
}
|
|
47
64
|
}
|
|
48
65
|
exports.getColumnPath = getColumnPath;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Query, SchemaOverview } from '@directus/shared/types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
|
+
type GetColumnOptions = {
|
|
4
|
+
query?: Query;
|
|
5
|
+
originalCollectionName?: string;
|
|
6
|
+
};
|
|
3
7
|
/**
|
|
4
8
|
* Return column prefixed by table. If column includes functions (like `year(date_created)`), the
|
|
5
9
|
* column is replaced with the appropriate SQL
|
|
@@ -8,6 +12,9 @@ import { Knex } from 'knex';
|
|
|
8
12
|
* @param table Collection or alias in which column resides
|
|
9
13
|
* @param column name of the column
|
|
10
14
|
* @param alias Whether or not to add a SQL AS statement
|
|
15
|
+
* @param schema For retrieval of the column type
|
|
16
|
+
* @param options Optional parameters
|
|
11
17
|
* @returns Knex raw instance
|
|
12
18
|
*/
|
|
13
|
-
export declare function getColumn(knex: Knex, table: string, column: string, alias: string | false | undefined, schema: SchemaOverview,
|
|
19
|
+
export declare function getColumn(knex: Knex, table: string, column: string, alias: string | false | undefined, schema: SchemaOverview, options?: GetColumnOptions): Knex.Raw;
|
|
20
|
+
export {};
|
package/dist/utils/get-column.js
CHANGED
|
@@ -14,21 +14,28 @@ const apply_function_to_column_name_1 = require("./apply-function-to-column-name
|
|
|
14
14
|
* @param table Collection or alias in which column resides
|
|
15
15
|
* @param column name of the column
|
|
16
16
|
* @param alias Whether or not to add a SQL AS statement
|
|
17
|
+
* @param schema For retrieval of the column type
|
|
18
|
+
* @param options Optional parameters
|
|
17
19
|
* @returns Knex raw instance
|
|
18
20
|
*/
|
|
19
|
-
function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column), schema,
|
|
21
|
+
function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column), schema, options) {
|
|
20
22
|
var _a, _b, _c, _d;
|
|
21
23
|
const fn = (0, helpers_1.getFunctions)(knex, schema);
|
|
22
24
|
if (column.includes('(') && column.includes(')')) {
|
|
23
25
|
const functionName = column.split('(')[0];
|
|
24
26
|
const columnName = column.match(constants_1.REGEX_BETWEEN_PARENS)[1];
|
|
25
27
|
if (functionName in fn) {
|
|
26
|
-
const
|
|
28
|
+
const collectionName = (options === null || options === void 0 ? void 0 : options.originalCollectionName) || table;
|
|
29
|
+
const type = (_d = (_c = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.collections[collectionName]) === null || _a === void 0 ? void 0 : _a.fields) === null || _b === void 0 ? void 0 : _b[columnName]) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : 'unknown';
|
|
27
30
|
const allowedFunctions = (0, utils_1.getFunctionsForType)(type);
|
|
28
31
|
if (allowedFunctions.includes(functionName) === false) {
|
|
29
32
|
throw new exceptions_1.InvalidQueryException(`Invalid function specified "${functionName}"`);
|
|
30
33
|
}
|
|
31
|
-
const result = fn[functionName](table, columnName, {
|
|
34
|
+
const result = fn[functionName](table, columnName, {
|
|
35
|
+
type,
|
|
36
|
+
query: options === null || options === void 0 ? void 0 : options.query,
|
|
37
|
+
originalCollectionName: options === null || options === void 0 ? void 0 : options.originalCollectionName,
|
|
38
|
+
});
|
|
32
39
|
if (alias) {
|
|
33
40
|
return knex.raw(result + ' AS ??', [alias]);
|
|
34
41
|
}
|
|
@@ -6,10 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getConfigFromEnv = void 0;
|
|
7
7
|
const camelcase_1 = __importDefault(require("camelcase"));
|
|
8
8
|
const lodash_1 = require("lodash");
|
|
9
|
-
const env_1 =
|
|
9
|
+
const env_1 = require("../env");
|
|
10
10
|
function getConfigFromEnv(prefix, omitPrefix, type = 'camelcase') {
|
|
11
|
+
const env = (0, env_1.getEnv)();
|
|
11
12
|
const config = {};
|
|
12
|
-
for (const [key, value] of Object.entries(
|
|
13
|
+
for (const [key, value] of Object.entries(env)) {
|
|
13
14
|
if (key.toLowerCase().startsWith(prefix.toLowerCase()) === false)
|
|
14
15
|
continue;
|
|
15
16
|
if (omitPrefix) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { SchemaOverview } from '@directus/schema/
|
|
1
|
+
import { SchemaOverview } from '@directus/schema/types/overview';
|
|
2
2
|
import { Column } from 'knex-schema-inspector/dist/types/column';
|
|
3
3
|
export default function getDefaultValue(column: SchemaOverview[string]['columns'][string] | Column): string | boolean | number | Record<string, any> | any[] | null;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SchemaOverview } from '@directus/shared/types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
export declare function getSchema(options?: {
|
|
4
|
-
accountability?: Accountability;
|
|
5
4
|
database?: Knex;
|
|
5
|
+
/**
|
|
6
|
+
* To bypass any cached schema if bypassCache is enabled.
|
|
7
|
+
* Used to ensure schema snapshot/apply is not using outdated schema
|
|
8
|
+
*/
|
|
9
|
+
bypassCache?: boolean;
|
|
6
10
|
}): Promise<SchemaOverview>;
|
package/dist/utils/get-schema.js
CHANGED
|
@@ -21,7 +21,7 @@ async function getSchema(options) {
|
|
|
21
21
|
const database = (options === null || options === void 0 ? void 0 : options.database) || (0, database_1.default)();
|
|
22
22
|
const schemaInspector = (0, schema_1.default)(database);
|
|
23
23
|
let result;
|
|
24
|
-
if (env_1.default.CACHE_SCHEMA !== false) {
|
|
24
|
+
if (!(options === null || options === void 0 ? void 0 : options.bypassCache) && env_1.default.CACHE_SCHEMA !== false) {
|
|
25
25
|
let cachedSchema;
|
|
26
26
|
try {
|
|
27
27
|
cachedSchema = (await (0, cache_1.getSystemCache)('schema'));
|
|
@@ -12,7 +12,7 @@ const lodash_1 = require("lodash");
|
|
|
12
12
|
async function getSnapshot(options) {
|
|
13
13
|
var _a, _b;
|
|
14
14
|
const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
|
|
15
|
-
const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database }));
|
|
15
|
+
const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database, bypassCache: true }));
|
|
16
16
|
const collectionsService = new services_1.CollectionsService({ knex: database, schema });
|
|
17
17
|
const fieldsService = new services_1.FieldsService({ knex: database, schema });
|
|
18
18
|
const relationsService = new services_1.RelationsService({ knex: database, schema });
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseXmp = exports.parseIptc = void 0;
|
|
4
|
+
const IPTC_ENTRY_TYPES = new Map([
|
|
5
|
+
[0x78, 'caption'],
|
|
6
|
+
[0x6e, 'credit'],
|
|
7
|
+
[0x19, 'keywords'],
|
|
8
|
+
[0x37, 'dateCreated'],
|
|
9
|
+
[0x50, 'byline'],
|
|
10
|
+
[0x55, 'bylineTitle'],
|
|
11
|
+
[0x7a, 'captionWriter'],
|
|
12
|
+
[0x69, 'headline'],
|
|
13
|
+
[0x74, 'copyright'],
|
|
14
|
+
[0x0f, 'category'],
|
|
15
|
+
]);
|
|
16
|
+
const IPTC_ENTRY_MARKER = Buffer.from([0x1c, 0x02]);
|
|
17
|
+
function parseIptc(buffer) {
|
|
18
|
+
if (!Buffer.isBuffer(buffer))
|
|
19
|
+
return {};
|
|
20
|
+
const iptc = {};
|
|
21
|
+
let lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER);
|
|
22
|
+
while (lastIptcEntryPos !== -1) {
|
|
23
|
+
lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER, lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength);
|
|
24
|
+
const iptcBlockTypePos = lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength;
|
|
25
|
+
const iptcBlockSizePos = iptcBlockTypePos + 1;
|
|
26
|
+
const iptcBlockDataPos = iptcBlockSizePos + 2;
|
|
27
|
+
const iptcBlockType = buffer.readUInt8(iptcBlockTypePos);
|
|
28
|
+
const iptcBlockSize = buffer.readUInt16BE(iptcBlockSizePos);
|
|
29
|
+
if (!IPTC_ENTRY_TYPES.has(iptcBlockType)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const iptcBlockTypeId = IPTC_ENTRY_TYPES.get(iptcBlockType);
|
|
33
|
+
const iptcData = buffer.subarray(iptcBlockDataPos, iptcBlockDataPos + iptcBlockSize).toString();
|
|
34
|
+
if (iptcBlockTypeId) {
|
|
35
|
+
if (iptc[iptcBlockTypeId] == null) {
|
|
36
|
+
iptc[iptcBlockTypeId] = iptcData;
|
|
37
|
+
}
|
|
38
|
+
else if (Array.isArray(iptc[iptcBlockTypeId])) {
|
|
39
|
+
iptc[iptcBlockTypeId].push(iptcData);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
iptc[iptcBlockTypeId] = [iptc[iptcBlockTypeId], iptcData];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return iptc;
|
|
47
|
+
}
|
|
48
|
+
exports.parseIptc = parseIptc;
|
|
49
|
+
function parseXmp(buffer) {
|
|
50
|
+
const xmp = {};
|
|
51
|
+
['title', 'description', 'rights', 'creator', 'subject'].forEach((x) => {
|
|
52
|
+
const tagRegex = new RegExp(`<dc:${x}>(.*?)</dc:${x}>`, 'smig'), tagMatches = tagRegex.exec(buffer.toString());
|
|
53
|
+
if (!tagMatches || tagMatches.length === 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const value = tagMatches[1].trim();
|
|
57
|
+
if (value.toLowerCase().indexOf('<rdf:bag>') === 0) {
|
|
58
|
+
const r = new RegExp('<rdf:li>(.*?)</rdf:li>', 'smig');
|
|
59
|
+
let match = r.exec(value);
|
|
60
|
+
const result = [];
|
|
61
|
+
while (match) {
|
|
62
|
+
result.push(match[1]);
|
|
63
|
+
match = r.exec(value);
|
|
64
|
+
}
|
|
65
|
+
xmp[x] = result;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
xmp[x] = value.replace(/<[^>]*>?/gm, '').trim();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return xmp;
|
|
72
|
+
}
|
|
73
|
+
exports.parseXmp = parseXmp;
|
package/dist/utils/track.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.track = void 0;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
7
|
const ms_1 = __importDefault(require("ms"));
|
|
9
8
|
const node_machine_id_1 = require("node-machine-id");
|
|
10
9
|
const os_1 = __importDefault(require("os"));
|
|
@@ -14,10 +13,11 @@ const env_1 = __importDefault(require("../env"));
|
|
|
14
13
|
const logger_1 = __importDefault(require("../logger"));
|
|
15
14
|
const utils_1 = require("@directus/shared/utils");
|
|
16
15
|
async function track(event) {
|
|
16
|
+
const axios = (await import('axios')).default;
|
|
17
17
|
if (env_1.default.TELEMETRY !== false) {
|
|
18
18
|
const info = await getEnvInfo(event);
|
|
19
19
|
try {
|
|
20
|
-
await
|
|
20
|
+
await axios.post('https://telemetry.directus.io/', info);
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
23
23
|
if (env_1.default.NODE_ENV === 'development') {
|
|
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.validateEnv = void 0;
|
|
7
|
-
const env_1 =
|
|
7
|
+
const env_1 = require("../env");
|
|
8
8
|
const logger_1 = __importDefault(require("../logger"));
|
|
9
9
|
function validateEnv(requiredKeys) {
|
|
10
|
+
const env = (0, env_1.getEnv)();
|
|
10
11
|
for (const requiredKey of requiredKeys) {
|
|
11
|
-
if (requiredKey in
|
|
12
|
+
if (requiredKey in env === false) {
|
|
12
13
|
logger_1.default.error(`"${requiredKey}" Environment Variable is missing.`);
|
|
13
14
|
process.exit(1);
|
|
14
15
|
}
|
package/dist/webhooks.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.unregister = exports.register = exports.reload = exports.init = void 0;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
7
|
const database_1 = __importDefault(require("./database"));
|
|
9
8
|
const emitter_1 = __importDefault(require("./emitter"));
|
|
10
9
|
const logger_1 = __importDefault(require("./logger"));
|
|
@@ -53,6 +52,7 @@ function unregister() {
|
|
|
53
52
|
exports.unregister = unregister;
|
|
54
53
|
function createHandler(webhook, event) {
|
|
55
54
|
return async (meta, context) => {
|
|
55
|
+
const axios = (await import('axios')).default;
|
|
56
56
|
if (webhook.collections.includes(meta.collection) === false)
|
|
57
57
|
return;
|
|
58
58
|
const webhookPayload = {
|
|
@@ -66,7 +66,7 @@ function createHandler(webhook, event) {
|
|
|
66
66
|
...meta,
|
|
67
67
|
};
|
|
68
68
|
try {
|
|
69
|
-
await (
|
|
69
|
+
await axios({
|
|
70
70
|
url: webhook.url,
|
|
71
71
|
method: webhook.method,
|
|
72
72
|
data: webhook.data ? webhookPayload : null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "directus",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.22.0",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -66,16 +66,7 @@
|
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@authenio/samlify-node-xmllint": "2.0.0",
|
|
68
68
|
"@aws-sdk/client-ses": "3.211.0",
|
|
69
|
-
"@directus/app": "9.21.0",
|
|
70
|
-
"@directus/drive": "9.21.0",
|
|
71
|
-
"@directus/drive-azure": "9.21.0",
|
|
72
|
-
"@directus/drive-gcs": "9.21.0",
|
|
73
|
-
"@directus/drive-s3": "9.21.0",
|
|
74
|
-
"@directus/extensions-sdk": "9.21.0",
|
|
75
69
|
"@directus/format-title": "9.15.0",
|
|
76
|
-
"@directus/schema": "9.21.0",
|
|
77
|
-
"@directus/shared": "9.21.0",
|
|
78
|
-
"@directus/specs": "9.21.0",
|
|
79
70
|
"@godaddy/terminus": "4.11.2",
|
|
80
71
|
"@rollup/plugin-alias": "4.0.2",
|
|
81
72
|
"@rollup/plugin-virtual": "3.0.1",
|
|
@@ -94,13 +85,12 @@
|
|
|
94
85
|
"csv-parser": "3.0.0",
|
|
95
86
|
"date-fns": "2.29.3",
|
|
96
87
|
"deep-diff": "1.0.2",
|
|
97
|
-
"deep-map": "2.0.0",
|
|
98
88
|
"destroy": "1.2.0",
|
|
99
89
|
"dotenv": "16.0.3",
|
|
100
90
|
"encodeurl": "1.0.2",
|
|
101
91
|
"eventemitter2": "6.4.9",
|
|
102
92
|
"execa": "5.1.1",
|
|
103
|
-
"
|
|
93
|
+
"exif-reader": "1.0.3",
|
|
104
94
|
"express": "4.18.2",
|
|
105
95
|
"fast-redact": "3.1.2",
|
|
106
96
|
"flat": "5.0.2",
|
|
@@ -109,6 +99,7 @@
|
|
|
109
99
|
"graphql": "16.6.0",
|
|
110
100
|
"graphql-compose": "9.0.10",
|
|
111
101
|
"helmet": "6.0.0",
|
|
102
|
+
"icc": "2.0.0",
|
|
112
103
|
"inquirer": "8.2.4",
|
|
113
104
|
"ioredis": "5.2.4",
|
|
114
105
|
"joi": "17.7.0",
|
|
@@ -138,9 +129,9 @@
|
|
|
138
129
|
"pino": "8.7.0",
|
|
139
130
|
"pino-http": "8.2.1",
|
|
140
131
|
"pino-http-print": "3.1.0",
|
|
132
|
+
"pino-pretty": "9.1.1",
|
|
141
133
|
"qs": "6.11.0",
|
|
142
134
|
"rate-limiter-flexible": "2.4.1",
|
|
143
|
-
"resolve-cwd": "3.0.0",
|
|
144
135
|
"rollup": "3.3.0",
|
|
145
136
|
"samlify": "2.8.7",
|
|
146
137
|
"sanitize-html": "2.7.3",
|
|
@@ -153,10 +144,21 @@
|
|
|
153
144
|
"uuid": "9.0.0",
|
|
154
145
|
"uuid-validate": "0.0.3",
|
|
155
146
|
"vm2": "3.9.11",
|
|
156
|
-
"wellknown": "0.5.0"
|
|
147
|
+
"wellknown": "0.5.0",
|
|
148
|
+
"@directus/app": "9.22.0",
|
|
149
|
+
"@directus/extensions-sdk": "9.22.0",
|
|
150
|
+
"@directus/schema": "9.22.0",
|
|
151
|
+
"@directus/shared": "9.22.0",
|
|
152
|
+
"@directus/specs": "9.22.0",
|
|
153
|
+
"@directus/storage": "9.22.0",
|
|
154
|
+
"@directus/storage-driver-azure": "9.22.0",
|
|
155
|
+
"@directus/storage-driver-cloudinary": "9.21.2",
|
|
156
|
+
"@directus/storage-driver-gcs": "9.22.0",
|
|
157
|
+
"@directus/storage-driver-local": "9.22.0",
|
|
158
|
+
"@directus/storage-driver-s3": "9.22.0"
|
|
157
159
|
},
|
|
158
160
|
"devDependencies": {
|
|
159
|
-
"@
|
|
161
|
+
"@ngneat/falso": "6.3.0",
|
|
160
162
|
"@types/async": "3.2.15",
|
|
161
163
|
"@types/busboy": "1.5.0",
|
|
162
164
|
"@types/bytes": "3.1.1",
|
|
@@ -165,10 +167,9 @@
|
|
|
165
167
|
"@types/deep-diff": "1.0.1",
|
|
166
168
|
"@types/destroy": "1.0.0",
|
|
167
169
|
"@types/encodeurl": "1.0.0",
|
|
170
|
+
"@types/exif-reader": "1.0.0",
|
|
168
171
|
"@types/express": "4.17.14",
|
|
169
|
-
"@types/express-pino-logger": "4.0.3",
|
|
170
172
|
"@types/express-serve-static-core": "4.17.31",
|
|
171
|
-
"@types/express-session": "1.17.5",
|
|
172
173
|
"@types/fast-redact": "3.0.2",
|
|
173
174
|
"@types/flat": "5.0.2",
|
|
174
175
|
"@types/fs-extra": "9.0.13",
|
|
@@ -192,7 +193,6 @@
|
|
|
192
193
|
"@types/sanitize-html": "2.6.2",
|
|
193
194
|
"@types/sharp": "0.31.0",
|
|
194
195
|
"@types/stream-json": "1.7.2",
|
|
195
|
-
"@types/supertest": "2.0.12",
|
|
196
196
|
"@types/uuid": "8.3.4",
|
|
197
197
|
"@types/uuid-validate": "0.0.1",
|
|
198
198
|
"@types/wellknown": "0.5.4",
|
|
@@ -200,8 +200,6 @@
|
|
|
200
200
|
"copyfiles": "2.4.1",
|
|
201
201
|
"form-data": "4.0.0",
|
|
202
202
|
"knex-mock-client": "1.8.4",
|
|
203
|
-
"rimraf": "3.0.2",
|
|
204
|
-
"supertest": "6.3.1",
|
|
205
203
|
"ts-node": "10.9.1",
|
|
206
204
|
"ts-node-dev": "2.0.0",
|
|
207
205
|
"typescript": "4.9.3",
|
|
@@ -222,9 +220,7 @@
|
|
|
222
220
|
"node": ">=12.20.0"
|
|
223
221
|
},
|
|
224
222
|
"scripts": {
|
|
225
|
-
"prebuild": "pnpm cleanup",
|
|
226
223
|
"build": "tsc --build && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
|
|
227
|
-
"cleanup": "rimraf dist",
|
|
228
224
|
"cli": "NODE_ENV=development SERVE_APP=false ts-node --script-mode --transpile-only src/cli/run.ts",
|
|
229
225
|
"dev": "NODE_ENV=development SERVE_APP=false ts-node-dev --files --transpile-only --respawn --watch \".env\" --inspect=0 --exit-child -- src/start.ts",
|
|
230
226
|
"start": "npx directus start",
|