Change some typescript compilation options and fix eslint

This commit is contained in:
Caramel 2023-06-15 13:09:23 +02:00
parent 3b6244461e
commit b8db72bac4
No known key found for this signature in database
175 changed files with 627 additions and 540 deletions

View File

@ -1,3 +1,22 @@
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.cjs', 'dist', '*.exclude.*'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
},
root: true,
};

View File

@ -1,27 +1,9 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin', 'require-extensions'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:require-extensions/recommended',
],
extends: ['../.eslintrc.cjs'],
root: false,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.cjs'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

View File

@ -19,7 +19,6 @@
"migrate": "PICSUR_PRODUCTION=\"true\" yarn typeorm migration:generate -d ./src/datasource.ts",
"format": "prettier --write \"src/**/*.ts\"",
"clean": "rimraf dist",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"purge": "rm -rf dist && rm -rf node_modules"
},
"dependencies": {
@ -40,10 +39,9 @@
"bcrypt": "^5.1.0",
"bmp-img": "^1.2.1",
"cors": "^2.8.5",
"eslint-plugin-require-extensions": "^0.1.3",
"file-type": "^18.5.0",
"is-docker": "^3.0.0",
"ms": "^2.1.3",
"ms": "3.0.0-canary.1",
"node-fetch": "^3.3.1",
"p-timeout": "^6.1.1",
"passport": "^0.6.0",
@ -77,11 +75,6 @@
"@types/passport-strategy": "^0.2.35",
"@types/sharp": "^0.32.0",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.8",
"source-map-support": "^0.5.21",
"ts-loader": "^9.4.3",

View File

@ -30,7 +30,7 @@ const imageCorsConfig = cors({
const imageCorsOverride = (
req: IncomingMessage,
res: ServerResponse,
next: Function,
next: () => void,
) => {
res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');

View File

@ -1,6 +1,11 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { FindResult } from 'picsur-shared/dist/types/find-result';
import { generateRandomString } from 'picsur-shared/dist/util/random';
import { Repository } from 'typeorm';

View File

@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types/failable';
import { FindResult } from 'picsur-shared/dist/types/find-result';
import { generateRandomString } from 'picsur-shared/dist/util/random';
import { In, LessThan, Repository } from 'typeorm';

View File

@ -1,7 +1,12 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ImageEntryVariant } from 'picsur-shared/dist/dto/image-entry-variant.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { LessThan, Repository } from 'typeorm';
import { EImageDerivativeBackend } from '../../database/entities/images/image-derivative.entity';
import { EImageFileBackend } from '../../database/entities/images/image-file.entity';

View File

@ -10,7 +10,7 @@ import {
Failable,
FT,
HasFailed,
} from 'picsur-shared/dist/types';
} from 'picsur-shared/dist/types/failable';
type Enum = Record<string, string>;
type EnumValue<E> = E[keyof E];

View File

@ -11,7 +11,12 @@ import {
SysPreferenceValidators,
SysPreferenceValueTypes,
} from 'picsur-shared/dist/dto/sys-preferences.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { Repository } from 'typeorm';
import {
ESysPreferenceBackend,
@ -37,7 +42,7 @@ export class SysPreferenceDbService {
value: PrefValueType,
): AsyncFailable<DecodedSysPref> {
// Validate
let sysPreference = await this.encodeSysPref(key, value);
const sysPreference = await this.encodeSysPref(key, value);
if (HasFailed(sysPreference)) return sysPreference;
// Set
@ -60,7 +65,7 @@ export class SysPreferenceDbService {
public async getPreference(key: string): AsyncFailable<DecodedSysPref> {
// Validate
let validatedKey = this.prefCommon.validatePrefKey(key, SysPreference);
const validatedKey = this.prefCommon.validatePrefKey(key, SysPreference);
if (HasFailed(validatedKey)) return validatedKey;
// See the comment in 'mutex-fallback.ts' for why we are using a mutex here
@ -112,7 +117,7 @@ export class SysPreferenceDbService {
key: string,
type: PrefValueTypeStrings,
): AsyncFailable<PrefValueType> {
let pref = await this.getPreference(key);
const pref = await this.getPreference(key);
if (HasFailed(pref)) return pref;
if (pref.type !== type)
return Fail(FT.UsrValidation, 'Invalid preference type');
@ -122,7 +127,7 @@ export class SysPreferenceDbService {
public async getAllPreferences(): AsyncFailable<DecodedSysPref[]> {
// TODO: We are fetching each value invidually, we should fetch all at once
let internalSysPrefs = await Promise.all(
const internalSysPrefs = await Promise.all(
SysPreferenceList.map((key) => this.getPreference(key)),
);
if (internalSysPrefs.some((pref) => HasFailed(pref))) {
@ -158,7 +163,7 @@ export class SysPreferenceDbService {
return Fail(FT.UsrValidation, undefined, valueValidated.error);
}
let verifySysPreference = new ESysPreferenceBackend();
const verifySysPreference = new ESysPreferenceBackend();
verifySysPreference.key = validated.key;
verifySysPreference.value = validated.value;

View File

@ -11,7 +11,12 @@ import {
UsrPreferenceValidators,
UsrPreferenceValueTypes,
} from 'picsur-shared/dist/dto/usr-preferences.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { Repository } from 'typeorm';
import {
EUsrPreferenceBackend,
@ -38,7 +43,7 @@ export class UsrPreferenceDbService {
value: PrefValueType,
): AsyncFailable<DecodedUsrPref> {
// Validate
let usrPreference = await this.encodeUsrPref(userid, key, value);
const usrPreference = await this.encodeUsrPref(userid, key, value);
if (HasFailed(usrPreference)) return usrPreference;
// Set
@ -66,7 +71,7 @@ export class UsrPreferenceDbService {
key: string,
): AsyncFailable<DecodedUsrPref> {
// Validate
let validatedKey = this.prefCommon.validatePrefKey(key, UsrPreference);
const validatedKey = this.prefCommon.validatePrefKey(key, UsrPreference);
if (HasFailed(validatedKey)) return validatedKey;
// See the comment in 'mutex-fallback.ts' for why we are using a mutex here
@ -145,7 +150,7 @@ export class UsrPreferenceDbService {
key: string,
type: PrefValueTypeStrings,
): AsyncFailable<PrefValueType> {
let pref = await this.getPreference(userid, key);
const pref = await this.getPreference(userid, key);
if (HasFailed(pref)) return pref;
if (pref.type !== type)
return Fail(FT.UsrValidation, 'Invalid preference type');
@ -157,7 +162,7 @@ export class UsrPreferenceDbService {
userid: string,
): AsyncFailable<DecodedUsrPref[]> {
// TODO: We are fetching each value invidually, we should fetch all at once
let internalSysPrefs = await Promise.all(
const internalSysPrefs = await Promise.all(
UsrPreferenceList.map((key) => this.getPreference(userid, key)),
);
if (internalSysPrefs.some((pref) => HasFailed(pref))) {
@ -199,7 +204,7 @@ export class UsrPreferenceDbService {
return Fail(FT.UsrValidation, undefined, valueValidated.error);
}
let verifySysPreference = new EUsrPreferenceBackend();
const verifySysPreference = new EUsrPreferenceBackend();
verifySysPreference.key = validated.key;
verifySysPreference.value = validated.value;
verifySysPreference.user_id = userid;

View File

@ -1,6 +1,6 @@
import { Logger, Module, OnModuleInit } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { EarlyConfigModule } from '../../config/early/early-config.module';
import { HostConfigService } from '../../config/early/host.config.service';
import { ERoleBackend } from '../../database/entities/users/role.entity';

View File

@ -7,7 +7,7 @@ import {
FT,
HasFailed,
HasSuccess,
} from 'picsur-shared/dist/types';
} from 'picsur-shared/dist/types/failable';
import { makeUnique } from 'picsur-shared/dist/util/unique';
import { In, Repository } from 'typeorm';
import { ERoleBackend } from '../../database/entities/users/role.entity';
@ -33,7 +33,7 @@ export class RoleDbService {
if (await this.exists(name))
return Fail(FT.Conflict, 'Role already exists');
let role = new ERoleBackend();
const role = new ERoleBackend();
role.name = name;
role.permissions = permissions;
@ -105,7 +105,7 @@ export class RoleDbService {
role: string | ERoleBackend,
permissions: Permissions,
// Extra bypass for internal use
allowImmutable: boolean = false,
allowImmutable = false,
): AsyncFailable<ERoleBackend> {
const roleToModify = await this.resolve(role);
if (HasFailed(roleToModify)) return roleToModify;
@ -166,7 +166,7 @@ export class RoleDbService {
return HasSuccess(await this.findOne(name));
}
public async nukeSystemRoles(IAmSure: boolean = false): AsyncFailable<true> {
public async nukeSystemRoles(IAmSure = false): AsyncFailable<true> {
if (!IAmSure)
return Fail(
FT.SysValidation,

View File

@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types/failable';
import { Repository } from 'typeorm';
import { ESystemStateBackend } from '../../database/entities/system/system-state.entity';

View File

@ -1,6 +1,6 @@
import { Logger, Module, OnModuleInit } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { generateRandomString } from 'picsur-shared/dist/util/random';
import { AuthConfigService } from '../../config/early/auth.config.service';
import { EarlyConfigModule } from '../../config/early/early-config.module';

View File

@ -8,7 +8,7 @@ import {
FT,
HasFailed,
HasSuccess,
} from 'picsur-shared/dist/types';
} from 'picsur-shared/dist/types/failable';
import { FindResult } from 'picsur-shared/dist/types/find-result';
import { makeUnique } from 'picsur-shared/dist/util/unique';
import { Repository } from 'typeorm';
@ -53,7 +53,7 @@ export class UserDbService {
const strength = await this.getBCryptStrength();
const hashedPassword = await bcrypt.hash(password, strength);
let user = new EUserBackend();
const user = new EUserBackend();
user.username = username;
user.hashed_password = hashedPassword;
if (byPassRoleCheck) {
@ -208,7 +208,7 @@ export class UserDbService {
username: string,
// Also fetch fields that aren't normally sent to the client
// (e.g. hashed password)
getPrivate: boolean = false,
getPrivate = false,
): AsyncFailable<EUserBackend> {
try {
const found = await this.usersRepository.findOne({

View File

@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm';
import { ParseInt, ParseString } from 'picsur-shared/dist/util/parse-simple';
import { EntityList } from '../../database/entities';
import { MigrationList } from '../../database/migrations';
import { EntityList } from '../../database/entities/index';
import { MigrationList } from '../../database/migrations/index';
import { DefaultName, EnvPrefix } from '../config.static';
import { HostConfigService } from './host.config.service';
@ -48,10 +48,10 @@ export class TypeOrmConfigService implements TypeOrmOptionsFactory {
return varOptions;
}
public createTypeOrmOptions(connectionName?: string) {
public createTypeOrmOptions() {
const varOptions = this.getTypeOrmServerOptions();
return {
type: 'postgres' as 'postgres',
type: 'postgres' as const,
synchronize: !this.hostService.isProduction(),
migrationsRun: true,

View File

@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { SysPreferenceDbService } from '../../collections/preference-db/sys-preference-db.service';
@Injectable()

View File

@ -1,7 +1,7 @@
import { FactoryProvider, Injectable, Logger } from '@nestjs/common';
import { JwtModuleOptions, JwtOptionsFactory } from '@nestjs/jwt';
import ms from 'ms';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { SysPreferenceDbService } from '../../collections/preference-db/sys-preference-db.service';
@Injectable()

View File

@ -1,6 +1,11 @@
import { Injectable } from '@nestjs/common';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { URLRegex, UUIDRegex } from 'picsur-shared/dist/util/common-regex';
import { SysPreferenceDbService } from '../../collections/preference-db/sys-preference-db.service';
import { ReportInterval, ReportUrl } from '../config.static';

View File

@ -1,6 +1,6 @@
import { IsEntityID } from 'picsur-shared/dist/validators/entity-id.validator';
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
import z from 'zod';
import * as z from 'zod';
export const ESysPreferenceSchema = z.object({
id: IsEntityID().optional(),

View File

@ -8,7 +8,7 @@ import {
PrimaryGeneratedColumn,
Unique,
} from 'typeorm';
import z from 'zod';
import * as z from 'zod';
import { EUserBackend } from '../users/user.entity';
export const EUsrPreferenceSchema = z.object({

View File

@ -1,3 +1,4 @@
import { MigrationInterface } from 'typeorm';
import { V030A1661692206479 } from './1661692206479-V_0_3_0_a';
import { V032A1662029904716 } from './1662029904716-V_0_3_2_a';
import { V040A1662314197741 } from './1662314197741-V_0_4_0_a';
@ -5,8 +6,9 @@ import { V040B1662485374471 } from './1662485374471-V_0_4_0_b';
import { V040C1662535484200 } from './1662535484200-V_0_4_0_c';
import { V040D1662728275448 } from './1662728275448-V_0_4_0_d';
import { V050A1672154027079 } from './1672154027079-V_0_5_0_a';
import { Newable } from 'picsur-shared/dist/types/newable.js';
export const MigrationList: Function[] = [
export const MigrationList: Newable<MigrationInterface>[] = [
V030A1661692206479,
V032A1662029904716,
V040A1662314197741,

View File

@ -1,12 +1,12 @@
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
import { Injectable, PipeTransform } from '@nestjs/common';
import { Ext2FileType } from 'picsur-shared/dist/dto/mimes.dto';
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import { FT, Fail, HasFailed } from 'picsur-shared/dist/types/failable';
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
import { ImageFullId } from '../../models/constants/image-full-id.const';
@Injectable()
export class ImageFullIdPipe implements PipeTransform<string, ImageFullId> {
transform(value: string, metadata: ArgumentMetadata): ImageFullId {
transform(value: string): ImageFullId {
const split = value.split('.');
if (split.length === 2) {
const [id, ext] = split;

View File

@ -1,10 +1,10 @@
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Injectable, PipeTransform } from '@nestjs/common';
import { FT, Fail } from 'picsur-shared/dist/types/failable';
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
@Injectable()
export class ImageIdPipe implements PipeTransform<string, string> {
transform(value: string, metadata: ArgumentMetadata): string {
transform(value: string): string {
if (UUIDRegex.test(value)) return value;
throw Fail(FT.UsrValidation, 'Invalid image id');
}

View File

@ -1,7 +1,7 @@
import { Multipart, MultipartFile } from '@fastify/multipart';
import { Injectable, Logger, PipeTransform, Scope } from '@nestjs/common';
import { FastifyRequest } from 'fastify';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Fail, FT } from 'picsur-shared/dist/types/failable';
import { MultipartConfigService } from '../../config/early/multipart.config.service';
@Injectable({ scope: Scope.REQUEST })
@ -12,7 +12,7 @@ export class PostFilePipe implements PipeTransform {
private readonly multipartConfigService: MultipartConfigService,
) {}
async transform({ request, data }: { data: any; request: FastifyRequest }) {
async transform({ request }: { request: FastifyRequest }) {
if (!request.isMultipart()) throw Fail(FT.UsrValidation, 'Invalid file');
// Only one file is allowed

View File

@ -1,13 +1,7 @@
import { MultipartFile } from '@fastify/multipart';
import {
ArgumentMetadata,
Injectable,
Logger,
PipeTransform,
Scope,
} from '@nestjs/common';
import { Injectable, Logger, PipeTransform, Scope } from '@nestjs/common';
import { FastifyRequest } from 'fastify';
import { Fail, FT } from 'picsur-shared/dist/types';
import { FT, Fail } from 'picsur-shared/dist/types/failable';
import { MultipartConfigService } from '../../config/early/multipart.config.service';
export type FileIterator = AsyncIterableIterator<MultipartFile>;
@ -20,10 +14,7 @@ export class MultiPartPipe implements PipeTransform {
private readonly multipartConfigService: MultipartConfigService,
) {}
async transform<T extends Object>(
{ request, data }: { data: any; request: FastifyRequest },
metadata: ArgumentMetadata,
) {
async transform({ request, data }: { data: any; request: FastifyRequest }) {
const filesLimit = typeof data === 'number' ? data : undefined;
if (!request.isMultipart()) throw Fail(FT.UsrValidation, 'Invalid files');

View File

@ -4,7 +4,7 @@ import {
SetMetadata,
UseGuards,
} from '@nestjs/common';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Fail, FT } from 'picsur-shared/dist/types/failable';
import { CombineFCDecorators } from 'picsur-shared/dist/util/decorator';
import { LocalAuthGuard } from '../managers/auth/guards/local-auth.guard';
import { Permission, Permissions } from '../models/constants/permissions.const';

View File

@ -1,5 +1,5 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Fail, FT } from 'picsur-shared/dist/types/failable';
import AuthFastifyRequest from '../models/interfaces/authrequest.dto';
export const ReqUser = createParamDecorator(

View File

@ -6,12 +6,12 @@ import { Newable } from 'picsur-shared/dist/types/newable';
type ReturnsMethodDecorator<ReturnType> = <
T extends (...args: any) => ReturnType | Promise<ReturnType>,
>(
target: Object,
target: object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>,
) => TypedPropertyDescriptor<T> | void;
export function Returns<N extends Object>(
export function Returns<N extends object>(
newable: Newable<N>,
): ReturnsMethodDecorator<N> {
return SetMetadata('returns', newable);

View File

@ -9,7 +9,7 @@ import {
import { Reflector } from '@nestjs/core';
import { FastifyReply } from 'fastify';
import { ApiAnySuccessResponse } from 'picsur-shared/dist/dto/api/api.dto';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Fail, FT } from 'picsur-shared/dist/types/failable';
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
import { map, Observable } from 'rxjs';
@ -20,7 +20,7 @@ export interface ZodValidationInterceptorOptions {
}
@Injectable()
export class SuccessInterceptor<T> implements NestInterceptor {
export class SuccessInterceptor implements NestInterceptor {
private readonly logger = new Logger();
// TODO: make work
@ -82,7 +82,7 @@ export class SuccessInterceptor<T> implements NestInterceptor {
);
}
let schema = schemaStatic.zodSchema;
const schema = schemaStatic.zodSchema;
const parseResult = schema.safeParse(data);
if (!parseResult.success) {
@ -105,7 +105,7 @@ export class SuccessInterceptor<T> implements NestInterceptor {
const response = context.switchToHttp().getResponse<FastifyReply>();
const newResponse: ApiAnySuccessResponse = {
success: true as true, // really typescript
success: true as const, // really typescript
statusCode: response.statusCode,
timestamp: new Date().toISOString(),
timeMs: Math.round(response.getResponseTime()),

View File

@ -1,10 +1,10 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';
import { Fail, FT } from 'picsur-shared/dist/types';
import { FT, Fail } from 'picsur-shared/dist/types/failable';
@Injectable()
export class PicsurThrottlerGuard extends ThrottlerGuard {
protected override throwThrottlingException(context: ExecutionContext): void {
protected override throwThrottlingException(): void {
throw Fail(FT.RateLimit);
}
}

View File

@ -9,7 +9,7 @@ import {
Optional,
PipeTransform,
} from '@nestjs/common';
import { Fail, FT } from 'picsur-shared/dist/types';
import { Fail, FT } from 'picsur-shared/dist/types/failable';
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
export interface ZodValidationPipeOptions {
@ -30,7 +30,7 @@ export class ZodValidationPipe implements PipeTransform {
public transform(value: unknown, metadata: ArgumentMetadata): unknown {
if (!this.validateCustom && metadata.type === 'custom') return value;
let zodSchema = (metadata?.metatype as ZodDtoStatic)?.zodSchema;
const zodSchema = (metadata?.metatype as ZodDtoStatic)?.zodSchema;
if (zodSchema) {
const parseResult = zodSchema.safeParse(value);

View File

@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { JwtData, JwtDataSchema } from 'picsur-shared/dist/dto/jwt.dto';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types/failable';
@Injectable()
export class AuthManagerService {

View File

@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { EUser, EUserSchema } from 'picsur-shared/dist/entities/user.entity';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { IsApiKey } from 'picsur-shared/dist/validators/api-key.validator';
import { ApiKeyDbService } from '../../../collections/apikey-db/apikey-db.service';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';
@ -23,7 +23,7 @@ export class ApiKeyStrategy extends PassportStrategy(
false,
(
apikey: string,
verified: (err: Error | null, user?: Object, info?: Object) => void,
verified: (err: Error | null, user?: object, info?: object) => void,
) => {
this.validate(apikey)
.then((user) => {

View File

@ -8,11 +8,12 @@ import { ReqType } from './reqtype';
class GuestPassportStrategy extends Strategy {
// Will be overridden by the nest implementation
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async validate(req: ReqType): Promise<any> {
return undefined;
}
override async authenticate(req: ReqType, options?: any) {
override async authenticate(req: ReqType) {
const user = await this.validate(req);
this.success(user);
}
@ -28,7 +29,7 @@ export class GuestStrategy extends PassportStrategy(
}
// Return the guest user created by the guestservice
override async validate(payload: any): Promise<EUser> {
override async validate(): Promise<EUser> {
return EUserBackend2EUser(await this.guestService.getGuestUser());
}
}

View File

@ -3,7 +3,7 @@ import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy as JwtPassportStrategy } from 'passport-jwt';
import { JwtDataSchema } from 'picsur-shared/dist/dto/jwt.dto';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';

View File

@ -2,7 +2,10 @@ import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { AsyncFailable, ThrowIfFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
ThrowIfFailed,
} from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';

View File

@ -9,7 +9,7 @@ import {
FT,
HasFailed,
ThrowIfFailed,
} from 'picsur-shared/dist/types';
} from 'picsur-shared/dist/types/failable';
import { makeUnique } from 'picsur-shared/dist/util/unique';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { Permissions } from '../../../models/constants/permissions.const';

View File

@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../collections/user-db/user-db.service';
import { EUserBackend } from '../../database/entities/users/user.entity';

View File

@ -6,7 +6,12 @@ import {
SupportedFileTypeCategory,
} from 'picsur-shared/dist/dto/mimes.dto';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { SharpOptions } from 'sharp';
import { SysPreferenceDbService } from '../../collections/preference-db/sys-preference-db.service';
import { SharpWrapper } from '../../workers/sharp.wrapper';

View File

@ -2,7 +2,7 @@ import { Logger, Module, OnModuleInit } from '@nestjs/common';
import { Interval } from '@nestjs/schedule';
import ms from 'ms';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import { HasFailed } from 'picsur-shared/dist/types';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { ImageDBModule } from '../../collections/image-db/image-db.module';
import { ImageDBService } from '../../collections/image-db/image-db.service';
import { ImageFileDBService } from '../../collections/image-db/image-file-db.service';

View File

@ -5,7 +5,12 @@ import {
SupportedFileTypeCategory,
} from 'picsur-shared/dist/dto/mimes.dto';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { ParseFileType } from 'picsur-shared/dist/util/parse-mime';
import { ImageConverterService } from './image-converter.service';
import { ImageResult } from './imageresult';

View File

@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common';
import Crypto from 'crypto';
import { createHash } from 'crypto';
import { fileTypeFromBuffer, FileTypeResult } from 'file-type';
import { ImageRequestParams } from 'picsur-shared/dist/dto/api/image.dto';
import { ImageEntryVariant } from 'picsur-shared/dist/dto/image-entry-variant.enum';
@ -11,7 +11,12 @@ import {
} from 'picsur-shared/dist/dto/mimes.dto';
import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum';
import { UsrPreference } from 'picsur-shared/dist/dto/usr-preferences.enum';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
FT,
HasFailed,
} from 'picsur-shared/dist/types/failable';
import { FindResult } from 'picsur-shared/dist/types/find-result';
import { ParseFileType } from 'picsur-shared/dist/util/parse-mime';
import { IsQOI } from 'qoi-img';
@ -229,7 +234,7 @@ export class ImageManagerService {
}
return {
[ImageEntryVariant.MASTER]: result[ImageEntryVariant.MASTER]!,
[ImageEntryVariant.MASTER]: result[ImageEntryVariant.MASTER],
[ImageEntryVariant.ORIGINAL]: result[ImageEntryVariant.ORIGINAL],
};
}
@ -268,7 +273,7 @@ export class ImageManagerService {
private getConvertHash(options: object) {
// Return a sha256 hash of the stringified options
const stringified = JSON.stringify(options);
const hash = Crypto.createHash('sha256');
const hash = createHash('sha256');
hash.update(stringified);
const digest = hash.digest('hex');
return digest;

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
// @ts-nocheck
/*
@ -310,8 +312,8 @@ export class WebPInfo extends StreamParserWritable {
['VP8', 'VP8L', 'ANMF'].map((t) => [t, true] as [ChunkType, true]),
);
private offset: number = 0;
private maxSeekableOffset: number = -1; // same as file size - 1
private offset = 0;
private maxSeekableOffset = -1; // same as file size - 1
private pending?: {
size: number;

View File

@ -1,8 +1,8 @@
import { Injectable, Logger } from '@nestjs/common';
import isDocker from 'is-docker';
import fetch from 'node-fetch';
import os from 'os';
import { FallbackIfFailed, HasFailed } from 'picsur-shared/dist/types';
import * as os from 'os';
import { FallbackIfFailed, HasFailed } from 'picsur-shared/dist/types/failable';
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
import { ImageDBService } from '../../collections/image-db/image-db.service';
import { SystemStateDbService } from '../../collections/system-state-db/system-state-db.service';

View File

@ -24,7 +24,7 @@ export const UndeletableRolesList: string[] = UndeletableRolesTuple;
export const SystemRolesList = UndeletableRolesList;
// Defaults
type SystemRole = typeof UndeletableRolesTuple[number];
type SystemRole = (typeof UndeletableRolesTuple)[number];
const SystemRoleDefaultsTyped: {
[key in SystemRole]: Permissions;
} = {

View File

@ -12,7 +12,7 @@ import {
ApiKeyUpdateResponse,
} from 'picsur-shared/dist/dto/api/apikeys.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { ApiKeyDbService } from '../../../collections/apikey-db/apikey-db.service';
import {
HasPermission,

View File

@ -3,8 +3,6 @@ import { NoPermissions } from '../../../decorators/permissions.decorator';
@Controller('api/experiment')
@NoPermissions()
export class ExperimentController {
constructor() {}
// @Get()
// @Returns(UserInfoResponse)
// async testRoute(

View File

@ -11,7 +11,7 @@ import {
SupportedImageFileTypes,
} from 'picsur-shared/dist/dto/mimes.dto';
import { TrackingState } from 'picsur-shared/dist/dto/tracking-state.enum';
import { FallbackIfFailed } from 'picsur-shared/dist/types';
import { FallbackIfFailed } from 'picsur-shared/dist/types/failable';
import { HostConfigService } from '../../../config/early/host.config.service';
import { InfoConfigService } from '../../../config/late/info.config.service';
import { UsageConfigService } from '../../../config/late/usage.config.service';

View File

@ -6,7 +6,7 @@ import {
UpdatePreferenceRequest,
UpdatePreferenceResponse,
} from 'picsur-shared/dist/dto/api/pref.dto';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { SysPreferenceDbService } from '../../../collections/preference-db/sys-preference-db.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
import { Returns } from '../../../decorators/returns.decorator';

View File

@ -6,7 +6,7 @@ import {
UpdatePreferenceRequest,
UpdatePreferenceResponse,
} from 'picsur-shared/dist/dto/api/pref.dto';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { UsrPreferenceDbService } from '../../../collections/preference-db/usr-preference-db.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
import { ReqUserID } from '../../../decorators/request-user.decorator';

View File

@ -12,7 +12,7 @@ import {
RoleUpdateResponse,
SpecialRolesResponse,
} from 'picsur-shared/dist/dto/api/roles.dto';
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types';
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { RoleDbService } from '../../../collections/role-db/role-db.service';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';

View File

@ -1,7 +1,7 @@
import { Controller, Logger, Post, Req, Res } from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import type { FastifyReply, FastifyRequest } from 'fastify';
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types';
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { UsageConfigService } from '../../../config/late/usage.config.service';
import { NoPermissions } from '../../../decorators/permissions.decorator';
import { ReturnsAnything } from '../../../decorators/returns.decorator';

View File

@ -13,7 +13,7 @@ import {
UserUpdateRequest,
UserUpdateResponse,
} from 'picsur-shared/dist/dto/api/user-manage.dto';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
import { Returns } from '../../../decorators/returns.decorator';

View File

@ -10,7 +10,7 @@ import {
UserRegisterResponse,
} from 'picsur-shared/dist/dto/api/user.dto';
import type { EUser } from 'picsur-shared/dist/entities/user.entity';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import {
NoPermissions,

View File

@ -21,7 +21,12 @@ import {
ImageUploadResponse,
} from 'picsur-shared/dist/dto/api/image-manage.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
import { Fail, FT, HasFailed, ThrowIfFailed } from 'picsur-shared/dist/types';
import {
Fail,
FT,
HasFailed,
ThrowIfFailed,
} from 'picsur-shared/dist/types/failable';
import { PostFiles } from '../../decorators/multipart/multipart.decorator';
import type { FileIterator } from '../../decorators/multipart/postfiles.pipe';
import {

View File

@ -7,7 +7,11 @@ import {
} from 'picsur-shared/dist/dto/api/image.dto';
import { ImageEntryVariant } from 'picsur-shared/dist/dto/image-entry-variant.enum';
import { FileType2Mime } from 'picsur-shared/dist/dto/mimes.dto';
import { FT, IsFailure, ThrowIfFailed } from 'picsur-shared/dist/types';
import {
FT,
IsFailure,
ThrowIfFailed,
} from 'picsur-shared/dist/types/failable';
import { UserDbService } from '../../collections/user-db/user-db.service';
import { ImageFullIdParam } from '../../decorators/image-id/image-full-id.decorator';
import { ImageIdParam } from '../../decorators/image-id/image-id.decorator';

View File

@ -1,6 +1,6 @@
import { readFile } from 'fs/promises';
import { resolve } from 'path';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types/failable';
import { PackageRoot } from '../config/config.static';
export const BrandingPath = resolve(PackageRoot, '../branding');

View File

@ -1,4 +1,4 @@
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types/failable';
export async function GetNextAsync<T>(
iterator: AsyncIterableIterator<T>,

View File

@ -1,7 +1,7 @@
import { Logger } from '@nestjs/common';
import { ChildProcess, fork } from 'child_process';
import pTimeout from 'p-timeout';
import path from 'path';
import { dirname, join as pathJoin } from 'path';
import { FileType } from 'picsur-shared/dist/dto/mimes.dto';
import {
AsyncFailable,
@ -9,7 +9,7 @@ import {
Failable,
FT,
HasFailed,
} from 'picsur-shared/dist/types';
} from 'picsur-shared/dist/types/failable';
import { Sharp, SharpOptions } from 'sharp';
import {
SharpWorkerFinishOptions,
@ -22,13 +22,13 @@ import {
import { SharpResult } from './sharp/universal-sharp';
const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname);
const __dirname = dirname(moduleURL.pathname);
export class SharpWrapper {
private readonly workerID: number = Math.floor(Math.random() * 100000);
private readonly logger: Logger = new Logger('SharpWrapper' + this.workerID);
private static readonly WORKER_PATH = path.join(
private static readonly WORKER_PATH = pathJoin(
__dirname,
'./sharp',
'sharp.worker.js',

View File

@ -1,5 +1,5 @@
import { FileType } from 'picsur-shared/dist/dto/mimes.dto';
import posix from 'posix.js';
import { setrlimit } from 'posix.js';
import { Sharp } from 'sharp';
import {
SharpWorkerFinishOptions,
@ -11,7 +11,7 @@ import {
import { UniversalSharpIn, UniversalSharpOut } from './universal-sharp';
export class SharpWorker {
private startTime: number = 0;
private startTime = 0;
private sharpi: Sharp | null = null;
constructor() {
@ -29,7 +29,7 @@ export class SharpWorker {
return this.purge('MEMORY_LIMIT_MB environment variable is not set');
}
posix.setrlimit('data', {
setrlimit('data', {
soft: 1000 * 1000 * memoryLimit,
hard: 1000 * 1000 * memoryLimit,
});

View File

@ -11,8 +11,5 @@
"declaration": true,
"sourceMap": true,
"emitDecoratorMetadata": true
},
"ts-node": {
"experimentalSpecifierResolution": "node"
}
}

9
frontend/.eslintrc.cjs Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
parserOptions: {
project: './tsconfig.base.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
ignorePatterns: ['src/environments', 'custom-webpack.config.js'],
root: false,
};

View File

@ -14,11 +14,7 @@ export default {
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
],
],
presets: [['@babel/preset-env']],
},
},
},

View File

@ -9,7 +9,7 @@
"scripts": {
"ng": "ng",
"start": "ng serve --host 0.0.0.0",
"build": "ng build",
"build": "ng build --verbose",
"watch": "ng build --watch --configuration development",
"purge": "rm -rf dist && rm -rf node_modules && rm -rf .angular"
},
@ -47,7 +47,6 @@
"browserslist": "^4.21.7",
"caniuse-lite": "^1.0.30001495",
"fuse.js": "^6.6.2",
"jwt-decode": "^3.1.2",
"material-icons": "^1.13.8",
"moment": "^2.29.4",
"ng-mat-select-infinite-scroll": "^4.0.0",
@ -62,5 +61,8 @@
"webpack-bundle-analyzer": "^4.9.0",
"zod": "^3.21.4",
"zone.js": "^0.13.0"
},
"dependencies": {
"@leteu/jwt-decoder": "^1.0.4"
}
}

View File

@ -25,14 +25,14 @@ export class AppComponent implements OnInit {
@ViewChild(MatSidenav) sidebar: MatSidenav;
loading: boolean = false;
loading = false;
private loadingTimeout: number | null = null;
wrapContentWithContainer: boolean = true;
wrapContentWithContainer = true;
sidebarPortal: Portal<any> | undefined = undefined;
isDesktop: boolean = false;
hasSidebar: boolean = false;
isDesktop = false;
hasSidebar = false;
public constructor(
private readonly router: Router,
@ -64,7 +64,7 @@ export class AppComponent implements OnInit {
if (event instanceof NavigationEnd) {
this.loadingEnd();
}
if (event instanceof NavigationEnd) this.onNavigationEnd(event);
if (event instanceof NavigationEnd) this.onNavigationEnd();
if (event instanceof NavigationError) this.onNavigationError(event);
});
}
@ -84,7 +84,7 @@ export class AppComponent implements OnInit {
this.router.navigate(['/error/404'], { replaceUrl: true });
}
private async onNavigationEnd(event: NavigationEnd) {
private async onNavigationEnd() {
const data = this.routeData;
this.wrapContentWithContainer = !data.noContainer;

View File

@ -3,10 +3,10 @@ import {
MatFormFieldAppearance,
SubscriptSizing,
} from '@angular/material/form-field';
import { FT, Fail } from 'picsur-shared/dist/types';
import { Logger } from 'src/app/services/logger/logger.service';
import { ClipboardService } from 'src/app/util/clipboard.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { FT, Fail } from 'picsur-shared/dist/types/failable';
import { Logger } from '../../services/logger/logger.service';
import { ClipboardService } from '../../util/clipboard.service';
import { ErrorService } from '../../util/error-manager/error.service';
@Component({
selector: 'copy-field',
@ -17,11 +17,11 @@ export class CopyFieldComponent {
private readonly logger = new Logger(CopyFieldComponent.name);
// Two parameters: name, value
@Input() label: string = 'Loading...';
@Input() value: string = 'Loading...';
@Input() label = 'Loading...';
@Input() value = 'Loading...';
@Input() showHideButton: boolean = false;
@Input() hidden: boolean = false;
@Input() showHideButton = false;
@Input() hidden = false;
@Input() color: 'primary' | 'accent' | 'warn' = 'primary';
@Input() appearance: MatFormFieldAppearance = 'outline';

View File

@ -3,8 +3,9 @@ import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
import { CopyFieldComponent } from './copy-field.component';
import { ErrorManagerModule } from '../../util/error-manager/error-manager.module';
@NgModule({
declarations: [CopyFieldComponent],
imports: [

View File

@ -5,11 +5,10 @@ import { Component, Input } from '@angular/core';
templateUrl: './fab.component.html',
})
export class FabComponent {
@Input('aria-label') ariaLabel: string = 'Floating Action Button';
@Input() icon: string = 'add';
@Input() color: string = 'primary';
@Input('aria-label') ariaLabel = 'Floating Action Button';
@Input() icon = 'add';
@Input() color = 'primary';
@Input('tooltip') tooltip: string;
// eslint-disable-next-line @typescript-eslint/no-empty-function
@Input() onClick: () => void = () => {};
constructor() {}
}

View File

@ -22,7 +22,7 @@
[matTooltip]="tooltip"
matTooltipPosition="left"
[matTooltipDisabled]="!openManager.isOpen"
(click)="click($event)"
(click)="click()"
aria-label=""
>
<mat-icon

View File

@ -9,19 +9,19 @@ import { SpeedDialAnimation } from './speed-dial.animation';
animations: [SpeedDialAnimation],
})
export class SpeedDialComponent {
@Input('aria-label') ariaLabel: string = 'Floating Action Button';
@Input('aria-label') ariaLabel = 'Floating Action Button';
@Input('icon') icon: string = 'add';
@Input('icon-hover') iconHover: string = 'close';
@Input('color') color: string = 'primary';
@Input('open-on-hover') openOnHover: boolean = false;
@Input('icon') icon = 'add';
@Input('icon-hover') iconHover = 'close';
@Input('color') color = 'primary';
@Input('open-on-hover') openOnHover = false;
@Input('tooltip') tooltip: string;
@Output('main-click') clickEmitter = new Subject<void>();
public openManager = new OpenManager();
private touchUntil: number = 0;
private touchUntil = 0;
@HostListener('document:touchstart', ['$event'])
@HostListener('document:touchend', ['$event'])
@ -35,13 +35,13 @@ export class SpeedDialComponent {
@HostListener('document:click', ['$event'])
@HostListener('document:keydown.escape', ['$event'])
anyClick(e: Event) {
anyClick() {
if (!this.openManager.isOpen || this.openManager.isAnimating) return;
this.openManager.close();
}
click(e: MouseEvent) {
click() {
if (!this.openManager.isOpen) {
this.openManager.open();
} else {

View File

@ -5,7 +5,7 @@ import {
OnInit,
} from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { InfoService } from 'src/app/services/api/info.service';
import { InfoService } from '../../services/api/info.service';
@Component({
selector: 'app-footer',
@ -19,8 +19,8 @@ export class FooterComponent implements OnInit {
private readonly changeDetector: ChangeDetectorRef,
) {}
isDemo: boolean = false;
version: string = 'Unkown Version';
isDemo = false;
version = 'Unkown Version';
ngOnInit(): void {
this.subscribeInfo();

View File

@ -11,11 +11,11 @@ import { Router } from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { HasFailed } from 'picsur-shared/dist/types';
import { PermissionService } from 'src/app/services/api/permission.service';
import { UserService } from 'src/app/services/api/user.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import { UserService } from '../../services/api/user.service';
import { PermissionService } from '../../services/api/permission.service';
import { Logger } from '../../services/logger/logger.service';
import { ErrorService } from '../../util/error-manager/error.service';
@Component({
selector: 'app-header',
@ -38,17 +38,17 @@ export class HeaderComponent implements OnInit {
this._enableHamburger = value;
this.changeDetector.markForCheck();
}
public _enableHamburger: boolean = true;
public _enableHamburger = true;
@Output('onHamburgerClick') onHamburgerClick = new EventEmitter<void>();
@Input('loading') public loading: boolean = false;
@Input('loading') public loading = false;
private currentUser: EUser | null = null;
public canLogIn: boolean = false;
public canAccessSettings: boolean = false;
public canUpload: boolean = false;
public canRegister: boolean = false;
public canLogIn = false;
public canAccessSettings = false;
public canUpload = false;
public canRegister = false;
public get user() {
return this.currentUser;

View File

@ -7,8 +7,8 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { RouterModule } from '@angular/router';
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
import { HeaderComponent } from './header.component';
import { ErrorManagerModule } from '../../util/error-manager/error-manager.module';
@NgModule({
imports: [

View File

@ -1,12 +1,11 @@
import { Directive, ElementRef, Inject } from '@angular/core';
import {
boxExtractor,
ResizeObserverDirective,
ResizeObserverService,
RESIZE_OPTION_BOX,
ResizeObserverService,
boxExtractor,
} from '@ng-web-apis/resize-observer';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { map, Observable } from 'rxjs';
import { Observable, map } from 'rxjs';
@Directive({
selector: '[masonry-item]',

View File

@ -12,9 +12,9 @@ import {
} from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { combineLatest, Subscription } from 'rxjs';
import { RemoveChildren } from 'src/app/util/remove-children';
import { Throttle } from 'src/app/util/throttle';
import { MasonryItemDirective } from './masonry-item.directive';
import { RemoveChildren } from '../../util/remove-children';
import { Throttle } from '../../util/throttle';
@Component({
selector: 'masonry',
@ -30,7 +30,7 @@ export class MasonryComponent implements AfterViewInit, OnDestroy {
this.changeDetector.markForCheck();
}
public _column_count = 1;
@Input('update-speed') update_speed: number = 200;
@Input('update-speed') update_speed = 200;
@ContentChildren(MasonryItemDirective)
private content: QueryList<MasonryItemDirective>;
@ -59,7 +59,7 @@ export class MasonryComponent implements AfterViewInit, OnDestroy {
this.sizesSubscription = combineLatest(sizes)
.pipe(Throttle(this.update_speed))
.subscribe((output) => {
.subscribe(() => {
this.resortItems(items);
});
@ -76,7 +76,7 @@ export class MasonryComponent implements AfterViewInit, OnDestroy {
RemoveChildren(columnsArray[i]);
}
const columnSizes = columnsArray.map((c) => 0);
const columnSizes = columnsArray.map(() => 0);
for (let i = 0; i < itemsArray.length; i++) {
const item = itemsArray[i];
@ -84,7 +84,7 @@ export class MasonryComponent implements AfterViewInit, OnDestroy {
let smallestColumn = 0;
let smallestColumnSize = columnSizes[0];
for (let j = columnSizes.length - 1; j >= 0; j--) {
let better_j = (j + i) % columnSizes.length;
const better_j = (j + i) % columnSizes.length;
if (columnSizes[better_j] <= smallestColumnSize) {
smallestColumn = better_j;

View File

@ -1,5 +1,5 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Required } from 'src/app/models/decorators/required.decorator';
import { Required } from '../../models/decorators/required.decorator';
@Component({
selector: 'paginator',
@ -13,18 +13,18 @@ export class PaginatorComponent implements OnInit {
this.calculateRanges();
}
page: number = 1;
page = 1;
@Input('page') set pageInput(value: number) {
this.page = value;
this.calculateRanges();
}
@Output('page') pageChange = new EventEmitter<number>();
@Input('show-first-last') showFirstLast: boolean = true;
@Input('show-first-last') showFirstLast = true;
@Input('shown-pages') shownPages: number = 7;
@Input('shown-first-pages') shownFirstPages: number = 1;
@Input('shown-last-pages') shownLastPages: number = 1;
@Input('shown-pages') shownPages = 7;
@Input('shown-first-pages') shownFirstPages = 1;
@Input('shown-last-pages') shownLastPages = 1;
firstPagesRange: [number, number] | null = null;
lastPagesRange: [number, number] | null = null;

View File

@ -2,8 +2,8 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { PipesModule } from 'src/app/pipes/pipes.module';
import { PaginatorComponent } from './paginator.component';
import { PipesModule } from '../../pipes/pipes.module';
@NgModule({
declarations: [PaginatorComponent],

View File

@ -14,7 +14,7 @@
<mat-icon *ngIf="state === 'error'">broken_image</mat-icon>
<mat-spinner
(nguiInview)="onInview($event)"
(nguiOutview)="onOutview($event)"
(nguiInview)="onInview()"
(nguiOutview)="onOutview()"
*ngIf="state === 'init' || state === 'loading'"
></mat-spinner>

View File

@ -5,16 +5,15 @@ import {
ElementRef,
Input,
OnChanges,
SimpleChanges,
ViewChild,
} from '@angular/core';
import { FileType, ImageFileType } from 'picsur-shared/dist/dto/mimes.dto';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types/failable';
import { URLRegex } from 'picsur-shared/dist/util/common-regex';
import { ParseMime2FileType } from 'picsur-shared/dist/util/parse-mime';
import { ApiService } from 'src/app/services/api/api.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { QoiWorkerService } from 'src/app/workers/qoi-worker.service';
import { ApiService } from '../../services/api/api.service';
import { Logger } from '../../services/logger/logger.service';
import { QoiWorkerService } from '../../workers/qoi-worker.service';
enum PicsurImgState {
Init = 'init',
@ -48,12 +47,12 @@ export class PicsurImgComponent implements OnChanges {
private readonly changeDetector: ChangeDetectorRef,
) {}
ngOnChanges(changes: SimpleChanges): void {
ngOnChanges(): void {
if (this.isInView) this.reload();
}
private reload() {
let url = this.imageURL ?? '';
const url = this.imageURL ?? '';
if (!URLRegex.test(url)) {
this.state = PicsurImgState.Loading;
this.changeDetector.markForCheck();
@ -68,7 +67,7 @@ export class PicsurImgComponent implements OnChanges {
this.changeDetector.markForCheck();
}
})
.catch((e) => this.logger.error);
.catch(this.logger.error);
}
private async update(url: string): AsyncFailable<void> {
@ -111,7 +110,7 @@ export class PicsurImgComponent implements OnChanges {
return ParseMime2FileType(mime);
}
onInview(e: any) {
onInview() {
this.isInView = true;
if (this.state === PicsurImgState.Init) {
@ -120,7 +119,7 @@ export class PicsurImgComponent implements OnChanges {
}
}
onOutview(e: any) {
onOutview() {
this.isInView = false;
}
}

View File

@ -5,13 +5,13 @@ import {
DecodedPref,
PrefValueType,
} from 'picsur-shared/dist/dto/preferences.dto';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types/failable';
import { filter } from 'rxjs';
import { Required } from 'src/app/models/decorators/required.decorator';
import { Logger } from 'src/app/services/logger/logger.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { Throttle } from 'src/app/util/throttle';
import { ZodTypeAny } from 'zod';
import { Required } from '../../models/decorators/required.decorator';
import { Logger } from '../../services/logger/logger.service';
import { ErrorService } from '../../util/error-manager/error.service';
import { Throttle } from '../../util/throttle';
@Component({
selector: 'pref-option',
@ -40,8 +40,8 @@ export class PrefOptionComponent implements OnInit {
pref: PrefValueType,
) => AsyncFailable<any>;
@Input() @Required name: string = '';
@Input() helpText: string = '';
@Input() @Required name = '';
@Input() helpText = '';
@Input() validator?: ZodTypeAny = undefined;
constructor(private readonly errorService: ErrorService) {}
@ -96,7 +96,7 @@ export class PrefOptionComponent implements OnInit {
subscribeUpdate() {
return this.formControl.valueChanges
.pipe(
filter((value) => this.formControl.errors === null),
filter(() => this.formControl.errors === null),
Throttle(300),
)
.subscribe(this.updatePreference.bind(this));

View File

@ -7,8 +7,8 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
import { PrefOptionComponent } from './pref-option.component';
import { ErrorManagerModule } from '../../util/error-manager/error-manager.module';
@NgModule({
imports: [

View File

@ -6,7 +6,7 @@ import { MatChipInputEvent } from '@angular/material/chips';
import Fuse from 'fuse.js';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { BehaviorSubject } from 'rxjs';
import { Required } from 'src/app/models/decorators/required.decorator';
import { Required } from '../../models/decorators/required.decorator';
@Component({
selector: 'values-picker',
@ -18,7 +18,7 @@ export class ValuesPickerComponent implements OnInit, OnChanges {
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
// Ui niceties
@Input('name') @Required name: string = '';
@Input('name') @Required name = '';
public get nameCap(): string {
return this.name.charAt(0).toUpperCase() + this.name.slice(1);
}
@ -107,14 +107,14 @@ export class ValuesPickerComponent implements OnInit, OnChanges {
@AutoUnsubscribe()
private subscribeInputValue() {
return this.inputControl.valueChanges.subscribe((value) => {
return this.inputControl.valueChanges.subscribe(() => {
this.updateSelectable();
});
}
@AutoUnsubscribe()
private subscribeMyValue() {
return this.myControl.valueChanges.subscribe((value) => {
return this.myControl.valueChanges.subscribe(() => {
this.updateSelectable();
});
}

View File

@ -4,7 +4,6 @@ import {
CanActivate,
CanActivateChild,
Router,
RouterStateSnapshot,
} from '@angular/router';
import { isPermissionsArray } from 'picsur-shared/dist/validators/permissions.validator';
import { PRouteData } from '../models/dto/picsur-routes.dto';
@ -24,18 +23,15 @@ export class PermissionGuard implements CanActivate, CanActivateChild {
private readonly router: Router,
) {}
async canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
) {
return await this.can(childRoute, state);
async canActivateChild(childRoute: ActivatedRouteSnapshot) {
return await this.can(childRoute);
}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return await this.can(route, state);
async canActivate(route: ActivatedRouteSnapshot) {
return await this.can(route);
}
private async can(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
private async can(route: ActivatedRouteSnapshot) {
const requiredPermissions: string[] = this.nestedPermissions(route);
const allPermissionsArray = await this.staticInfo.getAllPermissions();

View File

@ -1,9 +1,9 @@
import { TrackingState } from 'picsur-shared/dist/dto/tracking-state.enum';
export class ServerInfo {
production: boolean = false;
demo: boolean = false;
version: string = '0.0.0';
production = false;
demo = false;
version = '0.0.0';
host_override?: string;
tracking: {
state: TrackingState;

View File

@ -1,5 +1,5 @@
import { FormControl } from '@angular/forms';
import { Fail, Failable, FT } from 'picsur-shared/dist/types';
import { Fail, Failable, FT } from 'picsur-shared/dist/types/failable';
import { UserPassModel } from '../forms-dto/userpass.dto';
import {
CreatePasswordError,

View File

@ -1,5 +1,5 @@
import { FormControl } from '@angular/forms';
import { Fail, Failable, FT } from 'picsur-shared/dist/types';
import { Fail, Failable, FT } from 'picsur-shared/dist/types/failable';
import { UserPassModel } from '../forms-dto/userpass.dto';
import { Compare } from '../validators/compare.validator';
import {

View File

@ -11,7 +11,7 @@ import {
} from '../validators/user.validator';
export class UpdateUserControl {
private id: string = '';
private id = '';
public username = new FormControl('', UsernameValidators);
public password = new FormControl('', PasswordValidators);
public roles = new FormControl<string[]>([]);

View File

@ -4,9 +4,9 @@ import { Pipe, PipeTransform } from '@angular/core';
name: 'truncate',
})
export class TruncatePipe implements PipeTransform {
transform(text: string, length: number = 32, suffix: string = '...'): string {
transform(text: string, length = 32, suffix = '...'): string {
if (text.length > length) {
let truncated: string = text.substring(0, length).trim() + suffix;
const truncated: string = text.substring(0, length).trim() + suffix;
return truncated;
}

View File

@ -1,10 +1,10 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { PRoutes } from 'src/app/models/dto/picsur-routes.dto';
import { E401Component } from './401.component';
import { E404Component } from './404.component';
import { ImageDeleteFailureComponent } from './delete-failure.component';
import { ImageDeleteSuccessComponent } from './delete-success.component';
import { PRoutes } from '../../models/dto/picsur-routes.dto';
const routes: PRoutes = [
{

View File

@ -6,19 +6,19 @@ import { EImage } from 'picsur-shared/dist/entities/image.entity';
import { HasFailed } from 'picsur-shared/dist/types/failable';
import {
BehaviorSubject,
Observable,
filter,
map,
merge,
Observable,
switchMap,
timer,
} from 'rxjs';
import { ImageService } from 'src/app/services/api/image.service';
import { UserService } from 'src/app/services/api/user.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { BootstrapService, BSScreenSize } from 'src/app/util/bootstrap.service';
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { ImageService } from '../../services/api/image.service';
import { UserService } from '../../services/api/user.service';
import { Logger } from '../../services/logger/logger.service';
import { BSScreenSize, BootstrapService } from '../../util/bootstrap.service';
import { DialogService } from '../../util/dialog-manager/dialog.service';
import { ErrorService } from '../../util/error-manager/error.service';
@Component({
templateUrl: './images.component.html',
@ -39,8 +39,8 @@ export class ImagesComponent implements OnInit {
);
}
page: number = 1;
pages: number = 1;
page = 1;
pages = 1;
constructor(
private readonly route: ActivatedRoute,
@ -110,7 +110,7 @@ export class ImagesComponent implements OnInit {
merge(
...images
.filter((i) => i.expires_at !== null)
.map((i) => timer(i.expires_at!).pipe(map(() => i))),
.map((i) => timer(i.expires_at ?? new Date(0)).pipe(map(() => i))),
),
),
) as Observable<EImage>;

View File

@ -4,12 +4,12 @@ import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MomentModule } from 'ngx-moment';
import { MasonryModule } from 'src/app/components/masonry/masonry.module';
import { PaginatorModule } from 'src/app/components/paginator/paginator.module';
import { PicsurImgModule } from 'src/app/components/picsur-img/picsur-img.module';
import { PipesModule } from 'src/app/pipes/pipes.module';
import { DialogManagerModule } from 'src/app/util/dialog-manager/dialog-manager.module';
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
import { MasonryModule } from '../../components/masonry/masonry.module';
import { PaginatorModule } from '../../components/paginator/paginator.module';
import { PicsurImgModule } from '../../components/picsur-img/picsur-img.module';
import { PipesModule } from '../../pipes/pipes.module';
import { DialogManagerModule } from '../../util/dialog-manager/dialog-manager.module';
import { ErrorManagerModule } from '../../util/error-manager/error-manager.module';
import { ImagesComponent } from './images.component';
import { ImagesRoutingModule } from './images.routing.module';

View File

@ -1,9 +1,9 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
import { PermissionGuard } from 'src/app/guards/permission.guard';
import { PRoutes } from 'src/app/models/dto/picsur-routes.dto';
import { ImagesComponent } from './images.component';
import { PermissionGuard } from '../../guards/permission.guard';
import { PRoutes } from '../../models/dto/picsur-routes.dto';
const routes: PRoutes = [
{

View File

@ -1,11 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import { ProcessingViewMeta } from 'src/app/models/dto/processing-view-meta.dto';
import { ApiService } from 'src/app/services/api/api.service';
import { ImageService } from 'src/app/services/api/image.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types/failable';
import { ProcessingViewMeta } from '../../models/dto/processing-view-meta.dto';
import { ApiService } from '../../services/api/api.service';
import { ImageService } from '../../services/api/image.service';
import { Logger } from '../../services/logger/logger.service';
import { ErrorService } from '../../util/error-manager/error.service';
@Component({
templateUrl: './processing.component.html',

View File

@ -1,9 +1,9 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
import { ProcessingComponent } from './processing.component';
import { ProcessingRoutingModule } from './processing.routing.module';
import { ErrorManagerModule } from '../../util/error-manager/error-manager.module';
@NgModule({
declarations: [ProcessingComponent],

View File

@ -1,7 +1,7 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { PRoutes } from 'src/app/models/dto/picsur-routes.dto';
import { ProcessingComponent } from './processing.component';
import { PRoutes } from '../../models/dto/picsur-routes.dto';
const routes: PRoutes = [
{

View File

@ -1,5 +1,5 @@
<mat-form-field class="editfield" appearance="outline" color="primary">
<mat-label>Name</mat-label>
<input matInput [formControl]="field" (change)="update($event)" />
<input matInput [formControl]="field" (change)="update()" />
<mat-error *ngIf="field.invalid">{{ getErrorMessage() }}</mat-error>
</mat-form-field>

View File

@ -1,6 +1,6 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { Logger } from 'src/app/services/logger/logger.service';
import { Logger } from '../../../../services/logger/logger.service';
@Component({
selector: 'app-settings-apikey-editor',
@ -22,7 +22,7 @@ export class SettingsApiKeyEditorComponent {
Validators.maxLength(255),
]);
async update(event: Event) {
async update() {
if (this.field.invalid) {
return;
}

View File

@ -2,16 +2,16 @@ import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { EApiKey } from 'picsur-shared/dist/entities/apikey.entity';
import { FT, Fail, HasFailed } from 'picsur-shared/dist/types';
import { FT, Fail, HasFailed } from 'picsur-shared/dist/types/failable';
import { BehaviorSubject, Subject } from 'rxjs';
import { ApiKeysService } from 'src/app/services/api/apikeys.service';
import { UserService } from 'src/app/services/api/user.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { BootstrapService } from 'src/app/util/bootstrap.service';
import { ClipboardService } from 'src/app/util/clipboard.service';
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
import { ErrorService } from 'src/app/util/error-manager/error.service';
import { Throttle } from 'src/app/util/throttle';
import { ApiKeysService } from '../../../services/api/apikeys.service';
import { UserService } from '../../../services/api/user.service';
import { Logger } from '../../../services/logger/logger.service';
import { BootstrapService } from '../../../util/bootstrap.service';
import { ClipboardService } from '../../../util/clipboard.service';
import { DialogService } from '../../../util/dialog-manager/dialog.service';
import { ErrorService } from '../../../util/error-manager/error.service';
import { Throttle } from '../../../util/throttle';
@Component({
templateUrl: './settings-apikeys.component.html',
@ -31,7 +31,7 @@ export class SettingsApiKeysComponent implements OnInit {
public dataSubject = new BehaviorSubject<EApiKey[]>([]);
public updateSubject = new Subject<PageEvent>();
public totalApiKeys: number = 0;
public totalApiKeys = 0;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ -136,7 +136,7 @@ export class SettingsApiKeysComponent implements OnInit {
return this.updateSubject
.pipe(Throttle(500))
.subscribe(async (pageEvent: PageEvent) => {
let success = await this.fetchApiKeys(
const success = await this.fetchApiKeys(
pageEvent.pageSize,
pageEvent.pageIndex,
);

Some files were not shown because too many files have changed in this diff Show More