Merge pull request #12 from directus/system-crud

Add a bunch of system crud
This commit is contained in:
Rijk van Zanten
2020-06-18 16:04:17 -04:00
committed by GitHub
19 changed files with 588 additions and 4 deletions

View File

@@ -5,12 +5,28 @@ import express from 'express';
import bodyParser from 'body-parser';
import { errorHandler } from './error';
import itemsRouter from './routes/items';
import activityRouter from './routes/activity';
import collectionPresetsRouter from './routes/collection-presets';
import filesRouter from './routes/files';
import foldersRouter from './routes/folders';
import relationsRouter from './routes/relations';
import revisionsRouter from './routes/revisions';
import rolesRouter from './routes/roles';
import usersRouter from './routes/users';
import notFoundHandler from './routes/not-found';
const app = express()
.disable('x-powered-by')
.use(bodyParser.json())
.use('/items', itemsRouter)
.use('/files', filesRouter)
.use('/activity', activityRouter)
.use('/collection_presets', collectionPresetsRouter)
.use('/folders', foldersRouter)
.use('/relations', relationsRouter)
.use('/revisions', revisionsRouter)
.use('/roles', rolesRouter)
.use('/users', usersRouter)
.use(notFoundHandler)
.use(errorHandler);

View File

@@ -12,7 +12,7 @@ import asyncHandler from 'express-async-handler';
import APIError, { ErrorCode } from '../error';
const validateQuery: RequestHandler = asyncHandler(async (req, res, next) => {
if (!res.locals.collection) return next();
if (!req.params.collection) return next();
if (!res.locals.query) return next();
const query: Query = res.locals.query;
@@ -27,14 +27,14 @@ const validateQuery: RequestHandler = asyncHandler(async (req, res, next) => {
query.sort.forEach((sort) => fieldsToCheck.add(sort.column));
}
const fieldsExist = await hasFields(res.locals.collection, Array.from(fieldsToCheck));
const fieldsExist = await hasFields(req.params.collection, Array.from(fieldsToCheck));
Array.from(fieldsToCheck).forEach((field, index) => {
const exists = fieldsExist[index];
if (exists === false)
throw new APIError(
ErrorCode.FIELD_NOT_FOUND,
`Field ${field} doesn't exist in ${res.locals.collection}.`
`Field ${field} doesn't exist in ${req.params.collection}.`
);
});

34
src/routes/activity.ts Normal file
View File

@@ -0,0 +1,34 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import { readActivities, readActivity } from '../services/activity';
const router = express.Router();
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await readActivities(res.locals.query);
return res.json({
data: records,
});
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await readActivity(req.params.pk, res.locals.query);
return res.json({
data: record,
});
})
);
export default router;

View File

@@ -0,0 +1,63 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as CollectionPresetsService from '../services/collection-presets';
const router = express.Router();
router.post(
'/',
asyncHandler(async (req, res) => {
const records = await CollectionPresetsService.createCollectionPreset(
req.body,
res.locals.query
);
return res.json({ data: records });
})
);
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await CollectionPresetsService.readCollectionPresets(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await CollectionPresetsService.readCollectionPreset(
req.params.pk,
res.locals.query
);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await CollectionPresetsService.updateCollectionPreset(
req.params.pk,
req.body,
res.locals.query
);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await CollectionPresetsService.deleteCollectionPreset(req.params.pk);
return res.status(200).end();
})
);
export default router;

57
src/routes/files.ts Normal file
View File

@@ -0,0 +1,57 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as FilesService from '../services/files';
const router = express.Router();
/** @TODO This needs to support multipart form-data for file uploads */
// router.post(
// '/',
// asyncHandler(async (req, res) => {
// const records = await FilesService.createFile(
// req.body,
// res.locals.query
// );
// return res.json({ data: records });
// })
// );
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await FilesService.readFiles(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await FilesService.readFile(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await FilesService.updateFile(req.params.pk, req.body, res.locals.query);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await FilesService.deleteFile(req.params.pk);
return res.status(200).end();
})
);
export default router;

57
src/routes/folders.ts Normal file
View File

@@ -0,0 +1,57 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as FoldersService from '../services/folders';
const router = express.Router();
router.post(
'/',
asyncHandler(async (req, res) => {
const records = await FoldersService.createFolder(req.body, res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await FoldersService.readFolders(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await FoldersService.readFolder(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await FoldersService.updateFolder(
req.params.pk,
req.body,
res.locals.query
);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await FoldersService.deleteFolder(req.params.pk);
return res.status(200).end();
})
);
export default router;

57
src/routes/relations.ts Normal file
View File

@@ -0,0 +1,57 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as RelationsService from '../services/relations';
const router = express.Router();
router.post(
'/',
asyncHandler(async (req, res) => {
const records = await RelationsService.createRelation(req.body, res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await RelationsService.readRelations(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await RelationsService.readRelation(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await RelationsService.updateRelation(
req.params.pk,
req.body,
res.locals.query
);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await RelationsService.deleteRelation(req.params.pk);
return res.status(200).end();
})
);
export default router;

29
src/routes/revisions.ts Normal file
View File

@@ -0,0 +1,29 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as RevisionsService from '../services/revisions';
const router = express.Router();
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await RevisionsService.readRevisions(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await RevisionsService.readRevision(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
export default router;

53
src/routes/roles.ts Normal file
View File

@@ -0,0 +1,53 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as RolesService from '../services/roles';
const router = express.Router();
router.post(
'/',
asyncHandler(async (req, res) => {
const records = await RolesService.createRole(req.body, res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await RolesService.readRoles(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await RolesService.readRole(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await RolesService.updateRole(req.params.pk, req.body, res.locals.query);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await RolesService.deleteRole(req.params.pk);
return res.status(200).end();
})
);
export default router;

53
src/routes/users.ts Normal file
View File

@@ -0,0 +1,53 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import sanitizeQuery from '../middleware/sanitize-query';
import validateQuery from '../middleware/validate-query';
import * as UsersService from '../services/users';
const router = express.Router();
router.post(
'/',
asyncHandler(async (req, res) => {
const records = await UsersService.createUser(req.body, res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const records = await UsersService.readUsers(res.locals.query);
return res.json({ data: records });
})
);
router.get(
'/:pk',
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
const record = await UsersService.readUser(req.params.pk, res.locals.query);
return res.json({ data: record });
})
);
router.patch(
'/:pk',
asyncHandler(async (req, res) => {
const records = await UsersService.updateUser(req.params.pk, req.body, res.locals.query);
return res.json({ data: records });
})
);
router.delete(
'/:pk',
asyncHandler(async (req, res) => {
await UsersService.deleteUser(req.params.pk);
return res.status(200).end();
})
);
export default router;

10
src/services/activity.ts Normal file
View File

@@ -0,0 +1,10 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const readActivities = async (query: Query) => {
return await ItemsService.readItems('directus_activity', query);
};
export const readActivity = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_activity', pk, query);
};

View File

@@ -0,0 +1,26 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const createCollectionPreset = async (data: Record<string, any>, query: Query) => {
return await ItemsService.createItem('directus_collection_presets', data, query);
};
export const readCollectionPresets = async (query: Query) => {
return await ItemsService.readItems('directus_collection_presets', query);
};
export const readCollectionPreset = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_collection_presets', pk, query);
};
export const updateCollectionPreset = async (
pk: string | number,
data: Record<string, any>,
query: Query
) => {
return await ItemsService.updateItem('directus_collection_presets', pk, data, query);
};
export const deleteCollectionPreset = async (pk: string | number) => {
await ItemsService.deleteItem('directus_collection_presets', pk);
};

23
src/services/files.ts Normal file
View File

@@ -0,0 +1,23 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
/** @TODO This is a little more involved ofc, circling back later */
// export const createFile = async (data: Record<string, any>, query: Query) => {
// return await ItemsService.createItem('directus_files', data, query);
// };
export const readFiles = async (query: Query) => {
return await ItemsService.readItems('directus_files', query);
};
export const readFile = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_files', pk, query);
};
export const updateFile = async (pk: string | number, data: Record<string, any>, query: Query) => {
return await ItemsService.updateItem('directus_files', pk, data, query);
};
export const deleteFile = async (pk: string | number) => {
await ItemsService.deleteItem('directus_files', pk);
};

26
src/services/folders.ts Normal file
View File

@@ -0,0 +1,26 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const createFolder = async (data: Record<string, any>, query: Query) => {
return await ItemsService.createItem('directus_folders', data, query);
};
export const readFolders = async (query: Query) => {
return await ItemsService.readItems('directus_folders', query);
};
export const readFolder = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_folders', pk, query);
};
export const updateFolder = async (
pk: string | number,
data: Record<string, any>,
query: Query
) => {
return await ItemsService.updateItem('directus_folders', pk, data, query);
};
export const deleteFolder = async (pk: string | number) => {
await ItemsService.deleteItem('directus_folders', pk);
};

View File

@@ -6,7 +6,7 @@ export const createItem = async (
data: Record<string, any>,
query: Query = {}
) => {
return await database(collection).insert(data);
await database(collection).insert(data);
};
export const readItems = async (collection: string, query: Query = {}) => {

26
src/services/relations.ts Normal file
View File

@@ -0,0 +1,26 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const createRelation = async (data: Record<string, any>, query: Query) => {
return await ItemsService.createItem('directus_relations', data, query);
};
export const readRelations = async (query: Query) => {
return await ItemsService.readItems('directus_relations', query);
};
export const readRelation = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_relations', pk, query);
};
export const updateRelation = async (
pk: string | number,
data: Record<string, any>,
query: Query
) => {
return await ItemsService.updateItem('directus_relations', pk, data, query);
};
export const deleteRelation = async (pk: string | number) => {
await ItemsService.deleteItem('directus_relations', pk);
};

10
src/services/revisions.ts Normal file
View File

@@ -0,0 +1,10 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const readRevisions = async (query: Query) => {
return await ItemsService.readItems('directus_revisions', query);
};
export const readRevision = async (pk: string | number, query: Query) => {
return await ItemsService.readItem('directus_revisions', pk, query);
};

22
src/services/roles.ts Normal file
View File

@@ -0,0 +1,22 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const createRole = async (data: Record<string, any>, query: Query) => {
return await ItemsService.createItem('directus_roles', data, query);
};
export const readRoles = async (query: Query) => {
return await ItemsService.readItems('directus_roles', query);
};
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) => {
return await ItemsService.updateItem('directus_roles', pk, data, query);
};
export const deleteRole = async (pk: string | number) => {
await ItemsService.deleteItem('directus_roles', pk);
};

22
src/services/users.ts Normal file
View File

@@ -0,0 +1,22 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
export const createUser = async (data: Record<string, any>, query: Query) => {
return await ItemsService.createItem('directus_users', data, query);
};
export const readUsers = async (query: Query) => {
return await ItemsService.readItems('directus_users', query);
};
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) => {
return await ItemsService.updateItem('directus_users', pk, data, query);
};
export const deleteUser = async (pk: string | number) => {
await ItemsService.deleteItem('directus_users', pk);
};