mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(web): user profile (#1148)
* fix: allow updateUser for admin account * feat: update user first/last name * feat(web): change password
This commit is contained in:
@@ -5,7 +5,9 @@ import { AuthType, IMMICH_AUTH_TYPE_COOKIE } from '../../constants/jwt.constant'
|
||||
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
|
||||
import { UserResponseDto } from '../user/response-dto/user-response.dto';
|
||||
import { AuthService } from './auth.service';
|
||||
import { ChangePasswordDto } from './dto/change-password.dto';
|
||||
import { LoginCredentialDto } from './dto/login-credential.dto';
|
||||
import { SignUpDto } from './dto/sign-up.dto';
|
||||
import { AdminSignupResponseDto } from './response-dto/admin-signup-response.dto';
|
||||
@@ -45,6 +47,13 @@ export class AuthController {
|
||||
return new ValidateAccessTokenResponseDto(true);
|
||||
}
|
||||
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@Post('change-password')
|
||||
async changePassword(@GetAuthUser() authUser: AuthUserDto, @Body() dto: ChangePasswordDto): Promise<UserResponseDto> {
|
||||
return this.authService.changePassword(authUser, dto);
|
||||
}
|
||||
|
||||
@Post('/logout')
|
||||
async logout(@Req() req: Request, @Res({ passthrough: true }) response: Response): Promise<LogoutResponseDto> {
|
||||
const authType: AuthType = req.cookies[IMMICH_AUTH_TYPE_COOKIE];
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { BadRequestException, Inject, Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
Inject,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
Logger,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { UserEntity } from '../../../../../libs/database/src/entities/user.entity';
|
||||
import { AuthType } from '../../constants/jwt.constant';
|
||||
import { AuthUserDto } from '../../decorators/auth-user.decorator';
|
||||
import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
|
||||
import { IUserRepository, USER_REPOSITORY } from '../user/user-repository';
|
||||
import { ChangePasswordDto } from './dto/change-password.dto';
|
||||
import { LoginCredentialDto } from './dto/login-credential.dto';
|
||||
import { SignUpDto } from './dto/sign-up.dto';
|
||||
import { AdminSignupResponseDto, mapAdminSignupResponse } from './response-dto/admin-signup-response.dto';
|
||||
@@ -48,6 +57,23 @@ export class AuthService {
|
||||
return { successful: true, redirectUri: '/auth/login' };
|
||||
}
|
||||
|
||||
public async changePassword(authUser: AuthUserDto, dto: ChangePasswordDto) {
|
||||
const { password, newPassword } = dto;
|
||||
const user = await this.userRepository.getByEmail(authUser.email, true);
|
||||
if (!user) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
||||
const valid = await this.validatePassword(password, user);
|
||||
if (!valid) {
|
||||
throw new BadRequestException('Wrong password');
|
||||
}
|
||||
|
||||
user.password = newPassword;
|
||||
|
||||
return this.userRepository.update(user.id, user);
|
||||
}
|
||||
|
||||
public async adminSignUp(dto: SignUpDto): Promise<AdminSignupResponseDto> {
|
||||
const adminUser = await this.userRepository.getAdmin();
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
|
||||
|
||||
export class ChangePasswordDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ example: 'password' })
|
||||
password!: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MinLength(8)
|
||||
@ApiProperty({ example: 'password' })
|
||||
newPassword!: string;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ export class UserRepository implements IUserRepository {
|
||||
if (user.isAdmin) {
|
||||
const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } });
|
||||
|
||||
if (adminUser) {
|
||||
if (adminUser && adminUser.id !== id) {
|
||||
throw new BadRequestException('Admin user exists');
|
||||
}
|
||||
|
||||
|
||||
@@ -1707,6 +1707,42 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/auth/change-password": {
|
||||
"post": {
|
||||
"operationId": "changePassword",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ChangePasswordDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Authentication"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/auth/logout": {
|
||||
"post": {
|
||||
"operationId": "logout",
|
||||
@@ -3258,6 +3294,23 @@
|
||||
"authStatus"
|
||||
]
|
||||
},
|
||||
"ChangePasswordDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "password"
|
||||
},
|
||||
"newPassword": {
|
||||
"type": "string",
|
||||
"example": "password"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"password",
|
||||
"newPassword"
|
||||
]
|
||||
},
|
||||
"LogoutResponseDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user