auth-service-nestjs
Version:
Authorization service for lightweight systems
133 lines (130 loc) • 3.79 kB
text/typescript
import {
ForbiddenException,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import {
GetAllParam,
RegisterUser,
UserCreate,
UserItem,
UserList,
UserRoles,
UserUpdate,
} from 'src/users/users.dto';
import { InjectModel } from '@nestjs/sequelize';
import { UsersModel } from 'src/db/models/users.model';
import { Op } from 'sequelize';
import { SessionsModel } from 'src/db/models/sessions.model';
import { getPasswordHash } from 'src/utils/jsutils.cjs';
import { ErrorMessage } from 'src/utils/error';
import { DENY_ADMIN_CHANGE_ADMIN } from 'src/utils/const';
()
export class UsersService {
constructor(
(UsersModel) private userRepository: typeof UsersModel,
(SessionsModel) private sessionRepository: typeof SessionsModel,
) {}
async getAll(query: GetAllParam): Promise<UserList> {
const { limit, offset, sort, order, search } = query;
const or = search
? {
firstName: {
[Op.like]: `%${search}%`,
},
lastName: {
[Op.like]: `%${search}%`,
},
login: {
[Op.like]: `%${search}%`,
},
email: {
[Op.like]: `%${search}%`,
},
}
: undefined;
const where = or
? {
[Op.or]: or,
}
: undefined;
const data = await this.userRepository.findAndCountAll({
raw: true,
where,
limit,
offset,
attributes: { exclude: ['password'] },
order: sort && order ? [[sort, order]] : undefined,
});
return {
items: data.rows as UserItem[],
count: data.count,
};
}
async getUser(login: string): Promise<UsersModel> {
const userInfo = await this.userRepository.findOne({
where: { login },
raw: true,
});
if (!userInfo)
throw new HttpException(
ErrorMessage.UserNotFound,
HttpStatus.BAD_REQUEST,
);
return userInfo;
}
async delete(login: string): Promise<number> {
const user = await this.getUser(login);
if (+DENY_ADMIN_CHANGE_ADMIN && user.role === UserRoles.admin) {
throw new ForbiddenException();
}
await this.sessionRepository.destroy({ where: { login } });
return this.userRepository.destroy({ where: { login } });
}
async update(
login: string,
{ password, ...param }: UserUpdate,
tokenLogin: string,
): Promise<[number]> {
const userInfo = await this.getUser(login);
if (+DENY_ADMIN_CHANGE_ADMIN && userInfo.role === UserRoles.admin) {
const blockChangeLock =
param.locked !== undefined ? userInfo.locked !== param.locked : false;
const byMyself = tokenLogin === login;
const blockChangePassword =
password !== undefined && !byMyself
? userInfo.password !== getPasswordHash(password)
: false;
if (blockChangeLock || blockChangePassword)
throw new ForbiddenException();
}
return this.userRepository.update(
{
...param,
password: password ? getPasswordHash(password) : undefined,
},
{ where: { login } },
);
}
async create({ password, ...param }: UserCreate): Promise<UsersModel> {
return this.userRepository.create({
...param,
password: getPasswordHash(password),
});
}
async register(registerParams: RegisterUser) {
const { login } =
(await this.userRepository.findOne({
where: { login: registerParams.login },
raw: true,
})) ?? {};
if (login === registerParams.login) {
throw new HttpException(
ErrorMessage.NotAcceptable,
HttpStatus.NOT_ACCEPTABLE,
);
}
return this.create({ ...registerParams, locked: 1, role: UserRoles.guest });
}
}