directus 9.10.0 → 9.12.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.
Files changed (141) hide show
  1. package/dist/app.js +8 -1
  2. package/dist/auth/drivers/oauth2.d.ts +1 -1
  3. package/dist/auth/drivers/oauth2.js +14 -11
  4. package/dist/auth/drivers/openid.d.ts +1 -1
  5. package/dist/auth/drivers/openid.js +14 -11
  6. package/dist/cli/commands/schema/apply.js +4 -3
  7. package/dist/cli/utils/create-env/env-stub.liquid +266 -9
  8. package/dist/controllers/activity.js +1 -1
  9. package/dist/controllers/assets.js +8 -9
  10. package/dist/controllers/flows.d.ts +2 -0
  11. package/dist/controllers/flows.js +157 -0
  12. package/dist/controllers/folders.js +1 -1
  13. package/dist/controllers/notifications.js +1 -1
  14. package/dist/controllers/operations.d.ts +2 -0
  15. package/dist/controllers/operations.js +138 -0
  16. package/dist/database/helpers/date/dialects/sqlite.js +6 -2
  17. package/dist/database/index.js +15 -19
  18. package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -1
  19. package/dist/database/migrations/20210506A-rename-interfaces.js +2 -1
  20. package/dist/database/migrations/20210802A-replace-groups.js +2 -1
  21. package/dist/database/migrations/20210805A-update-groups.js +2 -1
  22. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -2
  23. package/dist/database/migrations/20211007A-update-presets.js +5 -4
  24. package/dist/database/migrations/20220429A-add-flows.d.ts +3 -0
  25. package/dist/database/migrations/20220429A-add-flows.js +83 -0
  26. package/dist/database/migrations/20220429B-add-color-to-insights-icon.d.ts +3 -0
  27. package/dist/database/migrations/20220429B-add-color-to-insights-icon.js +15 -0
  28. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.d.ts +3 -0
  29. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.js +15 -0
  30. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.d.ts +3 -0
  31. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.js +15 -0
  32. package/dist/database/run-ast.js +10 -14
  33. package/dist/database/seeds/05-activity.yaml +0 -1
  34. package/dist/database/system-data/collections/collections.yaml +4 -0
  35. package/dist/database/system-data/fields/activity.yaml +3 -0
  36. package/dist/database/system-data/fields/dashboards.yaml +3 -1
  37. package/dist/database/system-data/fields/flows.yaml +21 -0
  38. package/dist/database/system-data/fields/notifications.yaml +3 -1
  39. package/dist/database/system-data/fields/operations.yaml +19 -0
  40. package/dist/database/system-data/fields/panels.yaml +3 -1
  41. package/dist/database/system-data/fields/shares.yaml +3 -1
  42. package/dist/database/system-data/fields/users.yaml +2 -4
  43. package/dist/database/system-data/relations/relations.yaml +20 -0
  44. package/dist/env.d.ts +1 -1
  45. package/dist/env.js +167 -12
  46. package/dist/exceptions/index.d.ts +1 -0
  47. package/dist/exceptions/index.js +1 -0
  48. package/dist/exceptions/invalid-provider.d.ts +4 -0
  49. package/dist/exceptions/invalid-provider.js +10 -0
  50. package/dist/exceptions/range-not-satisfiable.d.ts +2 -2
  51. package/dist/exceptions/range-not-satisfiable.js +5 -1
  52. package/dist/extensions.d.ts +3 -0
  53. package/dist/extensions.js +73 -20
  54. package/dist/flows.d.ts +17 -0
  55. package/dist/flows.js +310 -0
  56. package/dist/messenger.d.ts +24 -0
  57. package/dist/messenger.js +64 -0
  58. package/dist/middleware/graphql.js +2 -1
  59. package/dist/operations/condition/index.d.ts +6 -0
  60. package/dist/operations/condition/index.js +15 -0
  61. package/dist/operations/item-create/index.d.ts +8 -0
  62. package/dist/operations/item-create/index.js +40 -0
  63. package/dist/operations/item-delete/index.d.ts +9 -0
  64. package/dist/operations/item-delete/index.js +45 -0
  65. package/dist/operations/item-read/index.d.ts +9 -0
  66. package/dist/operations/item-read/index.js +45 -0
  67. package/dist/operations/item-update/index.d.ts +10 -0
  68. package/dist/operations/item-update/index.js +50 -0
  69. package/dist/operations/log/index.d.ts +5 -0
  70. package/dist/operations/log/index.js +14 -0
  71. package/dist/operations/mail/index.d.ts +7 -0
  72. package/dist/operations/mail/index.js +16 -0
  73. package/dist/operations/notification/index.d.ts +8 -0
  74. package/dist/operations/notification/index.js +39 -0
  75. package/dist/operations/request/index.d.ts +9 -0
  76. package/dist/operations/request/index.js +14 -0
  77. package/dist/operations/sleep/index.d.ts +5 -0
  78. package/dist/operations/sleep/index.js +9 -0
  79. package/dist/operations/transform/index.d.ts +5 -0
  80. package/dist/operations/transform/index.js +10 -0
  81. package/dist/operations/trigger/index.d.ts +6 -0
  82. package/dist/operations/trigger/index.js +21 -0
  83. package/dist/services/activity.d.ts +1 -2
  84. package/dist/services/activity.js +10 -10
  85. package/dist/services/assets.js +27 -1
  86. package/dist/services/authentication.d.ts +2 -2
  87. package/dist/services/authentication.js +11 -8
  88. package/dist/services/authorization.js +12 -0
  89. package/dist/services/fields.js +15 -8
  90. package/dist/services/flows.d.ts +14 -0
  91. package/dist/services/flows.js +42 -0
  92. package/dist/services/graphql.js +56 -33
  93. package/dist/services/import-export.d.ts +1 -1
  94. package/dist/services/import-export.js +13 -12
  95. package/dist/services/index.d.ts +2 -0
  96. package/dist/services/index.js +2 -0
  97. package/dist/services/items.d.ts +3 -3
  98. package/dist/services/items.js +25 -2
  99. package/dist/services/mail/index.js +2 -1
  100. package/dist/services/notifications.d.ts +2 -1
  101. package/dist/services/notifications.js +4 -3
  102. package/dist/services/operations.d.ts +14 -0
  103. package/dist/services/operations.js +42 -0
  104. package/dist/services/payload.d.ts +2 -2
  105. package/dist/services/payload.js +8 -7
  106. package/dist/services/users.d.ts +4 -0
  107. package/dist/services/users.js +20 -0
  108. package/dist/services/webhooks.d.ts +2 -0
  109. package/dist/services/webhooks.js +8 -7
  110. package/dist/types/events.d.ts +18 -0
  111. package/dist/types/events.js +2 -0
  112. package/dist/types/index.d.ts +1 -1
  113. package/dist/types/index.js +1 -1
  114. package/dist/utils/apply-query.js +31 -4
  115. package/dist/utils/apply-snapshot.d.ts +3 -3
  116. package/dist/utils/apply-snapshot.js +64 -49
  117. package/dist/utils/construct-flow-tree.d.ts +2 -0
  118. package/dist/utils/construct-flow-tree.js +31 -0
  119. package/dist/utils/get-accountability-for-role.d.ts +7 -0
  120. package/dist/utils/get-accountability-for-role.js +36 -0
  121. package/dist/utils/get-ast-from-query.js +1 -7
  122. package/dist/utils/get-default-value.js +4 -3
  123. package/dist/utils/get-permissions.d.ts +1 -1
  124. package/dist/utils/get-permissions.js +9 -8
  125. package/dist/utils/get-schema.js +2 -1
  126. package/dist/utils/get-snapshot.js +22 -4
  127. package/dist/utils/operation-options.d.ts +3 -0
  128. package/dist/utils/operation-options.js +45 -0
  129. package/dist/utils/parse-json.d.ts +5 -0
  130. package/dist/utils/parse-json.js +19 -0
  131. package/dist/utils/sanitize-query.d.ts +1 -2
  132. package/dist/utils/sanitize-query.js +6 -5
  133. package/dist/utils/validate-keys.d.ts +6 -0
  134. package/dist/utils/validate-keys.js +28 -0
  135. package/dist/utils/validate-query.js +1 -1
  136. package/dist/webhooks.d.ts +2 -0
  137. package/dist/webhooks.js +17 -2
  138. package/package.json +18 -14
  139. package/dist/types/activity.d.ts +0 -9
  140. package/dist/types/activity.js +0 -13
  141. package/example.env +0 -202
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const constants_1 = require("../constants");
8
+ const exceptions_1 = require("../exceptions");
9
+ const flows_1 = require("../flows");
10
+ const respond_1 = require("../middleware/respond");
11
+ const use_collection_1 = __importDefault(require("../middleware/use-collection"));
12
+ const validate_batch_1 = require("../middleware/validate-batch");
13
+ const services_1 = require("../services");
14
+ const async_handler_1 = __importDefault(require("../utils/async-handler"));
15
+ const router = express_1.default.Router();
16
+ router.use((0, use_collection_1.default)('directus_flows'));
17
+ const webhookFlowHandler = (0, async_handler_1.default)(async (req, res, next) => {
18
+ const flowManager = (0, flows_1.getFlowManager)();
19
+ const result = await flowManager.runWebhookFlow(`${req.method}-${req.params.pk}`, {
20
+ path: req.path,
21
+ query: req.query,
22
+ body: req.body,
23
+ method: req.method,
24
+ headers: req.headers,
25
+ }, {
26
+ accountability: req.accountability,
27
+ schema: req.schema,
28
+ });
29
+ res.locals.payload = result;
30
+ return next();
31
+ });
32
+ router.get(`/trigger/:pk(${constants_1.UUID_REGEX})`, webhookFlowHandler, respond_1.respond);
33
+ router.post(`/trigger/:pk(${constants_1.UUID_REGEX})`, webhookFlowHandler, respond_1.respond);
34
+ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
35
+ const service = new services_1.FlowsService({
36
+ accountability: req.accountability,
37
+ schema: req.schema,
38
+ });
39
+ const savedKeys = [];
40
+ if (Array.isArray(req.body)) {
41
+ const keys = await service.createMany(req.body);
42
+ savedKeys.push(...keys);
43
+ }
44
+ else {
45
+ const key = await service.createOne(req.body);
46
+ savedKeys.push(key);
47
+ }
48
+ try {
49
+ if (Array.isArray(req.body)) {
50
+ const items = await service.readMany(savedKeys, req.sanitizedQuery);
51
+ res.locals.payload = { data: items };
52
+ }
53
+ else {
54
+ const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
55
+ res.locals.payload = { data: item };
56
+ }
57
+ }
58
+ catch (error) {
59
+ if (error instanceof exceptions_1.ForbiddenException) {
60
+ return next();
61
+ }
62
+ throw error;
63
+ }
64
+ return next();
65
+ }), respond_1.respond);
66
+ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
67
+ const service = new services_1.FlowsService({
68
+ accountability: req.accountability,
69
+ schema: req.schema,
70
+ });
71
+ const metaService = new services_1.MetaService({
72
+ accountability: req.accountability,
73
+ schema: req.schema,
74
+ });
75
+ const records = await service.readByQuery(req.sanitizedQuery);
76
+ const meta = await metaService.getMetaForQuery(req.collection, req.sanitizedQuery);
77
+ res.locals.payload = { data: records || null, meta };
78
+ return next();
79
+ });
80
+ router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
81
+ router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
82
+ router.get('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
83
+ const service = new services_1.FlowsService({
84
+ accountability: req.accountability,
85
+ schema: req.schema,
86
+ });
87
+ const record = await service.readOne(req.params.pk, req.sanitizedQuery);
88
+ res.locals.payload = { data: record || null };
89
+ return next();
90
+ }), respond_1.respond);
91
+ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
92
+ const service = new services_1.FlowsService({
93
+ accountability: req.accountability,
94
+ schema: req.schema,
95
+ });
96
+ let keys = [];
97
+ if (req.body.keys) {
98
+ keys = await service.updateMany(req.body.keys, req.body.data);
99
+ }
100
+ else {
101
+ keys = await service.updateByQuery(req.body.query, req.body.data);
102
+ }
103
+ try {
104
+ const result = await service.readMany(keys, req.sanitizedQuery);
105
+ res.locals.payload = { data: result };
106
+ }
107
+ catch (error) {
108
+ if (error instanceof exceptions_1.ForbiddenException) {
109
+ return next();
110
+ }
111
+ throw error;
112
+ }
113
+ return next();
114
+ }), respond_1.respond);
115
+ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
116
+ const service = new services_1.FlowsService({
117
+ accountability: req.accountability,
118
+ schema: req.schema,
119
+ });
120
+ const primaryKey = await service.updateOne(req.params.pk, req.body);
121
+ try {
122
+ const item = await service.readOne(primaryKey, req.sanitizedQuery);
123
+ res.locals.payload = { data: item || null };
124
+ }
125
+ catch (error) {
126
+ if (error instanceof exceptions_1.ForbiddenException) {
127
+ return next();
128
+ }
129
+ throw error;
130
+ }
131
+ return next();
132
+ }), respond_1.respond);
133
+ router.delete('/', (0, async_handler_1.default)(async (req, res, next) => {
134
+ const service = new services_1.FlowsService({
135
+ accountability: req.accountability,
136
+ schema: req.schema,
137
+ });
138
+ if (Array.isArray(req.body)) {
139
+ await service.deleteMany(req.body);
140
+ }
141
+ else if (req.body.keys) {
142
+ await service.deleteMany(req.body.keys);
143
+ }
144
+ else {
145
+ await service.deleteByQuery(req.body.query);
146
+ }
147
+ return next();
148
+ }), respond_1.respond);
149
+ router.delete('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
150
+ const service = new services_1.FlowsService({
151
+ accountability: req.accountability,
152
+ schema: req.schema,
153
+ });
154
+ await service.deleteOne(req.params.pk);
155
+ return next();
156
+ }), respond_1.respond);
157
+ exports.default = router;
@@ -63,7 +63,7 @@ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
63
63
  else {
64
64
  result = await service.readByQuery(req.sanitizedQuery);
65
65
  }
66
- const meta = await metaService.getMetaForQuery('directus_files', req.sanitizedQuery);
66
+ const meta = await metaService.getMetaForQuery('directus_folders', req.sanitizedQuery);
67
67
  res.locals.payload = { data: result, meta };
68
68
  return next();
69
69
  });
@@ -63,7 +63,7 @@ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
63
63
  else {
64
64
  result = await service.readByQuery(req.sanitizedQuery);
65
65
  }
66
- const meta = await metaService.getMetaForQuery('directus_presets', req.sanitizedQuery);
66
+ const meta = await metaService.getMetaForQuery('directus_notifications', req.sanitizedQuery);
67
67
  res.locals.payload = { data: result, meta };
68
68
  return next();
69
69
  });
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const exceptions_1 = require("../exceptions");
8
+ const respond_1 = require("../middleware/respond");
9
+ const use_collection_1 = __importDefault(require("../middleware/use-collection"));
10
+ const validate_batch_1 = require("../middleware/validate-batch");
11
+ const services_1 = require("../services");
12
+ const async_handler_1 = __importDefault(require("../utils/async-handler"));
13
+ const router = express_1.default.Router();
14
+ router.use((0, use_collection_1.default)('directus_operations'));
15
+ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
16
+ const service = new services_1.OperationsService({
17
+ accountability: req.accountability,
18
+ schema: req.schema,
19
+ });
20
+ const savedKeys = [];
21
+ if (Array.isArray(req.body)) {
22
+ const keys = await service.createMany(req.body);
23
+ savedKeys.push(...keys);
24
+ }
25
+ else {
26
+ const key = await service.createOne(req.body);
27
+ savedKeys.push(key);
28
+ }
29
+ try {
30
+ if (Array.isArray(req.body)) {
31
+ const items = await service.readMany(savedKeys, req.sanitizedQuery);
32
+ res.locals.payload = { data: items };
33
+ }
34
+ else {
35
+ const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
36
+ res.locals.payload = { data: item };
37
+ }
38
+ }
39
+ catch (error) {
40
+ if (error instanceof exceptions_1.ForbiddenException) {
41
+ return next();
42
+ }
43
+ throw error;
44
+ }
45
+ return next();
46
+ }), respond_1.respond);
47
+ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
48
+ const service = new services_1.OperationsService({
49
+ accountability: req.accountability,
50
+ schema: req.schema,
51
+ });
52
+ const metaService = new services_1.MetaService({
53
+ accountability: req.accountability,
54
+ schema: req.schema,
55
+ });
56
+ const records = await service.readByQuery(req.sanitizedQuery);
57
+ const meta = await metaService.getMetaForQuery(req.collection, req.sanitizedQuery);
58
+ res.locals.payload = { data: records || null, meta };
59
+ return next();
60
+ });
61
+ router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
62
+ router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
63
+ router.get('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
64
+ const service = new services_1.OperationsService({
65
+ accountability: req.accountability,
66
+ schema: req.schema,
67
+ });
68
+ const record = await service.readOne(req.params.pk, req.sanitizedQuery);
69
+ res.locals.payload = { data: record || null };
70
+ return next();
71
+ }), respond_1.respond);
72
+ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
73
+ const service = new services_1.OperationsService({
74
+ accountability: req.accountability,
75
+ schema: req.schema,
76
+ });
77
+ let keys = [];
78
+ if (req.body.keys) {
79
+ keys = await service.updateMany(req.body.keys, req.body.data);
80
+ }
81
+ else {
82
+ keys = await service.updateByQuery(req.body.query, req.body.data);
83
+ }
84
+ try {
85
+ const result = await service.readMany(keys, req.sanitizedQuery);
86
+ res.locals.payload = { data: result };
87
+ }
88
+ catch (error) {
89
+ if (error instanceof exceptions_1.ForbiddenException) {
90
+ return next();
91
+ }
92
+ throw error;
93
+ }
94
+ return next();
95
+ }), respond_1.respond);
96
+ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
97
+ const service = new services_1.OperationsService({
98
+ accountability: req.accountability,
99
+ schema: req.schema,
100
+ });
101
+ const primaryKey = await service.updateOne(req.params.pk, req.body);
102
+ try {
103
+ const item = await service.readOne(primaryKey, req.sanitizedQuery);
104
+ res.locals.payload = { data: item || null };
105
+ }
106
+ catch (error) {
107
+ if (error instanceof exceptions_1.ForbiddenException) {
108
+ return next();
109
+ }
110
+ throw error;
111
+ }
112
+ return next();
113
+ }), respond_1.respond);
114
+ router.delete('/', (0, async_handler_1.default)(async (req, res, next) => {
115
+ const service = new services_1.OperationsService({
116
+ accountability: req.accountability,
117
+ schema: req.schema,
118
+ });
119
+ if (Array.isArray(req.body)) {
120
+ await service.deleteMany(req.body);
121
+ }
122
+ else if (req.body.keys) {
123
+ await service.deleteMany(req.body.keys);
124
+ }
125
+ else {
126
+ await service.deleteByQuery(req.body.query);
127
+ }
128
+ return next();
129
+ }), respond_1.respond);
130
+ router.delete('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
131
+ const service = new services_1.OperationsService({
132
+ accountability: req.accountability,
133
+ schema: req.schema,
134
+ });
135
+ await service.deleteOne(req.params.pk);
136
+ return next();
137
+ }), respond_1.respond);
138
+ exports.default = router;
@@ -4,8 +4,12 @@ exports.DateHelperSQLite = void 0;
4
4
  const types_1 = require("../types");
5
5
  class DateHelperSQLite extends types_1.DateHelper {
6
6
  parse(date) {
7
- const newDate = new Date(date);
8
- return (newDate.getTime() - newDate.getTimezoneOffset() * 60 * 1000).toString();
7
+ // Return the time as string
8
+ if (date.length <= 8 && date.includes(':')) {
9
+ return date;
10
+ }
11
+ // Return dates in epoch milliseconds
12
+ return String(new Date(date).getTime());
9
13
  }
10
14
  fieldFlagForField(fieldType) {
11
15
  switch (fieldType) {
@@ -22,18 +22,9 @@ function getDatabase() {
22
22
  if (database) {
23
23
  return database;
24
24
  }
25
- const connectionConfig = (0, get_config_from_env_1.getConfigFromEnv)('DB_', [
26
- 'DB_CLIENT',
27
- 'DB_VERSION',
28
- 'DB_SEARCH_PATH',
29
- 'DB_CONNECTION_STRING',
30
- 'DB_POOL',
31
- 'DB_EXCLUDE_TABLES',
32
- 'DB_VERSION',
33
- ]);
34
- const poolConfig = (0, get_config_from_env_1.getConfigFromEnv)('DB_POOL');
25
+ const { client, version, searchPath, connectionString, pool: poolConfig = {}, ...connectionConfig } = (0, get_config_from_env_1.getConfigFromEnv)('DB_', ['DB_EXCLUDE_TABLES']);
35
26
  const requiredEnvVars = ['DB_CLIENT'];
36
- switch (env_1.default.DB_CLIENT) {
27
+ switch (client) {
37
28
  case 'sqlite3':
38
29
  requiredEnvVars.push('DB_FILENAME');
39
30
  break;
@@ -47,22 +38,27 @@ function getDatabase() {
47
38
  break;
48
39
  case 'cockroachdb':
49
40
  case 'pg':
50
- if (!env_1.default.DB_CONNECTION_STRING) {
41
+ if (!connectionString) {
51
42
  requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER');
52
43
  }
53
44
  else {
54
45
  requiredEnvVars.push('DB_CONNECTION_STRING');
55
46
  }
56
47
  break;
48
+ case 'mssql':
49
+ if (!env_1.default.DB_TYPE || env_1.default.DB_TYPE === 'default') {
50
+ requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
51
+ }
52
+ break;
57
53
  default:
58
54
  requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
59
55
  }
60
56
  (0, validate_env_1.validateEnv)(requiredEnvVars);
61
57
  const knexConfig = {
62
- client: env_1.default.DB_CLIENT,
63
- version: env_1.default.DB_VERSION,
64
- searchPath: env_1.default.DB_SEARCH_PATH,
65
- connection: env_1.default.DB_CONNECTION_STRING || connectionConfig,
58
+ client,
59
+ version,
60
+ searchPath,
61
+ connection: connectionString || connectionConfig,
66
62
  log: {
67
63
  warn: (msg) => {
68
64
  // Ignore warnings about returning not being supported in some DBs
@@ -79,7 +75,7 @@ function getDatabase() {
79
75
  },
80
76
  pool: poolConfig,
81
77
  };
82
- if (env_1.default.DB_CLIENT === 'sqlite3') {
78
+ if (client === 'sqlite3') {
83
79
  knexConfig.useNullAsDefault = true;
84
80
  poolConfig.afterCreate = async (conn, callback) => {
85
81
  logger_1.default.trace('Enabling SQLite Foreign Keys support...');
@@ -88,7 +84,7 @@ function getDatabase() {
88
84
  callback(null, conn);
89
85
  };
90
86
  }
91
- if (env_1.default.DB_CLIENT === 'cockroachdb') {
87
+ if (client === 'cockroachdb') {
92
88
  poolConfig.afterCreate = async (conn, callback) => {
93
89
  logger_1.default.trace('Setting CRDB serial_normalization and default_int_size');
94
90
  const run = (0, util_1.promisify)(conn.query.bind(conn));
@@ -97,7 +93,7 @@ function getDatabase() {
97
93
  callback(null, conn);
98
94
  };
99
95
  }
100
- if (env_1.default.DB_CLIENT === 'mssql') {
96
+ if (client === 'mssql') {
101
97
  // This brings MS SQL in line with the other DB vendors. We shouldn't do any automatic
102
98
  // timezone conversion on the database level, especially not when other database vendors don't
103
99
  // act the same
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
+ const parse_json_1 = require("../../utils/parse-json");
4
5
  async function up(knex) {
5
6
  var _a;
6
7
  await knex.schema.alterTable('directus_relations', (table) => {
@@ -11,7 +12,7 @@ async function up(knex) {
11
12
  .from('directus_fields')
12
13
  .whereIn('interface', ['one-to-many', 'm2a-builder', 'many-to-many']);
13
14
  for (const field of fieldsWithSort) {
14
- const options = typeof field.options === 'string' ? JSON.parse(field.options) : (_a = field.options) !== null && _a !== void 0 ? _a : {};
15
+ const options = typeof field.options === 'string' ? (0, parse_json_1.parseJSON)(field.options) : (_a = field.options) !== null && _a !== void 0 ? _a : {};
15
16
  if ('sortField' in options) {
16
17
  await knex('directus_relations')
17
18
  .update({
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
+ const parse_json_1 = require("../../utils/parse-json");
4
5
  // [before, after, after-option additions]
5
6
  const changes = [
6
7
  ['button-links', 'presentation-links'],
@@ -54,7 +55,7 @@ async function up(knex) {
54
55
  .from('directus_fields')
55
56
  .where({ interface: before });
56
57
  for (const { id, options: existingOptionsRaw } of fields) {
57
- const existingOptions = typeof existingOptionsRaw === 'string' ? JSON.parse(existingOptionsRaw) : existingOptionsRaw;
58
+ const existingOptions = typeof existingOptionsRaw === 'string' ? (0, parse_json_1.parseJSON)(existingOptionsRaw) : existingOptionsRaw;
58
59
  const newOptions = {
59
60
  ...(existingOptions || {}),
60
61
  ...options,
@@ -5,13 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.down = exports.up = void 0;
7
7
  const logger_1 = __importDefault(require("../../logger"));
8
+ const parse_json_1 = require("../../utils/parse-json");
8
9
  async function up(knex) {
9
10
  const dividerGroups = await knex.select('*').from('directus_fields').where('interface', '=', 'group-divider');
10
11
  for (const dividerGroup of dividerGroups) {
11
12
  const newOptions = { showHeader: true };
12
13
  if (dividerGroup.options) {
13
14
  try {
14
- const options = typeof dividerGroup.options === 'string' ? JSON.parse(dividerGroup.options) : dividerGroup.options;
15
+ const options = typeof dividerGroup.options === 'string' ? (0, parse_json_1.parseJSON)(dividerGroup.options) : dividerGroup.options;
15
16
  if (options.icon)
16
17
  newOptions.headerIcon = options.icon;
17
18
  if (options.color)
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
+ const parse_json_1 = require("../../utils/parse-json");
4
5
  async function up(knex) {
5
6
  const groups = await knex.select('*').from('directus_fields').where({ interface: 'group-standard' });
6
7
  const raw = [];
7
8
  const detail = [];
8
9
  for (const group of groups) {
9
- const options = typeof group.options === 'string' ? JSON.parse(group.options) : group.options || {};
10
+ const options = typeof group.options === 'string' ? (0, parse_json_1.parseJSON)(group.options) : group.options || {};
10
11
  if (options.showHeader === true) {
11
12
  detail.push(group);
12
13
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
+ const parse_json_1 = require("../../utils/parse-json");
4
5
  // Change image metadata structure to match the output from 'exifr'
5
6
  async function up(knex) {
6
7
  const files = await knex
@@ -10,7 +11,7 @@ async function up(knex) {
10
11
  for (const { id, metadata } of files) {
11
12
  let prevMetadata;
12
13
  try {
13
- prevMetadata = JSON.parse(metadata);
14
+ prevMetadata = (0, parse_json_1.parseJSON)(metadata);
14
15
  }
15
16
  catch {
16
17
  continue;
@@ -54,7 +55,7 @@ async function down(knex) {
54
55
  .whereNotNull('metadata')
55
56
  .whereNot('metadata', '{}');
56
57
  for (const { id, metadata } of files) {
57
- const prevMetadata = JSON.parse(metadata);
58
+ const prevMetadata = (0, parse_json_1.parseJSON)(metadata);
58
59
  // Update only required if metadata has keys other than 'icc' and 'iptc'
59
60
  if (Object.keys(prevMetadata).filter((key) => key !== 'icc' && key !== 'iptc').length > 0) {
60
61
  // Put all data under 'exif' and rename/move keys afterwards
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.down = exports.up = void 0;
4
4
  const nanoid_1 = require("nanoid");
5
+ const parse_json_1 = require("../../utils/parse-json");
5
6
  async function up(knex) {
6
7
  var _a;
7
8
  await knex.schema.alterTable('directus_presets', (table) => {
@@ -12,7 +13,7 @@ async function up(knex) {
12
13
  .from('directus_presets');
13
14
  for (const preset of presets) {
14
15
  if (preset.filters) {
15
- const oldFilters = (_a = (typeof preset.filters === 'string' ? JSON.parse(preset.filters) : preset.filters)) !== null && _a !== void 0 ? _a : [];
16
+ const oldFilters = (_a = (typeof preset.filters === 'string' ? (0, parse_json_1.parseJSON)(preset.filters) : preset.filters)) !== null && _a !== void 0 ? _a : [];
16
17
  if (oldFilters.length === 0)
17
18
  continue;
18
19
  const newFilter = {
@@ -34,7 +35,7 @@ async function up(knex) {
34
35
  }
35
36
  }
36
37
  if (preset.layout_query) {
37
- const layoutQuery = typeof preset.layout_query === 'string' ? JSON.parse(preset.layout_query) : preset.layout_query;
38
+ const layoutQuery = typeof preset.layout_query === 'string' ? (0, parse_json_1.parseJSON)(preset.layout_query) : preset.layout_query;
38
39
  for (const [layout, query] of Object.entries(layoutQuery)) {
39
40
  if (query.sort) {
40
41
  query.sort = [query.sort];
@@ -61,7 +62,7 @@ async function down(knex) {
61
62
  .from('directus_presets');
62
63
  for (const preset of presets) {
63
64
  if (preset.filter) {
64
- const newFilter = (_a = (typeof preset.filter === 'string' ? JSON.parse(preset.filter) : preset.filter)) !== null && _a !== void 0 ? _a : {};
65
+ const newFilter = (_a = (typeof preset.filter === 'string' ? (0, parse_json_1.parseJSON)(preset.filter) : preset.filter)) !== null && _a !== void 0 ? _a : {};
65
66
  if (Object.keys(newFilter).length === 0)
66
67
  continue;
67
68
  const oldFilters = [];
@@ -85,7 +86,7 @@ async function down(knex) {
85
86
  }
86
87
  }
87
88
  if (preset.layout_query) {
88
- const layoutQuery = typeof preset.layout_query === 'string' ? JSON.parse(preset.layout_query) : preset.layout_query;
89
+ const layoutQuery = typeof preset.layout_query === 'string' ? (0, parse_json_1.parseJSON)(preset.layout_query) : preset.layout_query;
89
90
  for (const [layout, query] of Object.entries(layoutQuery)) {
90
91
  if (query.sort && Array.isArray(query.sort)) {
91
92
  query.sort = (_l = (_k = query.sort) === null || _k === void 0 ? void 0 : _k[0]) !== null && _l !== void 0 ? _l : null;
@@ -0,0 +1,3 @@
1
+ import { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.down = exports.up = void 0;
4
+ const utils_1 = require("@directus/shared/utils");
5
+ const uuid_1 = require("uuid");
6
+ const parse_json_1 = require("../../utils/parse-json");
7
+ async function up(knex) {
8
+ await knex.schema.createTable('directus_flows', (table) => {
9
+ table.uuid('id').primary().notNullable();
10
+ table.string('name').notNullable();
11
+ table.string('icon', 30);
12
+ table.string('color').nullable();
13
+ table.text('description');
14
+ table.string('status').notNullable().defaultTo('active');
15
+ table.string('trigger');
16
+ table.string('accountability').defaultTo('all');
17
+ table.json('options');
18
+ table.uuid('operation').unique();
19
+ table.timestamp('date_created').defaultTo(knex.fn.now());
20
+ table.uuid('user_created').references('id').inTable('directus_users').onDelete('SET NULL');
21
+ });
22
+ await knex.schema.createTable('directus_operations', (table) => {
23
+ table.uuid('id').primary().notNullable();
24
+ table.string('name');
25
+ table.string('key').notNullable();
26
+ table.string('type').notNullable();
27
+ table.integer('position_x').notNullable();
28
+ table.integer('position_y').notNullable();
29
+ table.json('options');
30
+ table.uuid('resolve').unique().references('id').inTable('directus_operations');
31
+ table.uuid('reject').unique().references('id').inTable('directus_operations');
32
+ table.uuid('flow').notNullable().references('id').inTable('directus_flows').onDelete('CASCADE');
33
+ table.timestamp('date_created').defaultTo(knex.fn.now());
34
+ table.uuid('user_created').references('id').inTable('directus_users').onDelete('SET NULL');
35
+ });
36
+ const webhooks = await knex.select('*').from('directus_webhooks');
37
+ const flows = [];
38
+ const operations = [];
39
+ for (const webhook of webhooks) {
40
+ const flowID = (0, uuid_1.v4)();
41
+ flows.push({
42
+ id: flowID,
43
+ name: webhook.name,
44
+ status: 'inactive',
45
+ trigger: 'hook',
46
+ options: JSON.stringify({
47
+ name: webhook.name,
48
+ type: 'action',
49
+ scope: (0, utils_1.toArray)(webhook.actions).map((scope) => `items.${scope}`),
50
+ collections: (0, utils_1.toArray)(webhook.collections),
51
+ }),
52
+ });
53
+ operations.push({
54
+ id: (0, uuid_1.v4)(),
55
+ name: 'Request',
56
+ key: 'request',
57
+ type: 'request',
58
+ position_x: 21,
59
+ position_y: 1,
60
+ options: JSON.stringify({
61
+ url: webhook.url,
62
+ headers: typeof webhook.headers === 'string' ? (0, parse_json_1.parseJSON)(webhook.headers) : webhook.headers,
63
+ data: webhook.data ? '{{$trigger}}' : null,
64
+ method: webhook.method,
65
+ }),
66
+ date_created: new Date(),
67
+ flow: flowID,
68
+ });
69
+ }
70
+ if (flows.length && operations.length) {
71
+ await knex.insert(flows).into('directus_flows');
72
+ await knex.insert(operations).into('directus_operations');
73
+ for (const operation of operations) {
74
+ await knex('directus_flows').update({ operation: operation.id }).where({ id: operation.flow });
75
+ }
76
+ }
77
+ }
78
+ exports.up = up;
79
+ async function down(knex) {
80
+ await knex.schema.dropTable('directus_operations');
81
+ await knex.schema.dropTable('directus_flows');
82
+ }
83
+ exports.down = down;
@@ -0,0 +1,3 @@
1
+ import { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.down = exports.up = void 0;
4
+ async function up(knex) {
5
+ await knex.schema.alterTable('directus_dashboards', (table) => {
6
+ table.string('color').nullable();
7
+ });
8
+ }
9
+ exports.up = up;
10
+ async function down(knex) {
11
+ await knex.schema.alterTable('directus_dashboards', (table) => {
12
+ table.dropColumn('color');
13
+ });
14
+ }
15
+ exports.down = down;