users api
This commit is contained in:
29
package-lock.json
generated
29
package-lock.json
generated
@ -1847,6 +1847,15 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/bson": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
@ -1959,6 +1968,26 @@
|
|||||||
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
|
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/mongodb": {
|
||||||
|
"version": "3.5.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.25.tgz",
|
||||||
|
"integrity": "sha512-2H/Owt+pHCl9YmBOYnXc3VdnxejJEjVdH+QCWL5ZAfPehEn3evygKBX3/vKRv7aTwfNbUd0E5vjJdQklH/9a6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/bson": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/mongoose": {
|
||||||
|
"version": "5.7.32",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.7.32.tgz",
|
||||||
|
"integrity": "sha512-o1qijffQipTtYMJEYF8BOd+D8fy6ZGtGKP654udSEp6wysU3r1O2T8wHSP9QIC//QwQgKQGolu2y9vc9KXaq4w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/mongodb": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "13.13.15",
|
"version": "13.13.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz",
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
"@nestjs/testing": "^7.0.0",
|
"@nestjs/testing": "^7.0.0",
|
||||||
"@types/express": "^4.17.3",
|
"@types/express": "^4.17.3",
|
||||||
"@types/jest": "25.2.3",
|
"@types/jest": "25.2.3",
|
||||||
|
"@types/mongoose": "^5.7.32",
|
||||||
"@types/node": "^13.9.1",
|
"@types/node": "^13.9.1",
|
||||||
"@types/supertest": "^2.0.8",
|
"@types/supertest": "^2.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "3.0.2",
|
"@typescript-eslint/eslint-plugin": "3.0.2",
|
||||||
|
|||||||
@ -8,4 +8,4 @@ export const ALLOW_ORIGIN_ALL: [string, string] = ['Access-Control-Allow-Origin'
|
|||||||
export const ALLOW_CREDENTIALS: [string, string] = ['Access-Control-Allow-Credentials', 'true'];
|
export const ALLOW_CREDENTIALS: [string, string] = ['Access-Control-Allow-Credentials', 'true'];
|
||||||
export const CONTENT_LENGTH: [string, string] = ['Content-Length', '0'];
|
export const CONTENT_LENGTH: [string, string] = ['Content-Length', '0'];
|
||||||
export const ALLOW_METHOD: [string, string] = ['Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'];
|
export const ALLOW_METHOD: [string, string] = ['Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'];
|
||||||
export const ALLOW_HEADERS: [string, string] = ['Access-Control-Allow-Headers', 'Version, Authorization, Content-Type, Api-Name'];
|
export const ALLOW_HEADERS: [string, string] = ['Access-Control-Allow-Headers', 'Version, Authorization, Content-Type'];
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import {Controller, Get, Req, Post, Options, Header, Delete, HttpCode, Put, UseInterceptors, All} from '@nestjs/common';
|
import {Controller, Get, Req, Post, Options, Header, Delete, HttpCode, Put} from '@nestjs/common';
|
||||||
|
|
||||||
import {ApiResponse, ApiTags, ApiParam, ApiBody} from '@nestjs/swagger';
|
import {ApiResponse, ApiTags, ApiParam, ApiBody} from '@nestjs/swagger';
|
||||||
import {ALLOW_ORIGIN_ALL, ALLOW_METHOD, ALLOW_CREDENTIALS, CONTENT_LENGTH, ALLOW_HEADERS, USERS_CONTROLLER} from '../consts';
|
import {ALLOW_ORIGIN_ALL, ALLOW_METHOD, ALLOW_CREDENTIALS, CONTENT_LENGTH, ALLOW_HEADERS, USERS_CONTROLLER} from '../consts';
|
||||||
import {UserService} from './users.service';
|
import {UserService} from './users.service';
|
||||||
import {UserRequest} from './users.schema';
|
import {UserResponse, CreateUserRequest, UpdateUserRequest} from './users.schema';
|
||||||
|
import {Request} from 'express';
|
||||||
|
|
||||||
@Controller(USERS_CONTROLLER)
|
@Controller(USERS_CONTROLLER)
|
||||||
@ApiTags(USERS_CONTROLLER)
|
@ApiTags(USERS_CONTROLLER)
|
||||||
@ -17,12 +18,71 @@ export class UsersController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'Список всех пользователей',
|
description: 'Список всех пользователей',
|
||||||
type: [UserRequest]
|
type: [UserResponse]
|
||||||
})
|
})
|
||||||
async findAll(): Promise<UserRequest[]> {
|
async findAll(): Promise<UserResponse[]> {
|
||||||
return this.userService.findAll();
|
return this.userService.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get(':login')
|
||||||
|
@Header(...ALLOW_ORIGIN_ALL)
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Получить пользователя по логину'
|
||||||
|
})
|
||||||
|
@ApiParam({
|
||||||
|
name: 'login',
|
||||||
|
description: 'Логин пользователя',
|
||||||
|
})
|
||||||
|
async findOne(@Req() request: Request<{login: string}>): Promise<UserResponse> {
|
||||||
|
return await this.userService.findOne(request.params.login);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@Header(...ALLOW_ORIGIN_ALL)
|
||||||
|
@ApiResponse({
|
||||||
|
status: 201,
|
||||||
|
description: 'Создает пользователя в системе',
|
||||||
|
type: UserResponse,
|
||||||
|
})
|
||||||
|
@ApiBody({
|
||||||
|
type: CreateUserRequest,
|
||||||
|
description: 'Принимает объект для создания пользователя'
|
||||||
|
})
|
||||||
|
async createUser(@Req() request: Request<null, CreateUserRequest>): Promise<UserResponse> {
|
||||||
|
return await this.userService.create(request.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put()
|
||||||
|
@Header(...ALLOW_ORIGIN_ALL)
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Обновляет данные пользователя',
|
||||||
|
type: UpdateUserRequest
|
||||||
|
})
|
||||||
|
@ApiBody({
|
||||||
|
type: UpdateUserRequest,
|
||||||
|
description: 'Принимает объект для обновления данных пользователя'
|
||||||
|
})
|
||||||
|
async updateUser(@Req() request: Request<null, UpdateUserRequest>): Promise<UserResponse> {
|
||||||
|
return await this.userService.update(request.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':login')
|
||||||
|
@Header(...ALLOW_ORIGIN_ALL)
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Удаляет пользователя',
|
||||||
|
type: UpdateUserRequest,
|
||||||
|
})
|
||||||
|
@ApiParam({
|
||||||
|
name: 'login',
|
||||||
|
description: 'Логин пользователя',
|
||||||
|
})
|
||||||
|
async removeUser(@Req() request: Request<{login: string}>): Promise<UpdateUserRequest> {
|
||||||
|
return await this.userService.removeOne(request.params.login);
|
||||||
|
}
|
||||||
|
|
||||||
@Options()
|
@Options()
|
||||||
@Header(...ALLOW_ORIGIN_ALL)
|
@Header(...ALLOW_ORIGIN_ALL)
|
||||||
@Header(...ALLOW_METHOD)
|
@Header(...ALLOW_METHOD)
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
import { Document } from 'mongoose';
|
|
||||||
import {ApiProperty} from '@nestjs/swagger';
|
import {ApiProperty} from '@nestjs/swagger';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
|
||||||
interface Token {
|
interface Token {
|
||||||
token: string;
|
token: string;
|
||||||
expired_at: string;
|
expired_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserRequest {
|
export class CreateUserRequest {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
login: string;
|
login: string;
|
||||||
|
|
||||||
@ -15,7 +15,46 @@ export class UserRequest {
|
|||||||
avatar: string;
|
avatar: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
is_admin: string;
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateUserRequest {
|
||||||
|
@ApiProperty()
|
||||||
|
login: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
avatar: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UserResponse {
|
||||||
|
@ApiProperty()
|
||||||
|
login: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
avatar: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
is_admin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UserModel {
|
||||||
|
@ApiProperty()
|
||||||
|
login: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
avatar: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
is_admin: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
access_token: Token[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
refresh_token: Token[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema()
|
@Schema()
|
||||||
@ -44,20 +83,40 @@ export class User extends Document {
|
|||||||
is_admin: boolean;
|
is_admin: boolean;
|
||||||
|
|
||||||
@Prop({
|
@Prop({
|
||||||
type: {
|
type: [{
|
||||||
token: String,
|
token: String,
|
||||||
expired_at: String,
|
expired_at: String,
|
||||||
}
|
}]
|
||||||
})
|
})
|
||||||
access_token: Token;
|
access_token: Token[];
|
||||||
|
|
||||||
@Prop({
|
@Prop({
|
||||||
type: {
|
type: [{
|
||||||
token: String,
|
token: String,
|
||||||
expired_at: String,
|
expired_at: String,
|
||||||
}
|
}]
|
||||||
})
|
})
|
||||||
refresh_token: Token;
|
refresh_token: Token[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class UserUpdate extends Document {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
login: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
avatar: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
is_admin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserUpdateSchema = SchemaFactory.createForClass(UserUpdate);
|
||||||
export const UserSchema = SchemaFactory.createForClass(User);
|
export const UserSchema = SchemaFactory.createForClass(User);
|
||||||
|
|||||||
@ -1,20 +1,100 @@
|
|||||||
import {Model, Connection} from 'mongoose';
|
import {Model, Connection, Document} from 'mongoose';
|
||||||
import {Injectable} from '@nestjs/common';
|
import {Injectable, NotFoundException, BadGatewayException} from '@nestjs/common';
|
||||||
import {InjectConnection} from '@nestjs/mongoose';
|
import {InjectConnection} from '@nestjs/mongoose';
|
||||||
import {DB_NAME, USERS_CONTROLLER} from 'src/consts';
|
import {DB_NAME, USERS_CONTROLLER} from 'src/consts';
|
||||||
import {User, UserSchema} from './users.schema';
|
import {User, UserSchema, CreateUserRequest, UserResponse, UserModel, UpdateUserRequest} from './users.schema';
|
||||||
|
|
||||||
|
const validateModel = async (user: Document) => {
|
||||||
|
try {
|
||||||
|
await user.validate();
|
||||||
|
} catch (e) {
|
||||||
|
throw new BadGatewayException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const prepareUserToUserModel = (user: User): UserModel => ({
|
||||||
|
login: user.login,
|
||||||
|
avatar: user.avatar,
|
||||||
|
password: user.password,
|
||||||
|
is_admin: user.is_admin,
|
||||||
|
access_token: user.access_token,
|
||||||
|
refresh_token: user.refresh_token,
|
||||||
|
});
|
||||||
|
|
||||||
|
const prepareUserToUserResponse = (user: User): UserResponse => ({
|
||||||
|
login: user.login,
|
||||||
|
avatar: user.avatar,
|
||||||
|
is_admin: user.is_admin,
|
||||||
|
});
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectConnection(DB_NAME) private dbConnection: Connection,
|
@InjectConnection(DB_NAME) private dbConnection: Connection,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get userModel(): Model<User> {
|
userModel(): Model<User> {
|
||||||
return this.dbConnection.model<User>(USERS_CONTROLLER, UserSchema);
|
return this.dbConnection.model<User>(USERS_CONTROLLER, UserSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
findAll(): any {
|
async findUser(login: string): Promise<UserModel> {
|
||||||
return this.userModel.find().exec();
|
const user = await this.userModel().findOne({login});
|
||||||
|
return user ? prepareUserToUserModel(user) : user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(login: string): Promise<UserResponse> {
|
||||||
|
const user = await this.userModel().findOne({login});
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException(`Пользователь с логином ${login} не найден`);
|
||||||
|
}
|
||||||
|
return prepareUserToUserResponse(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(): Promise<UserResponse[]> {
|
||||||
|
const users = await this.userModel().find().exec();
|
||||||
|
return users.map(prepareUserToUserResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(user: CreateUserRequest): Promise<UserResponse> {
|
||||||
|
const searchUser = await this.findUser(user.login);
|
||||||
|
|
||||||
|
if (searchUser) {
|
||||||
|
throw new NotFoundException(`Пользователь с логином ${user.login} уже существует`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Model = await this.userModel();
|
||||||
|
const createUser = new Model(user);
|
||||||
|
await validateModel(createUser);
|
||||||
|
|
||||||
|
const savedUser = await createUser.save();
|
||||||
|
|
||||||
|
return prepareUserToUserResponse(savedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(user: UpdateUserRequest): Promise<UserResponse> {
|
||||||
|
const searchUser = await this.userModel().findOne({login: user.login});
|
||||||
|
|
||||||
|
const Model = await this.userModel();
|
||||||
|
const updateUser = new Model({
|
||||||
|
...user,
|
||||||
|
password: searchUser.password,
|
||||||
|
});
|
||||||
|
await validateModel(updateUser);
|
||||||
|
|
||||||
|
await searchUser.updateOne({
|
||||||
|
...{
|
||||||
|
avatar: user.avatar,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return prepareUserToUserResponse(updateUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeOne(login: string): Promise<UserResponse> {
|
||||||
|
const searchUser = await this.userModel().findOne({login});
|
||||||
|
|
||||||
|
await this.userModel().deleteOne({login});
|
||||||
|
|
||||||
|
return prepareUserToUserResponse(searchUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user