1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

feat(server,web): update email address (#1186)

* feat: change email

* test: change email
This commit is contained in:
Jason Rasmussen 2022-12-27 11:36:31 -05:00 committed by GitHub
parent fdf51a8855
commit 380f719fd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 48 additions and 8 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,13 @@
import { IsNotEmpty, IsOptional } from 'class-validator';
import { IsEmail, IsNotEmpty, IsOptional } from 'class-validator';
export class UpdateUserDto {
@IsNotEmpty()
id!: string;
@IsEmail()
@IsOptional()
email?: string;
@IsOptional()
password?: string;

View File

@ -28,6 +28,13 @@ export class UserCore {
throw new BadRequestException('Admin user exists');
}
if (dto.email) {
const duplicate = await this.userRepository.getByEmail(dto.email);
if (duplicate && duplicate.id !== id) {
throw new BadRequestException('Email already in user by another account');
}
}
try {
if (dto.password) {
dto.password = await hash(dto.password, SALT_ROUNDS);

View File

@ -102,6 +102,28 @@ describe('UserService', () => {
await expect(result).rejects.toBeInstanceOf(ForbiddenException);
});
it('should let a user change their email', async () => {
const dto = { id: immichUser.id, email: 'updated@test.com' };
userRepositoryMock.get.mockResolvedValue(immichUser);
userRepositoryMock.update.mockResolvedValue(immichUser);
await sut.updateUser(immichUser, dto);
expect(userRepositoryMock.update).toHaveBeenCalledWith(immichUser.id, { email: 'updated@test.com' });
});
it('should not let a user change their email to one already in use', async () => {
const dto = { id: immichUser.id, email: 'updated@test.com' };
userRepositoryMock.get.mockResolvedValue(immichUser);
userRepositoryMock.getByEmail.mockResolvedValue(adminUser);
await expect(sut.updateUser(immichUser, dto)).rejects.toBeInstanceOf(BadRequestException);
expect(userRepositoryMock.update).not.toHaveBeenCalled();
});
it('admin can update any user information', async () => {
const update: UpdateUserDto = {
id: immichUser.id,

View File

@ -2400,6 +2400,9 @@
"id": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},

View File

@ -1779,6 +1779,12 @@ export interface UpdateUserDto {
* @memberof UpdateUserDto
*/
'id': string;
/**
*
* @type {string}
* @memberof UpdateUserDto
*/
'email'?: string;
/**
*
* @type {string}

View File

@ -1,5 +1,6 @@
<script lang="ts" context="module">
export enum SettingInputFieldType {
EMAIL = 'email',
TEXT = 'text',
NUMBER = 'number',
PASSWORD = 'password'

View File

@ -5,6 +5,7 @@
} from '$lib/components/shared-components/notification/notification';
import { api, UserResponseDto } from '@api';
import { fade } from 'svelte/transition';
import { handleError } from '../../utils/handle-error';
import SettingInputField, {
SettingInputFieldType
} from '../admin-page/settings/setting-input-field.svelte';
@ -15,6 +16,7 @@
try {
const { data } = await api.userApi.updateUser({
id: user.id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName
});
@ -26,11 +28,7 @@
type: NotificationType.Info
});
} catch (error) {
console.error('Error [user-profile] [updateProfile]', error);
notificationController.show({
message: 'Unable to save profile',
type: NotificationType.Error
});
handleError(error, 'Unable to save profile');
}
};
</script>
@ -47,10 +45,9 @@
/>
<SettingInputField
inputType={SettingInputFieldType.TEXT}
inputType={SettingInputFieldType.EMAIL}
label="Email"
bind:value={user.email}
disabled={true}
/>
<SettingInputField