mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-12 14:55:39 +01:00
addres users by their id
This commit is contained in:
@@ -52,7 +52,10 @@ export class RolesService {
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.rolesRepository.remove(roleToModify);
|
||||
// Makes sure we can return the id
|
||||
const cloned = plainToClass(ERoleBackend, roleToModify);
|
||||
await this.rolesRepository.remove(roleToModify);
|
||||
return cloned;
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
HasSuccess
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { makeUnique } from 'picsur-shared/dist/util/unique';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Permissions } from '../../models/dto/permissions.dto';
|
||||
import {
|
||||
@@ -74,10 +73,8 @@ export class UsersService {
|
||||
return plainToClass(EUserBackend, user);
|
||||
}
|
||||
|
||||
public async delete(
|
||||
user: string | EUserBackend,
|
||||
): AsyncFailable<EUserBackend> {
|
||||
const userToModify = await this.resolve(user);
|
||||
public async delete(uuid: string): AsyncFailable<EUserBackend> {
|
||||
const userToModify = await this.findOne(uuid);
|
||||
if (HasFailed(userToModify)) return userToModify;
|
||||
|
||||
if (UndeletableUsersList.includes(userToModify.username)) {
|
||||
@@ -85,7 +82,10 @@ export class UsersService {
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.usersRepository.remove(userToModify);
|
||||
// Makes sure we can return the id
|
||||
const cloned = plainToClass(EUserBackend, userToModify);
|
||||
await this.usersRepository.remove(userToModify);
|
||||
return cloned;
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
@@ -94,10 +94,10 @@ export class UsersService {
|
||||
// Updating
|
||||
|
||||
public async setRoles(
|
||||
user: string | EUserBackend,
|
||||
uuid: string,
|
||||
roles: string[],
|
||||
): AsyncFailable<EUserBackend> {
|
||||
const userToModify = await this.resolve(user);
|
||||
const userToModify = await this.findOne(uuid);
|
||||
if (HasFailed(userToModify)) return userToModify;
|
||||
|
||||
if (ImmutableUsersList.includes(userToModify.username)) {
|
||||
@@ -138,20 +138,18 @@ export class UsersService {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async getPermissions(
|
||||
user: string | EUserBackend,
|
||||
): AsyncFailable<Permissions> {
|
||||
const userToModify = await this.resolve(user);
|
||||
public async getPermissions(uuid: string): AsyncFailable<Permissions> {
|
||||
const userToModify = await this.findOne(uuid);
|
||||
if (HasFailed(userToModify)) return userToModify;
|
||||
|
||||
return await this.rolesService.getPermissions(userToModify.roles);
|
||||
}
|
||||
|
||||
public async updatePassword(
|
||||
user: string | EUserBackend,
|
||||
uuid: string,
|
||||
password: string,
|
||||
): AsyncFailable<EUserBackend> {
|
||||
let userToModify = await this.resolve(user);
|
||||
let userToModify = await this.findOne(uuid);
|
||||
if (HasFailed(userToModify)) return userToModify;
|
||||
|
||||
const strength = await this.getBCryptStrength();
|
||||
@@ -174,7 +172,7 @@ export class UsersService {
|
||||
username: string,
|
||||
password: string,
|
||||
): AsyncFailable<EUserBackend> {
|
||||
const user = await this.findOne(username, true);
|
||||
const user = await this.findByUsername(username, true);
|
||||
if (HasFailed(user)) return user;
|
||||
|
||||
if (LockedLoginUsersList.includes(user.username)) {
|
||||
@@ -185,12 +183,12 @@ export class UsersService {
|
||||
if (!(await bcrypt.compare(password, user.password)))
|
||||
return Fail('Wrong password');
|
||||
|
||||
return await this.findOne(username);
|
||||
return await this.findOne(user.id);
|
||||
}
|
||||
|
||||
// Listing
|
||||
|
||||
public async findOne<B extends true | undefined = undefined>(
|
||||
public async findByUsername<B extends true | undefined = undefined>(
|
||||
username: string,
|
||||
// Also fetch fields that aren't normally sent to the client
|
||||
// (e.g. hashed password)
|
||||
@@ -213,6 +211,19 @@ export class UsersService {
|
||||
}
|
||||
}
|
||||
|
||||
public async findOne(uuid: string): AsyncFailable<EUserBackend> {
|
||||
try {
|
||||
const found = await this.usersRepository.findOne({
|
||||
where: { id: uuid },
|
||||
});
|
||||
|
||||
if (!found) return Fail('User not found');
|
||||
return found as EUserBackend;
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async findMany(
|
||||
count: number,
|
||||
page: number,
|
||||
@@ -231,26 +242,10 @@ export class UsersService {
|
||||
}
|
||||
|
||||
public async exists(username: string): Promise<boolean> {
|
||||
return HasSuccess(await this.findOne(username));
|
||||
return HasSuccess(await this.findByUsername(username));
|
||||
}
|
||||
|
||||
// Internal resolver
|
||||
|
||||
private async resolve(
|
||||
user: string | EUserBackend,
|
||||
): AsyncFailable<EUserBackend> {
|
||||
if (typeof user === 'string') {
|
||||
return await this.findOne(user);
|
||||
} else {
|
||||
user = plainToClass(EUserBackend, user);
|
||||
const errors = await strictValidate(user);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid user');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
// Internal
|
||||
|
||||
private filterAddedRoles(roles: string[]): string[] {
|
||||
const filteredRoles = roles.filter(
|
||||
|
||||
@@ -15,7 +15,6 @@ export class LocalAuthStrategy extends PassportStrategy(Strategy, 'local') {
|
||||
username: string,
|
||||
password: string,
|
||||
): AsyncFailable<EUserBackend> {
|
||||
|
||||
// All this does is call the usersservice authenticate for authentication
|
||||
const user = await this.usersService.authenticate(username, password);
|
||||
if (HasFailed(user)) {
|
||||
|
||||
@@ -50,7 +50,7 @@ export class MainAuthGuard extends AuthGuard(['jwt', 'guest']) {
|
||||
}
|
||||
|
||||
// These are the permissions the user has
|
||||
const userPermissions = await this.usersService.getPermissions(user);
|
||||
const userPermissions = await this.usersService.getPermissions(user.id);
|
||||
if (HasFailed(userPermissions)) {
|
||||
this.logger.warn('User Permissions: ' + userPermissions.getReason());
|
||||
throw new InternalServerErrorException();
|
||||
|
||||
@@ -14,7 +14,7 @@ export class GuestService {
|
||||
}
|
||||
|
||||
public async getGuestUser(): Promise<EUserBackend> {
|
||||
const user = await this.usersService.findOne('guest');
|
||||
const user = await this.usersService.findByUsername('guest');
|
||||
if (HasFailed(user)) {
|
||||
return this.fallBackUser;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export class UserController {
|
||||
@Get('me')
|
||||
@RequiredPermissions(Permission.UserKeepLogin)
|
||||
async me(@Request() req: AuthFasityRequest): Promise<UserMeResponse> {
|
||||
const user = await this.usersService.findOne(req.user.username);
|
||||
const user = await this.usersService.findOne(req.user.id);
|
||||
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
@@ -88,7 +88,7 @@ export class UserController {
|
||||
async refresh(
|
||||
@Request() req: AuthFasityRequest,
|
||||
): Promise<UserMePermissionsResponse> {
|
||||
const permissions = await this.usersService.getPermissions(req.user);
|
||||
const permissions = await this.usersService.getPermissions(req.user.id);
|
||||
if (HasFailed(permissions)) {
|
||||
this.logger.warn(permissions.getReason());
|
||||
throw new InternalServerErrorException('Could not get permissions');
|
||||
|
||||
@@ -78,9 +78,9 @@ export class UserManageController {
|
||||
|
||||
@Post('delete')
|
||||
async delete(
|
||||
@Body() deleteData: UserDeleteRequest,
|
||||
@Body() body: UserDeleteRequest,
|
||||
): Promise<UserDeleteResponse> {
|
||||
const user = await this.usersService.delete(deleteData.username);
|
||||
const user = await this.usersService.delete(body.id);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not delete user');
|
||||
@@ -91,7 +91,7 @@ export class UserManageController {
|
||||
|
||||
@Post('info')
|
||||
async getUser(@Body() body: UserInfoRequest): Promise<UserInfoResponse> {
|
||||
const user = await this.usersService.findOne(body.username);
|
||||
const user = await this.usersService.findOne(body.id);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not find user');
|
||||
@@ -104,14 +104,14 @@ export class UserManageController {
|
||||
async setPermissions(
|
||||
@Body() body: UserUpdateRequest,
|
||||
): Promise<UserUpdateResponse> {
|
||||
let user = await this.usersService.findOne(body.username);
|
||||
let user = await this.usersService.findOne(body.id);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not find user');
|
||||
}
|
||||
|
||||
if (body.roles) {
|
||||
user = await this.usersService.setRoles(user, body.roles);
|
||||
user = await this.usersService.setRoles(user.id, body.roles);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not update user');
|
||||
@@ -119,7 +119,7 @@ export class UserManageController {
|
||||
}
|
||||
|
||||
if (body.password) {
|
||||
user = await this.usersService.updatePassword(user, body.password);
|
||||
user = await this.usersService.updatePassword(user.id, body.password);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not update user');
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export interface FullUserModel {
|
||||
username: string;
|
||||
password: string;
|
||||
roles: string[];
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { FullUserModel } from '../forms-dto/fulluser.dto';
|
||||
import { UserCreateRequest, UserUpdateRequest } from 'picsur-shared/dist/dto/api/usermanage.dto';
|
||||
import {
|
||||
CreatePasswordError,
|
||||
CreateUsernameError,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '../validators/user.validator';
|
||||
|
||||
export class UpdateUserControl {
|
||||
private id: string = '';
|
||||
public username = new FormControl('', UsernameValidators);
|
||||
public password = new FormControl('', PasswordValidators);
|
||||
public roles = new FormControl([]);
|
||||
@@ -30,6 +31,10 @@ export class UpdateUserControl {
|
||||
|
||||
// Data interaction
|
||||
|
||||
public putId(id: string) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public putUsername(username: string) {
|
||||
this.username.setValue(username);
|
||||
}
|
||||
@@ -38,11 +43,18 @@ export class UpdateUserControl {
|
||||
this.roles.setValue(roles);
|
||||
}
|
||||
|
||||
public getData(): FullUserModel {
|
||||
public getDataCreate(): UserCreateRequest {
|
||||
return {
|
||||
username: this.username.value,
|
||||
password: this.password.value,
|
||||
roles: this.selectedRoles,
|
||||
};
|
||||
}
|
||||
|
||||
public getDataUpdate(): UserUpdateRequest {
|
||||
return {
|
||||
...this.getDataCreate(),
|
||||
id: this.id,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +80,11 @@ export class SettingsRolesComponent implements OnInit, AfterViewInit {
|
||||
const result = await this.rolesService.deleteRole(role.name);
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete user',
|
||||
'Failed to delete role',
|
||||
SnackBarType.Error
|
||||
);
|
||||
} else {
|
||||
this.utilService.showSnackBar('User deleted', SnackBarType.Success);
|
||||
this.utilService.showSnackBar('Role deleted', SnackBarType.Success);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,14 +60,14 @@ export class SettingsUsersEditComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async initUser() {
|
||||
const username = this.route.snapshot.paramMap.get('username');
|
||||
const uuid = this.route.snapshot.paramMap.get('uuid');
|
||||
|
||||
// Get special roles
|
||||
const SpecialRoles = await this.staticInfo.getSpecialRoles();
|
||||
this.soulBoundRoles = SpecialRoles.SoulBoundRoles;
|
||||
|
||||
// Check if edit or add
|
||||
if (!username) {
|
||||
if (!uuid) {
|
||||
this.mode = EditMode.add;
|
||||
|
||||
this.model.putRoles(SpecialRoles.DefaultRoles);
|
||||
@@ -76,10 +76,10 @@ export class SettingsUsersEditComponent implements OnInit {
|
||||
|
||||
// Set known data
|
||||
this.mode = EditMode.edit;
|
||||
this.model.putUsername(username);
|
||||
this.model.putId(uuid);
|
||||
|
||||
// Fetch more data
|
||||
const user = await this.userManageService.getUser(username);
|
||||
const user = await this.userManageService.getUser(uuid);
|
||||
if (HasFailed(user)) {
|
||||
this.utilService.showSnackBar('Failed to get user', SnackBarType.Error);
|
||||
return;
|
||||
@@ -128,9 +128,8 @@ export class SettingsUsersEditComponent implements OnInit {
|
||||
}
|
||||
|
||||
async updateUser() {
|
||||
const data = this.model.getData();
|
||||
|
||||
if (this.adding) {
|
||||
const data = this.model.getDataCreate();
|
||||
const resultUser = await this.userManageService.createUser(data);
|
||||
if (HasFailed(resultUser)) {
|
||||
this.utilService.showSnackBar(
|
||||
@@ -142,13 +141,10 @@ export class SettingsUsersEditComponent implements OnInit {
|
||||
|
||||
this.utilService.showSnackBar('User created', SnackBarType.Success);
|
||||
} else {
|
||||
const updateData = data.password
|
||||
? data
|
||||
: { username: data.username, roles: data.roles };
|
||||
const data = this.model.getDataUpdate();
|
||||
if (!data.password) delete data.password;
|
||||
|
||||
const resultUser = await this.userManageService.updateUser(
|
||||
updateData as any
|
||||
);
|
||||
const resultUser = await this.userManageService.updateUser(data);
|
||||
if (HasFailed(resultUser)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to update user',
|
||||
@@ -167,7 +163,9 @@ export class SettingsUsersEditComponent implements OnInit {
|
||||
if (this.adding) {
|
||||
return false;
|
||||
} else {
|
||||
return this.ImmutableUsersList.includes(this.model.getData().username);
|
||||
return this.ImmutableUsersList.includes(
|
||||
this.model.getDataCreate().username
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export class SettingsUsersComponent implements OnInit {
|
||||
}
|
||||
|
||||
public editUser(user: EUser) {
|
||||
this.router.navigate(['/settings/users/edit', user.username]);
|
||||
this.router.navigate(['/settings/users/edit', user.id]);
|
||||
}
|
||||
|
||||
public async deleteUser(user: EUser) {
|
||||
@@ -73,7 +73,7 @@ export class SettingsUsersComponent implements OnInit {
|
||||
});
|
||||
|
||||
if (pressedButton === 'delete') {
|
||||
const result = await this.userManageService.deleteUser(user.username);
|
||||
const result = await this.userManageService.deleteUser(user.id);
|
||||
if (HasFailed(result)) {
|
||||
this.utilService.showSnackBar(
|
||||
'Failed to delete user',
|
||||
|
||||
@@ -10,7 +10,7 @@ const routes: PRoutes = [
|
||||
component: SettingsUsersComponent,
|
||||
},
|
||||
{
|
||||
path: 'edit/:username',
|
||||
path: 'edit/:uuid',
|
||||
component: SettingsUsersEditComponent,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ export class RegisterComponent implements OnInit {
|
||||
}
|
||||
|
||||
if (!this.userService.isLoggedIn) {
|
||||
const loginResult = this.userService.login(data.username, data.password);
|
||||
const loginResult = await this.userService.login(data.username, data.password);
|
||||
if (HasFailed(loginResult)) {
|
||||
this.logger.warn(loginResult.getReason());
|
||||
this.utilService.showSnackBar(
|
||||
@@ -71,11 +71,16 @@ export class RegisterComponent implements OnInit {
|
||||
SnackBarType.Error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
this.utilService.showSnackBar(
|
||||
'Register successful',
|
||||
SnackBarType.Success
|
||||
);
|
||||
} else {
|
||||
this.utilService.showSnackBar(
|
||||
'Register successful, did not log in',
|
||||
SnackBarType.Success
|
||||
);
|
||||
}
|
||||
|
||||
this.router.navigate(['/']);
|
||||
|
||||
@@ -53,8 +53,6 @@ export class InfoService {
|
||||
const serverVersion = info.version;
|
||||
const clientVersion = this.getFrontendVersion();
|
||||
|
||||
console.log(serverVersion, clientVersion);
|
||||
|
||||
if (!isSemVer(serverVersion) || !isSemVer(clientVersion)) {
|
||||
return Fail(`Not a valid semver: ${serverVersion} or ${clientVersion}`);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
} from 'picsur-shared/dist/dto/api/usermanage.dto';
|
||||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { AsyncFailable, Open } from 'picsur-shared/dist/types';
|
||||
import { FullUserModel } from 'src/app/models/forms-dto/fulluser.dto';
|
||||
import { ApiService } from './api.service';
|
||||
|
||||
@Injectable({
|
||||
@@ -22,12 +21,12 @@ import { ApiService } from './api.service';
|
||||
export class UserManageService {
|
||||
constructor(private api: ApiService) {}
|
||||
|
||||
public async getUser(username: string): AsyncFailable<EUser> {
|
||||
public async getUser(id: string): AsyncFailable<EUser> {
|
||||
return await this.api.post(
|
||||
UserInfoRequest,
|
||||
UserInfoResponse,
|
||||
'api/user/info',
|
||||
{ username }
|
||||
{ id }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ export class UserManageService {
|
||||
return Open(result, 'users');
|
||||
}
|
||||
|
||||
public async createUser(user: FullUserModel): AsyncFailable<EUser> {
|
||||
public async createUser(user: UserCreateRequest): AsyncFailable<EUser> {
|
||||
return await this.api.post(
|
||||
UserCreateRequest,
|
||||
UserCreateResponse,
|
||||
@@ -54,7 +53,7 @@ export class UserManageService {
|
||||
);
|
||||
}
|
||||
|
||||
public async updateUser(user: FullUserModel): AsyncFailable<EUser> {
|
||||
public async updateUser(user: UserUpdateRequest): AsyncFailable<EUser> {
|
||||
return await this.api.post(
|
||||
UserUpdateRequest,
|
||||
UserUpdateResponse,
|
||||
@@ -63,12 +62,12 @@ export class UserManageService {
|
||||
);
|
||||
}
|
||||
|
||||
public async deleteUser(username: string): AsyncFailable<EUser> {
|
||||
public async deleteUser(id: string): AsyncFailable<EUser> {
|
||||
return await this.api.post(
|
||||
UserDeleteRequest,
|
||||
UserDeleteResponse,
|
||||
'/api/user/delete',
|
||||
{ username }
|
||||
{ id }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export class RoleUpdateRequest extends RoleNamePermsObject {}
|
||||
export class RoleUpdateResponse extends ERole {}
|
||||
|
||||
// RoleCreate
|
||||
export class RoleCreateRequest extends ERole {}
|
||||
export class RoleCreateRequest extends RoleNamePermsObject {}
|
||||
export class RoleCreateResponse extends ERole {}
|
||||
|
||||
// RoleDelete
|
||||
|
||||
@@ -5,10 +5,11 @@ import {
|
||||
IsOptional,
|
||||
ValidateNested
|
||||
} from 'class-validator';
|
||||
import { EUser, NamePassUser, UsernameUser } from '../../entities/user.entity';
|
||||
import { EUser, NamePassUser } from '../../entities/user.entity';
|
||||
import { IsPosInt } from '../../validators/positive-int.validator';
|
||||
import { IsStringList } from '../../validators/string-list.validator';
|
||||
import { IsPlainTextPwd } from '../../validators/user.validators';
|
||||
import { IsPlainTextPwd, IsUsername } from '../../validators/user.validators';
|
||||
import { EntityIDObject } from '../idobject.dto';
|
||||
|
||||
// UserList
|
||||
export class UserListRequest {
|
||||
@@ -42,15 +43,19 @@ export class UserCreateRequest extends NamePassUser {
|
||||
export class UserCreateResponse extends EUser {}
|
||||
|
||||
// UserDelete
|
||||
export class UserDeleteRequest extends UsernameUser {}
|
||||
export class UserDeleteRequest extends EntityIDObject {}
|
||||
export class UserDeleteResponse extends EUser {}
|
||||
|
||||
// UserInfo
|
||||
export class UserInfoRequest extends UsernameUser {}
|
||||
export class UserInfoRequest extends EntityIDObject {}
|
||||
export class UserInfoResponse extends EUser {}
|
||||
|
||||
// UserUpdateRoles
|
||||
export class UserUpdateRequest extends UsernameUser {
|
||||
// UserUpdate
|
||||
export class UserUpdateRequest extends EntityIDObject {
|
||||
@IsOptional()
|
||||
@IsUsername()
|
||||
username?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsStringList()
|
||||
roles?: string[];
|
||||
|
||||
Reference in New Issue
Block a user