Skip to content

Commit

Permalink
fix(server): restore user (#15763)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 authored Jan 29, 2025
1 parent 9033a99 commit a0aea02
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 6 deletions.
19 changes: 19 additions & 0 deletions e2e/src/api/specs/user-admin.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,5 +356,24 @@ describe('/admin/users', () => {
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});

it('should restore a user', async () => {
const user = await utils.userSetup(admin.accessToken, createUserDto.create('restore'));

await deleteUserAdmin({ id: user.userId, userAdminDeleteDto: {} }, { headers: asBearerAuth(admin.accessToken) });

const { status, body } = await request(app)
.post(`/admin/users/${user.userId}/restore`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual(
expect.objectContaining({
id: user.userId,
email: user.userEmail,
status: 'active',
deletedAt: null,
}),
);
});
});
});
2 changes: 1 addition & 1 deletion open-api/immich-openapi-specs.json
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@
}
],
"responses": {
"201": {
"200": {
"content": {
"application/json": {
"schema": {
Expand Down
2 changes: 1 addition & 1 deletion open-api/typescript-sdk/src/fetch-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ export function restoreUserAdmin({ id }: {
id: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 201;
status: 200;
data: UserAdminResponseDto;
}>(`/admin/users/${encodeURIComponent(id)}/restore`, {
...opts,
Expand Down
3 changes: 2 additions & 1 deletion server/src/controllers/user-admin.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthDto } from 'src/dtos/auth.dto';
import { UserPreferencesResponseDto, UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto';
Expand Down Expand Up @@ -75,6 +75,7 @@ export class UserAdminController {

@Post(':id/restore')
@Authenticated({ permission: Permission.ADMIN_USER_DELETE, admin: true })
@HttpCode(HttpStatus.OK)
restoreUserAdmin(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise<UserAdminResponseDto> {
return this.service.restore(auth, id);
}
Expand Down
1 change: 1 addition & 0 deletions server/src/interfaces/user.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface IUserRepository {
getUserStats(): Promise<UserStatsQueryResponse[]>;
create(user: Insertable<Users>): Promise<UserEntity>;
update(id: string, user: Updateable<Users>): Promise<UserEntity>;
restore(id: string): Promise<UserEntity>;
upsertMetadata<T extends keyof UserMetadata>(id: string, item: { key: T; value: UserMetadata[T] }): Promise<void>;
deleteMetadata<T extends keyof UserMetadata>(id: string, key: T): Promise<void>;
delete(user: UserEntity, hard?: boolean): Promise<UserEntity>;
Expand Down
11 changes: 11 additions & 0 deletions server/src/repositories/user.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DB, UserMetadata as DbUserMetadata, Users } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators';
import { UserMetadata } from 'src/entities/user-metadata.entity';
import { UserEntity, withMetadata } from 'src/entities/user.entity';
import { UserStatus } from 'src/enum';
import {
IUserRepository,
UserFindOptions,
Expand Down Expand Up @@ -140,6 +141,16 @@ export class UserRepository implements IUserRepository {
.executeTakeFirst() as unknown as Promise<UserEntity>;
}

restore(id: string): Promise<UserEntity> {
return this.db
.updateTable('users')
.set({ status: UserStatus.ACTIVE, deletedAt: null })
.where('users.id', '=', asUuid(id))
.returning(columns)
.returning(withMetadata)
.executeTakeFirst() as unknown as Promise<UserEntity>;
}

async upsertMetadata<T extends keyof UserMetadata>(id: string, { key, value }: { key: T; value: UserMetadata[T] }) {
await this.db
.insertInto('user_metadata')
Expand Down
4 changes: 2 additions & 2 deletions server/src/services/user-admin.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ describe(UserAdminService.name, () => {

it('should restore an user', async () => {
userMock.get.mockResolvedValue(userStub.user1);
userMock.update.mockResolvedValue(userStub.user1);
userMock.restore.mockResolvedValue(userStub.user1);
await expect(sut.restore(authStub.admin, userStub.user1.id)).resolves.toEqual(mapUserAdmin(userStub.user1));
expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { status: UserStatus.ACTIVE, deletedAt: null });
expect(userMock.restore).toHaveBeenCalledWith(userStub.user1.id);
});
});
});
2 changes: 1 addition & 1 deletion server/src/services/user-admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export class UserAdminService extends BaseService {
async restore(auth: AuthDto, id: string): Promise<UserAdminResponseDto> {
await this.findOrFail(id, { withDeleted: true });
await this.albumRepository.restoreAll(id);
const user = await this.userRepository.update(id, { deletedAt: null, status: UserStatus.ACTIVE });
const user = await this.userRepository.restore(id);
return mapUserAdmin(user);
}

Expand Down
1 change: 1 addition & 0 deletions server/test/repositories/user.repository.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const newUserRepositoryMock = (): Mocked<IUserRepository> => {
create: vitest.fn(),
update: vitest.fn(),
delete: vitest.fn(),
restore: vitest.fn(),
getDeletedUsers: vitest.fn(),
hasAdmin: vitest.fn(),
updateUsage: vitest.fn(),
Expand Down

0 comments on commit a0aea02

Please sign in to comment.