add ability to make image expire

This commit is contained in:
rubikscraft
2022-09-09 15:13:56 +02:00
parent 08af514758
commit e0e804d27d
20 changed files with 247 additions and 29 deletions

View File

@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TypeOrmOptionsFactory } from '@nestjs/typeorm';
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';
@@ -52,19 +52,21 @@ export class TypeOrmConfigService implements TypeOrmOptionsFactory {
const varOptions = this.getTypeOrmServerOptions();
return {
type: 'postgres' as 'postgres',
synchronize: false, //!this.hostService.isProduction(),
synchronize: !this.hostService.isProduction(),
migrationsRun: true,
entities: EntityList,
migrations: MigrationList,
useUTC: true,
cli: {
migrationsDir: 'src/database/migrations',
entitiesDir: 'src/database/entities',
},
...varOptions,
};
} as TypeOrmModuleOptions;
}
}

View File

@@ -41,13 +41,13 @@ export class EApiKeyBackend<
name: string;
@Column({
type: 'timestamp',
type: 'timestamptz',
nullable: false,
})
created: Date;
@Column({
type: 'timestamp',
type: 'timestamptz',
nullable: true,
})
last_used: Date;

View File

@@ -36,7 +36,11 @@ export class EImageDerivativeBackend {
@Column({ nullable: false })
filetype: string;
@Column({ type: 'timestamp', name: 'last_read', nullable: false })
@Column({
type: 'timestamptz',
name: 'last_read',
nullable: false,
})
last_read: Date;
// Binary data

View File

@@ -15,7 +15,7 @@ export class EImageBackend implements EImage {
user_id: string;
@Column({
type: 'timestamp',
type: 'timestamptz',
nullable: false,
})
created: Date;
@@ -27,7 +27,7 @@ export class EImageBackend implements EImage {
file_name: string;
@Column({
type: 'timestamp',
type: "timestamptz",
nullable: true,
})
expires_at: Date | null;

View File

@@ -0,0 +1,22 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class V040D1662728275448 implements MigrationInterface {
name = 'V040D1662728275448'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "e_api_key_backend" ALTER COLUMN "created" SET DATA TYPE TIMESTAMP WITH TIME ZONE, ALTER COLUMN "created" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "e_api_key_backend" ALTER COLUMN "last_used" SET DATA TYPE TIMESTAMP WITH TIME ZONE`);
await queryRunner.query(`ALTER TABLE "e_image_backend" ALTER COLUMN "created" SET DATA TYPE TIMESTAMP WITH TIME ZONE, ALTER COLUMN "created" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "e_image_backend" ALTER COLUMN "expires_at" SET DATA TYPE TIMESTAMP WITH TIME ZONE`);
await queryRunner.query(`ALTER TABLE "e_image_derivative_backend" ALTER COLUMN "last_read" SET DATA TYPE TIMESTAMP WITH TIME ZONE, ALTER COLUMN "last_read" SET NOT NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "e_image_derivative_backend" ALTER COLUMN "last_read" SET DATA TYPE TIMESTAMP, ALTER COLUMN "last_read" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "e_image_backend" ALTER COLUMN "expires_at" SET DATA TYPE TIMESTAMP`);
await queryRunner.query(`ALTER TABLE "e_image_backend" ALTER COLUMN "created" SET DATA TYPE TIMESTAMP, ALTER COLUMN "created" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "e_api_key_backend" ALTER COLUMN "last_used" SET DATA TYPE TIMESTAMP`);
await queryRunner.query(`ALTER TABLE "e_api_key_backend" ALTER COLUMN "created" SET DATA TYPE TIMESTAMP, ALTER COLUMN "created" SET NOT NULL`);
}
}

View File

@@ -3,6 +3,7 @@ import { V032A1662029904716 } from './1662029904716-V_0_3_2_a';
import { V040A1662314197741 } from './1662314197741-V_0_4_0_a';
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';
export const MigrationList: Function[] = [
V030A1661692206479,
@@ -10,4 +11,5 @@ export const MigrationList: Function[] = [
V040A1662314197741,
V040B1662485374471,
V040C1662535484200,
V040D1662728275448,
];

View File

@@ -17,7 +17,7 @@ async function createDataSource() {
const configFactory = app.get(TypeOrmConfigService);
const config = await configFactory.createTypeOrmOptions();
return new DataSource(config);
return new DataSource(config as any);
}
export default createDataSource();

View File

@@ -61,7 +61,7 @@ export class ImageManagerModule implements OnModuleInit, OnModuleDestroy {
const result = await this.imageFileDB.cleanupDerivatives(after_ms / 1000);
if (HasFailed(result)) {
this.logger.warn(`Failed to cleanup derivatives`);
this.logger.warn(result.print());
}
this.logger.log(`Cleaned up ${result} derivatives`);
@@ -71,7 +71,7 @@ export class ImageManagerModule implements OnModuleInit, OnModuleDestroy {
const cleanedUp = await this.imageDB.cleanupExpired();
if (HasFailed(cleanedUp)) {
this.logger.warn(`Failed to cleanup expired images`);
this.logger.warn(cleanedUp.print());
}
this.logger.log(`Cleaned up ${cleanedUp} expired images`);

View File

@@ -57,6 +57,11 @@ export class ImageManagerService {
userid: string | undefined,
options: Partial<Pick<EImageBackend, 'file_name' | 'expires_at'>>,
): AsyncFailable<EImageBackend> {
if (options.expires_at !== undefined && options.expires_at !== null) {
if (options.expires_at < new Date()) {
return Fail(FT.UsrValidation, 'Expiration date must be in the future');
}
}
return await this.imagesService.update(id, userid, options);
}