directus 9.8.0 → 9.9.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/__mocks__/cache.d.ts +5 -0
- package/dist/__mocks__/cache.js +7 -0
- package/dist/auth/drivers/ldap.js +10 -11
- package/dist/auth/drivers/oauth2.js +9 -4
- package/dist/auth/drivers/openid.js +7 -4
- package/dist/cli/commands/schema/apply.js +9 -3
- package/dist/controllers/assets.js +5 -0
- package/dist/controllers/files.d.ts +2 -0
- package/dist/controllers/files.js +10 -5
- package/dist/database/helpers/date/dialects/mssql.d.ts +4 -0
- package/dist/database/helpers/date/dialects/mssql.js +12 -0
- package/dist/database/helpers/date/dialects/mysql.d.ts +5 -0
- package/dist/database/helpers/date/dialects/mysql.js +16 -0
- package/dist/database/helpers/date/dialects/oracle.d.ts +4 -0
- package/dist/database/helpers/date/dialects/oracle.js +15 -0
- package/dist/database/helpers/date/dialects/sqlite.d.ts +1 -0
- package/dist/database/helpers/date/dialects/sqlite.js +8 -0
- package/dist/database/helpers/date/index.d.ts +3 -3
- package/dist/database/helpers/date/index.js +6 -6
- package/dist/database/helpers/date/types.d.ts +3 -0
- package/dist/database/helpers/date/types.js +10 -0
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/migrations/20220402A-remove-default-value-panel-icon.d.ts +3 -0
- package/dist/database/migrations/20220402A-remove-default-value-panel-icon.js +22 -0
- package/dist/database/system-data/fields/settings.yaml +0 -1
- package/dist/database/system-data/fields/users.yaml +3 -0
- package/dist/env.js +3 -1
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/exceptions/index.js +1 -0
- package/dist/exceptions/token-expired.d.ts +4 -0
- package/dist/exceptions/token-expired.js +10 -0
- package/dist/middleware/cache.js +10 -0
- package/dist/services/authorization.js +72 -30
- package/dist/services/collections.d.ts +2 -0
- package/dist/services/collections.js +8 -0
- package/dist/services/fields.js +24 -1
- package/dist/services/files.d.ts +5 -1
- package/dist/services/files.js +59 -40
- package/dist/services/graphql.d.ts +2 -3
- package/dist/services/graphql.js +39 -9
- package/dist/services/payload.d.ts +1 -0
- package/dist/services/payload.js +19 -16
- package/dist/types/files.d.ts +8 -0
- package/dist/utils/apply-query.js +17 -7
- package/dist/utils/apply-snapshot.d.ts +3 -1
- package/dist/utils/apply-snapshot.js +34 -5
- package/dist/utils/get-graphql-type.js +1 -0
- package/dist/utils/get-local-type.js +5 -0
- package/dist/utils/jwt.js +1 -1
- package/dist/utils/validate-query.js +19 -15
- package/example.env +4 -0
- package/package.json +14 -13
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setSystemCache = exports.clearSystemCache = exports.flushCaches = exports.getCache = void 0;
|
|
4
|
+
exports.getCache = jest.fn().mockReturnValue({ cache: undefined, systemCache: undefined, lockCache: undefined });
|
|
5
|
+
exports.flushCaches = jest.fn();
|
|
6
|
+
exports.clearSystemCache = jest.fn();
|
|
7
|
+
exports.setSystemCache = jest.fn();
|
|
@@ -71,12 +71,8 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
|
|
|
71
71
|
res.on('searchEntry', () => {
|
|
72
72
|
resolve();
|
|
73
73
|
});
|
|
74
|
-
res.on('error', (
|
|
75
|
-
|
|
76
|
-
reject(handleError(err));
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// Rebind on OperationsError
|
|
74
|
+
res.on('error', () => {
|
|
75
|
+
// Attempt to rebind on search error
|
|
80
76
|
this.bindClient.bind(bindDn, bindPassword, (err) => {
|
|
81
77
|
if (err) {
|
|
82
78
|
const error = handleError(err);
|
|
@@ -93,8 +89,8 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
|
|
|
93
89
|
});
|
|
94
90
|
});
|
|
95
91
|
res.on('end', (result) => {
|
|
92
|
+
// Handle edge case where authenticated bind user cannot read their own DN
|
|
96
93
|
if ((result === null || result === void 0 ? void 0 : result.status) === 0) {
|
|
97
|
-
// Handle edge case where authenticated bind user could not fetch their own DN
|
|
98
94
|
reject(new exceptions_1.UnexpectedResponseException('Failed to find bind user record'));
|
|
99
95
|
}
|
|
100
96
|
});
|
|
@@ -177,12 +173,12 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
|
|
|
177
173
|
return user === null || user === void 0 ? void 0 : user.id;
|
|
178
174
|
}
|
|
179
175
|
async getUserID(payload) {
|
|
180
|
-
var _a;
|
|
176
|
+
var _a, _b, _c;
|
|
181
177
|
if (!payload.identifier) {
|
|
182
178
|
throw new exceptions_1.InvalidCredentialsException();
|
|
183
179
|
}
|
|
184
180
|
await this.validateBindClient();
|
|
185
|
-
const { userDn, userScope, userAttribute, groupDn, groupScope, groupAttribute } = this.config;
|
|
181
|
+
const { userDn, userScope, userAttribute, groupDn, groupScope, groupAttribute, defaultRoleId } = this.config;
|
|
186
182
|
const userInfo = await this.fetchUserInfo(userDn, new ldapjs_1.EqualityFilter({
|
|
187
183
|
attribute: userAttribute !== null && userAttribute !== void 0 ? userAttribute : 'cn',
|
|
188
184
|
value: payload.identifier,
|
|
@@ -209,7 +205,10 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
|
|
|
209
205
|
}
|
|
210
206
|
const userId = await this.fetchUserId(userInfo.dn);
|
|
211
207
|
if (userId) {
|
|
212
|
-
|
|
208
|
+
// Only sync roles if the AD groups are configured
|
|
209
|
+
if (groupDn) {
|
|
210
|
+
await this.usersService.updateOne(userId, { role: (_b = (_a = userRole === null || userRole === void 0 ? void 0 : userRole.id) !== null && _a !== void 0 ? _a : defaultRoleId) !== null && _b !== void 0 ? _b : null });
|
|
211
|
+
}
|
|
213
212
|
return userId;
|
|
214
213
|
}
|
|
215
214
|
if (!userInfo) {
|
|
@@ -221,7 +220,7 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
|
|
|
221
220
|
last_name: userInfo.lastName,
|
|
222
221
|
email: userInfo.email,
|
|
223
222
|
external_identifier: userInfo.dn,
|
|
224
|
-
role: userRole === null || userRole === void 0 ? void 0 : userRole.id,
|
|
223
|
+
role: (_c = userRole === null || userRole === void 0 ? void 0 : userRole.id) !== null && _c !== void 0 ? _c : defaultRoleId,
|
|
225
224
|
});
|
|
226
225
|
return (await this.fetchUserId(userInfo.dn));
|
|
227
226
|
}
|
|
@@ -8,6 +8,7 @@ const express_1 = require("express");
|
|
|
8
8
|
const openid_client_1 = require("openid-client");
|
|
9
9
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
10
10
|
const ms_1 = __importDefault(require("ms"));
|
|
11
|
+
const flat_1 = __importDefault(require("flat"));
|
|
11
12
|
const local_1 = require("./local");
|
|
12
13
|
const auth_1 = require("../../auth");
|
|
13
14
|
const env_1 = __importDefault(require("../../env"));
|
|
@@ -91,12 +92,14 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
91
92
|
catch (e) {
|
|
92
93
|
throw handleError(e);
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
// Flatten response to support dot indexes
|
|
96
|
+
userInfo = (0, flat_1.default)(userInfo);
|
|
97
|
+
const { provider, emailKey, identifierKey, allowPublicRegistration } = this.config;
|
|
95
98
|
const email = userInfo[emailKey !== null && emailKey !== void 0 ? emailKey : 'email'];
|
|
96
99
|
// Fallback to email if explicit identifier not found
|
|
97
100
|
const identifier = (_a = userInfo[identifierKey]) !== null && _a !== void 0 ? _a : email;
|
|
98
101
|
if (!identifier) {
|
|
99
|
-
logger_1.default.warn(`[OAuth2] Failed to find user identifier for provider "${
|
|
102
|
+
logger_1.default.warn(`[OAuth2] Failed to find user identifier for provider "${provider}"`);
|
|
100
103
|
throw new exceptions_1.InvalidCredentialsException();
|
|
101
104
|
}
|
|
102
105
|
const userId = await this.fetchUserId(identifier);
|
|
@@ -111,11 +114,13 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
111
114
|
}
|
|
112
115
|
// Is public registration allowed?
|
|
113
116
|
if (!allowPublicRegistration) {
|
|
114
|
-
logger_1.default.trace(`[OAuth2] User doesn't exist, and public registration not allowed for provider "${
|
|
117
|
+
logger_1.default.trace(`[OAuth2] User doesn't exist, and public registration not allowed for provider "${provider}"`);
|
|
115
118
|
throw new exceptions_1.InvalidCredentialsException();
|
|
116
119
|
}
|
|
117
120
|
await this.usersService.createOne({
|
|
118
|
-
provider
|
|
121
|
+
provider,
|
|
122
|
+
first_name: userInfo[this.config.firstNameKey],
|
|
123
|
+
last_name: userInfo[this.config.lastNameKey],
|
|
119
124
|
email: email,
|
|
120
125
|
external_identifier: identifier,
|
|
121
126
|
role: this.config.defaultRoleId,
|
|
@@ -8,6 +8,7 @@ const express_1 = require("express");
|
|
|
8
8
|
const openid_client_1 = require("openid-client");
|
|
9
9
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
10
10
|
const ms_1 = __importDefault(require("ms"));
|
|
11
|
+
const flat_1 = __importDefault(require("flat"));
|
|
11
12
|
const local_1 = require("./local");
|
|
12
13
|
const auth_1 = require("../../auth");
|
|
13
14
|
const env_1 = __importDefault(require("../../env"));
|
|
@@ -105,12 +106,14 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
105
106
|
catch (e) {
|
|
106
107
|
throw handleError(e);
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
// Flatten response to support dot indexes
|
|
110
|
+
userInfo = (0, flat_1.default)(userInfo);
|
|
111
|
+
const { provider, identifierKey, allowPublicRegistration, requireVerifiedEmail } = this.config;
|
|
109
112
|
const email = userInfo.email;
|
|
110
113
|
// Fallback to email if explicit identifier not found
|
|
111
114
|
const identifier = (_a = userInfo[identifierKey !== null && identifierKey !== void 0 ? identifierKey : 'sub']) !== null && _a !== void 0 ? _a : email;
|
|
112
115
|
if (!identifier) {
|
|
113
|
-
logger_1.default.warn(`[OpenID] Failed to find user identifier for provider "${
|
|
116
|
+
logger_1.default.warn(`[OpenID] Failed to find user identifier for provider "${provider}"`);
|
|
114
117
|
throw new exceptions_1.InvalidCredentialsException();
|
|
115
118
|
}
|
|
116
119
|
const userId = await this.fetchUserId(identifier);
|
|
@@ -126,11 +129,11 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
126
129
|
const isEmailVerified = !requireVerifiedEmail || userInfo.email_verified;
|
|
127
130
|
// Is public registration allowed?
|
|
128
131
|
if (!allowPublicRegistration || !isEmailVerified) {
|
|
129
|
-
logger_1.default.trace(`[OpenID] User doesn't exist, and public registration not allowed for provider "${
|
|
132
|
+
logger_1.default.trace(`[OpenID] User doesn't exist, and public registration not allowed for provider "${provider}"`);
|
|
130
133
|
throw new exceptions_1.InvalidCredentialsException();
|
|
131
134
|
}
|
|
132
135
|
await this.usersService.createOne({
|
|
133
|
-
provider
|
|
136
|
+
provider,
|
|
134
137
|
first_name: userInfo.given_name,
|
|
135
138
|
last_name: userInfo.family_name,
|
|
136
139
|
email: email,
|
|
@@ -93,13 +93,19 @@ async function apply(snapshotPath, options) {
|
|
|
93
93
|
if (snapshotDiff.fields.length > 0) {
|
|
94
94
|
message += '\n\n' + chalk_1.default.black.underline.bold('Fields:');
|
|
95
95
|
for (const { collection, field, diff } of snapshotDiff.fields) {
|
|
96
|
-
if (((_e = diff[0]) === null || _e === void 0 ? void 0 : _e.kind) === 'E') {
|
|
96
|
+
if (((_e = diff[0]) === null || _e === void 0 ? void 0 : _e.kind) === 'E' || (0, apply_snapshot_1.isNestedMetaUpdate)(diff[0])) {
|
|
97
97
|
message += `\n - ${chalk_1.default.blue('Update')} ${collection}.${field}`;
|
|
98
98
|
for (const change of diff) {
|
|
99
|
+
const path = change.path.slice(1).join('.');
|
|
99
100
|
if (change.kind === 'E') {
|
|
100
|
-
const path = change.path.slice(1).join('.');
|
|
101
101
|
message += `\n - Set ${path} to ${change.rhs}`;
|
|
102
102
|
}
|
|
103
|
+
else if (change.kind === 'D') {
|
|
104
|
+
message += `\n - Remove ${path}`;
|
|
105
|
+
}
|
|
106
|
+
else if (change.kind === 'N') {
|
|
107
|
+
message += `\n - Add ${path} and set it to ${change.rhs}`;
|
|
108
|
+
}
|
|
103
109
|
}
|
|
104
110
|
}
|
|
105
111
|
else if (((_f = diff[0]) === null || _f === void 0 ? void 0 : _f.kind) === 'D') {
|
|
@@ -143,7 +149,7 @@ async function apply(snapshotPath, options) {
|
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
|
-
message
|
|
152
|
+
message = 'The following changes will be applied:\n\n' + chalk_1.default.black(message);
|
|
147
153
|
if (dryRun) {
|
|
148
154
|
logger_1.default.info(message);
|
|
149
155
|
process.exit(0);
|
|
@@ -126,6 +126,11 @@ router.get('/:pk',
|
|
|
126
126
|
res.setHeader('Content-Type', file.type);
|
|
127
127
|
res.setHeader('Accept-Ranges', 'bytes');
|
|
128
128
|
res.setHeader('Cache-Control', `${access}, max-age=${(0, ms_1.default)(env_1.default.ASSETS_CACHE_TTL) / 1000}`);
|
|
129
|
+
const unixTime = Date.parse(file.modified_on);
|
|
130
|
+
if (!Number.isNaN(unixTime)) {
|
|
131
|
+
const lastModifiedDate = new Date(unixTime);
|
|
132
|
+
res.setHeader('Last-Modified', lastModifiedDate.toUTCString());
|
|
133
|
+
}
|
|
129
134
|
if (range) {
|
|
130
135
|
res.setHeader('Content-Range', `bytes ${range.start}-${range.end || stat.size - 1}/${stat.size}`);
|
|
131
136
|
res.status(206);
|
|
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.multipartHandler = void 0;
|
|
6
7
|
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
8
|
+
const utils_1 = require("@directus/shared/utils");
|
|
7
9
|
const busboy_1 = __importDefault(require("busboy"));
|
|
8
10
|
const express_1 = __importDefault(require("express"));
|
|
9
11
|
const joi_1 = __importDefault(require("joi"));
|
|
@@ -15,10 +17,9 @@ const use_collection_1 = __importDefault(require("../middleware/use-collection")
|
|
|
15
17
|
const validate_batch_1 = require("../middleware/validate-batch");
|
|
16
18
|
const services_1 = require("../services");
|
|
17
19
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
18
|
-
const utils_1 = require("@directus/shared/utils");
|
|
19
20
|
const router = express_1.default.Router();
|
|
20
21
|
router.use((0, use_collection_1.default)('directus_files'));
|
|
21
|
-
const multipartHandler = (
|
|
22
|
+
const multipartHandler = (req, res, next) => {
|
|
22
23
|
if (req.is('multipart/form-data') === false)
|
|
23
24
|
return next();
|
|
24
25
|
let headers;
|
|
@@ -87,12 +88,16 @@ const multipartHandler = (0, async_handler_1.default)(async (req, res, next) =>
|
|
|
87
88
|
req.pipe(busboy);
|
|
88
89
|
function tryDone() {
|
|
89
90
|
if (savedFiles.length === fileCount) {
|
|
91
|
+
if (fileCount === 0) {
|
|
92
|
+
return next(new exceptions_1.InvalidPayloadException(`No files where included in the body`));
|
|
93
|
+
}
|
|
90
94
|
res.locals.savedFiles = savedFiles;
|
|
91
95
|
return next();
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
|
-
}
|
|
95
|
-
|
|
98
|
+
};
|
|
99
|
+
exports.multipartHandler = multipartHandler;
|
|
100
|
+
router.post('/', (0, async_handler_1.default)(exports.multipartHandler), (0, async_handler_1.default)(async (req, res, next) => {
|
|
96
101
|
if (req.is('multipart/form-data') === false) {
|
|
97
102
|
throw new exceptions_1.UnsupportedMediaTypeException(`Unsupported Content-Type header`);
|
|
98
103
|
}
|
|
@@ -214,7 +219,7 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
|
|
|
214
219
|
}
|
|
215
220
|
return next();
|
|
216
221
|
}), respond_1.respond);
|
|
217
|
-
router.patch('/:pk', multipartHandler, (0, async_handler_1.default)(async (req, res, next) => {
|
|
222
|
+
router.patch('/:pk', (0, async_handler_1.default)(exports.multipartHandler), (0, async_handler_1.default)(async (req, res, next) => {
|
|
218
223
|
const service = new services_1.FilesService({
|
|
219
224
|
accountability: req.accountability,
|
|
220
225
|
schema: req.schema,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DateHelperMSSQL = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
6
|
+
class DateHelperMSSQL extends types_1.DateHelper {
|
|
7
|
+
writeTimestamp(date) {
|
|
8
|
+
const parsedDate = (0, date_fns_1.parseISO)(date);
|
|
9
|
+
return new Date(parsedDate.getTime() + parsedDate.getTimezoneOffset() * 60000);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.DateHelperMSSQL = DateHelperMSSQL;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DateHelperMySQL = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
6
|
+
class DateHelperMySQL extends types_1.DateHelper {
|
|
7
|
+
readTimestampString(date) {
|
|
8
|
+
const parsedDate = new Date(date);
|
|
9
|
+
return new Date(parsedDate.getTime() - parsedDate.getTimezoneOffset() * 60000).toISOString();
|
|
10
|
+
}
|
|
11
|
+
writeTimestamp(date) {
|
|
12
|
+
const parsedDate = (0, date_fns_1.parseISO)(date);
|
|
13
|
+
return new Date(parsedDate.getTime() + parsedDate.getTimezoneOffset() * 60000);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.DateHelperMySQL = DateHelperMySQL;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DateHelperOracle = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class DateHelperOracle extends types_1.DateHelper {
|
|
6
|
+
fieldFlagForField(fieldType) {
|
|
7
|
+
switch (fieldType) {
|
|
8
|
+
case 'dateTime':
|
|
9
|
+
return 'cast-datetime';
|
|
10
|
+
default:
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.DateHelperOracle = DateHelperOracle;
|
|
@@ -7,5 +7,13 @@ class DateHelperSQLite extends types_1.DateHelper {
|
|
|
7
7
|
const newDate = new Date(date);
|
|
8
8
|
return (newDate.getTime() - newDate.getTimezoneOffset() * 60 * 1000).toString();
|
|
9
9
|
}
|
|
10
|
+
fieldFlagForField(fieldType) {
|
|
11
|
+
switch (fieldType) {
|
|
12
|
+
case 'timestamp':
|
|
13
|
+
return 'cast-timestamp';
|
|
14
|
+
default:
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
10
18
|
}
|
|
11
19
|
exports.DateHelperSQLite = DateHelperSQLite;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { DateHelperDefault as postgres } from './dialects/default';
|
|
2
2
|
export { DateHelperDefault as redshift } from './dialects/default';
|
|
3
3
|
export { DateHelperDefault as cockroachdb } from './dialects/default';
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
4
|
+
export { DateHelperOracle as oracle } from './dialects/oracle';
|
|
5
|
+
export { DateHelperMySQL as mysql } from './dialects/mysql';
|
|
6
|
+
export { DateHelperMSSQL as mssql } from './dialects/mssql';
|
|
7
7
|
export { DateHelperSQLite as sqlite } from './dialects/sqlite';
|
|
@@ -7,11 +7,11 @@ var default_2 = require("./dialects/default");
|
|
|
7
7
|
Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return default_2.DateHelperDefault; } });
|
|
8
8
|
var default_3 = require("./dialects/default");
|
|
9
9
|
Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return default_3.DateHelperDefault; } });
|
|
10
|
-
var
|
|
11
|
-
Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return
|
|
12
|
-
var
|
|
13
|
-
Object.defineProperty(exports, "mysql", { enumerable: true, get: function () { return
|
|
14
|
-
var
|
|
15
|
-
Object.defineProperty(exports, "mssql", { enumerable: true, get: function () { return
|
|
10
|
+
var oracle_1 = require("./dialects/oracle");
|
|
11
|
+
Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return oracle_1.DateHelperOracle; } });
|
|
12
|
+
var mysql_1 = require("./dialects/mysql");
|
|
13
|
+
Object.defineProperty(exports, "mysql", { enumerable: true, get: function () { return mysql_1.DateHelperMySQL; } });
|
|
14
|
+
var mssql_1 = require("./dialects/mssql");
|
|
15
|
+
Object.defineProperty(exports, "mssql", { enumerable: true, get: function () { return mssql_1.DateHelperMSSQL; } });
|
|
16
16
|
var sqlite_1 = require("./dialects/sqlite");
|
|
17
17
|
Object.defineProperty(exports, "sqlite", { enumerable: true, get: function () { return sqlite_1.DateHelperSQLite; } });
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { DatabaseHelper } from '../types';
|
|
2
2
|
export declare abstract class DateHelper extends DatabaseHelper {
|
|
3
3
|
parse(date: string): string;
|
|
4
|
+
readTimestampString(date: string): string;
|
|
5
|
+
writeTimestamp(date: string): Date;
|
|
6
|
+
fieldFlagForField(_fieldType: string): string;
|
|
4
7
|
}
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DateHelper = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
5
6
|
class DateHelper extends types_1.DatabaseHelper {
|
|
6
7
|
parse(date) {
|
|
7
8
|
return date;
|
|
8
9
|
}
|
|
10
|
+
readTimestampString(date) {
|
|
11
|
+
return date;
|
|
12
|
+
}
|
|
13
|
+
writeTimestamp(date) {
|
|
14
|
+
return (0, date_fns_1.parseISO)(date);
|
|
15
|
+
}
|
|
16
|
+
fieldFlagForField(_fieldType) {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
9
19
|
}
|
|
10
20
|
exports.DateHelper = DateHelper;
|
|
@@ -5,7 +5,7 @@ import * as fnHelpers from './fn';
|
|
|
5
5
|
import * as geometryHelpers from './geometry';
|
|
6
6
|
import * as schemaHelpers from './schema';
|
|
7
7
|
export declare function getHelpers(database: Knex): {
|
|
8
|
-
date: dateHelpers.postgres | dateHelpers.sqlite;
|
|
8
|
+
date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.mysql | dateHelpers.mssql | dateHelpers.sqlite;
|
|
9
9
|
st: geometryHelpers.postgres | geometryHelpers.redshift | geometryHelpers.oracle | geometryHelpers.sqlite | geometryHelpers.mysql | geometryHelpers.mssql;
|
|
10
10
|
schema: schemaHelpers.postgres | schemaHelpers.cockroachdb | schemaHelpers.oracle;
|
|
11
11
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.down = exports.up = void 0;
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
const helper = (0, helpers_1.getHelpers)(knex).schema;
|
|
7
|
+
await helper.changeToString('directus_panels', 'icon', {
|
|
8
|
+
nullable: true,
|
|
9
|
+
default: null,
|
|
10
|
+
length: 30,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
exports.up = up;
|
|
14
|
+
async function down(knex) {
|
|
15
|
+
const helper = (0, helpers_1.getHelpers)(knex).schema;
|
|
16
|
+
await helper.changeToString('directus_panels', 'icon', {
|
|
17
|
+
nullable: true,
|
|
18
|
+
default: 'insert_chart',
|
|
19
|
+
length: 30,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
exports.down = down;
|
|
@@ -72,6 +72,8 @@ fields:
|
|
|
72
72
|
- field: language
|
|
73
73
|
interface: system-language
|
|
74
74
|
width: half
|
|
75
|
+
options:
|
|
76
|
+
includeProjectDefault: true
|
|
75
77
|
|
|
76
78
|
- field: theme
|
|
77
79
|
interface: select-dropdown
|
|
@@ -152,6 +154,7 @@ fields:
|
|
|
152
154
|
- field: last_access
|
|
153
155
|
width: half
|
|
154
156
|
display: datetime
|
|
157
|
+
readonly: true
|
|
155
158
|
display_options:
|
|
156
159
|
relative: true
|
|
157
160
|
|
package/dist/env.js
CHANGED
|
@@ -14,7 +14,7 @@ const lodash_1 = require("lodash");
|
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const require_yaml_1 = require("./utils/require-yaml");
|
|
16
16
|
const utils_1 = require("@directus/shared/utils");
|
|
17
|
-
const acceptedEnvTypes = ['string', 'number', 'regex', 'array'];
|
|
17
|
+
const acceptedEnvTypes = ['string', 'number', 'regex', 'array', 'json'];
|
|
18
18
|
const defaults = {
|
|
19
19
|
CONFIG_PATH: path_1.default.resolve(process.cwd(), '.env'),
|
|
20
20
|
HOST: '0.0.0.0',
|
|
@@ -69,6 +69,7 @@ const defaults = {
|
|
|
69
69
|
SERVE_APP: true,
|
|
70
70
|
RELATIONAL_BATCH_SIZE: 25000,
|
|
71
71
|
EXPORT_BATCH_SIZE: 5000,
|
|
72
|
+
FILE_METADATA_ALLOW_LIST: 'ifd0.Make,ifd0.Model,exif.FNumber,exif.ExposureTime,exif.FocalLength,exif.ISO',
|
|
72
73
|
};
|
|
73
74
|
// Allows us to force certain environment variable into a type, instead of relying
|
|
74
75
|
// on the auto-parsed type in processValues. ref #3705
|
|
@@ -82,6 +83,7 @@ const typeMap = {
|
|
|
82
83
|
DB_PORT: 'number',
|
|
83
84
|
DB_EXCLUDE_TABLES: 'array',
|
|
84
85
|
IMPORT_IP_DENY_LIST: 'array',
|
|
86
|
+
FILE_METADATA_ALLOW_LIST: 'array',
|
|
85
87
|
};
|
|
86
88
|
let env = {
|
|
87
89
|
...defaults,
|
|
@@ -13,6 +13,7 @@ export * from './method-not-allowed';
|
|
|
13
13
|
export * from './range-not-satisfiable';
|
|
14
14
|
export * from './route-not-found';
|
|
15
15
|
export * from './service-unavailable';
|
|
16
|
+
export * from './token-expired';
|
|
16
17
|
export * from './unprocessable-entity';
|
|
17
18
|
export * from './unsupported-media-type';
|
|
18
19
|
export * from './user-suspended';
|
package/dist/exceptions/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __exportStar(require("./method-not-allowed"), exports);
|
|
|
25
25
|
__exportStar(require("./range-not-satisfiable"), exports);
|
|
26
26
|
__exportStar(require("./route-not-found"), exports);
|
|
27
27
|
__exportStar(require("./service-unavailable"), exports);
|
|
28
|
+
__exportStar(require("./token-expired"), exports);
|
|
28
29
|
__exportStar(require("./unprocessable-entity"), exports);
|
|
29
30
|
__exportStar(require("./unsupported-media-type"), exports);
|
|
30
31
|
__exportStar(require("./user-suspended"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenExpiredException = void 0;
|
|
4
|
+
const exceptions_1 = require("@directus/shared/exceptions");
|
|
5
|
+
class TokenExpiredException extends exceptions_1.BaseException {
|
|
6
|
+
constructor(message = 'Token expired.') {
|
|
7
|
+
super(message, 401, 'TOKEN_EXPIRED');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.TokenExpiredException = TokenExpiredException;
|
package/dist/middleware/cache.js
CHANGED
|
@@ -19,6 +19,8 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
19
19
|
if (!cache)
|
|
20
20
|
return next();
|
|
21
21
|
if (((_a = req.headers['cache-control']) === null || _a === void 0 ? void 0 : _a.includes('no-store')) || ((_b = req.headers['Cache-Control']) === null || _b === void 0 ? void 0 : _b.includes('no-store'))) {
|
|
22
|
+
if (env_1.default.CACHE_STATUS_HEADER)
|
|
23
|
+
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'MISS');
|
|
22
24
|
return next();
|
|
23
25
|
}
|
|
24
26
|
const key = (0, get_cache_key_1.getCacheKey)(req);
|
|
@@ -28,6 +30,8 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
28
30
|
}
|
|
29
31
|
catch (err) {
|
|
30
32
|
logger_1.default.warn(err, `[cache] Couldn't read key ${key}. ${err.message}`);
|
|
33
|
+
if (env_1.default.CACHE_STATUS_HEADER)
|
|
34
|
+
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'MISS');
|
|
31
35
|
return next();
|
|
32
36
|
}
|
|
33
37
|
if (cachedData) {
|
|
@@ -37,14 +41,20 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
37
41
|
}
|
|
38
42
|
catch (err) {
|
|
39
43
|
logger_1.default.warn(err, `[cache] Couldn't read key ${`${key}__expires_at`}. ${err.message}`);
|
|
44
|
+
if (env_1.default.CACHE_STATUS_HEADER)
|
|
45
|
+
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'MISS');
|
|
40
46
|
return next();
|
|
41
47
|
}
|
|
42
48
|
const cacheTTL = cacheExpiryDate ? cacheExpiryDate - Date.now() : null;
|
|
43
49
|
res.setHeader('Cache-Control', (0, get_cache_headers_1.getCacheControlHeader)(req, cacheTTL));
|
|
44
50
|
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
51
|
+
if (env_1.default.CACHE_STATUS_HEADER)
|
|
52
|
+
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'HIT');
|
|
45
53
|
return res.json(cachedData);
|
|
46
54
|
}
|
|
47
55
|
else {
|
|
56
|
+
if (env_1.default.CACHE_STATUS_HEADER)
|
|
57
|
+
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'MISS');
|
|
48
58
|
return next();
|
|
49
59
|
}
|
|
50
60
|
});
|