Files
immich/server/src/database.ts

478 lines
11 KiB
TypeScript
Raw Normal View History

2025-04-10 18:36:29 +02:00
import { Selectable } from 'kysely';
import { MapAsset } from 'src/dtos/asset-response.dto';
import {
AlbumUserRole,
AssetFileType,
AssetType,
AssetVisibility,
MemoryType,
Permission,
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
PluginContext,
PluginTriggerType,
SharedLinkType,
SourceType,
2025-04-28 09:54:51 -04:00
UserAvatarColor,
UserStatus,
} from 'src/enum';
2025-06-30 13:19:16 -04:00
import { AlbumTable } from 'src/schema/tables/album.table';
2025-07-14 10:13:06 -04:00
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
import { PluginActionTable, PluginFilterTable, PluginTable } from 'src/schema/tables/plugin.table';
import { WorkflowActionTable, WorkflowFilterTable, WorkflowTable } from 'src/schema/tables/workflow.table';
2025-06-27 12:20:13 -04:00
import { UserMetadataItem } from 'src/types';
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
import type { ActionConfig, FilterConfig, JSONSchema } from 'src/types/plugin-schema.types';
export type AuthUser = {
id: string;
isAdmin: boolean;
name: string;
email: string;
quotaUsageInBytes: number;
quotaSizeInBytes: number | null;
};
2025-04-10 11:53:21 -04:00
export type AlbumUser = {
user: User;
role: AlbumUserRole;
};
2025-04-10 13:26:27 -04:00
export type AssetFile = {
id: string;
type: AssetFileType;
path: string;
};
export type Library = {
id: string;
ownerId: string;
createdAt: Date;
updatedAt: Date;
updateId: string;
name: string;
importPaths: string[];
exclusionPatterns: string[];
deletedAt: Date | null;
refreshedAt: Date | null;
assets?: MapAsset[];
};
export type AuthApiKey = {
id: string;
permissions: Permission[];
};
export type Activity = {
id: string;
createdAt: Date;
updatedAt: Date;
albumId: string;
userId: string;
user: User;
assetId: string | null;
comment: string | null;
isLiked: boolean;
updateId: string;
};
export type ApiKey = {
id: string;
name: string;
userId: string;
createdAt: Date;
updatedAt: Date;
permissions: Permission[];
};
2025-04-08 12:40:03 -04:00
export type Tag = {
id: string;
value: string;
createdAt: Date;
updatedAt: Date;
color: string | null;
parentId: string | null;
};
export type Memory = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
memoryAt: Date;
seenAt: Date | null;
showAt: Date | null;
hideAt: Date | null;
type: MemoryType;
2025-06-27 12:20:13 -04:00
data: object;
2025-04-08 12:40:03 -04:00
ownerId: string;
isSaved: boolean;
assets: MapAsset[];
};
export type Asset = {
id: string;
checksum: Buffer<ArrayBufferLike>;
deviceAssetId: string;
deviceId: string;
fileCreatedAt: Date;
fileModifiedAt: Date;
isExternal: boolean;
visibility: AssetVisibility;
libraryId: string | null;
livePhotoVideoId: string | null;
localDateTime: Date;
originalFileName: string;
originalPath: string;
ownerId: string;
type: AssetType;
2025-04-08 12:40:03 -04:00
};
export type User = {
id: string;
name: string;
email: string;
2025-04-28 09:54:51 -04:00
avatarColor: UserAvatarColor | null;
profileImagePath: string;
profileChangedAt: Date;
};
export type UserAdmin = User & {
storageLabel: string | null;
shouldChangePassword: boolean;
isAdmin: boolean;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
oauthId: string;
quotaSizeInBytes: number | null;
quotaUsageInBytes: number;
status: UserStatus;
2025-04-09 11:45:30 -04:00
metadata: UserMetadataItem[];
};
export type StorageAsset = {
id: string;
ownerId: string;
files: AssetFile[];
encodedVideoPath: string | null;
};
export type Stack = {
id: string;
primaryAssetId: string;
owner?: User;
ownerId: string;
assets: MapAsset[];
assetCount?: number;
};
export type AuthSharedLink = {
id: string;
expiresAt: Date | null;
userId: string;
showExif: boolean;
allowUpload: boolean;
allowDownload: boolean;
password: string | null;
};
export type SharedLink = {
id: string;
album?: Album | null;
albumId: string | null;
allowDownload: boolean;
allowUpload: boolean;
assets: MapAsset[];
createdAt: Date;
description: string | null;
expiresAt: Date | null;
key: Buffer;
password: string | null;
showExif: boolean;
type: SharedLinkType;
userId: string;
slug: string | null;
};
2025-06-30 13:19:16 -04:00
export type Album = Selectable<AlbumTable> & {
owner: User;
assets: MapAsset[];
};
export type AuthSession = {
id: string;
hasElevatedPermission: boolean;
};
export type Partner = {
sharedById: string;
sharedBy: User;
sharedWithId: string;
sharedWith: User;
createdAt: Date;
createId: string;
updatedAt: Date;
updateId: string;
inTimeline: boolean;
};
2025-04-09 10:24:38 -04:00
export type Place = {
admin1Code: string | null;
admin1Name: string | null;
admin2Code: string | null;
admin2Name: string | null;
alternateNames: string | null;
countryCode: string;
id: number;
latitude: number;
longitude: number;
modificationDate: Date;
name: string;
};
export type Session = {
id: string;
createdAt: Date;
updatedAt: Date;
2025-05-15 18:08:31 -04:00
expiresAt: Date | null;
2025-04-09 10:24:38 -04:00
deviceOS: string;
deviceType: string;
appVersion: string | null;
pinExpiresAt: Date | null;
2025-07-11 09:38:02 -04:00
isPendingSyncReset: boolean;
2025-04-09 10:24:38 -04:00
};
export type Exif = Omit<Selectable<AssetExifTable>, 'updatedAt' | 'updateId' | 'lockedProperties'>;
2025-04-10 18:36:29 +02:00
export type Person = {
createdAt: Date;
id: string;
ownerId: string;
updatedAt: Date;
updateId: string;
isFavorite: boolean;
name: string;
birthDate: Date | null;
color: string | null;
faceAssetId: string | null;
isHidden: boolean;
thumbnailPath: string;
};
export type AssetFace = {
id: string;
deletedAt: Date | null;
assetId: string;
boundingBoxX1: number;
boundingBoxX2: number;
boundingBoxY1: number;
boundingBoxY2: number;
imageHeight: number;
imageWidth: number;
personId: string | null;
sourceType: SourceType;
person?: Person | null;
updatedAt: Date;
updateId: string;
};
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
export type Plugin = Selectable<PluginTable>;
export type PluginFilter = Selectable<PluginFilterTable> & {
methodName: string;
title: string;
description: string;
supportedContexts: PluginContext[];
schema: JSONSchema | null;
};
export type PluginAction = Selectable<PluginActionTable> & {
methodName: string;
title: string;
description: string;
supportedContexts: PluginContext[];
schema: JSONSchema | null;
};
export type Workflow = Selectable<WorkflowTable> & {
triggerType: PluginTriggerType;
name: string | null;
description: string;
enabled: boolean;
};
export type WorkflowFilter = Selectable<WorkflowFilterTable> & {
workflowId: string;
pluginFilterId: string;
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
filterConfig: FilterConfig | null;
order: number;
};
export type WorkflowAction = Selectable<WorkflowActionTable> & {
workflowId: string;
pluginActionId: string;
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
actionConfig: ActionConfig | null;
order: number;
};
2025-04-28 09:54:51 -04:00
const userColumns = ['id', 'name', 'email', 'avatarColor', 'profileImagePath', 'profileChangedAt'] as const;
const userWithPrefixColumns = [
2025-07-14 10:13:06 -04:00
'user2.id',
'user2.name',
'user2.email',
'user2.avatarColor',
'user2.profileImagePath',
'user2.profileChangedAt',
2025-04-28 09:54:51 -04:00
] as const;
2025-01-15 23:31:26 -05:00
export const columns = {
asset: [
2025-07-14 10:13:06 -04:00
'asset.id',
'asset.checksum',
'asset.deviceAssetId',
'asset.deviceId',
'asset.fileCreatedAt',
'asset.fileModifiedAt',
'asset.isExternal',
'asset.visibility',
'asset.libraryId',
'asset.livePhotoVideoId',
'asset.localDateTime',
'asset.originalFileName',
'asset.originalPath',
'asset.ownerId',
'asset.type',
],
2025-07-14 10:13:06 -04:00
assetFiles: ['asset_file.id', 'asset_file.path', 'asset_file.type'],
authUser: ['user.id', 'user.name', 'user.email', 'user.isAdmin', 'user.quotaUsageInBytes', 'user.quotaSizeInBytes'],
authApiKey: ['api_key.id', 'api_key.permissions'],
authSession: ['session.id', 'session.updatedAt', 'session.pinExpiresAt', 'session.appVersion'],
authSharedLink: [
2025-07-14 10:13:06 -04:00
'shared_link.id',
'shared_link.userId',
'shared_link.expiresAt',
'shared_link.showExif',
'shared_link.allowUpload',
'shared_link.allowDownload',
'shared_link.password',
],
user: userColumns,
2025-04-28 09:54:51 -04:00
userWithPrefix: userWithPrefixColumns,
userAdmin: [
...userColumns,
'createdAt',
'updatedAt',
'deletedAt',
'isAdmin',
'status',
'oauthId',
'profileImagePath',
'shouldChangePassword',
'storageLabel',
'quotaSizeInBytes',
'quotaUsageInBytes',
],
2025-07-14 10:13:06 -04:00
tag: ['tag.id', 'tag.value', 'tag.createdAt', 'tag.updatedAt', 'tag.color', 'tag.parentId'],
apiKey: ['id', 'name', 'userId', 'createdAt', 'updatedAt', 'permissions'],
notification: ['id', 'createdAt', 'level', 'type', 'title', 'description', 'data', 'readAt'],
syncAsset: [
2025-07-14 10:13:06 -04:00
'asset.id',
'asset.ownerId',
'asset.originalFileName',
'asset.thumbhash',
'asset.checksum',
'asset.fileCreatedAt',
'asset.fileModifiedAt',
'asset.localDateTime',
'asset.type',
'asset.deletedAt',
'asset.isFavorite',
'asset.visibility',
'asset.duration',
2025-07-14 11:57:25 -04:00
'asset.livePhotoVideoId',
'asset.stackId',
'asset.libraryId',
2025-06-30 16:41:06 -04:00
],
syncAlbumUser: ['album_user.albumId as albumId', 'album_user.userId as userId', 'album_user.role'],
2025-07-14 10:13:06 -04:00
syncStack: ['stack.id', 'stack.createdAt', 'stack.updatedAt', 'stack.primaryAssetId', 'stack.ownerId'],
syncUser: ['id', 'name', 'email', 'avatarColor', 'deletedAt', 'updateId', 'profileImagePath', 'profileChangedAt'],
stack: ['stack.id', 'stack.primaryAssetId', 'ownerId'],
syncAssetExif: [
2025-07-14 10:13:06 -04:00
'asset_exif.assetId',
'asset_exif.description',
'asset_exif.exifImageWidth',
'asset_exif.exifImageHeight',
'asset_exif.fileSizeInByte',
'asset_exif.orientation',
'asset_exif.dateTimeOriginal',
'asset_exif.modifyDate',
'asset_exif.timeZone',
'asset_exif.latitude',
'asset_exif.longitude',
'asset_exif.projectionType',
'asset_exif.city',
'asset_exif.state',
'asset_exif.country',
'asset_exif.make',
'asset_exif.model',
'asset_exif.lensModel',
'asset_exif.fNumber',
'asset_exif.focalLength',
'asset_exif.iso',
'asset_exif.exposureTime',
'asset_exif.profileDescription',
'asset_exif.rating',
'asset_exif.fps',
],
exif: [
2025-07-14 10:13:06 -04:00
'asset_exif.assetId',
'asset_exif.autoStackId',
'asset_exif.bitsPerSample',
'asset_exif.city',
'asset_exif.colorspace',
'asset_exif.country',
'asset_exif.dateTimeOriginal',
'asset_exif.description',
'asset_exif.exifImageHeight',
'asset_exif.exifImageWidth',
'asset_exif.exposureTime',
'asset_exif.fileSizeInByte',
'asset_exif.fNumber',
'asset_exif.focalLength',
'asset_exif.fps',
'asset_exif.iso',
'asset_exif.latitude',
'asset_exif.lensModel',
'asset_exif.livePhotoCID',
'asset_exif.longitude',
'asset_exif.make',
'asset_exif.model',
'asset_exif.modifyDate',
'asset_exif.orientation',
'asset_exif.profileDescription',
'asset_exif.projectionType',
'asset_exif.rating',
'asset_exif.state',
'asset_exif.timeZone',
],
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
plugin: [
'plugin.id as id',
'plugin.name as name',
'plugin.title as title',
'plugin.description as description',
'plugin.author as author',
'plugin.version as version',
'plugin.wasmPath as wasmPath',
'plugin.createdAt as createdAt',
'plugin.updatedAt as updatedAt',
],
2025-01-15 23:31:26 -05:00
} as const;
export type LockableProperty = (typeof lockableProperties)[number];
export const lockableProperties = [
'description',
'dateTimeOriginal',
'latitude',
'longitude',
'rating',
'timeZone',
] as const;