Add item singleton support

This commit is contained in:
rijkvanzanten
2020-07-09 17:55:10 -04:00
parent f14d0c016e
commit 06d04fff50
4 changed files with 73 additions and 62 deletions

View File

@@ -1,32 +0,0 @@
/**
* Check if you're allowed to add an additional item when POSTing to a singleton
*/
import { RequestHandler } from 'express';
import asyncHandler from 'express-async-handler';
import database from '../database';
import { ItemLimitException } from '../exceptions';
const validateCollection: RequestHandler = asyncHandler(async (req, res, next) => {
if (!req.collection) return next();
const collectionInfo = await database
.select('single')
.from('directus_collections')
.where({ collection: req.collection })
.first();
if (!collectionInfo) return next();
if (collectionInfo.single === false) return next();
const { count } = await database.count('*').as('count').from(req.collection).first();
if (Number(count) === 0) return next();
throw new ItemLimitException(
`You can only create a single item in singleton "${req.collection}"`
);
});
export default validateCollection;

View File

@@ -3,19 +3,22 @@ import asyncHandler from 'express-async-handler';
import * as ItemsService from '../services/items';
import sanitizeQuery from '../middleware/sanitize-query';
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 { RouteNotFoundException } from '../exceptions';
const router = express.Router();
router.post(
'/:collection',
validateCollection,
validateSingleton,
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
if (req.single) {
throw new RouteNotFoundException(req.path);
}
const primaryKey = await ItemsService.createItem(req.collection, req.body, {
ip: req.ip,
userAgent: req.get('user-agent'),
@@ -35,7 +38,9 @@ router.get(
validateQuery,
asyncHandler(async (req, res) => {
const [records, meta] = await Promise.all([
ItemsService.readItems(req.collection, req.sanitizedQuery),
req.single
? ItemsService.readSingleton(req.collection, req.sanitizedQuery)
: ItemsService.readItems(req.collection, req.sanitizedQuery),
MetaService.getMetaForQuery(req.collection, req.sanitizedQuery),
]);
@@ -52,6 +57,10 @@ router.get(
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
if (req.single) {
throw new RouteNotFoundException(req.path);
}
const record = await ItemsService.readItem(
req.collection,
req.params.pk,
@@ -64,12 +73,38 @@ router.get(
})
);
router.patch(
'/:collection',
validateCollection,
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
if (req.single === false) {
throw new RouteNotFoundException(req.path);
}
await ItemsService.upsertSingleton(req.collection, req.body, {
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await ItemsService.readSingleton(req.collection, req.sanitizedQuery);
return res.json({ data: item || null });
})
);
router.patch(
'/:collection/:pk',
validateCollection,
sanitizeQuery,
validateQuery,
asyncHandler(async (req, res) => {
if (req.single) {
throw new RouteNotFoundException(req.path);
}
const primaryKey = await ItemsService.updateItem(req.collection, req.params.pk, req.body, {
ip: req.ip,
userAgent: req.get('user-agent'),

View File

@@ -173,3 +173,36 @@ export const deleteItem = async (
.delete()
.where({ [primaryKeyField]: pk });
};
export const readSingleton = async (collection: string, query: Query = {}) => {
const records = await readItems(collection, { ...query, limit: 1 });
const record = records[0];
if (!record) {
const columns = await schemaInspector.columnInfo(collection);
const defaults = {};
for (const column of columns) {
defaults[column.name] = column.default_value;
}
return defaults;
}
return record;
};
export const upsertSingleton = async (
collection: string,
data: Record<string, any>,
accountability: Accountability
) => {
const primaryKeyField = await schemaInspector.primary(collection);
const record = await database.select(primaryKeyField).from(collection).limit(1).first();
if (record) {
return await updateItem(collection, record.id, data, accountability);
}
return await createItem(collection, data, accountability);
};

View File

@@ -1,36 +1,11 @@
import { Query } from '../types/query';
import * as ItemsService from './items';
import { Accountability } from '../types';
import database, { schemaInspector } from '../database';
export const readSettings = async (query: Query) => {
const settings = await ItemsService.readItems('directus_settings', {
...query,
limit: 1,
});
const settingsObj = settings[0];
if (!settingsObj) {
const settingsColumns = await schemaInspector.columnInfo('directus_settings');
const defaults = {};
for (const column of settingsColumns) {
defaults[column.name] = column.default_value;
}
return defaults;
}
return settingsObj;
return await ItemsService.readSingleton('directus_settings', query);
};
export const updateSettings = async (data: Record<string, any>, accountability: Accountability) => {
const record = await database.select('id').from('directus_settings').limit(1).first();
if (record) {
return await ItemsService.updateItem('directus_settings', record.id, data, accountability);
}
return await ItemsService.createItem('directus_settings', data, accountability);
return await ItemsService.upsertSingleton('directus_settings', data, accountability);
};