mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Syntax fixes (#5367)
* Declare return types on functions And a very few other type related minor fixes * Minor syntax fixes * Remove unnecessary escape chars in regexes * Remove unnecessary awaits * Replace deprecated req.connection with req.socket * Replace deprecated upload with uploadOne * Remove unnecessary eslint-disable-next-line comments * Comment empty functions / catch or finally clauses * Fix irregular whitespaces * Add missing returns (null) * Remove unreachable code * A few logical fixes * Remove / Handle non-null assertions which are certainly unnecessary (e.g. in tests)
This commit is contained in:
@@ -5,7 +5,7 @@ import path from 'path';
|
||||
import { Knex } from 'knex';
|
||||
import { Accountability, AbstractServiceOptions, Transformation } from '../types';
|
||||
import { AuthorizationService } from './authorization';
|
||||
import { Range } from '@directus/drive';
|
||||
import { Range, StatResponse } from '@directus/drive';
|
||||
import { RangeNotSatisfiableException } from '../exceptions';
|
||||
|
||||
export class AssetsService {
|
||||
@@ -19,7 +19,11 @@ export class AssetsService {
|
||||
this.authorizationService = new AuthorizationService(options);
|
||||
}
|
||||
|
||||
async getAsset(id: string, transformation: Transformation, range?: Range) {
|
||||
async getAsset(
|
||||
id: string,
|
||||
transformation: Transformation,
|
||||
range?: Range
|
||||
): Promise<{ stream: NodeJS.ReadableStream; file: any; stat: StatResponse }> {
|
||||
const publicSettings = await this.knex
|
||||
.select('project_logo', 'public_background', 'public_foreground')
|
||||
.from('directus_settings')
|
||||
|
||||
@@ -50,7 +50,9 @@ export class AuthenticationService {
|
||||
* Password is optional to allow usage of this function within the SSO flow and extensions. Make sure
|
||||
* to handle password existence checks elsewhere
|
||||
*/
|
||||
async authenticate(options: AuthenticateOptions) {
|
||||
async authenticate(
|
||||
options: AuthenticateOptions
|
||||
): Promise<{ accessToken: any; refreshToken: any; expires: any; id?: any }> {
|
||||
const settingsService = new SettingsService({
|
||||
knex: this.knex,
|
||||
schema: this.schema,
|
||||
@@ -196,7 +198,7 @@ export class AuthenticationService {
|
||||
};
|
||||
}
|
||||
|
||||
async refresh(refreshToken: string) {
|
||||
async refresh(refreshToken: string): Promise<Record<string, any>> {
|
||||
if (!refreshToken) {
|
||||
throw new InvalidCredentialsException();
|
||||
}
|
||||
@@ -235,16 +237,16 @@ export class AuthenticationService {
|
||||
};
|
||||
}
|
||||
|
||||
async logout(refreshToken: string) {
|
||||
async logout(refreshToken: string): Promise<void> {
|
||||
await this.knex.delete().from('directus_sessions').where({ token: refreshToken });
|
||||
}
|
||||
|
||||
generateTFASecret() {
|
||||
generateTFASecret(): string {
|
||||
const secret = authenticator.generateSecret();
|
||||
return secret;
|
||||
}
|
||||
|
||||
async generateOTPAuthURL(pk: string, secret: string) {
|
||||
async generateOTPAuthURL(pk: string, secret: string): Promise<string> {
|
||||
const user = await this.knex.select('first_name', 'last_name').from('directus_users').where({ id: pk }).first();
|
||||
const name = `${user.first_name} ${user.last_name}`;
|
||||
return authenticator.keyuri(name, 'Directus', secret);
|
||||
@@ -261,7 +263,7 @@ export class AuthenticationService {
|
||||
return authenticator.check(otp, secret);
|
||||
}
|
||||
|
||||
async verifyPassword(pk: string, password: string) {
|
||||
async verifyPassword(pk: string, password: string): Promise<boolean> {
|
||||
const userRecord = await this.knex.select('password').from('directus_users').where({ id: pk }).first();
|
||||
|
||||
if (!userRecord || !userRecord.password) {
|
||||
|
||||
@@ -304,7 +304,7 @@ export class AuthorizationService {
|
||||
return errors;
|
||||
}
|
||||
|
||||
async checkAccess(action: PermissionsAction, collection: string, pk: PrimaryKey | PrimaryKey[]) {
|
||||
async checkAccess(action: PermissionsAction, collection: string, pk: PrimaryKey | PrimaryKey[]): Promise<void> {
|
||||
if (this.accountability?.admin === true) return;
|
||||
|
||||
const itemsService = new ItemsService(collection, {
|
||||
|
||||
@@ -114,7 +114,10 @@ export class CollectionsService {
|
||||
/**
|
||||
* Create multiple new collections
|
||||
*/
|
||||
async createMany(payloads: Partial<Collection> & { collection: string }[], opts?: MutationOptions) {
|
||||
async createMany(
|
||||
payloads: Partial<Collection> & { collection: string }[],
|
||||
opts?: MutationOptions
|
||||
): Promise<string[]> {
|
||||
const collections = await this.knex.transaction(async (trx) => {
|
||||
const service = new CollectionsService({
|
||||
schema: this.schema,
|
||||
|
||||
@@ -157,7 +157,7 @@ export class FieldsService {
|
||||
return result;
|
||||
}
|
||||
|
||||
async readOne(collection: string, field: string) {
|
||||
async readOne(collection: string, field: string): Promise<Record<string, any>> {
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
if (this.hasReadAccess === false) {
|
||||
throw new ForbiddenException();
|
||||
@@ -188,7 +188,9 @@ export class FieldsService {
|
||||
try {
|
||||
column = await this.schemaInspector.columnInfo(collection, field);
|
||||
column.default_value = getDefaultValue(column);
|
||||
} catch {}
|
||||
} finally {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
const data = {
|
||||
collection,
|
||||
@@ -205,7 +207,7 @@ export class FieldsService {
|
||||
collection: string,
|
||||
field: Partial<Field> & { field: string; type: typeof types[number] },
|
||||
table?: Knex.CreateTableBuilder // allows collection creation to
|
||||
) {
|
||||
): Promise<void> {
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
throw new ForbiddenException('Only admins can perform this action.');
|
||||
}
|
||||
@@ -246,7 +248,7 @@ export class FieldsService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateField(collection: string, field: RawField) {
|
||||
async updateField(collection: string, field: RawField): Promise<string> {
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
throw new ForbiddenException('Only admins can perform this action');
|
||||
}
|
||||
@@ -289,7 +291,7 @@ export class FieldsService {
|
||||
}
|
||||
|
||||
/** @todo save accountability */
|
||||
async deleteField(collection: string, field: string) {
|
||||
async deleteField(collection: string, field: string): Promise<void> {
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
throw new ForbiddenException('Only admins can perform this action.');
|
||||
}
|
||||
@@ -375,7 +377,7 @@ export class FieldsService {
|
||||
});
|
||||
}
|
||||
|
||||
public addColumnToTable(table: Knex.CreateTableBuilder, field: RawField | Field, alter: Column | null = null) {
|
||||
public addColumnToTable(table: Knex.CreateTableBuilder, field: RawField | Field, alter: Column | null = null): void {
|
||||
let column: Knex.ColumnBuilder;
|
||||
|
||||
if (field.schema?.has_auto_increment) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class FilesService extends ItemsService {
|
||||
stream: NodeJS.ReadableStream,
|
||||
data: Partial<File> & { filename_download: string; storage: string },
|
||||
primaryKey?: PrimaryKey
|
||||
) {
|
||||
): Promise<PrimaryKey> {
|
||||
const payload = clone(data);
|
||||
|
||||
if (primaryKey !== undefined) {
|
||||
@@ -140,7 +140,7 @@ export class FilesService extends ItemsService {
|
||||
/**
|
||||
* Import a single file from an external URL
|
||||
*/
|
||||
async importOne(importURL: string, body: Partial<File>) {
|
||||
async importOne(importURL: string, body: Partial<File>): Promise<PrimaryKey> {
|
||||
const fileCreatePermissions = this.schema.permissions.find(
|
||||
(permission) => permission.collection === 'directus_files' && permission.action === 'create'
|
||||
);
|
||||
@@ -174,7 +174,7 @@ export class FilesService extends ItemsService {
|
||||
...(body || {}),
|
||||
};
|
||||
|
||||
return await this.upload(fileResponse.data, payload);
|
||||
return await this.uploadOne(fileResponse.data, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,7 +220,7 @@ export class FilesService extends ItemsService {
|
||||
stream: NodeJS.ReadableStream,
|
||||
data: Partial<File> & { filename_download: string; storage: string },
|
||||
primaryKey?: PrimaryKey
|
||||
) {
|
||||
): Promise<PrimaryKey> {
|
||||
logger.warn('FilesService.upload is deprecated and will be removed before v9.0.0. Use uploadOne instead.');
|
||||
|
||||
return await this.uploadOne(stream, data, primaryKey);
|
||||
@@ -229,7 +229,7 @@ export class FilesService extends ItemsService {
|
||||
/**
|
||||
* @deprecated Use `importOne` instead
|
||||
*/
|
||||
async import(importURL: string, body: Partial<File>) {
|
||||
async import(importURL: string, body: Partial<File>): Promise<PrimaryKey> {
|
||||
return await this.importOne(importURL, body);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Knex } from 'knex';
|
||||
import database from '../database';
|
||||
import { AbstractServiceOptions, Accountability, Query, SchemaOverview, GraphQLParams, Action } from '../types';
|
||||
import { AbstractServiceOptions, Accountability, Query, SchemaOverview, GraphQLParams, Action, Item } from '../types';
|
||||
import argon2 from 'argon2';
|
||||
import {
|
||||
GraphQLString,
|
||||
@@ -122,7 +122,12 @@ export class GraphQLService {
|
||||
/**
|
||||
* Execute a GraphQL structure
|
||||
*/
|
||||
async execute({ document, variables, operationName, contextValue }: GraphQLParams) {
|
||||
async execute({
|
||||
document,
|
||||
variables,
|
||||
operationName,
|
||||
contextValue,
|
||||
}: GraphQLParams): Promise<FormattedExecutionResult> {
|
||||
const schema = this.getSchema();
|
||||
|
||||
const validationErrors = validate(schema, document, specifiedRules);
|
||||
@@ -158,8 +163,9 @@ export class GraphQLService {
|
||||
*/
|
||||
getSchema(): GraphQLSchema;
|
||||
getSchema(type: 'schema'): GraphQLSchema;
|
||||
getSchema(type: 'sdl'): string;
|
||||
getSchema(type: 'schema' | 'sdl' = 'schema') {
|
||||
getSchema(type: 'sdl'): GraphQLSchema | string;
|
||||
getSchema(type: 'schema' | 'sdl' = 'schema'): GraphQLSchema | string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
|
||||
const schemaComposer = new SchemaComposer<GraphQLParams['contextValue']>();
|
||||
@@ -798,7 +804,7 @@ export class GraphQLService {
|
||||
* Generic resolver that's used for every "regular" items/system query. Converts the incoming GraphQL AST / fragments into
|
||||
* Directus' query structure which is then executed by the services.
|
||||
*/
|
||||
async resolveQuery(info: GraphQLResolveInfo) {
|
||||
async resolveQuery(info: GraphQLResolveInfo): Promise<Partial<Item> | null> {
|
||||
let collection = info.fieldName;
|
||||
if (this.scope === 'system') collection = `directus_${collection}`;
|
||||
|
||||
@@ -841,7 +847,10 @@ export class GraphQLService {
|
||||
* Generic mutation resolver that converts the incoming GraphQL mutation AST into a Directus query and executes the
|
||||
* appropriate C-UD operation
|
||||
*/
|
||||
async resolveMutation(args: Record<string, any>, info: GraphQLResolveInfo) {
|
||||
async resolveMutation(
|
||||
args: Record<string, any>,
|
||||
info: GraphQLResolveInfo
|
||||
): Promise<Partial<Item> | boolean | undefined> {
|
||||
const action = info.fieldName.split('_')[0] as 'create' | 'update' | 'delete';
|
||||
let collection = info.fieldName.substring(action.length + 1);
|
||||
if (this.scope === 'system') collection = `directus_${collection}`;
|
||||
@@ -906,7 +915,7 @@ export class GraphQLService {
|
||||
/**
|
||||
* Execute the read action on the correct service. Checks for singleton as well.
|
||||
*/
|
||||
async read(collection: string, query: Query) {
|
||||
async read(collection: string, query: Query): Promise<Partial<Item>> {
|
||||
const service = this.getService(collection);
|
||||
|
||||
const result = this.schema.collections[collection].singleton
|
||||
@@ -919,7 +928,11 @@ export class GraphQLService {
|
||||
/**
|
||||
* Upsert and read singleton item
|
||||
*/
|
||||
async upsertSingleton(collection: string, body: Record<string, any> | Record<string, any>[], query: Query) {
|
||||
async upsertSingleton(
|
||||
collection: string,
|
||||
body: Record<string, any> | Record<string, any>[],
|
||||
query: Query
|
||||
): Promise<Partial<Item> | boolean> {
|
||||
const service = this.getService(collection);
|
||||
|
||||
try {
|
||||
@@ -988,7 +1001,7 @@ export class GraphQLService {
|
||||
rawQuery: Query,
|
||||
selections: readonly SelectionNode[],
|
||||
variableValues: GraphQLResolveInfo['variableValues']
|
||||
) {
|
||||
): Query {
|
||||
const query: Query = sanitizeQuery(rawQuery, this.accountability);
|
||||
|
||||
const parseFields = (selections: readonly SelectionNode[], parent?: string): string[] => {
|
||||
@@ -1052,7 +1065,7 @@ export class GraphQLService {
|
||||
/**
|
||||
* Convert Directus-Exception into a GraphQL format, so it can be returned by GraphQL properly.
|
||||
*/
|
||||
formatError(error: BaseException | BaseException[]) {
|
||||
formatError(error: BaseException | BaseException[]): GraphQLError {
|
||||
if (Array.isArray(error)) {
|
||||
return new GraphQLError(error[0].message, undefined, undefined, undefined, undefined, error[0]);
|
||||
}
|
||||
@@ -1064,7 +1077,7 @@ export class GraphQLService {
|
||||
* Select the correct service for the given collection. This allows the individual services to run
|
||||
* their custom checks (f.e. it allows UsersService to prevent updating TFA secret from outside)
|
||||
*/
|
||||
getService(collection: string) {
|
||||
getService(collection: string): RolesService {
|
||||
const opts = {
|
||||
knex: this.knex,
|
||||
accountability: this.accountability,
|
||||
@@ -1150,7 +1163,7 @@ export class GraphQLService {
|
||||
update: SchemaOverview;
|
||||
delete: SchemaOverview;
|
||||
}
|
||||
) {
|
||||
): SchemaComposer<any> {
|
||||
const AuthTokens = schemaComposer.createObjectTC({
|
||||
name: 'auth_tokens',
|
||||
fields: {
|
||||
|
||||
@@ -527,7 +527,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
|
||||
/**
|
||||
* Upsert a single item
|
||||
*/
|
||||
async upsertOne(payload: Partial<Item>, opts?: MutationOptions) {
|
||||
async upsertOne(payload: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey> {
|
||||
const primaryKeyField = this.schema.collections[this.collection].primary;
|
||||
const primaryKey: PrimaryKey | undefined = payload[primaryKeyField];
|
||||
|
||||
@@ -549,7 +549,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
|
||||
/**
|
||||
* Upsert many items
|
||||
*/
|
||||
async upsertMany(payloads: Partial<Item>[], opts?: MutationOptions) {
|
||||
async upsertMany(payloads: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]> {
|
||||
const primaryKeys = await this.knex.transaction(async (trx) => {
|
||||
const service = new ItemsService(this.collection, {
|
||||
accountability: this.accountability,
|
||||
@@ -702,7 +702,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
|
||||
/**
|
||||
* Upsert/treat collection as singleton
|
||||
*/
|
||||
async upsertSingleton(data: Partial<Item>, opts?: MutationOptions) {
|
||||
async upsertSingleton(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey> {
|
||||
const primaryKeyField = this.schema.collections[this.collection].primary;
|
||||
const record = await this.knex.select(primaryKeyField).from(this.collection).limit(1).first();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export class MetaService {
|
||||
this.schema = options.schema;
|
||||
}
|
||||
|
||||
async getMetaForQuery(collection: string, query: Query) {
|
||||
async getMetaForQuery(collection: string, query: Query): Promise<Record<string, any> | undefined> {
|
||||
if (!query || !query.meta) return;
|
||||
|
||||
const results = await Promise.all(
|
||||
@@ -35,7 +35,7 @@ export class MetaService {
|
||||
}, {});
|
||||
}
|
||||
|
||||
async totalCount(collection: string) {
|
||||
async totalCount(collection: string): Promise<number> {
|
||||
const dbQuery = this.knex(collection).count('*', { as: 'count' }).first();
|
||||
|
||||
if (this.accountability?.admin !== true) {
|
||||
@@ -55,7 +55,7 @@ export class MetaService {
|
||||
return Number(result?.count ?? 0);
|
||||
}
|
||||
|
||||
async filterCount(collection: string, query: Query) {
|
||||
async filterCount(collection: string, query: Query): Promise<number> {
|
||||
const dbQuery = this.knex(collection).count('*', { as: 'count' });
|
||||
|
||||
let filter = query.filter || {};
|
||||
|
||||
@@ -191,7 +191,7 @@ export class PayloadService {
|
||||
payload: Partial<Item>,
|
||||
action: Action,
|
||||
accountability: Accountability | null
|
||||
) {
|
||||
): Promise<any> {
|
||||
if (!field.special) return payload[field.field];
|
||||
const fieldSpecials = field.special ? toArray(field.special) : [];
|
||||
|
||||
@@ -215,7 +215,10 @@ export class PayloadService {
|
||||
* Knex returns `datetime` and `date` columns as Date.. This is wrong for date / datetime, as those
|
||||
* shouldn't return with time / timezone info respectively
|
||||
*/
|
||||
async processDates(payloads: Partial<Record<string, any>>[], action: Action) {
|
||||
async processDates(
|
||||
payloads: Partial<Record<string, any>>[],
|
||||
action: Action
|
||||
): Promise<Partial<Record<string, any>>[]> {
|
||||
const fieldsInCollection = Object.entries(this.schema.collections[this.collection].fields);
|
||||
|
||||
const dateColumns = fieldsInCollection.filter(([name, field]) =>
|
||||
|
||||
@@ -10,7 +10,7 @@ export class PermissionsService extends ItemsService {
|
||||
super('directus_permissions', options);
|
||||
}
|
||||
|
||||
getAllowedFields(action: PermissionsAction, collection?: string) {
|
||||
getAllowedFields(action: PermissionsAction, collection?: string): Record<string, string[]> {
|
||||
const results = this.schema.permissions.filter((permission) => {
|
||||
let matchesCollection = true;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export class RevisionsService extends ItemsService {
|
||||
super('directus_revisions', options);
|
||||
}
|
||||
|
||||
async revert(pk: PrimaryKey) {
|
||||
async revert(pk: PrimaryKey): Promise<void> {
|
||||
const revision = await super.readOne(pk);
|
||||
|
||||
if (!revision) throw new ForbiddenException();
|
||||
|
||||
@@ -30,7 +30,7 @@ export class ServerService {
|
||||
this.settingsService = new SettingsService({ knex: this.knex, schema: this.schema });
|
||||
}
|
||||
|
||||
async serverInfo() {
|
||||
async serverInfo(): Promise<Record<string, any>> {
|
||||
const info: Record<string, any> = {};
|
||||
|
||||
const projectInfo = await this.settingsService.readSingleton({
|
||||
@@ -70,7 +70,7 @@ export class ServerService {
|
||||
return info;
|
||||
}
|
||||
|
||||
async health() {
|
||||
async health(): Promise<Record<string, any>> {
|
||||
const checkID = nanoid(5);
|
||||
|
||||
// Based on https://tools.ietf.org/id/draft-inadarei-api-health-check-05.html#name-componenttype
|
||||
|
||||
@@ -217,7 +217,7 @@ export class UsersService extends ItemsService {
|
||||
return keys;
|
||||
}
|
||||
|
||||
async inviteUser(email: string | string[], role: string, url: string | null) {
|
||||
async inviteUser(email: string | string[], role: string, url: string | null): Promise<void> {
|
||||
const emails = toArray(email);
|
||||
|
||||
const urlWhitelist = toArray(env.USER_INVITE_URL_ALLOW_LIST);
|
||||
@@ -263,7 +263,7 @@ export class UsersService extends ItemsService {
|
||||
});
|
||||
}
|
||||
|
||||
async acceptInvite(token: string, password: string) {
|
||||
async acceptInvite(token: string, password: string): Promise<void> {
|
||||
const { email, scope } = jwt.verify(token, env.SECRET as string) as {
|
||||
email: string;
|
||||
scope: string;
|
||||
@@ -286,7 +286,7 @@ export class UsersService extends ItemsService {
|
||||
}
|
||||
}
|
||||
|
||||
async requestPasswordReset(email: string, url: string | null) {
|
||||
async requestPasswordReset(email: string, url: string | null): Promise<void> {
|
||||
const user = await this.knex.select('id').from('directus_users').where({ email }).first();
|
||||
if (!user) throw new ForbiddenException();
|
||||
|
||||
@@ -321,7 +321,7 @@ export class UsersService extends ItemsService {
|
||||
});
|
||||
}
|
||||
|
||||
async resetPassword(token: string, password: string) {
|
||||
async resetPassword(token: string, password: string): Promise<void> {
|
||||
const { email, scope } = jwt.verify(token, env.SECRET as string) as {
|
||||
email: string;
|
||||
scope: string;
|
||||
@@ -344,7 +344,7 @@ export class UsersService extends ItemsService {
|
||||
}
|
||||
}
|
||||
|
||||
async enableTFA(pk: string) {
|
||||
async enableTFA(pk: string): Promise<Record<string, string>> {
|
||||
const user = await this.knex.select('tfa_secret').from('directus_users').where({ id: pk }).first();
|
||||
|
||||
if (user?.tfa_secret !== null) {
|
||||
@@ -366,7 +366,7 @@ export class UsersService extends ItemsService {
|
||||
};
|
||||
}
|
||||
|
||||
async disableTFA(pk: string) {
|
||||
async disableTFA(pk: string): Promise<void> {
|
||||
await this.knex('directus_users').update({ tfa_secret: null }).where({ id: pk });
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export class UtilsService {
|
||||
this.schema = options.schema;
|
||||
}
|
||||
|
||||
async sort(collection: string, { item, to }: { item: PrimaryKey; to: PrimaryKey }) {
|
||||
async sort(collection: string, { item, to }: { item: PrimaryKey; to: PrimaryKey }): Promise<void> {
|
||||
const sortFieldResponse =
|
||||
(await this.knex.select('sort_field').from('directus_collections').where({ collection }).first()) ||
|
||||
systemCollectionRows;
|
||||
|
||||
Reference in New Issue
Block a user