mirror of
https://github.com/immich-app/immich.git
synced 2025-12-27 01:11:42 +03:00
feat(web): Added admin user config to user settings (#15380)
* feat(web): Added admin user config to user settings * feat (web) - cleaned up the files and added tests * feat (web) - added missing files * feat (web) - updated per review comments * feat (web) - e2e admin command test failures
This commit is contained in:
@@ -37,6 +37,24 @@ export class CliService extends BaseService {
|
||||
await this.updateConfig(config);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
async disableOAuthLogin(): Promise<void> {
|
||||
const config = await this.getConfig({ withCache: false });
|
||||
config.oauth.enabled = false;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { JobName, UserStatus } from 'src/enum';
|
||||
import { UserAdminService } from 'src/services/user-admin.service';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
import { factory } from 'test/small.factory';
|
||||
import { newTestService, ServiceMocks } from 'test/utils';
|
||||
import { describe } from 'vitest';
|
||||
|
||||
@@ -116,7 +117,7 @@ describe(UserAdminService.name, () => {
|
||||
it('should throw error if user could not be found', async () => {
|
||||
mocks.user.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.delete(authStub.admin, userStub.admin.id, {})).rejects.toThrowError(BadRequestException);
|
||||
await expect(sut.delete(authStub.admin, 'not-found', {})).rejects.toThrowError(BadRequestException);
|
||||
expect(mocks.user.delete).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -124,8 +125,11 @@ describe(UserAdminService.name, () => {
|
||||
await expect(sut.delete(authStub.admin, userStub.admin.id, {})).rejects.toBeInstanceOf(ForbiddenException);
|
||||
});
|
||||
|
||||
it('should require the auth user be an admin', async () => {
|
||||
await expect(sut.delete(authStub.user1, authStub.admin.user.id, {})).rejects.toBeInstanceOf(ForbiddenException);
|
||||
it('should not allow deleting own account', async () => {
|
||||
const user = factory.userAdmin({ isAdmin: false });
|
||||
const auth = factory.auth({ user });
|
||||
mocks.user.get.mockResolvedValue(user);
|
||||
await expect(sut.delete(auth, user.id, {})).rejects.toBeInstanceOf(ForbiddenException);
|
||||
|
||||
expect(mocks.user.delete).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -52,6 +52,10 @@ export class UserAdminService extends BaseService {
|
||||
async update(auth: AuthDto, id: string, dto: UserAdminUpdateDto): Promise<UserAdminResponseDto> {
|
||||
const user = await this.findOrFail(id, {});
|
||||
|
||||
if (dto.isAdmin !== undefined && dto.isAdmin !== auth.user.isAdmin && auth.user.id === id) {
|
||||
throw new BadRequestException('Admin status can only be changed by another admin');
|
||||
}
|
||||
|
||||
if (dto.quotaSizeInBytes && user.quotaSizeInBytes !== dto.quotaSizeInBytes) {
|
||||
await this.userRepository.syncUsage(id);
|
||||
}
|
||||
@@ -89,9 +93,9 @@ export class UserAdminService extends BaseService {
|
||||
|
||||
async delete(auth: AuthDto, id: string, dto: UserAdminDeleteDto): Promise<UserAdminResponseDto> {
|
||||
const { force } = dto;
|
||||
const { isAdmin } = await this.findOrFail(id, {});
|
||||
if (isAdmin) {
|
||||
throw new ForbiddenException('Cannot delete admin user');
|
||||
await this.findOrFail(id, {});
|
||||
if (auth.user.id === id) {
|
||||
throw new ForbiddenException('Cannot delete your own account');
|
||||
}
|
||||
|
||||
await this.albumRepository.softDeleteAll(id);
|
||||
|
||||
Reference in New Issue
Block a user