mirror of
https://github.com/directus/directus.git
synced 2026-01-24 00:18:08 -05:00
Add toArray util
This commit is contained in:
@@ -12,6 +12,7 @@ import { UsersService, AuthenticationService } from '../services';
|
||||
import grantConfig from '../grant';
|
||||
import { RouteNotFoundException } from '../exceptions';
|
||||
import { respond } from '../middleware/respond';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -213,7 +214,7 @@ router.post(
|
||||
router.get(
|
||||
'/oauth',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const providers = env.OAUTH_PROVIDERS as string[];
|
||||
const providers = toArray(env.OAUTH_PROVIDERS);
|
||||
res.locals.payload = { data: providers.length > 0 ? providers : null };
|
||||
return next();
|
||||
}),
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Query, Item } from '../types';
|
||||
import { PayloadService } from '../services/payload';
|
||||
import applyQuery from '../utils/apply-query';
|
||||
import Knex, { QueryBuilder } from 'knex';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
type RunASTOptions = {
|
||||
query?: AST['query'];
|
||||
@@ -172,7 +173,7 @@ function applyParentFilters(
|
||||
nestedCollectionNodes: NestedCollectionNode[],
|
||||
parentItem: Item | Item[]
|
||||
) {
|
||||
const parentItems = Array.isArray(parentItem) ? parentItem : [parentItem];
|
||||
const parentItems = toArray(parentItem);
|
||||
|
||||
for (const nestedNode of nestedCollectionNodes) {
|
||||
if (!nestedNode.relation) continue;
|
||||
@@ -245,8 +246,8 @@ function mergeWithParentItems(
|
||||
nestedNode: NestedCollectionNode,
|
||||
o2mLimit?: number | null
|
||||
) {
|
||||
const nestedItems = Array.isArray(nestedItem) ? nestedItem : [nestedItem];
|
||||
const parentItems = clone(Array.isArray(parentItem) ? parentItem : [parentItem]);
|
||||
const nestedItems = toArray(nestedItem);
|
||||
const parentItems = clone(toArray(parentItem));
|
||||
|
||||
if (nestedNode.type === 'm2o') {
|
||||
for (const parentItem of parentItems) {
|
||||
@@ -307,7 +308,7 @@ function removeTemporaryFields(
|
||||
primaryKeyField: string,
|
||||
parentItem?: Item
|
||||
): null | Item | Item[] {
|
||||
const rawItems = cloneDeep(Array.isArray(rawItem) ? rawItem : [rawItem]);
|
||||
const rawItems = cloneDeep(toArray(rawItem));
|
||||
const items: Item[] = [];
|
||||
|
||||
if (ast.type === 'm2a') {
|
||||
|
||||
@@ -2,13 +2,14 @@ import { ErrorRequestHandler } from 'express';
|
||||
import { BaseException } from '../exceptions';
|
||||
import logger from '../logger';
|
||||
import env from '../env';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
|
||||
let payload: any = {
|
||||
errors: [],
|
||||
};
|
||||
|
||||
const errors = Array.isArray(err) ? err : [err];
|
||||
const errors = toArray(err);
|
||||
|
||||
if (errors.some((err) => err instanceof BaseException === false)) {
|
||||
res.status(500);
|
||||
|
||||
@@ -18,6 +18,7 @@ import { uniq, merge, flatten } from 'lodash';
|
||||
import generateJoi from '../utils/generate-joi';
|
||||
import { ItemsService } from './items';
|
||||
import { parseFilter } from '../utils/parse-filter';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
export class AuthorizationService {
|
||||
knex: Knex;
|
||||
@@ -199,7 +200,7 @@ export class AuthorizationService {
|
||||
): Promise<Partial<Item>[] | Partial<Item>> {
|
||||
const validationErrors: FailedValidationException[] = [];
|
||||
|
||||
let payloads = Array.isArray(payload) ? payload : [payload];
|
||||
let payloads = toArray(payload);
|
||||
|
||||
let permission: Permission | undefined;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import SchemaInspector from 'knex-schema-inspector';
|
||||
import { FieldsService } from '../services/fields';
|
||||
import { ItemsService } from '../services/items';
|
||||
import cache from '../cache';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
export class CollectionsService {
|
||||
knex: Knex;
|
||||
@@ -23,7 +24,7 @@ export class CollectionsService {
|
||||
throw new ForbiddenException('Only admins can perform this action.');
|
||||
}
|
||||
|
||||
const payloads = (Array.isArray(data) ? data : [data]).map((collection) => {
|
||||
const payloads = toArray(data).map((collection) => {
|
||||
if (!collection.fields) collection.fields = [];
|
||||
|
||||
collection.fields = collection.fields.map((field) => {
|
||||
@@ -105,7 +106,7 @@ export class CollectionsService {
|
||||
knex: this.knex,
|
||||
accountability: this.accountability,
|
||||
});
|
||||
const collectionKeys = Array.isArray(collection) ? collection : [collection];
|
||||
const collectionKeys = toArray(collection);
|
||||
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
const permissions = await this.knex
|
||||
@@ -212,7 +213,7 @@ export class CollectionsService {
|
||||
throw new InvalidPayloadException(`"meta" key is required`);
|
||||
}
|
||||
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
|
||||
for (const key of keys) {
|
||||
const exists =
|
||||
@@ -232,7 +233,7 @@ export class CollectionsService {
|
||||
return key;
|
||||
}
|
||||
|
||||
const payloads = Array.isArray(data) ? data : [data];
|
||||
const payloads = toArray(data);
|
||||
|
||||
const collectionUpdates = payloads.map((collection) => {
|
||||
return {
|
||||
@@ -264,7 +265,7 @@ export class CollectionsService {
|
||||
|
||||
const tablesInDatabase = await schemaInspector.tables();
|
||||
|
||||
const collectionKeys = Array.isArray(collection) ? collection : [collection];
|
||||
const collectionKeys = toArray(collection);
|
||||
|
||||
for (const collectionKey of collectionKeys) {
|
||||
if (tablesInDatabase.includes(collectionKey) === false) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { AbstractServiceOptions, File, PrimaryKey } from '../types';
|
||||
import { clone } from 'lodash';
|
||||
import cache from '../cache';
|
||||
import { ForbiddenException } from '../exceptions';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
export class FilesService extends ItemsService {
|
||||
constructor(options?: AbstractServiceOptions) {
|
||||
@@ -89,14 +90,14 @@ export class FilesService extends ItemsService {
|
||||
delete(key: PrimaryKey): Promise<PrimaryKey>;
|
||||
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
||||
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
let files = await super.readByKey(keys, { fields: ['id', 'storage'] });
|
||||
|
||||
if (!files) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
files = Array.isArray(files) ? files : [files];
|
||||
files = toArray(files);
|
||||
|
||||
for (const file of files) {
|
||||
const disk = storage.disk(file.storage);
|
||||
|
||||
@@ -16,6 +16,7 @@ import Knex from 'knex';
|
||||
import cache from '../cache';
|
||||
import emitter from '../emitter';
|
||||
import logger from '../logger';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
import { PayloadService } from './payload';
|
||||
import { AuthorizationService } from './authorization';
|
||||
@@ -50,7 +51,7 @@ export class ItemsService implements AbstractService {
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const columns = await this.schemaInspector.columns(this.collection);
|
||||
|
||||
let payloads = clone(Array.isArray(data) ? data : [data]);
|
||||
let payloads = clone(toArray(data));
|
||||
|
||||
const savedPrimaryKeys = await this.knex.transaction(async (trx) => {
|
||||
const payloadService = new PayloadService(this.collection, {
|
||||
@@ -224,7 +225,7 @@ export class ItemsService implements AbstractService {
|
||||
): Promise<null | Item | Item[]> {
|
||||
query = clone(query);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
|
||||
if (keys.length === 1) {
|
||||
query.single = true;
|
||||
@@ -270,7 +271,7 @@ export class ItemsService implements AbstractService {
|
||||
|
||||
// Updating one or more items to the same payload
|
||||
if (data && key) {
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
|
||||
let payload = clone(data);
|
||||
|
||||
@@ -404,7 +405,7 @@ export class ItemsService implements AbstractService {
|
||||
knex: trx,
|
||||
});
|
||||
|
||||
const payloads = Array.isArray(data) ? data : [data];
|
||||
const payloads = toArray(data);
|
||||
|
||||
for (const single of payloads as Partial<Item>[]) {
|
||||
let payload = clone(single);
|
||||
@@ -432,7 +433,7 @@ export class ItemsService implements AbstractService {
|
||||
const itemsService = new ItemsService(this.collection, { knex: this.knex });
|
||||
|
||||
let itemsToUpdate = await itemsService.readByQuery(readQuery);
|
||||
itemsToUpdate = Array.isArray(itemsToUpdate) ? itemsToUpdate : [itemsToUpdate];
|
||||
itemsToUpdate = toArray(itemsToUpdate);
|
||||
|
||||
const keys: PrimaryKey[] = itemsToUpdate.map(
|
||||
(item: Partial<Item>) => item[primaryKeyField]
|
||||
@@ -445,7 +446,7 @@ export class ItemsService implements AbstractService {
|
||||
upsert(data: Partial<Item>): Promise<PrimaryKey>;
|
||||
async upsert(data: Partial<Item> | Partial<Item>[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const payloads = Array.isArray(data) ? data : [data];
|
||||
const payloads = toArray(data);
|
||||
const primaryKeys: PrimaryKey[] = [];
|
||||
|
||||
for (const payload of payloads) {
|
||||
@@ -473,7 +474,7 @@ export class ItemsService implements AbstractService {
|
||||
delete(key: PrimaryKey): Promise<PrimaryKey>;
|
||||
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
||||
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const keys = (Array.isArray(key) ? key : [key]) as PrimaryKey[];
|
||||
const keys = toArray(key);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
@@ -537,7 +538,7 @@ export class ItemsService implements AbstractService {
|
||||
const itemsService = new ItemsService(this.collection);
|
||||
|
||||
let itemsToDelete = await itemsService.readByQuery(readQuery);
|
||||
itemsToDelete = Array.isArray(itemsToDelete) ? itemsToDelete : [itemsToDelete];
|
||||
itemsToDelete = toArray(itemsToDelete);
|
||||
|
||||
const keys: PrimaryKey[] = itemsToDelete.map(
|
||||
(item: Partial<Item>) => item[primaryKeyField]
|
||||
|
||||
@@ -16,6 +16,7 @@ import SchemaInspector from 'knex-schema-inspector';
|
||||
import getLocalType from '../utils/get-local-type';
|
||||
import { format, formatISO } from 'date-fns';
|
||||
import { ForbiddenException } from '../exceptions';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
type Action = 'create' | 'read' | 'update';
|
||||
|
||||
@@ -141,7 +142,7 @@ export class PayloadService {
|
||||
action: Action,
|
||||
payload: Partial<Item> | Partial<Item>[]
|
||||
): Promise<Partial<Item> | Partial<Item>[]> {
|
||||
let processedPayload = (Array.isArray(payload) ? payload : [payload]) as Partial<Item>[];
|
||||
let processedPayload = toArray(payload);
|
||||
|
||||
if (processedPayload.length === 0) return [];
|
||||
|
||||
@@ -338,7 +339,7 @@ export class PayloadService {
|
||||
.from('directus_relations')
|
||||
.where({ one_collection: this.collection });
|
||||
|
||||
const payloads = clone(Array.isArray(payload) ? payload : [payload]);
|
||||
const payloads = clone(toArray(payload));
|
||||
|
||||
for (let i = 0; i < payloads.length; i++) {
|
||||
let payload = payloads[i];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ItemsService } from './items';
|
||||
import { AbstractServiceOptions, Query, PrimaryKey, PermissionsAction, Relation } from '../types';
|
||||
import { PermissionsService } from './permissions';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
/**
|
||||
* @TODO update foreign key constraints when relations are updated
|
||||
@@ -62,7 +63,7 @@ export class RelationsService extends ItemsService {
|
||||
'read'
|
||||
);
|
||||
|
||||
relations = Array.isArray(relations) ? relations : [relations];
|
||||
relations = toArray(relations);
|
||||
|
||||
return relations.filter((relation) => {
|
||||
let collectionsAllowed = true;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PermissionsService } from './permissions';
|
||||
import { UsersService } from './users';
|
||||
import { PresetsService } from './presets';
|
||||
import { UnprocessableEntityException } from '../exceptions';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
export class RolesService extends ItemsService {
|
||||
constructor(options?: AbstractServiceOptions) {
|
||||
@@ -13,7 +14,7 @@ export class RolesService extends ItemsService {
|
||||
delete(key: PrimaryKey): Promise<PrimaryKey>;
|
||||
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
||||
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
|
||||
// Make sure there's at least one admin role left after this deletion is done
|
||||
const otherAdminRoles = await this.knex
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Accountability, PrimaryKey, Item, AbstractServiceOptions } from '../typ
|
||||
import Knex from 'knex';
|
||||
import env from '../env';
|
||||
import cache from '../cache';
|
||||
import { toArray } from '../utils/to-array';
|
||||
|
||||
export class UsersService extends ItemsService {
|
||||
knex: Knex;
|
||||
@@ -39,7 +40,7 @@ export class UsersService extends ItemsService {
|
||||
* This is just an extra bit of hardcoded security. We don't want anybody to be able to disable 2fa through
|
||||
* the regular /users endpoint. Period. You should only be able to manage the 2fa status through the /tfa endpoint.
|
||||
*/
|
||||
const payloads = Array.isArray(data) ? data : [data];
|
||||
const payloads = toArray(data);
|
||||
|
||||
for (const payload of payloads) {
|
||||
if (payload.hasOwnProperty('tfa_secret')) {
|
||||
@@ -57,7 +58,7 @@ export class UsersService extends ItemsService {
|
||||
delete(key: PrimaryKey): Promise<PrimaryKey>;
|
||||
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
||||
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
const keys = toArray(key);
|
||||
|
||||
// Make sure there's at least one admin user left after this deletion is done
|
||||
const otherAdminUsers = await this.knex
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import env from './env';
|
||||
import { validateEnv } from './utils/validate-env';
|
||||
import { getConfigFromEnv } from './utils/get-config-from-env';
|
||||
import { toArray } from './utils/to-array';
|
||||
|
||||
/** @todo dynamically load these storage adapters */
|
||||
import { AmazonWebServicesS3Storage } from '@slynova/flydrive-s3';
|
||||
@@ -25,7 +26,7 @@ function getStorageConfig(): StorageManagerConfig {
|
||||
disks: {},
|
||||
};
|
||||
|
||||
const locations = env.STORAGE_LOCATIONS as string[];
|
||||
const locations = toArray(env.STORAGE_LOCATIONS);
|
||||
|
||||
locations.forEach((location: string) => {
|
||||
location = location.trim();
|
||||
|
||||
3
api/src/utils/to-array.ts
Normal file
3
api/src/utils/to-array.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function toArray<T = any>(val: T | T[]): T[] {
|
||||
return Array.isArray(val) ? val : [val];
|
||||
}
|
||||
Reference in New Issue
Block a user