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:
Pascal Jufer
2021-04-29 18:11:43 +02:00
committed by GitHub
parent 40eba791fa
commit acd41eb0be
231 changed files with 646 additions and 527 deletions

View File

@@ -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')

View File

@@ -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) {

View File

@@ -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, {

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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: {

View File

@@ -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();

View File

@@ -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 || {};

View File

@@ -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]) =>

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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 });
}

View File

@@ -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;