forked from immich-app/immich
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(server): cli service (immich-app#9672)
- Loading branch information
Showing
9 changed files
with
174 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { ICryptoRepository } from 'src/interfaces/crypto.interface'; | ||
import { ILibraryRepository } from 'src/interfaces/library.interface'; | ||
import { ILoggerRepository } from 'src/interfaces/logger.interface'; | ||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; | ||
import { IUserRepository } from 'src/interfaces/user.interface'; | ||
import { CliService } from 'src/services/cli.service'; | ||
import { userStub } from 'test/fixtures/user.stub'; | ||
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; | ||
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; | ||
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; | ||
import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; | ||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; | ||
import { Mocked, describe, it } from 'vitest'; | ||
|
||
describe(CliService.name, () => { | ||
let sut: CliService; | ||
|
||
let userMock: Mocked<IUserRepository>; | ||
let cryptoMock: Mocked<ICryptoRepository>; | ||
let libraryMock: Mocked<ILibraryRepository>; | ||
let systemMock: Mocked<ISystemMetadataRepository>; | ||
let loggerMock: Mocked<ILoggerRepository>; | ||
|
||
beforeEach(() => { | ||
cryptoMock = newCryptoRepositoryMock(); | ||
libraryMock = newLibraryRepositoryMock(); | ||
systemMock = newSystemMetadataRepositoryMock(); | ||
userMock = newUserRepositoryMock(); | ||
loggerMock = newLoggerRepositoryMock(); | ||
|
||
sut = new CliService(cryptoMock, libraryMock, systemMock, userMock, loggerMock); | ||
}); | ||
|
||
describe('resetAdminPassword', () => { | ||
it('should only work when there is an admin account', async () => { | ||
userMock.getAdmin.mockResolvedValue(null); | ||
const ask = vitest.fn().mockResolvedValue('new-password'); | ||
|
||
await expect(sut.resetAdminPassword(ask)).rejects.toThrowError('Admin account does not exist'); | ||
|
||
expect(ask).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should default to a random password', async () => { | ||
userMock.getAdmin.mockResolvedValue(userStub.admin); | ||
const ask = vitest.fn().mockImplementation(() => {}); | ||
|
||
const response = await sut.resetAdminPassword(ask); | ||
|
||
const [id, update] = userMock.update.mock.calls[0]; | ||
|
||
expect(response.provided).toBe(false); | ||
expect(ask).toHaveBeenCalled(); | ||
expect(id).toEqual(userStub.admin.id); | ||
expect(update.password).toBeDefined(); | ||
}); | ||
|
||
it('should use the supplied password', async () => { | ||
userMock.getAdmin.mockResolvedValue(userStub.admin); | ||
const ask = vitest.fn().mockResolvedValue('new-password'); | ||
|
||
const response = await sut.resetAdminPassword(ask); | ||
|
||
const [id, update] = userMock.update.mock.calls[0]; | ||
|
||
expect(response.provided).toBe(true); | ||
expect(ask).toHaveBeenCalled(); | ||
expect(id).toEqual(userStub.admin.id); | ||
expect(update.password).toBeDefined(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { Inject, Injectable } from '@nestjs/common'; | ||
import { SystemConfigCore } from 'src/cores/system-config.core'; | ||
import { UserCore } from 'src/cores/user.core'; | ||
import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; | ||
import { ICryptoRepository } from 'src/interfaces/crypto.interface'; | ||
import { ILibraryRepository } from 'src/interfaces/library.interface'; | ||
import { ILoggerRepository } from 'src/interfaces/logger.interface'; | ||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; | ||
import { IUserRepository } from 'src/interfaces/user.interface'; | ||
|
||
@Injectable() | ||
export class CliService { | ||
private configCore: SystemConfigCore; | ||
private userCore: UserCore; | ||
|
||
constructor( | ||
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, | ||
@Inject(ILibraryRepository) libraryRepository: ILibraryRepository, | ||
@Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, | ||
@Inject(IUserRepository) private userRepository: IUserRepository, | ||
@Inject(ILoggerRepository) private logger: ILoggerRepository, | ||
) { | ||
this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); | ||
this.logger.setContext(CliService.name); | ||
this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); | ||
} | ||
|
||
async listUsers(): Promise<UserResponseDto[]> { | ||
const users = await this.userRepository.getList({ withDeleted: true }); | ||
return users.map((user) => mapUser(user)); | ||
} | ||
|
||
async resetAdminPassword(ask: (admin: UserResponseDto) => Promise<string | undefined>) { | ||
const admin = await this.userRepository.getAdmin(); | ||
if (!admin) { | ||
throw new Error('Admin account does not exist'); | ||
} | ||
|
||
const providedPassword = await ask(mapUser(admin)); | ||
const password = providedPassword || this.cryptoRepository.newPassword(24); | ||
|
||
await this.userCore.updateUser(admin, admin.id, { password }); | ||
|
||
return { admin, password, provided: !!providedPassword }; | ||
} | ||
|
||
async disablePasswordLogin(): Promise<void> { | ||
const config = await this.configCore.getConfig(); | ||
config.passwordLogin.enabled = false; | ||
await this.configCore.updateConfig(config); | ||
} | ||
|
||
async enablePasswordLogin(): Promise<void> { | ||
const config = await this.configCore.getConfig(); | ||
config.passwordLogin.enabled = true; | ||
await this.configCore.updateConfig(config); | ||
} | ||
|
||
async disableOAuthLogin(): Promise<void> { | ||
const config = await this.configCore.getConfig(); | ||
config.oauth.enabled = false; | ||
await this.configCore.updateConfig(config); | ||
} | ||
|
||
async enableOAuthLogin(): Promise<void> { | ||
const config = await this.configCore.getConfig(); | ||
config.oauth.enabled = true; | ||
await this.configCore.updateConfig(config); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters