mirror of
https://github.com/directus/directus.git
synced 2026-01-29 14:48:02 -05:00
32
package.json
32
package.json
@@ -31,12 +31,12 @@
|
||||
"@types/atob": "^2.1.2",
|
||||
"@types/busboy": "^0.2.3",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express": "^4.17.7",
|
||||
"@types/express-pino-logger": "^4.0.2",
|
||||
"@types/express-session": "^1.17.0",
|
||||
"@types/hapi__joi": "^17.1.2",
|
||||
"@types/hapi__joi": "^17.1.3",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/lodash": "^4.14.156",
|
||||
"@types/lodash": "^4.14.157",
|
||||
"@types/ms": "^0.7.31",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
"@types/pino": "^6.3.0",
|
||||
@@ -44,16 +44,16 @@
|
||||
"@types/uuid": "^8.0.0",
|
||||
"@types/uuid-validate": "0.0.1",
|
||||
"copyfiles": "^2.3.0",
|
||||
"eslint": "^7.3.1",
|
||||
"eslint": "^7.4.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.10",
|
||||
"pino-colada": "^1.6.1",
|
||||
"lint-staged": "^10.2.11",
|
||||
"pino-colada": "^2.0.1",
|
||||
"prettier": "^2.0.5",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^8.10.2",
|
||||
"tslint": "^6.1.2",
|
||||
"typescript": "^3.9.5"
|
||||
"typescript": "^3.9.6"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -67,9 +67,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hapi/joi": "^17.1.1",
|
||||
"@slynova/flydrive": "^1.0.1",
|
||||
"@slynova/flydrive-gcs": "^1.0.1",
|
||||
"@slynova/flydrive-s3": "^1.0.1",
|
||||
"@slynova/flydrive": "^1.0.2",
|
||||
"@slynova/flydrive-gcs": "^1.0.2",
|
||||
"@slynova/flydrive-s3": "^1.0.2",
|
||||
"argon2": "^0.26.2",
|
||||
"atob": "^2.1.2",
|
||||
"body-parser": "^1.19.0",
|
||||
@@ -87,19 +87,19 @@
|
||||
"icc": "^2.0.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"knex": "^0.21.1",
|
||||
"liquidjs": "^9.12.0",
|
||||
"lodash": "^4.17.15",
|
||||
"liquidjs": "^9.14.1",
|
||||
"lodash": "^4.17.19",
|
||||
"ms": "^2.1.2",
|
||||
"mssql": "^6.2.0",
|
||||
"mysql": "^2.18.1",
|
||||
"nanoid": "^3.1.10",
|
||||
"nodemailer": "^6.4.10",
|
||||
"oracledb": "^4.2.0",
|
||||
"pg": "^8.2.1",
|
||||
"oracledb": "^5.0.0",
|
||||
"pg": "^8.3.0",
|
||||
"pino": "^6.3.2",
|
||||
"sharp": "^0.25.4",
|
||||
"sqlite3": "^4.2.0",
|
||||
"ts-node-dev": "^1.0.0-pre.49",
|
||||
"sqlite3": "^5.0.0",
|
||||
"ts-node-dev": "^1.0.0-pre.51",
|
||||
"uuid": "^8.2.0",
|
||||
"uuid-validate": "0.0.3"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,12 @@ router.post(
|
||||
const { error } = collectionSchema.validate(req.body);
|
||||
if (error) throw new InvalidPayloadException(error.message);
|
||||
|
||||
const createdCollection = await CollectionsService.create(req.body);
|
||||
const createdCollection = await CollectionsService.create(req.body, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
res.json({ data: createdCollection });
|
||||
})
|
||||
);
|
||||
@@ -65,7 +70,12 @@ router.delete(
|
||||
throw new CollectionNotFoundException(req.params.collection);
|
||||
}
|
||||
|
||||
await CollectionsService.deleteCollection(req.params.collection);
|
||||
await CollectionsService.deleteCollection(req.params.collection, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
res.end();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -61,7 +61,11 @@ router.post(
|
||||
|
||||
const field: Partial<Field> = req.body;
|
||||
|
||||
const createdField = await FieldsService.createField(req.collection, field);
|
||||
const createdField = await FieldsService.createField(req.collection, field, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
res.json({ data: createdField });
|
||||
})
|
||||
|
||||
@@ -55,29 +55,26 @@ const multipartHandler = (operation: 'create' | 'update') =>
|
||||
|
||||
try {
|
||||
if (operation === 'create') {
|
||||
const file = await FilesService.createFile(payload, fileStream);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPLOAD,
|
||||
collection: 'directus_files',
|
||||
item: file.id,
|
||||
const pk = await FilesService.createFile(payload, fileStream, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
const file = await FilesService.readFile(pk, req.sanitizedQuery);
|
||||
|
||||
savedFiles.push(file);
|
||||
} else {
|
||||
const file = await FilesService.updateFile(req.params.pk, payload, fileStream);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: 'directus_files',
|
||||
item: file.id,
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
});
|
||||
const pk = await FilesService.updateFile(
|
||||
req.params.pk,
|
||||
payload,
|
||||
{
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
},
|
||||
fileStream
|
||||
);
|
||||
const file = await FilesService.readFile(pk, req.sanitizedQuery);
|
||||
|
||||
savedFiles.push(file);
|
||||
}
|
||||
@@ -130,16 +127,12 @@ router.patch(
|
||||
if (req.is('multipart/form-data')) {
|
||||
file = await multipartHandler('update')(req, res, next);
|
||||
} else {
|
||||
file = await FilesService.updateFile(req.params.pk, req.body);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: 'directus_files',
|
||||
item: file.id,
|
||||
const pk = await FilesService.updateFile(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
file = await FilesService.readFile(pk, req.sanitizedQuery);
|
||||
}
|
||||
|
||||
return res.status(200).json({ data: file });
|
||||
@@ -150,7 +143,11 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_files'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await FilesService.deleteFile(req.params.pk);
|
||||
await FilesService.deleteFile(req.params.pk, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
return res.status(200).end();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -12,17 +12,13 @@ router.post(
|
||||
'/',
|
||||
useCollection('directus_folders'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const record = await FoldersService.createFolder(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: record.id,
|
||||
const primaryKey = await FoldersService.createFolder(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const record = await FoldersService.readFolder(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: record });
|
||||
})
|
||||
);
|
||||
@@ -53,21 +49,14 @@ router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_folders'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const record = await FoldersService.updateFolder(
|
||||
req.params.pk,
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: record.id,
|
||||
const primaryKey = await FoldersService.updateFolder(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const record = await FoldersService.readFolder(primaryKey, req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: record });
|
||||
})
|
||||
);
|
||||
@@ -76,7 +65,11 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_folders'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await FoldersService.deleteFolder(req.params.pk);
|
||||
await FoldersService.deleteFolder(req.params.pk, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
|
||||
@@ -6,7 +6,6 @@ import validateCollection from '../middleware/validate-collection';
|
||||
import validateSingleton from '../middleware/validate-singleton';
|
||||
import validateQuery from '../middleware/validate-query';
|
||||
import * as MetaService from '../services/meta';
|
||||
import * as ActivityService from '../services/activity';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -17,19 +16,14 @@ router.post(
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const primaryKey = await ItemsService.createItem(req.collection, req.body);
|
||||
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
/** @TODO don't forget to use real primary key here */
|
||||
item: item.id,
|
||||
const primaryKey = await ItemsService.createItem(req.collection, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery);
|
||||
|
||||
res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -76,18 +70,14 @@ router.patch(
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const primaryKey = await ItemsService.updateItem(req.collection, req.params.pk, req.body);
|
||||
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await ItemsService.updateItem(req.collection, req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -96,15 +86,10 @@ router.delete(
|
||||
'/:collection/:pk',
|
||||
validateCollection,
|
||||
asyncHandler(async (req, res) => {
|
||||
await ItemsService.deleteItem(req.collection, req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await ItemsService.deleteItem(req.collection, req.params.pk, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
|
||||
@@ -3,7 +3,6 @@ import asyncHandler from 'express-async-handler';
|
||||
import sanitizeQuery from '../middleware/sanitize-query';
|
||||
import validateQuery from '../middleware/validate-query';
|
||||
import * as PermissionsService from '../services/permissions';
|
||||
import * as ActivityService from '../services/activity';
|
||||
import useCollection from '../middleware/use-collection';
|
||||
|
||||
const router = express.Router();
|
||||
@@ -12,17 +11,14 @@ router.post(
|
||||
'/',
|
||||
useCollection('directus_permissions'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await PermissionsService.createPermission(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await PermissionsService.createPermission(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await PermissionsService.readPermission(primaryKey, req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -44,7 +40,10 @@ router.get(
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const record = await PermissionsService.readPermission(req.params.pk, req.sanitizedQuery);
|
||||
const record = await PermissionsService.readPermission(
|
||||
Number(req.params.pk),
|
||||
req.sanitizedQuery
|
||||
);
|
||||
return res.json({ data: record });
|
||||
})
|
||||
);
|
||||
@@ -53,20 +52,17 @@ router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_permissions'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await PermissionsService.updatePermission(
|
||||
req.params.pk,
|
||||
const primaryKey = await PermissionsService.updatePermission(
|
||||
Number(req.params.pk),
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
{
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
}
|
||||
);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
});
|
||||
const item = await PermissionsService.readPermission(primaryKey, req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: item });
|
||||
})
|
||||
@@ -76,15 +72,10 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_permissions'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await PermissionsService.deletePermission(req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await PermissionsService.deletePermission(Number(req.params.pk), {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
|
||||
@@ -4,25 +4,21 @@ import sanitizeQuery from '../middleware/sanitize-query';
|
||||
import validateQuery from '../middleware/validate-query';
|
||||
import * as RelationsService from '../services/relations';
|
||||
import useCollection from '../middleware/use-collection';
|
||||
import * as ActivityService from '../services/activity';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
useCollection('directus_relations'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await RelationsService.createRelation(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await RelationsService.createRelation(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await RelationsService.readRelation(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -52,22 +48,15 @@ router.get(
|
||||
router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_relations'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await RelationsService.updateRelation(
|
||||
req.params.pk,
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await RelationsService.updateRelation(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await RelationsService.readRelation(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -76,15 +65,10 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_relations'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await RelationsService.deleteRelation(req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await RelationsService.deleteRelation(Number(req.params.pk), {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
|
||||
@@ -11,18 +11,15 @@ const router = express.Router();
|
||||
router.post(
|
||||
'/',
|
||||
useCollection('directus_roles'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await RolesService.createRole(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await RolesService.createRole(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await RolesService.readRole(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -52,18 +49,15 @@ router.get(
|
||||
router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_roles'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await RolesService.updateRole(req.params.pk, req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await RolesService.updateRole(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await RolesService.readRole(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -72,15 +66,10 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_roles'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await RolesService.deleteRole(req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await RolesService.deleteRole(req.params.pk, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
|
||||
@@ -13,7 +13,7 @@ router.get(
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const records = await SettingsService.readSettings(1, req.sanitizedQuery);
|
||||
const records = await SettingsService.readSettings(req.sanitizedQuery);
|
||||
return res.json({ data: records });
|
||||
})
|
||||
);
|
||||
@@ -21,13 +21,22 @@ router.get(
|
||||
router.patch(
|
||||
'/',
|
||||
useCollection('directus_settings'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const records = await SettingsService.updateSettings(
|
||||
const primaryKey = await SettingsService.updateSettings(
|
||||
req.params.pk /** @TODO Singleton */,
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
{
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
}
|
||||
);
|
||||
return res.json({ data: records });
|
||||
|
||||
const record = await SettingsService.readSettings(req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: record });
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -6,25 +6,21 @@ import * as UsersService from '../services/users';
|
||||
import Joi from '@hapi/joi';
|
||||
import { InvalidPayloadException, InvalidCredentialsException } from '../exceptions';
|
||||
import useCollection from '../middleware/use-collection';
|
||||
import * as ActivityService from '../services/activity';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
useCollection('directus_users'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await UsersService.createUser(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await UsersService.createUser(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -36,7 +32,6 @@ router.get(
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await UsersService.readUsers(req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -77,17 +72,13 @@ router.patch(
|
||||
throw new InvalidCredentialsException();
|
||||
}
|
||||
|
||||
const item = await UsersService.updateUser(req.user, req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await UsersService.updateUser(req.user, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -95,18 +86,15 @@ router.patch(
|
||||
router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_users'),
|
||||
sanitizeQuery,
|
||||
validateQuery,
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await UsersService.updateUser(req.params.pk, req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await UsersService.updateUser(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -115,15 +103,10 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_users'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await UsersService.deleteUser(req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await UsersService.deleteUser(req.params.pk, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
@@ -141,7 +124,11 @@ router.post(
|
||||
asyncHandler(async (req, res) => {
|
||||
const { error } = inviteSchema.validate(req.body);
|
||||
if (error) throw new InvalidPayloadException(error.message);
|
||||
await UsersService.inviteUser(req.body.email, req.body.role);
|
||||
await UsersService.inviteUser(req.body.email, req.body.role, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
res.end();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -12,17 +12,14 @@ router.post(
|
||||
'/',
|
||||
useCollection('directus_webhooks'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await WebhooksService.createWebhook(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await WebhooksService.createWebhook(req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await WebhooksService.readWebhook(primaryKey, req.sanitizedQuery);
|
||||
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -53,21 +50,12 @@ router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_webhooks'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const item = await WebhooksService.updateWebhook(
|
||||
req.params.pk,
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
collection: req.collection,
|
||||
item: item.id,
|
||||
const primaryKey = await WebhooksService.updateWebhook(req.params.pk, req.body, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
const item = await WebhooksService.readWebhook(primaryKey, req.sanitizedQuery);
|
||||
return res.json({ data: item });
|
||||
})
|
||||
);
|
||||
@@ -76,15 +64,10 @@ router.delete(
|
||||
'/:pk',
|
||||
useCollection('directus_webhooks'),
|
||||
asyncHandler(async (req, res) => {
|
||||
await WebhooksService.deleteWebhook(req.params.pk);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.DELETE,
|
||||
collection: req.collection,
|
||||
item: req.params.pk,
|
||||
await WebhooksService.deleteWebhook(req.params.pk, {
|
||||
ip: req.ip,
|
||||
user_agent: req.get('user-agent'),
|
||||
action_by: req.user,
|
||||
userAgent: req.get('user-agent'),
|
||||
user: req.user,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
|
||||
@@ -11,9 +11,8 @@ export enum Action {
|
||||
AUTHENTICATE = 'authenticate',
|
||||
}
|
||||
|
||||
export const createActivity = async (data: Record<string, any>, query?: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_activity', data);
|
||||
return await ItemsService.readItem('directus_activity', primaryKey, query);
|
||||
export const createActivity = async (data: Record<string, any>) => {
|
||||
return await ItemsService.createItem('directus_activity', data);
|
||||
};
|
||||
|
||||
export const readActivities = async (query?: Query) => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
/** @todo check if we want to save activity for collection presets */
|
||||
|
||||
export const createCollectionPreset = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_collection_presets', data);
|
||||
return await ItemsService.readItem('directus_collection_presets', primaryKey, query);
|
||||
|
||||
@@ -3,9 +3,10 @@ import * as ItemsService from '../services/items';
|
||||
import { Collection } from '../types/collection';
|
||||
import { Query } from '../types/query';
|
||||
import { ColumnBuilder } from 'knex';
|
||||
import { Accountability } from '../types/accountability';
|
||||
|
||||
/** @Todo properly type this */
|
||||
export const create = async (payload: any) => {
|
||||
export const create = async (payload: any, accountability: Accountability) => {
|
||||
await database.schema.createTable(payload.collection, (table) => {
|
||||
if (payload.note) {
|
||||
table.comment(payload.note);
|
||||
@@ -13,6 +14,8 @@ export const create = async (payload: any) => {
|
||||
|
||||
/** @todo move this into fields service */
|
||||
|
||||
/** @todo adhere to new nested structure system vs database */
|
||||
|
||||
payload.fields?.forEach((field: any) => {
|
||||
let column: ColumnBuilder;
|
||||
|
||||
@@ -36,16 +39,18 @@ export const create = async (payload: any) => {
|
||||
});
|
||||
});
|
||||
|
||||
const primaryKey = await ItemsService.createItem('directus_collections', {
|
||||
collection: payload.collection,
|
||||
hidden: payload.hidden || false,
|
||||
single: payload.single || false,
|
||||
icon: payload.icon || null,
|
||||
note: payload.note || null,
|
||||
translation: payload.translation || null,
|
||||
});
|
||||
|
||||
const collection = await ItemsService.createItem('directus_collections', primaryKey);
|
||||
const primaryKey = await ItemsService.createItem(
|
||||
'directus_collections',
|
||||
{
|
||||
collection: payload.collection,
|
||||
hidden: payload.hidden || false,
|
||||
single: payload.single || false,
|
||||
icon: payload.icon || null,
|
||||
note: payload.note || null,
|
||||
translation: payload.translation || null,
|
||||
},
|
||||
accountability
|
||||
);
|
||||
|
||||
/**
|
||||
* @TODO make this flexible and based on payload
|
||||
@@ -62,7 +67,7 @@ export const create = async (payload: any) => {
|
||||
}))
|
||||
);
|
||||
|
||||
return collection;
|
||||
return await ItemsService.readItem('directus_collections', primaryKey);
|
||||
};
|
||||
|
||||
export const readAll = async (query?: Query) => {
|
||||
@@ -105,10 +110,10 @@ export const readOne = async (collection: string, query?: Query) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const deleteCollection = async (collection: string) => {
|
||||
export const deleteCollection = async (collection: string, accountability: Accountability) => {
|
||||
await Promise.all([
|
||||
database.schema.dropTable(collection),
|
||||
ItemsService.deleteItem('directus_collections', collection),
|
||||
ItemsService.deleteItem('directus_collections', collection, accountability),
|
||||
database.delete().from('directus_fields').where({ collection }),
|
||||
database
|
||||
.delete()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import database, { schemaInspector } from '../database';
|
||||
import { Field } from '../types/field';
|
||||
import { uniq } from 'lodash';
|
||||
import { Accountability } from '../types';
|
||||
import * as ItemsService from '../services/items';
|
||||
|
||||
export const fieldsInCollection = async (collection: string) => {
|
||||
const [fields, columns] = await Promise.all([
|
||||
@@ -55,20 +57,30 @@ export const readOne = async (collection: string, field: string) => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createField = async (collection: string, field: Partial<Field>) => {
|
||||
await database.schema.alterTable('articles', (table) => {
|
||||
export const createField = async (
|
||||
collection: string,
|
||||
field: Partial<Field>,
|
||||
accountability: Accountability
|
||||
) => {
|
||||
await database.schema.alterTable(collection, (table) => {
|
||||
table.specificType(field.field, field.database.type);
|
||||
/** @todo add support for other database info (length etc) */
|
||||
});
|
||||
|
||||
if (field.system) {
|
||||
await database('directus_fields').insert({
|
||||
...field.system,
|
||||
collection: collection,
|
||||
field: field.field,
|
||||
});
|
||||
await ItemsService.createItem(
|
||||
'directus_fields',
|
||||
{
|
||||
...field.system,
|
||||
collection: collection,
|
||||
field: field.field,
|
||||
},
|
||||
accountability
|
||||
);
|
||||
}
|
||||
|
||||
const createdField = await readOne(collection, field.field);
|
||||
return createdField;
|
||||
};
|
||||
|
||||
/** @todo add update / delete field */
|
||||
|
||||
@@ -9,11 +9,13 @@ import parseEXIF from 'exif-reader';
|
||||
import parseIPTC from '../utils/parse-iptc';
|
||||
import path from 'path';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Accountability } from '../types';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
export const createFile = async (
|
||||
data: Record<string, any>,
|
||||
stream: NodeJS.ReadableStream,
|
||||
query?: Query
|
||||
accountability: Accountability
|
||||
) => {
|
||||
const id = uuidv4();
|
||||
|
||||
@@ -51,8 +53,7 @@ export const createFile = async (
|
||||
}
|
||||
|
||||
await storage.disk(data.storage).put(payload.filename_disk, stream.pipe(pipeline));
|
||||
const primaryKey = await ItemsService.createItem('directus_files', payload);
|
||||
return await ItemsService.readItem('directus_files', primaryKey, query);
|
||||
return await ItemsService.createItem('directus_files', payload, accountability);
|
||||
};
|
||||
|
||||
export const readFiles = async (query: Query) => {
|
||||
@@ -63,12 +64,11 @@ export const readFile = async (pk: string | number, query: Query) => {
|
||||
return await ItemsService.readItem('directus_files', pk, query);
|
||||
};
|
||||
|
||||
// @todo Add query support
|
||||
export const updateFile = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
stream?: NodeJS.ReadableStream,
|
||||
query?: Query
|
||||
accountability: Accountability,
|
||||
stream?: NodeJS.ReadableStream
|
||||
) => {
|
||||
/**
|
||||
* @TODO
|
||||
@@ -87,15 +87,13 @@ export const updateFile = async (
|
||||
.where({ id: pk })
|
||||
.first();
|
||||
|
||||
// @todo type of stream in flydrive is wrong: https://github.com/Slynova-Org/flydrive/issues/145
|
||||
await storage.disk(file.storage).put(file.filename_disk, stream as any);
|
||||
await storage.disk(file.storage).put(file.filename_disk, stream as Readable);
|
||||
}
|
||||
|
||||
const primaryKey = await ItemsService.updateItem('directus_files', pk, data);
|
||||
return await ItemsService.readItem('directus_files', primaryKey, query);
|
||||
return await ItemsService.updateItem('directus_files', pk, data, accountability);
|
||||
};
|
||||
|
||||
export const deleteFile = async (pk: string | number) => {
|
||||
export const deleteFile = async (pk: string, accountability: Accountability) => {
|
||||
const file = await database
|
||||
.select('storage', 'filename_disk')
|
||||
.from('directus_files')
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
import { Accountability, Query } from '../types';
|
||||
|
||||
export const createFolder = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_folders', data);
|
||||
return await ItemsService.readItem('directus_folders', primaryKey, query);
|
||||
export const createFolder = async (
|
||||
data: Record<string, any>,
|
||||
accountability: Accountability
|
||||
): Promise<string> => {
|
||||
return (await ItemsService.createItem('directus_folders', data, accountability)) as string;
|
||||
};
|
||||
|
||||
export const readFolders = async (query: Query) => {
|
||||
return await ItemsService.readItems('directus_folders', query);
|
||||
};
|
||||
|
||||
export const readFolder = async (pk: string | number, query: Query) => {
|
||||
export const readFolder = async (pk: string, query: Query) => {
|
||||
return await ItemsService.readItem('directus_folders', pk, query);
|
||||
};
|
||||
|
||||
export const updateFolder = async (
|
||||
pk: string | number,
|
||||
pk: string,
|
||||
data: Record<string, any>,
|
||||
query: Query
|
||||
) => {
|
||||
const primaryKey = await ItemsService.updateItem('directus_folders', pk, data);
|
||||
return await ItemsService.readItem('directus_folders', primaryKey, query);
|
||||
accountability: Accountability
|
||||
): Promise<string> => {
|
||||
return (await ItemsService.updateItem('directus_folders', pk, data, accountability)) as string;
|
||||
};
|
||||
|
||||
export const deleteFolder = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_folders', pk);
|
||||
export const deleteFolder = async (pk: string, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_folders', pk, accountability);
|
||||
};
|
||||
|
||||
@@ -3,9 +3,46 @@ import { Query } from '../types/query';
|
||||
import runAST from '../database/run-ast';
|
||||
import getAST from '../utils/get-ast';
|
||||
import * as PayloadService from './payload';
|
||||
import { pick } from 'lodash';
|
||||
import { Accountability } from '../types/accountability';
|
||||
|
||||
export const createItem = async (collection: string, data: Record<string, any>) => {
|
||||
import * as ActivityService from './activity';
|
||||
import * as RevisionsService from './revisions';
|
||||
|
||||
import { pick } from 'lodash';
|
||||
import logger from '../logger';
|
||||
|
||||
async function saveActivityAndRevision(
|
||||
action: ActivityService.Action,
|
||||
collection: string,
|
||||
item: string,
|
||||
payload: Record<string, any>,
|
||||
accountability: Accountability
|
||||
) {
|
||||
const activityID = await ActivityService.createActivity({
|
||||
action,
|
||||
collection,
|
||||
item,
|
||||
ip: accountability.ip,
|
||||
user_agent: accountability.userAgent,
|
||||
action_by: accountability.user,
|
||||
});
|
||||
|
||||
await RevisionsService.createRevision({
|
||||
activity: activityID,
|
||||
collection,
|
||||
item,
|
||||
delta: payload,
|
||||
/** @todo make this configurable */
|
||||
data: await readItem(collection, item, { fields: ['*'] }),
|
||||
parent: accountability.parent,
|
||||
});
|
||||
}
|
||||
|
||||
export const createItem = async (
|
||||
collection: string,
|
||||
data: Record<string, any>,
|
||||
accountability?: Accountability
|
||||
): Promise<string | number> => {
|
||||
let payload = await PayloadService.processValues('create', collection, data);
|
||||
|
||||
payload = await PayloadService.processM2O(collection, payload);
|
||||
@@ -14,13 +51,14 @@ export const createItem = async (collection: string, data: Record<string, any>)
|
||||
|
||||
// Only insert the values that actually save to an existing column. This ensures we ignore aliases etc
|
||||
const columns = await schemaInspector.columns(collection);
|
||||
|
||||
const payloadWithoutAlias = pick(
|
||||
payload,
|
||||
columns.map(({ column }) => column)
|
||||
);
|
||||
|
||||
const primaryKeys = await database(collection)
|
||||
.insert(
|
||||
pick(
|
||||
payload,
|
||||
columns.map(({ column }) => column)
|
||||
)
|
||||
)
|
||||
.insert(payloadWithoutAlias)
|
||||
.returning(primaryKeyField);
|
||||
|
||||
// This allows the o2m values to be populated correctly
|
||||
@@ -28,6 +66,17 @@ export const createItem = async (collection: string, data: Record<string, any>)
|
||||
|
||||
await PayloadService.processO2M(collection, payload);
|
||||
|
||||
if (accountability) {
|
||||
// Don't await this. It can run async in the background
|
||||
saveActivityAndRevision(
|
||||
ActivityService.Action.CREATE,
|
||||
collection,
|
||||
primaryKeys[0],
|
||||
payloadWithoutAlias,
|
||||
accountability
|
||||
).catch((err) => logger.error(err));
|
||||
}
|
||||
|
||||
return primaryKeys[0];
|
||||
};
|
||||
|
||||
@@ -67,9 +116,10 @@ export const readItem = async <T = any>(
|
||||
export const updateItem = async (
|
||||
collection: string,
|
||||
pk: number | string,
|
||||
data: Record<string, any>
|
||||
) => {
|
||||
let payload = await PayloadService.processValues('create', collection, data);
|
||||
data: Record<string, any>,
|
||||
accountability?: Accountability
|
||||
): Promise<string | number> => {
|
||||
let payload = await PayloadService.processValues('update', collection, data);
|
||||
|
||||
payload = await PayloadService.processM2O(collection, payload);
|
||||
|
||||
@@ -77,21 +127,49 @@ export const updateItem = async (
|
||||
|
||||
// Only insert the values that actually save to an existing column. This ensures we ignore aliases etc
|
||||
const columns = await schemaInspector.columns(collection);
|
||||
|
||||
const payloadWithoutAlias = pick(
|
||||
payload,
|
||||
columns.map(({ column }) => column)
|
||||
);
|
||||
|
||||
const primaryKeys = await database(collection)
|
||||
.update(
|
||||
pick(
|
||||
payload,
|
||||
columns.map(({ column }) => column)
|
||||
)
|
||||
)
|
||||
.update(payloadWithoutAlias)
|
||||
.where({ [primaryKeyField]: pk })
|
||||
.returning(primaryKeyField);
|
||||
|
||||
if (accountability) {
|
||||
// Don't await this. It can run async in the background
|
||||
saveActivityAndRevision(
|
||||
ActivityService.Action.UPDATE,
|
||||
collection,
|
||||
primaryKeys[0],
|
||||
payloadWithoutAlias,
|
||||
accountability
|
||||
).catch((err) => logger.error(err));
|
||||
}
|
||||
|
||||
return primaryKeys[0];
|
||||
};
|
||||
|
||||
export const deleteItem = async (collection: string, pk: number | string) => {
|
||||
export const deleteItem = async (
|
||||
collection: string,
|
||||
pk: number | string,
|
||||
accountability?: Accountability
|
||||
) => {
|
||||
const primaryKeyField = await schemaInspector.primary(collection);
|
||||
|
||||
if (accountability) {
|
||||
// Don't await this. It can run async in the background
|
||||
saveActivityAndRevision(
|
||||
ActivityService.Action.DELETE,
|
||||
collection,
|
||||
String(pk),
|
||||
{},
|
||||
accountability
|
||||
).catch((err) => logger.error(err));
|
||||
}
|
||||
|
||||
return await database(collection)
|
||||
.delete()
|
||||
.where({ [primaryKeyField]: pk });
|
||||
|
||||
@@ -7,7 +7,7 @@ import { System } from '../types/field';
|
||||
import argon2 from 'argon2';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import database from '../database';
|
||||
import { clone } from 'lodash';
|
||||
import { clone, isObject } from 'lodash';
|
||||
import { File } from '../types/files';
|
||||
import { Relation } from '../types/relation';
|
||||
import * as ItemsService from './items';
|
||||
@@ -24,6 +24,10 @@ type Transformers = {
|
||||
|
||||
/**
|
||||
* @todo allow this to be extended
|
||||
*
|
||||
* @todo allow these extended special types to have "field dependencies"?
|
||||
* f.e. the file-links transformer needs the id and filename_download to be fetched from the DB
|
||||
* in order to work
|
||||
*/
|
||||
const transformers: Transformers = {
|
||||
async hash(operation, value) {
|
||||
@@ -42,10 +46,13 @@ const transformers: Transformers = {
|
||||
|
||||
return value;
|
||||
},
|
||||
async 'file-info'(operation, value, payload: File) {
|
||||
if (operation === 'read' && payload) {
|
||||
async 'file-links'(operation, value, payload: File) {
|
||||
if (operation === 'read' && payload && payload.storage && payload.filename_disk) {
|
||||
const publicKey = `STORAGE_${payload.storage.toUpperCase()}_PUBLIC_URL`;
|
||||
|
||||
return {
|
||||
asset_url: new URL(`/assets/${payload.id}`, process.env.PUBLIC_URL),
|
||||
public_url: new URL(payload.filename_disk, process.env[publicKey]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -131,7 +138,7 @@ export const processM2O = async (collection: string, payload: Record<string, any
|
||||
const relationsToProcess = relations.filter((relation) => {
|
||||
return (
|
||||
payloadClone.hasOwnProperty(relation.field_many) &&
|
||||
typeof payloadClone[relation.field_many] === 'object'
|
||||
isObject(payloadClone[relation.field_many])
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
import { Query } from '../types/query';
|
||||
import { Accountability, Query } from '../types';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
export const createPermission = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_permissions', data);
|
||||
return await ItemsService.readItem('directus_permissions', primaryKey, query);
|
||||
export const createPermission = async (
|
||||
data: Record<string, any>,
|
||||
accountability: Accountability
|
||||
): Promise<number> => {
|
||||
return (await ItemsService.createItem('directus_permissions', data, accountability)) as number;
|
||||
};
|
||||
|
||||
export const readPermissions = async (query: Query) => {
|
||||
return await ItemsService.readItems('directus_permissions', query);
|
||||
};
|
||||
|
||||
export const readPermission = async (pk: string | number, query: Query) => {
|
||||
export const readPermission = async (pk: number, query: Query) => {
|
||||
return await ItemsService.readItem('directus_permissions', pk, query);
|
||||
};
|
||||
|
||||
export const updatePermission = async (
|
||||
pk: string | number,
|
||||
pk: number,
|
||||
data: Record<string, any>,
|
||||
query: Query
|
||||
) => {
|
||||
const primaryKey = await ItemsService.updateItem('directus_permissions', pk, data);
|
||||
return await ItemsService.readItem('directus_permissions', primaryKey, query);
|
||||
accountability: Accountability
|
||||
): Promise<number> => {
|
||||
return (await ItemsService.updateItem(
|
||||
'directus_permissions',
|
||||
pk,
|
||||
data,
|
||||
accountability
|
||||
)) as number;
|
||||
};
|
||||
|
||||
export const deletePermission = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_permissions', pk);
|
||||
export const deletePermission = async (pk: number, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_permissions', pk, accountability);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Query } from '../types/query';
|
||||
import { Accountability, Query } from '../types';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
export const createRelation = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_relations', data);
|
||||
return ItemsService.readItem('directus_relations', primaryKey, query);
|
||||
export const createRelation = async (data: Record<string, any>, accountability: Accountability) => {
|
||||
return await ItemsService.createItem('directus_relations', data, accountability);
|
||||
};
|
||||
|
||||
export const readRelations = async (query: Query) => {
|
||||
@@ -17,12 +16,11 @@ export const readRelation = async (pk: string | number, query: Query) => {
|
||||
export const updateRelation = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
query: Query
|
||||
accountability: Accountability
|
||||
) => {
|
||||
const primaryKey = await ItemsService.updateItem('directus_relations', pk, data);
|
||||
return ItemsService.readItem('directus_relations', primaryKey, query);
|
||||
return await ItemsService.updateItem('directus_relations', pk, data, accountability);
|
||||
};
|
||||
|
||||
export const deleteRelation = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_relations', pk);
|
||||
export const deleteRelation = async (pk: number, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_relations', pk, accountability);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
export const createRevision = async (data: Record<string, any>) => {
|
||||
return await ItemsService.createItem('directus_revisions', data);
|
||||
};
|
||||
|
||||
export const readRevisions = async (query: Query) => {
|
||||
return await ItemsService.readItems('directus_revisions', query);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Query } from '../types/query';
|
||||
import { Accountability, Query } from '../types';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
export const createRole = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_roles', data);
|
||||
return await ItemsService.readItem('directus_roles', primaryKey, query);
|
||||
export const createRole = async (data: Record<string, any>, accountability: Accountability) => {
|
||||
return await ItemsService.createItem('directus_roles', data, accountability);
|
||||
};
|
||||
|
||||
export const readRoles = async (query: Query) => {
|
||||
@@ -14,11 +13,14 @@ export const readRole = async (pk: string | number, query: Query) => {
|
||||
return await ItemsService.readItem('directus_roles', pk, query);
|
||||
};
|
||||
|
||||
export const updateRole = async (pk: string | number, data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.updateItem('directus_roles', pk, data);
|
||||
return await ItemsService.readItem('directus_roles', primaryKey, query);
|
||||
export const updateRole = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
accountability: Accountability
|
||||
) => {
|
||||
return await ItemsService.updateItem('directus_roles', pk, data, accountability);
|
||||
};
|
||||
|
||||
export const deleteRole = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_roles', pk);
|
||||
export const deleteRole = async (pk: string | number, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_roles', pk, accountability);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
import { Accountability } from '../types';
|
||||
|
||||
export const readSettings = async (pk: string | number, query: Query) => {
|
||||
export const readSettings = async (query: Query) => {
|
||||
const settings = await ItemsService.readItems('directus_settings', {
|
||||
...query,
|
||||
limit: 1,
|
||||
@@ -13,9 +14,8 @@ export const readSettings = async (pk: string | number, query: Query) => {
|
||||
export const updateSettings = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
query: Query
|
||||
accountability: Accountability
|
||||
) => {
|
||||
/** @NOTE I guess this can technically update _all_ items, as we expect there to only be one */
|
||||
const primaryKey = await ItemsService.updateItem('directus_settings', pk, data);
|
||||
return await ItemsService.readItem('directus_settings', primaryKey, query);
|
||||
return await ItemsService.updateItem('directus_settings', pk, data, accountability);
|
||||
};
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { sendInviteMail } from '../mail';
|
||||
import database from '../database';
|
||||
import argon2 from 'argon2';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
import { Accountability, Query } from '../types';
|
||||
|
||||
export const createUser = async (data: Record<string, any>, query?: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_users', data);
|
||||
return await ItemsService.readItem('directus_user', primaryKey, query);
|
||||
export const createUser = async (data: Record<string, any>, accountability: Accountability) => {
|
||||
return await ItemsService.createItem('directus_users', data, accountability);
|
||||
};
|
||||
|
||||
export const readUsers = async (query?: Query) => {
|
||||
@@ -19,23 +18,26 @@ export const readUser = async (pk: string | number, query?: Query) => {
|
||||
return await ItemsService.readItem('directus_users', pk, query);
|
||||
};
|
||||
|
||||
export const updateUser = async (pk: string | number, data: Record<string, any>, query?: Query) => {
|
||||
export const updateUser = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
accountability: Accountability
|
||||
) => {
|
||||
/**
|
||||
* @todo
|
||||
* Remove "other" refresh token sessions when changing password to enforce "logout everywhere" on password change
|
||||
*
|
||||
* Maybe make this an option?
|
||||
*/
|
||||
const primaryKey = await ItemsService.updateItem('directus_users', pk, data);
|
||||
return await ItemsService.readItem('directus_user', primaryKey, query);
|
||||
return await ItemsService.updateItem('directus_users', pk, data, accountability);
|
||||
};
|
||||
|
||||
export const deleteUser = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_users', pk);
|
||||
export const deleteUser = async (pk: string | number, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_users', pk, accountability);
|
||||
};
|
||||
|
||||
export const inviteUser = async (email: string, role: string) => {
|
||||
await createUser({ email, role, status: 'invited' });
|
||||
export const inviteUser = async (email: string, role: string, accountability: Accountability) => {
|
||||
await createUser({ email, role, status: 'invited' }, accountability);
|
||||
|
||||
const payload = { email };
|
||||
const token = jwt.sign(payload, process.env.SECRET, { expiresIn: '7d' });
|
||||
@@ -45,7 +47,7 @@ export const inviteUser = async (email: string, role: string) => {
|
||||
};
|
||||
|
||||
export const acceptInvite = async (token: string, password: string) => {
|
||||
const { email } = jwt.verify(token, process.env.SECRET) as Record<string, any>;
|
||||
const { email } = jwt.verify(token, process.env.SECRET) as { email: string };
|
||||
const user = await database
|
||||
.select('id', 'status')
|
||||
.from('directus_users')
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Query } from '../types/query';
|
||||
import { Accountability, Query } from '../types';
|
||||
import * as ItemsService from './items';
|
||||
|
||||
export const createWebhook = async (data: Record<string, any>, query: Query) => {
|
||||
const primaryKey = await ItemsService.createItem('directus_webhooks', data);
|
||||
return await ItemsService.readItem('directus_webhooks', primaryKey, query);
|
||||
export const createWebhook = async (data: Record<string, any>, accountability: Accountability) => {
|
||||
return await ItemsService.createItem('directus_webhooks', data, accountability);
|
||||
};
|
||||
|
||||
export const readWebhooks = async (query: Query) => {
|
||||
@@ -17,12 +16,11 @@ export const readWebhook = async (pk: string | number, query: Query) => {
|
||||
export const updateWebhook = async (
|
||||
pk: string | number,
|
||||
data: Record<string, any>,
|
||||
query: Query
|
||||
accountability: Accountability
|
||||
) => {
|
||||
const primaryKey = await ItemsService.updateItem('directus_webhooks', pk, data);
|
||||
return await ItemsService.readItem('directus_webhooks', primaryKey, query);
|
||||
return await ItemsService.updateItem('directus_webhooks', pk, data, accountability);
|
||||
};
|
||||
|
||||
export const deleteWebhook = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_webhooks', pk);
|
||||
export const deleteWebhook = async (pk: string | number, accountability: Accountability) => {
|
||||
await ItemsService.deleteItem('directus_webhooks', pk, accountability);
|
||||
};
|
||||
|
||||
7
src/types/accountability.ts
Normal file
7
src/types/accountability.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export type Accountability = {
|
||||
ip?: string;
|
||||
userAgent?: string;
|
||||
user?: string;
|
||||
|
||||
parent?: number;
|
||||
};
|
||||
@@ -2,4 +2,5 @@
|
||||
export type File = {
|
||||
id: string; // uuid
|
||||
filename_disk: string;
|
||||
storage: string;
|
||||
};
|
||||
|
||||
10
src/types/index.ts
Normal file
10
src/types/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from './accountability';
|
||||
export * from './assets';
|
||||
export * from './ast';
|
||||
export * from './collection';
|
||||
export * from './field';
|
||||
export * from './files';
|
||||
export * from './meta';
|
||||
export * from './query';
|
||||
export * from './relation';
|
||||
export * from './sessions';
|
||||
Reference in New Issue
Block a user