mirror of
https://github.com/KevinMidboe/immich.git
synced 2026-01-28 03:56:28 +00:00
refactor(server): flatten infra folders (#2120)
* refactor: flatten infra folders * fix: database migrations * fix: test related import * fix: github actions workflow * chore: rename schemas to typesense-schemas
This commit is contained in:
52
server/libs/infra/src/entities/album.entity.ts
Normal file
52
server/libs/infra/src/entities/album.entity.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { SharedLinkEntity } from './shared-link.entity';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('albums')
|
||||
export class AlbumEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
||||
owner!: UserEntity;
|
||||
|
||||
@Column()
|
||||
ownerId!: string;
|
||||
|
||||
@Column({ default: 'Untitled Album' })
|
||||
albumName!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: string;
|
||||
|
||||
@ManyToOne(() => AssetEntity, { nullable: true, onDelete: 'SET NULL', onUpdate: 'CASCADE' })
|
||||
albumThumbnailAsset!: AssetEntity | null;
|
||||
|
||||
@Column({ comment: 'Asset ID to be used as thumbnail', nullable: true })
|
||||
albumThumbnailAssetId!: string | null;
|
||||
|
||||
@ManyToMany(() => UserEntity)
|
||||
@JoinTable()
|
||||
sharedUsers!: UserEntity[];
|
||||
|
||||
@ManyToMany(() => AssetEntity)
|
||||
@JoinTable()
|
||||
assets!: AssetEntity[];
|
||||
|
||||
@OneToMany(() => SharedLinkEntity, (link) => link.album)
|
||||
sharedLinks!: SharedLinkEntity[];
|
||||
}
|
||||
26
server/libs/infra/src/entities/api-key.entity.ts
Normal file
26
server/libs/infra/src/entities/api-key.entity.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('api_keys')
|
||||
export class APIKeyEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column()
|
||||
name!: string;
|
||||
|
||||
@Column({ select: false })
|
||||
key?: string;
|
||||
|
||||
@ManyToOne(() => UserEntity)
|
||||
user?: UserEntity;
|
||||
|
||||
@Column()
|
||||
userId!: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: string;
|
||||
}
|
||||
113
server/libs/infra/src/entities/asset.entity.ts
Normal file
113
server/libs/infra/src/entities/asset.entity.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Unique,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { AlbumEntity } from './album.entity';
|
||||
import { ExifEntity } from './exif.entity';
|
||||
import { SharedLinkEntity } from './shared-link.entity';
|
||||
import { SmartInfoEntity } from './smart-info.entity';
|
||||
import { TagEntity } from './tag.entity';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('assets')
|
||||
@Unique('UQ_userid_checksum', ['owner', 'checksum'])
|
||||
export class AssetEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column()
|
||||
deviceAssetId!: string;
|
||||
|
||||
@ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
||||
owner!: UserEntity;
|
||||
|
||||
@Column()
|
||||
ownerId!: string;
|
||||
|
||||
@Column()
|
||||
deviceId!: string;
|
||||
|
||||
@Column()
|
||||
type!: AssetType;
|
||||
|
||||
@Column()
|
||||
originalPath!: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
resizePath!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, default: '' })
|
||||
webpPath!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, default: '' })
|
||||
encodedVideoPath!: string | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
fileCreatedAt!: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
fileModifiedAt!: string;
|
||||
|
||||
@Column({ type: 'boolean', default: false })
|
||||
isFavorite!: boolean;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
mimeType!: string | null;
|
||||
|
||||
@Column({ type: 'bytea', nullable: true, select: false })
|
||||
@Index({ where: `'checksum' IS NOT NULL` }) // avoid null index
|
||||
checksum?: Buffer | null; // sha1 checksum
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
duration!: string | null;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
isVisible!: boolean;
|
||||
|
||||
@OneToOne(() => AssetEntity, { nullable: true, onUpdate: 'CASCADE', onDelete: 'SET NULL' })
|
||||
@JoinColumn()
|
||||
livePhotoVideo!: AssetEntity | null;
|
||||
|
||||
@Column({ nullable: true })
|
||||
livePhotoVideoId!: string | null;
|
||||
|
||||
@OneToOne(() => ExifEntity, (exifEntity) => exifEntity.asset)
|
||||
exifInfo?: ExifEntity;
|
||||
|
||||
@OneToOne(() => SmartInfoEntity, (smartInfoEntity) => smartInfoEntity.asset)
|
||||
smartInfo?: SmartInfoEntity;
|
||||
|
||||
@ManyToMany(() => TagEntity, (tag) => tag.assets, { cascade: true })
|
||||
@JoinTable({ name: 'tag_asset' })
|
||||
tags!: TagEntity[];
|
||||
|
||||
@ManyToMany(() => SharedLinkEntity, (link) => link.assets, { cascade: true })
|
||||
@JoinTable({ name: 'shared_link__asset' })
|
||||
sharedLinks!: SharedLinkEntity[];
|
||||
|
||||
@ManyToMany(() => AlbumEntity, (album) => album.assets)
|
||||
albums?: AlbumEntity[];
|
||||
}
|
||||
|
||||
export enum AssetType {
|
||||
IMAGE = 'IMAGE',
|
||||
VIDEO = 'VIDEO',
|
||||
AUDIO = 'AUDIO',
|
||||
OTHER = 'OTHER',
|
||||
}
|
||||
32
server/libs/infra/src/entities/device-info.entity.ts
Normal file
32
server/libs/infra/src/entities/device-info.entity.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
||||
|
||||
@Entity('device_info')
|
||||
@Unique(['userId', 'deviceId'])
|
||||
export class DeviceInfoEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column()
|
||||
userId!: string;
|
||||
|
||||
@Column()
|
||||
deviceId!: string;
|
||||
|
||||
@Column()
|
||||
deviceType!: DeviceType;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
notificationToken!: string | null;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt!: string;
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
isAutoBackup!: boolean;
|
||||
}
|
||||
|
||||
export enum DeviceType {
|
||||
IOS = 'IOS',
|
||||
ANDROID = 'ANDROID',
|
||||
WEB = 'WEB',
|
||||
}
|
||||
100
server/libs/infra/src/entities/exif.entity.ts
Normal file
100
server/libs/infra/src/entities/exif.entity.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Index, JoinColumn, OneToOne, PrimaryColumn } from 'typeorm';
|
||||
import { Column } from 'typeorm/decorator/columns/Column';
|
||||
import { Entity } from 'typeorm/decorator/entity/Entity';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
|
||||
@Entity('exif')
|
||||
export class ExifEntity {
|
||||
@OneToOne(() => AssetEntity, { onDelete: 'CASCADE', nullable: true })
|
||||
@JoinColumn()
|
||||
asset?: AssetEntity;
|
||||
|
||||
@PrimaryColumn()
|
||||
assetId!: string;
|
||||
|
||||
/* General info */
|
||||
@Column({ type: 'text', default: '' })
|
||||
description!: string; // or caption
|
||||
|
||||
@Column({ type: 'integer', nullable: true })
|
||||
exifImageWidth!: number | null;
|
||||
|
||||
@Column({ type: 'integer', nullable: true })
|
||||
exifImageHeight!: number | null;
|
||||
|
||||
@Column({ type: 'bigint', nullable: true })
|
||||
fileSizeInByte!: number | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
orientation!: string | null;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
dateTimeOriginal!: Date | null;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
modifyDate!: Date | null;
|
||||
|
||||
@Column({ type: 'float', nullable: true })
|
||||
latitude!: number | null;
|
||||
|
||||
@Column({ type: 'float', nullable: true })
|
||||
longitude!: number | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
city!: string | null;
|
||||
|
||||
@Index('IDX_live_photo_cid')
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
livePhotoCID!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
state!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
country!: string | null;
|
||||
|
||||
/* Image info */
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
make!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
model!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
imageName!: string | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
lensModel!: string | null;
|
||||
|
||||
@Column({ type: 'float8', nullable: true })
|
||||
fNumber!: number | null;
|
||||
|
||||
@Column({ type: 'float8', nullable: true })
|
||||
focalLength!: number | null;
|
||||
|
||||
@Column({ type: 'integer', nullable: true })
|
||||
iso!: number | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
exposureTime!: string | null;
|
||||
|
||||
/* Video info */
|
||||
@Column({ type: 'float8', nullable: true })
|
||||
fps?: number | null;
|
||||
|
||||
@Index('exif_text_searchable', { synchronize: false })
|
||||
@Column({
|
||||
type: 'tsvector',
|
||||
generatedType: 'STORED',
|
||||
asExpression: `TO_TSVECTOR('english',
|
||||
COALESCE(make, '') || ' ' ||
|
||||
COALESCE(model, '') || ' ' ||
|
||||
COALESCE(orientation, '') || ' ' ||
|
||||
COALESCE("lensModel", '') || ' ' ||
|
||||
COALESCE("imageName", '') || ' ' ||
|
||||
COALESCE("city", '') || ' ' ||
|
||||
COALESCE("state", '') || ' ' ||
|
||||
COALESCE("country", ''))`,
|
||||
})
|
||||
exifTextSearchableColumn!: string;
|
||||
}
|
||||
33
server/libs/infra/src/entities/index.ts
Normal file
33
server/libs/infra/src/entities/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { AlbumEntity } from './album.entity';
|
||||
import { APIKeyEntity } from './api-key.entity';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
import { DeviceInfoEntity } from './device-info.entity';
|
||||
import { SharedLinkEntity } from './shared-link.entity';
|
||||
import { SmartInfoEntity } from './smart-info.entity';
|
||||
import { SystemConfigEntity } from './system-config.entity';
|
||||
import { UserTokenEntity } from './user-token.entity';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
export * from './album.entity';
|
||||
export * from './api-key.entity';
|
||||
export * from './asset.entity';
|
||||
export * from './device-info.entity';
|
||||
export * from './exif.entity';
|
||||
export * from './shared-link.entity';
|
||||
export * from './smart-info.entity';
|
||||
export * from './system-config.entity';
|
||||
export * from './tag.entity';
|
||||
export * from './user-token.entity';
|
||||
export * from './user.entity';
|
||||
|
||||
export const databaseEntities = [
|
||||
AssetEntity,
|
||||
AlbumEntity,
|
||||
APIKeyEntity,
|
||||
DeviceInfoEntity,
|
||||
UserEntity,
|
||||
SharedLinkEntity,
|
||||
SmartInfoEntity,
|
||||
SystemConfigEntity,
|
||||
UserTokenEntity,
|
||||
];
|
||||
68
server/libs/infra/src/entities/shared-link.entity.ts
Normal file
68
server/libs/infra/src/entities/shared-link.entity.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { AlbumEntity } from './album.entity';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('shared_links')
|
||||
@Unique('UQ_sharedlink_key', ['key'])
|
||||
export class SharedLinkEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@Column()
|
||||
userId!: string;
|
||||
|
||||
@ManyToOne(() => UserEntity)
|
||||
user!: UserEntity;
|
||||
|
||||
@Index('IDX_sharedlink_key')
|
||||
@Column({ type: 'bytea' })
|
||||
key!: Buffer; // use to access the inidividual asset
|
||||
|
||||
@Column()
|
||||
type!: SharedLinkType;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: string;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
expiresAt!: string | null;
|
||||
|
||||
@Column({ type: 'boolean', default: false })
|
||||
allowUpload!: boolean;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
allowDownload!: boolean;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
showExif!: boolean;
|
||||
|
||||
@ManyToMany(() => AssetEntity, (asset) => asset.sharedLinks)
|
||||
assets!: AssetEntity[];
|
||||
|
||||
@Index('IDX_sharedlink_albumId')
|
||||
@ManyToOne(() => AlbumEntity, (album) => album.sharedLinks)
|
||||
album?: AlbumEntity;
|
||||
}
|
||||
|
||||
export enum SharedLinkType {
|
||||
ALBUM = 'ALBUM',
|
||||
|
||||
/**
|
||||
* Individual asset
|
||||
* or group of assets that are not in an album
|
||||
*/
|
||||
INDIVIDUAL = 'INDIVIDUAL',
|
||||
}
|
||||
25
server/libs/infra/src/entities/smart-info.entity.ts
Normal file
25
server/libs/infra/src/entities/smart-info.entity.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Column, Entity, JoinColumn, OneToOne, PrimaryColumn } from 'typeorm';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
|
||||
@Entity('smart_info')
|
||||
export class SmartInfoEntity {
|
||||
@OneToOne(() => AssetEntity, { onDelete: 'CASCADE', nullable: true })
|
||||
@JoinColumn({ name: 'assetId', referencedColumnName: 'id' })
|
||||
asset?: AssetEntity;
|
||||
|
||||
@PrimaryColumn()
|
||||
assetId!: string;
|
||||
|
||||
@Column({ type: 'text', array: true, nullable: true })
|
||||
tags!: string[] | null;
|
||||
|
||||
@Column({ type: 'text', array: true, nullable: true })
|
||||
objects!: string[] | null;
|
||||
|
||||
@Column({
|
||||
type: 'float4',
|
||||
array: true,
|
||||
nullable: true,
|
||||
})
|
||||
clipEmbedding!: number[] | null;
|
||||
}
|
||||
69
server/libs/infra/src/entities/system-config.entity.ts
Normal file
69
server/libs/infra/src/entities/system-config.entity.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity('system_config')
|
||||
export class SystemConfigEntity<T = string | boolean> {
|
||||
@PrimaryColumn()
|
||||
key!: SystemConfigKey;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true, transformer: { to: JSON.stringify, from: JSON.parse } })
|
||||
value!: T;
|
||||
}
|
||||
|
||||
export type SystemConfigValue = any;
|
||||
|
||||
// dot notation matches path in `SystemConfig`
|
||||
export enum SystemConfigKey {
|
||||
FFMPEG_CRF = 'ffmpeg.crf',
|
||||
FFMPEG_PRESET = 'ffmpeg.preset',
|
||||
FFMPEG_TARGET_VIDEO_CODEC = 'ffmpeg.targetVideoCodec',
|
||||
FFMPEG_TARGET_AUDIO_CODEC = 'ffmpeg.targetAudioCodec',
|
||||
FFMPEG_TARGET_SCALING = 'ffmpeg.targetScaling',
|
||||
FFMPEG_TRANSCODE = 'ffmpeg.transcode',
|
||||
OAUTH_ENABLED = 'oauth.enabled',
|
||||
OAUTH_ISSUER_URL = 'oauth.issuerUrl',
|
||||
OAUTH_CLIENT_ID = 'oauth.clientId',
|
||||
OAUTH_CLIENT_SECRET = 'oauth.clientSecret',
|
||||
OAUTH_SCOPE = 'oauth.scope',
|
||||
OAUTH_AUTO_LAUNCH = 'oauth.autoLaunch',
|
||||
OAUTH_BUTTON_TEXT = 'oauth.buttonText',
|
||||
OAUTH_AUTO_REGISTER = 'oauth.autoRegister',
|
||||
OAUTH_MOBILE_OVERRIDE_ENABLED = 'oauth.mobileOverrideEnabled',
|
||||
OAUTH_MOBILE_REDIRECT_URI = 'oauth.mobileRedirectUri',
|
||||
PASSWORD_LOGIN_ENABLED = 'passwordLogin.enabled',
|
||||
STORAGE_TEMPLATE = 'storageTemplate.template',
|
||||
}
|
||||
|
||||
export enum TranscodePreset {
|
||||
ALL = 'all',
|
||||
OPTIMAL = 'optimal',
|
||||
REQUIRED = 'required',
|
||||
}
|
||||
|
||||
export interface SystemConfig {
|
||||
ffmpeg: {
|
||||
crf: string;
|
||||
preset: string;
|
||||
targetVideoCodec: string;
|
||||
targetAudioCodec: string;
|
||||
targetScaling: string;
|
||||
transcode: TranscodePreset;
|
||||
};
|
||||
oauth: {
|
||||
enabled: boolean;
|
||||
issuerUrl: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
scope: string;
|
||||
buttonText: string;
|
||||
autoRegister: boolean;
|
||||
autoLaunch: boolean;
|
||||
mobileOverrideEnabled: boolean;
|
||||
mobileRedirectUri: string;
|
||||
};
|
||||
passwordLogin: {
|
||||
enabled: boolean;
|
||||
};
|
||||
storageTemplate: {
|
||||
template: string;
|
||||
};
|
||||
}
|
||||
45
server/libs/infra/src/entities/tag.entity.ts
Normal file
45
server/libs/infra/src/entities/tag.entity.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('tags')
|
||||
@Unique('UQ_tag_name_userId', ['name', 'userId'])
|
||||
export class TagEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column()
|
||||
type!: TagType;
|
||||
|
||||
@Column()
|
||||
name!: string;
|
||||
|
||||
@ManyToOne(() => UserEntity, (user) => user.tags)
|
||||
user!: UserEntity;
|
||||
|
||||
@Column()
|
||||
userId!: string;
|
||||
|
||||
@Column({ type: 'uuid', comment: 'The new renamed tagId', nullable: true })
|
||||
renameTagId!: string;
|
||||
|
||||
@ManyToMany(() => AssetEntity, (asset) => asset.tags)
|
||||
assets!: AssetEntity[];
|
||||
}
|
||||
|
||||
export enum TagType {
|
||||
/**
|
||||
* Tag that is detected by the ML model for object detection will use this type
|
||||
*/
|
||||
OBJECT = 'OBJECT',
|
||||
|
||||
/**
|
||||
* Face that is detected by the ML model for facial detection (TBD/NOT YET IMPLEMENTED) will use this type
|
||||
*/
|
||||
FACE = 'FACE',
|
||||
|
||||
/**
|
||||
* Tag that is created by the user will use this type
|
||||
*/
|
||||
CUSTOM = 'CUSTOM',
|
||||
}
|
||||
20
server/libs/infra/src/entities/user-token.entity.ts
Normal file
20
server/libs/infra/src/entities/user-token.entity.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
@Entity('user_token')
|
||||
export class UserTokenEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column({ select: false })
|
||||
token!: string;
|
||||
|
||||
@ManyToOne(() => UserEntity)
|
||||
user!: UserEntity;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt!: string;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: string;
|
||||
}
|
||||
56
server/libs/infra/src/entities/user.entity.ts
Normal file
56
server/libs/infra/src/entities/user.entity.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { AssetEntity } from './asset.entity';
|
||||
import { TagEntity } from './tag.entity';
|
||||
|
||||
@Entity('users')
|
||||
export class UserEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
firstName!: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
lastName!: string;
|
||||
|
||||
@Column({ default: false })
|
||||
isAdmin!: boolean;
|
||||
|
||||
@Column({ unique: true })
|
||||
email!: string;
|
||||
|
||||
@Column({ default: '', select: false })
|
||||
password?: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
oauthId!: string;
|
||||
|
||||
@Column({ default: '' })
|
||||
profileImagePath!: string;
|
||||
|
||||
@Column({ default: true })
|
||||
shouldChangePassword!: boolean;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt!: string;
|
||||
|
||||
@DeleteDateColumn()
|
||||
deletedAt?: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt!: string;
|
||||
|
||||
@OneToMany(() => TagEntity, (tag) => tag.user)
|
||||
tags!: TagEntity[];
|
||||
|
||||
@OneToMany(() => AssetEntity, (asset) => asset.owner)
|
||||
assets!: AssetEntity[];
|
||||
}
|
||||
Reference in New Issue
Block a user