Files
immich/server/src/services/cli.service.ts

132 lines
3.8 KiB
TypeScript
Raw Normal View History

import { Injectable } from '@nestjs/common';
import { isAbsolute } from 'node:path';
import { SALT_ROUNDS } from 'src/constants';
import { UserAdminResponseDto, mapUserAdmin } from 'src/dtos/user.dto';
import { BaseService } from 'src/services/base.service';
2024-05-22 16:23:47 -04:00
@Injectable()
export class CliService extends BaseService {
async listUsers(): Promise<UserAdminResponseDto[]> {
2024-05-22 16:23:47 -04:00
const users = await this.userRepository.getList({ withDeleted: true });
return users.map((user) => mapUserAdmin(user));
2024-05-22 16:23:47 -04:00
}
async resetAdminPassword(ask: (admin: UserAdminResponseDto) => Promise<string | undefined>) {
2024-05-22 16:23:47 -04:00
const admin = await this.userRepository.getAdmin();
if (!admin) {
throw new Error('Admin account does not exist');
}
const providedPassword = await ask(mapUserAdmin(admin));
const password = providedPassword || this.cryptoRepository.randomBytesAsText(24);
const hashedPassword = await this.cryptoRepository.hashBcrypt(password, SALT_ROUNDS);
2024-05-22 16:23:47 -04:00
await this.userRepository.update(admin.id, { password: hashedPassword });
2024-05-22 16:23:47 -04:00
return { admin, password, provided: !!providedPassword };
}
async disablePasswordLogin(): Promise<void> {
const config = await this.getConfig({ withCache: false });
2024-05-22 16:23:47 -04:00
config.passwordLogin.enabled = false;
await this.updateConfig(config);
2024-05-22 16:23:47 -04:00
}
async enablePasswordLogin(): Promise<void> {
const config = await this.getConfig({ withCache: false });
2024-05-22 16:23:47 -04:00
config.passwordLogin.enabled = true;
await this.updateConfig(config);
2024-05-22 16:23:47 -04:00
}
async grantAdminAccess(email: string): Promise<void> {
const user = await this.userRepository.getByEmail(email);
if (!user) {
throw new Error('User does not exist');
}
await this.userRepository.update(user.id, { isAdmin: true });
}
async revokeAdminAccess(email: string): Promise<void> {
const user = await this.userRepository.getByEmail(email);
if (!user) {
throw new Error('User does not exist');
}
await this.userRepository.update(user.id, { isAdmin: false });
}
2024-05-22 16:23:47 -04:00
async disableOAuthLogin(): Promise<void> {
const config = await this.getConfig({ withCache: false });
2024-05-22 16:23:47 -04:00
config.oauth.enabled = false;
await this.updateConfig(config);
2024-05-22 16:23:47 -04:00
}
async enableOAuthLogin(): Promise<void> {
const config = await this.getConfig({ withCache: false });
2024-05-22 16:23:47 -04:00
config.oauth.enabled = true;
await this.updateConfig(config);
2024-05-22 16:23:47 -04:00
}
async getSampleFilePaths(): Promise<string[]> {
const [assets, people, users] = await Promise.all([
this.assetRepository.getFileSamples(),
this.personRepository.getFileSamples(),
this.userRepository.getFileSamples(),
]);
const paths = [];
for (const person of people) {
paths.push(person.thumbnailPath);
}
for (const user of users) {
paths.push(user.profileImagePath);
}
for (const asset of assets) {
paths.push(
asset.originalPath,
asset.sidecarPath,
asset.encodedVideoPath,
...asset.files.map((file) => file.path),
);
}
return paths.filter(Boolean) as string[];
}
async migrateFilePaths({
oldValue,
newValue,
confirm,
}: {
oldValue: string;
newValue: string;
confirm: (data: { sourceFolder: string; targetFolder: string }) => Promise<boolean>;
}): Promise<boolean> {
let sourceFolder = oldValue;
if (sourceFolder.startsWith('./')) {
sourceFolder = sourceFolder.slice(2);
}
const targetFolder = newValue;
if (!isAbsolute(targetFolder)) {
throw new Error('Target media location must be an absolute path');
}
if (!(await confirm({ sourceFolder, targetFolder }))) {
return false;
}
await this.databaseRepository.migrateFilePaths(sourceFolder, targetFolder);
return true;
}
cleanup() {
return this.databaseRepository.shutdown();
}
2024-05-22 16:23:47 -04:00
}