mirror of
https://github.com/immich-app/immich.git
synced 2025-04-21 07:26:25 +02:00
refactor: repositories (#15561)
* refactor: version history repository * refactor: oauth repository * refactor: trash repository * refactor: telemetry repository * refactor: metadata repository * refactor: cron repository * refactor: map repository * refactor: server-info repository * refactor: album user repository * refactor: notification repository
This commit is contained in:
parent
995314446b
commit
1869b1b41a
57 changed files with 372 additions and 469 deletions
server
src
app.module.ts
controllers
emails
interfaces
album-user.interface.tscron.interface.tsjob.interface.tsmap.interface.tsmetadata.interface.tsnotification.interface.tsoauth.interface.tsserver-info.interface.tstelemetry.interface.tstrash.interface.tsversion-history.interface.ts
repositories
album-user.repository.tsasset.repository.tscron.repository.tsindex.tsmap.repository.tsmetadata.repository.tsnotification.repository.spec.tsnotification.repository.tsoauth.repository.tsserver-info.repository.tstelemetry.repository.tstrash.repository.tsversion-history.repository.ts
services
album.service.spec.tsauth.service.spec.tsauth.service.tsbackup.service.spec.tsbase.service.tsjob.service.spec.tslibrary.service.spec.tsmap.service.spec.tsmetadata.service.spec.tsmetadata.service.tsnotification.service.spec.tsnotification.service.tstrash.service.spec.tsversion.service.spec.ts
types.tstest
fixtures
repositories
album-user.repository.mock.tscron.repository.mock.tsmap.repository.mock.tsmetadata.repository.mock.tsnotification.repository.mock.tsoauth.repository.mock.tsserver-info.repository.mock.tstelemetry.repository.mock.tstrash.repository.mock.tsversion-history.repository.mock.ts
utils.ts
|
@ -13,7 +13,6 @@ import { entities } from 'src/entities';
|
|||
import { ImmichWorker } from 'src/enum';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository } from 'src/interfaces/job.interface';
|
||||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { AuthGuard } from 'src/middleware/auth.guard';
|
||||
import { ErrorInterceptor } from 'src/middleware/error.interceptor';
|
||||
import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor';
|
||||
|
@ -22,7 +21,7 @@ import { LoggingInterceptor } from 'src/middleware/logging.interceptor';
|
|||
import { providers, repositories } from 'src/repositories';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { teardownTelemetry } from 'src/repositories/telemetry.repository';
|
||||
import { teardownTelemetry, TelemetryRepository } from 'src/repositories/telemetry.repository';
|
||||
import { services } from 'src/services';
|
||||
import { CliService } from 'src/services/cli.service';
|
||||
import { DatabaseService } from 'src/services/database.service';
|
||||
|
@ -67,7 +66,7 @@ class BaseModule implements OnModuleInit, OnModuleDestroy {
|
|||
logger: LoggingRepository,
|
||||
@Inject(IEventRepository) private eventRepository: IEventRepository,
|
||||
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
||||
@Inject(ITelemetryRepository) private telemetryRepository: ITelemetryRepository,
|
||||
private telemetryRepository: TelemetryRepository,
|
||||
) {
|
||||
logger.setAppName(this.worker);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ import { ApiTags } from '@nestjs/swagger';
|
|||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { TemplateDto, TemplateResponseDto, TestEmailResponseDto } from 'src/dtos/notification.dto';
|
||||
import { SystemConfigSmtpDto } from 'src/dtos/system-config.dto';
|
||||
import { EmailTemplate } from 'src/interfaces/notification.interface';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { EmailTemplate } from 'src/repositories/notification.repository';
|
||||
import { NotificationService } from 'src/services/notification.service';
|
||||
|
||||
@ApiTags('Notifications')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Img, Link, Section, Text } from '@react-email/components';
|
|||
import * as React from 'react';
|
||||
import { ImmichButton } from 'src/emails/components/button.component';
|
||||
import ImmichLayout from 'src/emails/components/immich.layout';
|
||||
import { AlbumInviteEmailProps } from 'src/interfaces/notification.interface';
|
||||
import { AlbumInviteEmailProps } from 'src/repositories/notification.repository';
|
||||
import { replaceTemplateTags } from 'src/utils/replace-template-tags';
|
||||
|
||||
export const AlbumInviteEmail = ({
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Img, Link, Section, Text } from '@react-email/components';
|
|||
import * as React from 'react';
|
||||
import { ImmichButton } from 'src/emails/components/button.component';
|
||||
import ImmichLayout from 'src/emails/components/immich.layout';
|
||||
import { AlbumUpdateEmailProps } from 'src/interfaces/notification.interface';
|
||||
import { AlbumUpdateEmailProps } from 'src/repositories/notification.repository';
|
||||
import { replaceTemplateTags } from 'src/utils/replace-template-tags';
|
||||
|
||||
export const AlbumUpdateEmail = ({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Link, Row, Text } from '@react-email/components';
|
||||
import * as React from 'react';
|
||||
import ImmichLayout from 'src/emails/components/immich.layout';
|
||||
import { TestEmailProps } from 'src/interfaces/notification.interface';
|
||||
import { TestEmailProps } from 'src/repositories/notification.repository';
|
||||
|
||||
export const TestEmail = ({ baseUrl, displayName }: TestEmailProps) => (
|
||||
<ImmichLayout preview="This is a test email from Immich.">
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Link, Section, Text } from '@react-email/components';
|
|||
import * as React from 'react';
|
||||
import { ImmichButton } from 'src/emails/components/button.component';
|
||||
import ImmichLayout from 'src/emails/components/immich.layout';
|
||||
import { WelcomeEmailProps } from 'src/interfaces/notification.interface';
|
||||
import { WelcomeEmailProps } from 'src/repositories/notification.repository';
|
||||
import { replaceTemplateTags } from 'src/utils/replace-template-tags';
|
||||
|
||||
export const WelcomeEmail = ({ baseUrl, displayName, username, password, customTemplate }: WelcomeEmailProps) => {
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import { Insertable, Selectable, Updateable } from 'kysely';
|
||||
import { AlbumsSharedUsersUsers } from 'src/db';
|
||||
|
||||
export const IAlbumUserRepository = 'IAlbumUserRepository';
|
||||
|
||||
export type AlbumPermissionId = {
|
||||
albumsId: string;
|
||||
usersId: string;
|
||||
};
|
||||
|
||||
export interface IAlbumUserRepository {
|
||||
create(albumUser: Insertable<AlbumsSharedUsersUsers>): Promise<Selectable<AlbumsSharedUsersUsers>>;
|
||||
update(
|
||||
id: AlbumPermissionId,
|
||||
albumPermission: Updateable<AlbumsSharedUsersUsers>,
|
||||
): Promise<Selectable<AlbumsSharedUsersUsers>>;
|
||||
delete(id: AlbumPermissionId): Promise<void>;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
export const ICronRepository = 'ICronRepository';
|
||||
|
||||
type CronBase = {
|
||||
name: string;
|
||||
start?: boolean;
|
||||
};
|
||||
|
||||
export type CronCreate = CronBase & {
|
||||
expression: string;
|
||||
onTick: () => void;
|
||||
};
|
||||
|
||||
export type CronUpdate = CronBase & {
|
||||
expression?: string;
|
||||
};
|
||||
|
||||
export interface ICronRepository {
|
||||
create(cron: CronCreate): void;
|
||||
update(cron: CronUpdate): void;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { ClassConstructor } from 'class-transformer';
|
||||
import { EmailImageAttachment } from 'src/interfaces/notification.interface';
|
||||
import { EmailImageAttachment } from 'src/repositories/notification.repository';
|
||||
|
||||
export enum QueueName {
|
||||
THUMBNAIL_GENERATION = 'thumbnailGeneration',
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
export const IMapRepository = 'IMapRepository';
|
||||
|
||||
export interface MapMarkerSearchOptions {
|
||||
isArchived?: boolean;
|
||||
isFavorite?: boolean;
|
||||
fileCreatedBefore?: Date;
|
||||
fileCreatedAfter?: Date;
|
||||
}
|
||||
|
||||
export interface GeoPoint {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
export interface ReverseGeocodeResult {
|
||||
country: string | null;
|
||||
state: string | null;
|
||||
city: string | null;
|
||||
}
|
||||
|
||||
export interface MapMarker extends ReverseGeocodeResult {
|
||||
id: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
export interface IMapRepository {
|
||||
init(): Promise<void>;
|
||||
reverseGeocode(point: GeoPoint): Promise<ReverseGeocodeResult>;
|
||||
getMapMarkers(ownerIds: string[], albumIds: string[], options?: MapMarkerSearchOptions): Promise<MapMarker[]>;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
import { BinaryField, Tags } from 'exiftool-vendored';
|
||||
|
||||
export const IMetadataRepository = 'IMetadataRepository';
|
||||
|
||||
export interface ExifDuration {
|
||||
Value: number;
|
||||
Scale?: number;
|
||||
}
|
||||
|
||||
type StringOrNumber = string | number;
|
||||
|
||||
type TagsWithWrongTypes =
|
||||
| 'FocalLength'
|
||||
| 'Duration'
|
||||
| 'Description'
|
||||
| 'ImageDescription'
|
||||
| 'RegionInfo'
|
||||
| 'TagsList'
|
||||
| 'Keywords'
|
||||
| 'HierarchicalSubject'
|
||||
| 'ISO';
|
||||
export interface ImmichTags extends Omit<Tags, TagsWithWrongTypes> {
|
||||
ContentIdentifier?: string;
|
||||
MotionPhoto?: number;
|
||||
MotionPhotoVersion?: number;
|
||||
MotionPhotoPresentationTimestampUs?: number;
|
||||
MediaGroupUUID?: string;
|
||||
ImagePixelDepth?: string;
|
||||
FocalLength?: number;
|
||||
Duration?: number | string | ExifDuration;
|
||||
EmbeddedVideoType?: string;
|
||||
EmbeddedVideoFile?: BinaryField;
|
||||
MotionPhotoVideo?: BinaryField;
|
||||
TagsList?: StringOrNumber[];
|
||||
HierarchicalSubject?: StringOrNumber[];
|
||||
Keywords?: StringOrNumber | StringOrNumber[];
|
||||
ISO?: number | number[];
|
||||
|
||||
// Type is wrong, can also be number.
|
||||
Description?: StringOrNumber;
|
||||
ImageDescription?: StringOrNumber;
|
||||
|
||||
// Extended properties for image regions, such as faces
|
||||
RegionInfo?: {
|
||||
AppliedToDimensions: {
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
RegionList: {
|
||||
Area: {
|
||||
// (X,Y) // center of the rectangle
|
||||
X: number;
|
||||
Y: number;
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
Rotation?: number;
|
||||
Type?: string;
|
||||
Name?: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IMetadataRepository {
|
||||
teardown(): Promise<void>;
|
||||
readTags(path: string): Promise<ImmichTags>;
|
||||
writeTags(path: string, tags: Partial<Tags>): Promise<void>;
|
||||
extractBinaryTag(tagName: string, path: string): Promise<Buffer>;
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
export const INotificationRepository = 'INotificationRepository';
|
||||
|
||||
export type EmailImageAttachment = {
|
||||
filename: string;
|
||||
path: string;
|
||||
cid: string;
|
||||
};
|
||||
|
||||
export type SendEmailOptions = {
|
||||
from: string;
|
||||
to: string;
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
text: string;
|
||||
imageAttachments?: EmailImageAttachment[];
|
||||
smtp: SmtpOptions;
|
||||
};
|
||||
|
||||
export type SmtpOptions = {
|
||||
host: string;
|
||||
port?: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
ignoreCert?: boolean;
|
||||
};
|
||||
|
||||
export enum EmailTemplate {
|
||||
TEST_EMAIL = 'test',
|
||||
|
||||
// AUTH
|
||||
WELCOME = 'welcome',
|
||||
RESET_PASSWORD = 'reset-password',
|
||||
|
||||
// ALBUM
|
||||
ALBUM_INVITE = 'album-invite',
|
||||
ALBUM_UPDATE = 'album-update',
|
||||
}
|
||||
|
||||
interface BaseEmailProps {
|
||||
baseUrl: string;
|
||||
customTemplate?: string;
|
||||
}
|
||||
|
||||
export interface TestEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface WelcomeEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
username: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
export interface AlbumInviteEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
senderName: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export interface AlbumUpdateEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export type EmailRenderRequest =
|
||||
| {
|
||||
template: EmailTemplate.TEST_EMAIL;
|
||||
data: TestEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.WELCOME;
|
||||
data: WelcomeEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_INVITE;
|
||||
data: AlbumInviteEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_UPDATE;
|
||||
data: AlbumUpdateEmailProps;
|
||||
customTemplate: string;
|
||||
};
|
||||
|
||||
export type SendEmailResponse = {
|
||||
messageId: string;
|
||||
response: any;
|
||||
};
|
||||
|
||||
export interface INotificationRepository {
|
||||
renderEmail(request: EmailRenderRequest): Promise<{ html: string; text: string }>;
|
||||
sendEmail(options: SendEmailOptions): Promise<SendEmailResponse>;
|
||||
verifySmtp(options: SmtpOptions): Promise<true>;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import { UserinfoResponse } from 'openid-client';
|
||||
|
||||
export const IOAuthRepository = 'IOAuthRepository';
|
||||
|
||||
export type OAuthConfig = {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
issuerUrl: string;
|
||||
mobileOverrideEnabled: boolean;
|
||||
mobileRedirectUri: string;
|
||||
profileSigningAlgorithm: string;
|
||||
scope: string;
|
||||
signingAlgorithm: string;
|
||||
};
|
||||
export type OAuthProfile = UserinfoResponse;
|
||||
|
||||
export interface IOAuthRepository {
|
||||
init(): void;
|
||||
authorize(config: OAuthConfig, redirectUrl: string): Promise<string>;
|
||||
getLogoutEndpoint(config: OAuthConfig): Promise<string | undefined>;
|
||||
getProfile(config: OAuthConfig, url: string, redirectUrl: string): Promise<OAuthProfile>;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
export interface GitHubRelease {
|
||||
id: number;
|
||||
url: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface ServerBuildVersions {
|
||||
nodejs: string;
|
||||
ffmpeg: string;
|
||||
libvips: string;
|
||||
exiftool: string;
|
||||
imagemagick: string;
|
||||
}
|
||||
|
||||
export const IServerInfoRepository = 'IServerInfoRepository';
|
||||
|
||||
export interface IServerInfoRepository {
|
||||
getGitHubRelease(): Promise<GitHubRelease>;
|
||||
getBuildVersions(): Promise<ServerBuildVersions>;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import { MetricOptions } from '@opentelemetry/api';
|
||||
import { ClassConstructor } from 'class-transformer';
|
||||
|
||||
export const ITelemetryRepository = 'ITelemetryRepository';
|
||||
|
||||
export interface MetricGroupOptions {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface IMetricGroupRepository {
|
||||
addToCounter(name: string, value: number, options?: MetricOptions): void;
|
||||
addToGauge(name: string, value: number, options?: MetricOptions): void;
|
||||
addToHistogram(name: string, value: number, options?: MetricOptions): void;
|
||||
configure(options: MetricGroupOptions): this;
|
||||
}
|
||||
|
||||
export interface ITelemetryRepository {
|
||||
setup(options: { repositories: ClassConstructor<unknown>[] }): void;
|
||||
api: IMetricGroupRepository;
|
||||
host: IMetricGroupRepository;
|
||||
jobs: IMetricGroupRepository;
|
||||
repo: IMetricGroupRepository;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
export const ITrashRepository = 'ITrashRepository';
|
||||
|
||||
export interface ITrashRepository {
|
||||
empty(userId: string): Promise<number>;
|
||||
restore(userId: string): Promise<number>;
|
||||
restoreAll(assetIds: string[]): Promise<number>;
|
||||
getDeletedIds(): AsyncIterableIterator<{ id: string }>;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
import { VersionHistoryEntity } from 'src/entities/version-history.entity';
|
||||
|
||||
export const IVersionHistoryRepository = 'IVersionHistoryRepository';
|
||||
|
||||
export interface IVersionHistoryRepository {
|
||||
create(version: Omit<VersionHistoryEntity, 'id' | 'createdAt'>): Promise<VersionHistoryEntity>;
|
||||
getAll(): Promise<VersionHistoryEntity[]>;
|
||||
getLatest(): Promise<VersionHistoryEntity | undefined>;
|
||||
}
|
|
@ -4,10 +4,14 @@ import { InjectKysely } from 'nestjs-kysely';
|
|||
import { AlbumsSharedUsersUsers, DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { AlbumUserRole } from 'src/enum';
|
||||
import { AlbumPermissionId, IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
|
||||
export type AlbumPermissionId = {
|
||||
albumsId: string;
|
||||
usersId: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class AlbumUserRepository implements IAlbumUserRepository {
|
||||
export class AlbumUserRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
|
||||
|
@ -16,10 +20,7 @@ export class AlbumUserRepository implements IAlbumUserRepository {
|
|||
}
|
||||
|
||||
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] })
|
||||
update(
|
||||
{ usersId, albumsId }: AlbumPermissionId,
|
||||
dto: Updateable<AlbumsSharedUsersUsers>,
|
||||
): Promise<Selectable<AlbumsSharedUsersUsers>> {
|
||||
update({ usersId, albumsId }: AlbumPermissionId, dto: Updateable<AlbumsSharedUsersUsers>) {
|
||||
return this.db
|
||||
.updateTable('albums_shared_users_users')
|
||||
.set(dto)
|
||||
|
|
|
@ -43,8 +43,8 @@ import {
|
|||
WithProperty,
|
||||
WithoutProperty,
|
||||
} from 'src/interfaces/asset.interface';
|
||||
import { MapMarker, MapMarkerSearchOptions } from 'src/interfaces/map.interface';
|
||||
import { AssetSearchOptions, SearchExploreItem, SearchExploreItemSet } from 'src/interfaces/search.interface';
|
||||
import { MapMarker, MapMarkerSearchOptions } from 'src/repositories/map.repository';
|
||||
import { anyUuid, asUuid, mapUpsertColumns } from 'src/utils/database';
|
||||
import { Paginated, PaginationOptions, paginationHelper } from 'src/utils/pagination';
|
||||
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { CronJob, CronTime } from 'cron';
|
||||
import { CronCreate, CronUpdate, ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
type CronBase = {
|
||||
name: string;
|
||||
start?: boolean;
|
||||
};
|
||||
|
||||
export type CronCreate = CronBase & {
|
||||
expression: string;
|
||||
onTick: () => void;
|
||||
};
|
||||
|
||||
export type CronUpdate = CronBase & {
|
||||
expression?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class CronRepository implements ICronRepository {
|
||||
export class CronRepository {
|
||||
constructor(
|
||||
private schedulerRegistry: SchedulerRegistry,
|
||||
private logger: LoggingRepository,
|
||||
|
|
|
@ -1,33 +1,23 @@
|
|||
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||
import { IDatabaseRepository } from 'src/interfaces/database.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository } from 'src/interfaces/job.interface';
|
||||
import { ILibraryRepository } from 'src/interfaces/library.interface';
|
||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
import { IOAuthRepository } from 'src/interfaces/oauth.interface';
|
||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||
import { IProcessRepository } from 'src/interfaces/process.interface';
|
||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
|
||||
import { ISessionRepository } from 'src/interfaces/session.interface';
|
||||
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
|
||||
import { IStackRepository } from 'src/interfaces/stack.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
|
@ -71,44 +61,44 @@ import { ViewRepository } from 'src/repositories/view-repository';
|
|||
export const repositories = [
|
||||
AccessRepository,
|
||||
ActivityRepository,
|
||||
AlbumUserRepository,
|
||||
AuditRepository,
|
||||
ApiKeyRepository,
|
||||
ConfigRepository,
|
||||
CronRepository,
|
||||
LoggingRepository,
|
||||
MapRepository,
|
||||
MediaRepository,
|
||||
MemoryRepository,
|
||||
MetadataRepository,
|
||||
NotificationRepository,
|
||||
OAuthRepository,
|
||||
ServerInfoRepository,
|
||||
TelemetryRepository,
|
||||
TrashRepository,
|
||||
ViewRepository,
|
||||
VersionHistoryRepository,
|
||||
];
|
||||
|
||||
export const providers = [
|
||||
{ provide: IAlbumRepository, useClass: AlbumRepository },
|
||||
{ provide: IAlbumUserRepository, useClass: AlbumUserRepository },
|
||||
{ provide: IAssetRepository, useClass: AssetRepository },
|
||||
{ provide: ICronRepository, useClass: CronRepository },
|
||||
{ provide: ICryptoRepository, useClass: CryptoRepository },
|
||||
{ provide: IDatabaseRepository, useClass: DatabaseRepository },
|
||||
{ provide: IEventRepository, useClass: EventRepository },
|
||||
{ provide: IJobRepository, useClass: JobRepository },
|
||||
{ provide: ILibraryRepository, useClass: LibraryRepository },
|
||||
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository },
|
||||
{ provide: IMapRepository, useClass: MapRepository },
|
||||
{ provide: IMetadataRepository, useClass: MetadataRepository },
|
||||
{ provide: IMoveRepository, useClass: MoveRepository },
|
||||
{ provide: INotificationRepository, useClass: NotificationRepository },
|
||||
{ provide: IOAuthRepository, useClass: OAuthRepository },
|
||||
{ provide: IPartnerRepository, useClass: PartnerRepository },
|
||||
{ provide: IPersonRepository, useClass: PersonRepository },
|
||||
{ provide: IProcessRepository, useClass: ProcessRepository },
|
||||
{ provide: ISearchRepository, useClass: SearchRepository },
|
||||
{ provide: IServerInfoRepository, useClass: ServerInfoRepository },
|
||||
{ provide: ISessionRepository, useClass: SessionRepository },
|
||||
{ provide: ISharedLinkRepository, useClass: SharedLinkRepository },
|
||||
{ provide: IStackRepository, useClass: StackRepository },
|
||||
{ provide: IStorageRepository, useClass: StorageRepository },
|
||||
{ provide: ISystemMetadataRepository, useClass: SystemMetadataRepository },
|
||||
{ provide: ITagRepository, useClass: TagRepository },
|
||||
{ provide: ITelemetryRepository, useClass: TelemetryRepository },
|
||||
{ provide: ITrashRepository, useClass: TrashRepository },
|
||||
{ provide: IUserRepository, useClass: UserRepository },
|
||||
{ provide: IVersionHistoryRepository, useClass: VersionHistoryRepository },
|
||||
];
|
||||
|
|
|
@ -11,24 +11,41 @@ import { DB, GeodataPlaces, NaturalearthCountries } from 'src/db';
|
|||
import { AssetEntity, withExif } from 'src/entities/asset.entity';
|
||||
import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity';
|
||||
import { LogLevel, SystemMetadataKey } from 'src/enum';
|
||||
import {
|
||||
GeoPoint,
|
||||
IMapRepository,
|
||||
MapMarker,
|
||||
MapMarkerSearchOptions,
|
||||
ReverseGeocodeResult,
|
||||
} from 'src/interfaces/map.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export interface MapMarkerSearchOptions {
|
||||
isArchived?: boolean;
|
||||
isFavorite?: boolean;
|
||||
fileCreatedBefore?: Date;
|
||||
fileCreatedAfter?: Date;
|
||||
}
|
||||
|
||||
export interface GeoPoint {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
export interface ReverseGeocodeResult {
|
||||
country: string | null;
|
||||
state: string | null;
|
||||
city: string | null;
|
||||
}
|
||||
|
||||
export interface MapMarker extends ReverseGeocodeResult {
|
||||
id: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
interface MapDB extends DB {
|
||||
geodata_places_tmp: GeodataPlaces;
|
||||
naturalearth_countries_tmp: NaturalearthCountries;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class MapRepository implements IMapRepository {
|
||||
export class MapRepository {
|
||||
constructor(
|
||||
private configRepository: ConfigRepository,
|
||||
@Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository,
|
||||
|
|
|
@ -1,11 +1,72 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
|
||||
import { BinaryField, DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
|
||||
import geotz from 'geo-tz';
|
||||
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
interface ExifDuration {
|
||||
Value: number;
|
||||
Scale?: number;
|
||||
}
|
||||
|
||||
type StringOrNumber = string | number;
|
||||
|
||||
type TagsWithWrongTypes =
|
||||
| 'FocalLength'
|
||||
| 'Duration'
|
||||
| 'Description'
|
||||
| 'ImageDescription'
|
||||
| 'RegionInfo'
|
||||
| 'TagsList'
|
||||
| 'Keywords'
|
||||
| 'HierarchicalSubject'
|
||||
| 'ISO';
|
||||
|
||||
export interface ImmichTags extends Omit<Tags, TagsWithWrongTypes> {
|
||||
ContentIdentifier?: string;
|
||||
MotionPhoto?: number;
|
||||
MotionPhotoVersion?: number;
|
||||
MotionPhotoPresentationTimestampUs?: number;
|
||||
MediaGroupUUID?: string;
|
||||
ImagePixelDepth?: string;
|
||||
FocalLength?: number;
|
||||
Duration?: number | string | ExifDuration;
|
||||
EmbeddedVideoType?: string;
|
||||
EmbeddedVideoFile?: BinaryField;
|
||||
MotionPhotoVideo?: BinaryField;
|
||||
TagsList?: StringOrNumber[];
|
||||
HierarchicalSubject?: StringOrNumber[];
|
||||
Keywords?: StringOrNumber | StringOrNumber[];
|
||||
ISO?: number | number[];
|
||||
|
||||
// Type is wrong, can also be number.
|
||||
Description?: StringOrNumber;
|
||||
ImageDescription?: StringOrNumber;
|
||||
|
||||
// Extended properties for image regions, such as faces
|
||||
RegionInfo?: {
|
||||
AppliedToDimensions: {
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
RegionList: {
|
||||
Area: {
|
||||
// (X,Y) // center of the rectangle
|
||||
X: number;
|
||||
Y: number;
|
||||
W: number;
|
||||
H: number;
|
||||
Unit: string;
|
||||
};
|
||||
Rotation?: number;
|
||||
Type?: string;
|
||||
Name?: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class MetadataRepository implements IMetadataRepository {
|
||||
export class MetadataRepository {
|
||||
private exiftool = new ExifTool({
|
||||
defaultVideosToUTC: true,
|
||||
backfillTimezones: true,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { EmailRenderRequest, EmailTemplate } from 'src/interfaces/notification.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { EmailRenderRequest, EmailTemplate, NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { ILoggingRepository } from 'src/types';
|
||||
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
|
|
@ -6,18 +6,104 @@ import { AlbumInviteEmail } from 'src/emails/album-invite.email';
|
|||
import { AlbumUpdateEmail } from 'src/emails/album-update.email';
|
||||
import { TestEmail } from 'src/emails/test.email';
|
||||
import { WelcomeEmail } from 'src/emails/welcome.email';
|
||||
import {
|
||||
EmailRenderRequest,
|
||||
EmailTemplate,
|
||||
INotificationRepository,
|
||||
SendEmailOptions,
|
||||
SendEmailResponse,
|
||||
SmtpOptions,
|
||||
} from 'src/interfaces/notification.interface';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export type EmailImageAttachment = {
|
||||
filename: string;
|
||||
path: string;
|
||||
cid: string;
|
||||
};
|
||||
|
||||
export type SendEmailOptions = {
|
||||
from: string;
|
||||
to: string;
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
text: string;
|
||||
imageAttachments?: EmailImageAttachment[];
|
||||
smtp: SmtpOptions;
|
||||
};
|
||||
|
||||
export type SmtpOptions = {
|
||||
host: string;
|
||||
port?: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
ignoreCert?: boolean;
|
||||
};
|
||||
|
||||
export enum EmailTemplate {
|
||||
TEST_EMAIL = 'test',
|
||||
|
||||
// AUTH
|
||||
WELCOME = 'welcome',
|
||||
RESET_PASSWORD = 'reset-password',
|
||||
|
||||
// ALBUM
|
||||
ALBUM_INVITE = 'album-invite',
|
||||
ALBUM_UPDATE = 'album-update',
|
||||
}
|
||||
|
||||
interface BaseEmailProps {
|
||||
baseUrl: string;
|
||||
customTemplate?: string;
|
||||
}
|
||||
|
||||
export interface TestEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface WelcomeEmailProps extends BaseEmailProps {
|
||||
displayName: string;
|
||||
username: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
export interface AlbumInviteEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
senderName: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export interface AlbumUpdateEmailProps extends BaseEmailProps {
|
||||
albumName: string;
|
||||
albumId: string;
|
||||
recipientName: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export type EmailRenderRequest =
|
||||
| {
|
||||
template: EmailTemplate.TEST_EMAIL;
|
||||
data: TestEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.WELCOME;
|
||||
data: WelcomeEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_INVITE;
|
||||
data: AlbumInviteEmailProps;
|
||||
customTemplate: string;
|
||||
}
|
||||
| {
|
||||
template: EmailTemplate.ALBUM_UPDATE;
|
||||
data: AlbumUpdateEmailProps;
|
||||
customTemplate: string;
|
||||
};
|
||||
|
||||
export type SendEmailResponse = {
|
||||
messageId: string;
|
||||
response: any;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class NotificationRepository implements INotificationRepository {
|
||||
export class NotificationRepository {
|
||||
constructor(private logger: LoggingRepository) {
|
||||
this.logger.setContext(NotificationRepository.name);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
import { Injectable, InternalServerErrorException } from '@nestjs/common';
|
||||
import { custom, generators, Issuer } from 'openid-client';
|
||||
import { IOAuthRepository, OAuthConfig, OAuthProfile } from 'src/interfaces/oauth.interface';
|
||||
import { custom, generators, Issuer, UserinfoResponse } from 'openid-client';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export type OAuthConfig = {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
issuerUrl: string;
|
||||
mobileOverrideEnabled: boolean;
|
||||
mobileRedirectUri: string;
|
||||
profileSigningAlgorithm: string;
|
||||
scope: string;
|
||||
signingAlgorithm: string;
|
||||
};
|
||||
export type OAuthProfile = UserinfoResponse;
|
||||
|
||||
@Injectable()
|
||||
export class OAuthRepository implements IOAuthRepository {
|
||||
export class OAuthRepository {
|
||||
constructor(private logger: LoggingRepository) {
|
||||
this.logger.setContext(OAuthRepository.name);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,27 @@ import { exec as execCallback } from 'node:child_process';
|
|||
import { readFile } from 'node:fs/promises';
|
||||
import { promisify } from 'node:util';
|
||||
import sharp from 'sharp';
|
||||
import { GitHubRelease, IServerInfoRepository, ServerBuildVersions } from 'src/interfaces/server-info.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
export interface GitHubRelease {
|
||||
id: number;
|
||||
url: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface ServerBuildVersions {
|
||||
nodejs: string;
|
||||
ffmpeg: string;
|
||||
libvips: string;
|
||||
exiftool: string;
|
||||
imagemagick: string;
|
||||
}
|
||||
|
||||
const exec = promisify(execCallback);
|
||||
const maybeFirstLine = async (command: string): Promise<string> => {
|
||||
try {
|
||||
|
@ -34,7 +51,7 @@ const getLockfileVersion = (name: string, lockfile?: BuildLockfile) => {
|
|||
};
|
||||
|
||||
@Injectable()
|
||||
export class ServerInfoRepository implements IServerInfoRepository {
|
||||
export class ServerInfoRepository {
|
||||
constructor(
|
||||
private configRepository: ConfigRepository,
|
||||
private logger: LoggingRepository,
|
||||
|
|
|
@ -15,11 +15,12 @@ import { MetricService } from 'nestjs-otel';
|
|||
import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils';
|
||||
import { serverVersion } from 'src/constants';
|
||||
import { ImmichTelemetry, MetadataKey } from 'src/enum';
|
||||
import { IMetricGroupRepository, ITelemetryRepository, MetricGroupOptions } from 'src/interfaces/telemetry.interface';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
|
||||
class MetricGroupRepository implements IMetricGroupRepository {
|
||||
type MetricGroupOptions = { enabled: boolean };
|
||||
|
||||
export class MetricGroupRepository {
|
||||
private enabled = false;
|
||||
|
||||
constructor(private metricService: MetricService) {}
|
||||
|
@ -86,7 +87,7 @@ export const teardownTelemetry = async () => {
|
|||
};
|
||||
|
||||
@Injectable()
|
||||
export class TelemetryRepository implements ITelemetryRepository {
|
||||
export class TelemetryRepository {
|
||||
api: MetricGroupRepository;
|
||||
host: MetricGroupRepository;
|
||||
jobs: MetricGroupRepository;
|
||||
|
|
|
@ -3,9 +3,8 @@ import { InjectKysely } from 'nestjs-kysely';
|
|||
import { DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { AssetStatus } from 'src/enum';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
|
||||
export class TrashRepository implements ITrashRepository {
|
||||
export class TrashRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
getDeletedIds(): AsyncIterableIterator<{ id: string }> {
|
||||
|
|
|
@ -3,25 +3,23 @@ import { Insertable, Kysely } from 'kysely';
|
|||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB, VersionHistory } from 'src/db';
|
||||
import { GenerateSql } from 'src/decorators';
|
||||
import { VersionHistoryEntity } from 'src/entities/version-history.entity';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
|
||||
@Injectable()
|
||||
export class VersionHistoryRepository implements IVersionHistoryRepository {
|
||||
export class VersionHistoryRepository {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql()
|
||||
getAll(): Promise<VersionHistoryEntity[]> {
|
||||
getAll() {
|
||||
return this.db.selectFrom('version_history').selectAll().orderBy('createdAt', 'desc').execute();
|
||||
}
|
||||
|
||||
@GenerateSql()
|
||||
getLatest(): Promise<VersionHistoryEntity | undefined> {
|
||||
getLatest() {
|
||||
return this.db.selectFrom('version_history').selectAll().orderBy('createdAt', 'desc').executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [{ version: 'v1.123.0' }] })
|
||||
create(version: Insertable<VersionHistory>): Promise<VersionHistoryEntity> {
|
||||
create(version: Insertable<VersionHistory>) {
|
||||
return this.db.insertInto('version_history').values(version).returningAll().executeTakeFirstOrThrow();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ import { BadRequestException } from '@nestjs/common';
|
|||
import _ from 'lodash';
|
||||
import { BulkIdErrorReason } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AlbumUserRole } from 'src/enum';
|
||||
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { AlbumService } from 'src/services/album.service';
|
||||
import { IAlbumUserRepository } from 'src/types';
|
||||
import { albumStub } from 'test/fixtures/album.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
|
|
|
@ -5,13 +5,12 @@ import { UserEntity } from 'src/entities/user.entity';
|
|||
import { AuthType, Permission } from 'src/enum';
|
||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IOAuthRepository } from 'src/interfaces/oauth.interface';
|
||||
import { ISessionRepository } from 'src/interfaces/session.interface';
|
||||
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { AuthService } from 'src/services/auth.service';
|
||||
import { IApiKeyRepository } from 'src/types';
|
||||
import { IApiKeyRepository, IOAuthRepository } from 'src/types';
|
||||
import { keyStub } from 'test/fixtures/api-key.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { sessionStub } from 'test/fixtures/session.stub';
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
import { UserAdminResponseDto, mapUserAdmin } from 'src/dtos/user.dto';
|
||||
import { UserEntity } from 'src/entities/user.entity';
|
||||
import { AuthType, ImmichCookie, ImmichHeader, ImmichQuery, Permission } from 'src/enum';
|
||||
import { OAuthProfile } from 'src/interfaces/oauth.interface';
|
||||
import { OAuthProfile } from 'src/repositories/oauth.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { AuthApiKey } from 'src/types';
|
||||
import { isGranted } from 'src/utils/access';
|
||||
|
|
|
@ -2,14 +2,13 @@ import { PassThrough } from 'node:stream';
|
|||
import { defaults, SystemConfig } from 'src/config';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { ImmichWorker, StorageFolder } from 'src/enum';
|
||||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { IDatabaseRepository } from 'src/interfaces/database.interface';
|
||||
import { JobStatus } from 'src/interfaces/job.interface';
|
||||
import { IProcessRepository } from 'src/interfaces/process.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { BackupService } from 'src/services/backup.service';
|
||||
import { IConfigRepository } from 'src/types';
|
||||
import { IConfigRepository, ICronRepository } from 'src/types';
|
||||
import { systemConfigStub } from 'test/fixtures/system-config.stub';
|
||||
import { mockSpawn, newTestService } from 'test/utils';
|
||||
import { describe, Mocked } from 'vitest';
|
||||
|
|
|
@ -6,44 +6,44 @@ import { SALT_ROUNDS } from 'src/constants';
|
|||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { Users } from 'src/db';
|
||||
import { UserEntity } from 'src/entities/user.entity';
|
||||
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||
import { IDatabaseRepository } from 'src/interfaces/database.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository } from 'src/interfaces/job.interface';
|
||||
import { ILibraryRepository } from 'src/interfaces/library.interface';
|
||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
import { IOAuthRepository } from 'src/interfaces/oauth.interface';
|
||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||
import { IProcessRepository } from 'src/interfaces/process.interface';
|
||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
|
||||
import { ISessionRepository } from 'src/interfaces/session.interface';
|
||||
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
|
||||
import { IStackRepository } from 'src/interfaces/stack.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { CronRepository } from 'src/repositories/cron.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MapRepository } from 'src/repositories/map.repository';
|
||||
import { MediaRepository } from 'src/repositories/media.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { MetadataRepository } from 'src/repositories/metadata.repository';
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { OAuthRepository } from 'src/repositories/oauth.repository';
|
||||
import { ServerInfoRepository } from 'src/repositories/server-info.repository';
|
||||
import { TelemetryRepository } from 'src/repositories/telemetry.repository';
|
||||
import { TrashRepository } from 'src/repositories/trash.repository';
|
||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
||||
import { getConfig, updateConfig } from 'src/utils/config';
|
||||
|
@ -57,10 +57,10 @@ export class BaseService {
|
|||
protected activityRepository: ActivityRepository,
|
||||
protected auditRepository: AuditRepository,
|
||||
@Inject(IAlbumRepository) protected albumRepository: IAlbumRepository,
|
||||
@Inject(IAlbumUserRepository) protected albumUserRepository: IAlbumUserRepository,
|
||||
protected albumUserRepository: AlbumUserRepository,
|
||||
@Inject(IAssetRepository) protected assetRepository: IAssetRepository,
|
||||
protected configRepository: ConfigRepository,
|
||||
@Inject(ICronRepository) protected cronRepository: ICronRepository,
|
||||
protected cronRepository: CronRepository,
|
||||
@Inject(ICryptoRepository) protected cryptoRepository: ICryptoRepository,
|
||||
@Inject(IDatabaseRepository) protected databaseRepository: IDatabaseRepository,
|
||||
@Inject(IEventRepository) protected eventRepository: IEventRepository,
|
||||
|
@ -68,28 +68,28 @@ export class BaseService {
|
|||
protected keyRepository: ApiKeyRepository,
|
||||
@Inject(ILibraryRepository) protected libraryRepository: ILibraryRepository,
|
||||
@Inject(IMachineLearningRepository) protected machineLearningRepository: IMachineLearningRepository,
|
||||
@Inject(IMapRepository) protected mapRepository: IMapRepository,
|
||||
protected mapRepository: MapRepository,
|
||||
protected mediaRepository: MediaRepository,
|
||||
protected memoryRepository: MemoryRepository,
|
||||
@Inject(IMetadataRepository) protected metadataRepository: IMetadataRepository,
|
||||
protected metadataRepository: MetadataRepository,
|
||||
@Inject(IMoveRepository) protected moveRepository: IMoveRepository,
|
||||
@Inject(INotificationRepository) protected notificationRepository: INotificationRepository,
|
||||
@Inject(IOAuthRepository) protected oauthRepository: IOAuthRepository,
|
||||
protected notificationRepository: NotificationRepository,
|
||||
protected oauthRepository: OAuthRepository,
|
||||
@Inject(IPartnerRepository) protected partnerRepository: IPartnerRepository,
|
||||
@Inject(IPersonRepository) protected personRepository: IPersonRepository,
|
||||
@Inject(IProcessRepository) protected processRepository: IProcessRepository,
|
||||
@Inject(ISearchRepository) protected searchRepository: ISearchRepository,
|
||||
@Inject(IServerInfoRepository) protected serverInfoRepository: IServerInfoRepository,
|
||||
protected serverInfoRepository: ServerInfoRepository,
|
||||
@Inject(ISessionRepository) protected sessionRepository: ISessionRepository,
|
||||
@Inject(ISharedLinkRepository) protected sharedLinkRepository: ISharedLinkRepository,
|
||||
@Inject(IStackRepository) protected stackRepository: IStackRepository,
|
||||
@Inject(IStorageRepository) protected storageRepository: IStorageRepository,
|
||||
@Inject(ISystemMetadataRepository) protected systemMetadataRepository: ISystemMetadataRepository,
|
||||
@Inject(ITagRepository) protected tagRepository: ITagRepository,
|
||||
@Inject(ITelemetryRepository) protected telemetryRepository: ITelemetryRepository,
|
||||
@Inject(ITrashRepository) protected trashRepository: ITrashRepository,
|
||||
protected telemetryRepository: TelemetryRepository,
|
||||
protected trashRepository: TrashRepository,
|
||||
@Inject(IUserRepository) protected userRepository: IUserRepository,
|
||||
@Inject(IVersionHistoryRepository) protected versionRepository: IVersionHistoryRepository,
|
||||
protected versionRepository: VersionHistoryRepository,
|
||||
protected viewRepository: ViewRepository,
|
||||
) {
|
||||
this.logger.setContext(this.constructor.name);
|
||||
|
|
|
@ -3,10 +3,10 @@ import { defaults, SystemConfig } from 'src/config';
|
|||
import { ImmichWorker } from 'src/enum';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { IJobRepository, JobCommand, JobItem, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface';
|
||||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { JobService } from 'src/services/job.service';
|
||||
import { IConfigRepository, ILoggingRepository } from 'src/types';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { ITelemetryRepositoryMock } from 'test/repositories/telemetry.repository.mock';
|
||||
import { newTestService } from 'test/utils';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
|
@ -16,7 +16,7 @@ describe(JobService.name, () => {
|
|||
let configMock: Mocked<IConfigRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let loggerMock: Mocked<ILoggingRepository>;
|
||||
let telemetryMock: Mocked<ITelemetryRepository>;
|
||||
let telemetryMock: ITelemetryRepositoryMock;
|
||||
|
||||
beforeEach(() => {
|
||||
({ sut, assetMock, configMock, jobMock, loggerMock, telemetryMock } = newTestService(JobService, {}));
|
||||
|
|
|
@ -5,7 +5,6 @@ import { mapLibrary } from 'src/dtos/library.dto';
|
|||
import { UserEntity } from 'src/entities/user.entity';
|
||||
import { AssetType, ImmichWorker } from 'src/enum';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { IDatabaseRepository } from 'src/interfaces/database.interface';
|
||||
import {
|
||||
IJobRepository,
|
||||
|
@ -18,7 +17,7 @@ import {
|
|||
import { ILibraryRepository } from 'src/interfaces/library.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { LibraryService } from 'src/services/library.service';
|
||||
import { IConfigRepository } from 'src/types';
|
||||
import { IConfigRepository, ICronRepository } from 'src/types';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { libraryStub } from 'test/fixtures/library.stub';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||
import { MapService } from 'src/services/map.service';
|
||||
import { IMapRepository } from 'src/types';
|
||||
import { albumStub } from 'test/fixtures/album.stub';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
|
|
|
@ -10,15 +10,14 @@ import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interfac
|
|||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
|
||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { ImmichTags } from 'src/repositories/metadata.repository';
|
||||
import { MetadataService } from 'src/services/metadata.service';
|
||||
import { IConfigRepository, IMediaRepository } from 'src/types';
|
||||
import { IConfigRepository, IMapRepository, IMediaRepository, IMetadataRepository } from 'src/types';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { fileStub } from 'test/fixtures/file.stub';
|
||||
import { probeStub } from 'test/fixtures/media.stub';
|
||||
|
|
|
@ -18,8 +18,8 @@ import { WithoutProperty } from 'src/interfaces/asset.interface';
|
|||
import { DatabaseLock } from 'src/interfaces/database.interface';
|
||||
import { ArgOf } from 'src/interfaces/event.interface';
|
||||
import { JobName, JobOf, JOBS_ASSET_PAGINATION_SIZE, JobStatus, QueueName } from 'src/interfaces/job.interface';
|
||||
import { ReverseGeocodeResult } from 'src/interfaces/map.interface';
|
||||
import { ImmichTags } from 'src/interfaces/metadata.interface';
|
||||
import { ReverseGeocodeResult } from 'src/repositories/map.repository';
|
||||
import { ImmichTags } from 'src/repositories/metadata.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { isFaceImportEnabled } from 'src/utils/misc';
|
||||
import { usePagination } from 'src/utils/pagination';
|
||||
|
|
|
@ -8,10 +8,11 @@ import { IAlbumRepository } from 'src/interfaces/album.interface';
|
|||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository, INotifyAlbumUpdateJob, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||
import { EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||
import { EmailTemplate } from 'src/repositories/notification.repository';
|
||||
import { NotificationService } from 'src/services/notification.service';
|
||||
import { INotificationRepository } from 'src/types';
|
||||
import { albumStub } from 'test/fixtures/album.stub';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
JobStatus,
|
||||
QueueName,
|
||||
} from 'src/interfaces/job.interface';
|
||||
import { EmailImageAttachment, EmailTemplate } from 'src/interfaces/notification.interface';
|
||||
import { EmailImageAttachment, EmailTemplate } from 'src/repositories/notification.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { getAssetFiles } from 'src/utils/asset.util';
|
||||
import { getFilenameExtension } from 'src/utils/file';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BadRequestException } from '@nestjs/common';
|
||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { TrashService } from 'src/services/trash.service';
|
||||
import { ITrashRepository } from 'src/types';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
import { newTestService } from 'test/utils';
|
||||
|
|
|
@ -4,11 +4,9 @@ import { serverVersion } from 'src/constants';
|
|||
import { ImmichEnvironment, SystemMetadataKey } from 'src/enum';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
import { VersionService } from 'src/services/version.service';
|
||||
import { IConfigRepository, ILoggingRepository } from 'src/types';
|
||||
import { IConfigRepository, ILoggingRepository, IServerInfoRepository, IVersionHistoryRepository } from 'src/types';
|
||||
import { mockEnvData } from 'test/repositories/config.repository.mock';
|
||||
import { newTestService } from 'test/utils';
|
||||
import { Mocked } from 'vitest';
|
||||
|
|
|
@ -2,12 +2,22 @@ import { UserEntity } from 'src/entities/user.entity';
|
|||
import { ExifOrientation, ImageFormat, Permission, TranscodeTarget, VideoCodec } from 'src/enum';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { CronRepository } from 'src/repositories/cron.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MapRepository } from 'src/repositories/map.repository';
|
||||
import { MediaRepository } from 'src/repositories/media.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { MetadataRepository } from 'src/repositories/metadata.repository';
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { OAuthRepository } from 'src/repositories/oauth.repository';
|
||||
import { ServerInfoRepository } from 'src/repositories/server-info.repository';
|
||||
import { MetricGroupRepository, TelemetryRepository } from 'src/repositories/telemetry.repository';
|
||||
import { TrashRepository } from 'src/repositories/trash.repository';
|
||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
|
||||
export type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
||||
|
@ -23,9 +33,11 @@ export type RepositoryInterface<T extends object> = Pick<T, keyof T>;
|
|||
|
||||
export type IActivityRepository = RepositoryInterface<ActivityRepository>;
|
||||
export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInterface<AccessRepository[K]> };
|
||||
export type IAlbumUserRepository = RepositoryInterface<AlbumUserRepository>;
|
||||
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
||||
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
||||
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
||||
export type ICronRepository = RepositoryInterface<CronRepository>;
|
||||
export type ILoggingRepository = Pick<
|
||||
LoggingRepository,
|
||||
| 'verbose'
|
||||
|
@ -39,9 +51,18 @@ export type ILoggingRepository = Pick<
|
|||
| 'setContext'
|
||||
| 'setAppName'
|
||||
>;
|
||||
export type IMapRepository = RepositoryInterface<MapRepository>;
|
||||
export type IMediaRepository = RepositoryInterface<MediaRepository>;
|
||||
export type IMemoryRepository = RepositoryInterface<MemoryRepository>;
|
||||
export type IMetadataRepository = RepositoryInterface<MetadataRepository>;
|
||||
export type IMetricGroupRepository = RepositoryInterface<MetricGroupRepository>;
|
||||
export type INotificationRepository = RepositoryInterface<NotificationRepository>;
|
||||
export type IOAuthRepository = RepositoryInterface<OAuthRepository>;
|
||||
export type IServerInfoRepository = RepositoryInterface<ServerInfoRepository>;
|
||||
export type ITelemetryRepository = RepositoryInterface<TelemetryRepository>;
|
||||
export type ITrashRepository = RepositoryInterface<TrashRepository>;
|
||||
export type IViewRepository = RepositoryInterface<ViewRepository>;
|
||||
export type IVersionHistoryRepository = RepositoryInterface<VersionHistoryRepository>;
|
||||
|
||||
export type ActivityItem =
|
||||
| Awaited<ReturnType<IActivityRepository['create']>>
|
||||
|
|
2
server/test/fixtures/metadata.stub.ts
vendored
2
server/test/fixtures/metadata.stub.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import { ImmichTags } from 'src/interfaces/metadata.interface';
|
||||
import { ImmichTags } from 'src/repositories/metadata.repository';
|
||||
import { personStub } from 'test/fixtures/person.stub';
|
||||
|
||||
export const metadataStub = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||
import { IAlbumUserRepository } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newAlbumUserRepositoryMock = (): Mocked<IAlbumUserRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ICronRepository } from 'src/interfaces/cron.interface';
|
||||
import { ICronRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newCronRepositoryMock = (): Mocked<ICronRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMapRepository } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newMapRepositoryMock = (): Mocked<IMapRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMetadataRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newMetadataRepositoryMock = (): Mocked<IMetadataRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
import { INotificationRepository } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newNotificationRepositoryMock = (): Mocked<INotificationRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IOAuthRepository } from 'src/interfaces/oauth.interface';
|
||||
import { IOAuthRepository } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newOAuthRepositoryMock = (): Mocked<IOAuthRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
|
||||
import { IServerInfoRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newServerInfoRepositoryMock = (): Mocked<IServerInfoRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
|
||||
import { ITelemetryRepository, RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const newMetricGroupMock = () => {
|
||||
|
@ -10,7 +10,11 @@ const newMetricGroupMock = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const newTelemetryRepositoryMock = (): Mocked<ITelemetryRepository> => {
|
||||
export type ITelemetryRepositoryMock = {
|
||||
[K in keyof ITelemetryRepository]: Mocked<RepositoryInterface<ITelemetryRepository[K]>>;
|
||||
};
|
||||
|
||||
export const newTelemetryRepositoryMock = (): ITelemetryRepositoryMock => {
|
||||
return {
|
||||
setup: vitest.fn(),
|
||||
api: newMetricGroupMock(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { ITrashRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newTrashRepositoryMock = (): Mocked<ITrashRepository> => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
|
||||
import { IVersionHistoryRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newVersionHistoryRepositoryMock = (): Mocked<IVersionHistoryRepository> => {
|
||||
|
|
|
@ -2,24 +2,42 @@ import { ChildProcessWithoutNullStreams } from 'node:child_process';
|
|||
import { Writable } from 'node:stream';
|
||||
import { PNG } from 'pngjs';
|
||||
import { ImmichWorker } from 'src/enum';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { CronRepository } from 'src/repositories/cron.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MapRepository } from 'src/repositories/map.repository';
|
||||
import { MediaRepository } from 'src/repositories/media.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { MetadataRepository } from 'src/repositories/metadata.repository';
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { OAuthRepository } from 'src/repositories/oauth.repository';
|
||||
import { ServerInfoRepository } from 'src/repositories/server-info.repository';
|
||||
import { TelemetryRepository } from 'src/repositories/telemetry.repository';
|
||||
import { TrashRepository } from 'src/repositories/trash.repository';
|
||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import {
|
||||
IAccessRepository,
|
||||
IActivityRepository,
|
||||
IAlbumUserRepository,
|
||||
IApiKeyRepository,
|
||||
IAuditRepository,
|
||||
ICronRepository,
|
||||
ILoggingRepository,
|
||||
IMapRepository,
|
||||
IMediaRepository,
|
||||
IMemoryRepository,
|
||||
IMetadataRepository,
|
||||
INotificationRepository,
|
||||
IOAuthRepository,
|
||||
IServerInfoRepository,
|
||||
ITrashRepository,
|
||||
IVersionHistoryRepository,
|
||||
IViewRepository,
|
||||
} from 'src/types';
|
||||
import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
|
@ -66,7 +84,7 @@ import { Mocked, vitest } from 'vitest';
|
|||
|
||||
type Overrides = {
|
||||
worker?: ImmichWorker;
|
||||
metadataRepository?: IMetadataRepository;
|
||||
metadataRepository?: MetadataRepository;
|
||||
};
|
||||
type BaseServiceArgs = ConstructorParameters<typeof BaseService>;
|
||||
type Constructor<Type, Args extends Array<any>> = {
|
||||
|
@ -125,10 +143,10 @@ export const newTestService = <T extends BaseService>(
|
|||
activityMock as IActivityRepository as ActivityRepository,
|
||||
auditMock as IAuditRepository as AuditRepository,
|
||||
albumMock,
|
||||
albumUserMock,
|
||||
albumUserMock as IAlbumUserRepository as AlbumUserRepository,
|
||||
assetMock,
|
||||
configMock,
|
||||
cronMock,
|
||||
cronMock as ICronRepository as CronRepository,
|
||||
cryptoMock,
|
||||
databaseMock,
|
||||
eventMock,
|
||||
|
@ -136,28 +154,28 @@ export const newTestService = <T extends BaseService>(
|
|||
keyMock as IApiKeyRepository as ApiKeyRepository,
|
||||
libraryMock,
|
||||
machineLearningMock,
|
||||
mapMock,
|
||||
mapMock as IMapRepository as MapRepository,
|
||||
mediaMock as IMediaRepository as MediaRepository,
|
||||
memoryMock as IMemoryRepository as MemoryRepository,
|
||||
metadataMock,
|
||||
metadataMock as IMetadataRepository as MetadataRepository,
|
||||
moveMock,
|
||||
notificationMock,
|
||||
oauthMock,
|
||||
notificationMock as INotificationRepository as NotificationRepository,
|
||||
oauthMock as IOAuthRepository as OAuthRepository,
|
||||
partnerMock,
|
||||
personMock,
|
||||
processMock,
|
||||
searchMock,
|
||||
serverInfoMock,
|
||||
serverInfoMock as IServerInfoRepository as ServerInfoRepository,
|
||||
sessionMock,
|
||||
sharedLinkMock,
|
||||
stackMock,
|
||||
storageMock,
|
||||
systemMock,
|
||||
tagMock,
|
||||
telemetryMock,
|
||||
trashMock,
|
||||
telemetryMock as unknown as TelemetryRepository,
|
||||
trashMock as ITrashRepository as TrashRepository,
|
||||
userMock,
|
||||
versionHistoryMock,
|
||||
versionHistoryMock as IVersionHistoryRepository as VersionHistoryRepository,
|
||||
viewMock as IViewRepository as ViewRepository,
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue