Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 28 create user controller and service #32

Merged
merged 23 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
],
},
};
2 changes: 1 addition & 1 deletion src/activity/controllers/activity/activity.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { CreateActivityDto } from '../../dto/create-activity.dto';
import { UpdateActivityDto } from '../../dto/update-activity.dto';
import { Query as ExpressQuery } from 'express-serve-static-core';
import { AuthGuard } from '@nestjs/passport';
import { Role } from '../../../auth/schemas/userAuthSchema';
import { Role } from '../../../auth/schemas/userAuth.model';

@Controller('events')
export class ActivityController {
Expand Down
2 changes: 1 addition & 1 deletion src/activity/dto/create-activity.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from 'class-validator';
import { IsTime } from '../../../custom-validators/is-time';
import { IsSocialMedia } from '../../../custom-validators/is-social-media';
import { User } from '../../auth/schemas/userAuthSchema';
import { User } from '../../auth/schemas/userAuth.model';

export class CreateActivityDto {
@IsEmpty({ message: 'You cannot pass user id.' })
Expand Down
2 changes: 1 addition & 1 deletion src/activity/dto/update-activity.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from 'class-validator';
import { IsTime } from '../../../custom-validators/is-time';
import { IsSocialMedia } from '../../../custom-validators/is-social-media';
import { User } from '../../auth/schemas/userAuthSchema';
import { User } from '../../auth/schemas/userAuth.model';

export class UpdateActivityDto {
@IsEmpty({ message: 'You cannot pass user id.' })
Expand Down
2 changes: 1 addition & 1 deletion src/activity/schemas/activity.schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { User } from '../../auth/schemas/userAuthSchema';
import { User } from '../../auth/schemas/userAuth.model';
import mongoose from 'mongoose';

export interface SocialMedia {
Expand Down
3 changes: 2 additions & 1 deletion src/activity/services/activity/activity.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-disable prettier/prettier */
import { Test, TestingModule } from '@nestjs/testing';
import { ActivityService } from './activity.service';
import mongoose, { Model } from 'mongoose';
import { getModelToken } from '@nestjs/mongoose';
import { Activity } from '../../schemas/activity.schema';
import { CreateActivityDto } from '../../dto/create-activity.dto';
import { User } from '../../../auth/schemas/userAuthSchema';
import { User } from '../../../auth/schemas/userAuth.model';
import { BadRequestException, NotFoundException } from '@nestjs/common';
import createMockActivity from '../../../../test/mock-data/createMockActivity';
import mockActivityFromDB from '../../../../test/mock-data/returned-mock-activity';
Expand Down
2 changes: 1 addition & 1 deletion src/activity/services/activity/activity.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { InjectModel } from '@nestjs/mongoose';
import mongoose, { Model } from 'mongoose';
import { Activity } from '../../schemas/activity.schema';
import { Query } from 'express-serve-static-core';
import { User } from '../../../auth/schemas/userAuthSchema';
import { User } from '../../../auth/schemas/userAuth.model';

@Injectable()
export class ActivityService {
Expand Down
4 changes: 1 addition & 3 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
/*
import { UserModule } from './user/user.module';
*/
import { ActivityModule } from './activity/activity.module';
import { AuthModule } from './auth/auth.module';

Expand All @@ -14,7 +12,7 @@ import { AuthModule } from './auth/auth.module';
isGlobal: true,
}),
MongooseModule.forRoot(process.env.MONGODB_URI),
/*UserModule,*/
UserModule,
ActivityModule,
AuthModule,
],
Expand Down
2 changes: 1 addition & 1 deletion src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { MongooseModule } from '@nestjs/mongoose';
import { UserAuthSchema } from './schemas/userAuthSchema';
import { UserAuthSchema } from './schemas/userAuth.model';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
Expand Down
8 changes: 6 additions & 2 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from './schemas/userAuthSchema';

import { User } from './schemas/userAuth.model';
import * as bcrypt from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { SignUpDto } from './dto/signup.dto';
Expand All @@ -19,7 +18,12 @@ export class AuthService {

async signUp(signUpDto: SignUpDto): Promise<{ token: string }> {
const { name, email, password, role } = signUpDto;

console.log('name: ', name);
console.log('email: ', email);
console.log('password: ', password);
const hashedPassword = await bcrypt.hash(password, 10);
console.log('hashedPassword: ', hashedPassword);
const user = await this.userModel.create({
name,
email,
Expand Down
2 changes: 1 addition & 1 deletion src/auth/dto/signup.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
import { Role } from '../schemas/userAuthSchema';
import { Role } from '../schemas/userAuth.model';

export class SignUpDto {
@IsNotEmpty()
Expand Down
2 changes: 1 addition & 1 deletion src/auth/jwt.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { InjectModel } from '@nestjs/mongoose';
import { PassportStrategy } from '@nestjs/passport';
import { Model } from 'mongoose';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { User } from './schemas/userAuthSchema';
import { User } from './schemas/userAuth.model';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
Expand Down
27 changes: 27 additions & 0 deletions src/auth/schemas/userAuth.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Document } from 'mongoose';
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

export enum Role {
admin = 'admin',
creator = 'creator',
user = 'user',
}

@Schema({
timestamps: true,
})
export class User extends Document {
@Prop()
name: string;

@Prop({ unique: [true, 'Duplicate email entered'] })
email: string;

@Prop()
password: string;

@Prop()
role: Role;
}

export const UserAuthSchema = SchemaFactory.createForClass(User);
70 changes: 70 additions & 0 deletions src/user/controllers/user/user.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// import { Test, TestingModule } from '@nestjs/testing';
// import { UserController } from './user.controller';
// import { UserService } from '../../services/user/user.service';
// import { Role } from 'src/auth/schemas/userAuth.model';
// import { CreateUserDto } from 'src/user/dto/create-user.dto';

// const mockUserService = {
// adminAddUser: jest.fn().mockResolvedValue('someId'),
// adminUpdateUser: jest.fn().mockResolvedValue(null),
// adminDeleteUser: jest.fn().mockResolvedValue(null),
// };

// describe('UserController', () => {
// let controller: UserController;

// beforeEach(async () => {
// const module: TestingModule = await Test.createTestingModule({
// controllers: [UserController],
// providers: [
// {
// provide: UserService,
// useValue: mockUserService,
// },
// ],
// }).compile();

// controller = module.get<UserController>(UserController);
// jest.clearAllMocks();
// });

// describe('Admin CRUD operations', () => {
// it('should add, update, and delete a user', async () => {
// const createUserDto: CreateUserDto = {
// id: 'testId',
// name: 'test',
// email: '[email protected]',
// password: '1234567890',
// role: Role.admin,
// };
// const updatedName = 'updatedName';
// const req = { user: { role: 'admin' } };

// // Create
// const generatedId = await controller.adminAddUser(createUserDto, req);
// expect(generatedId.id).toEqual('someId');
// expect(mockUserService.adminAddUser).toHaveBeenCalledWith(
// createUserDto.name,
// createUserDto.email,
// createUserDto.password,
// createUserDto.role,
// );

// // Update
// createUserDto.name = updatedName;
// await controller.adminUpdateUser(generatedId.id, createUserDto, req);
// expect(mockUserService.adminUpdateUser).toHaveBeenCalledWith(
// generatedId.id,
// updatedName,
// createUserDto.email,
// createUserDto.role,
// );

// // Delete
// await controller.adminDeleteUser(generatedId.id, req);
// expect(mockUserService.adminDeleteUser).toHaveBeenCalledWith(
// generatedId.id,
// );
// }, 30000);
// });
// });
112 changes: 71 additions & 41 deletions src/user/controllers/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,71 @@
// import { Body, Controller, Get, Param, Patch, Post } from '@nestjs/common';
// import { UserService } from '../../services/user/user.service';
// import { Role } from '../../schemas/user.model';
//
// @Controller('user')
// export class UserController {
// constructor(private readonly userService: UserService) {}
// @Post('add')
// async addUser(
// @Body('name') name: string,
// @Body('email') email: string,
// @Body('role') role: string,
// ) {
// const generatedId = await this.userService.addUser(name, email, role);
// return { id: generatedId };
// }
//
// @Get('')
// async getAllUsers() {
// return await this.userService.getAllUsers();
// }
//
// @Get(':id')
// async getUserById(@Param('id') id: string) {
// return this.userService.getUserById(id);
// }
//
// @Get('email/:email')
// async getUserByEmail(@Param('email') email: string) {
// return await this.userService.getUserByEmail(email);
// }
// @Patch('update/:id')
// async updateUser(
// @Param('id') id: string,
// @Body('name') name: string,
// @Body('email') email: string,
// @Body('role') role: Role,
// ) {
// await this.userService.updateUser(id, name, email, role);
// }
// }
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Req,
} from '@nestjs/common';
import { UserService } from '../../services/user/user.service';
import { Role } from '../../schemas/user.model';
import { CreateUserDto } from 'src/user/dto/create-user.dto';

// ================== User admin routes ======================== \\
// TODO: Add AuthGuard to all admin routes and check for admin roles
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}

// ----------------- Add User ------------------------------- \\
@Post('new')
// @UseGuards(AuthGuard())
async adminAddUser(@Body() createUserDto: CreateUserDto, @Req() req: any) {
const generatedId = await this.userService.newUser(createUserDto);
return { id: generatedId };
}

// ----------------- Get Users ----------------------------- \\
@Get('')
// @UseGuards(AuthGuard())
async getAllUsers() {
return await this.userService.getAllUsers();
}

// ----------------- Get User ------------------------------ \\
@Get('find/:id')
// @UseGuards(AuthGuard())
async getUserById(@Param('id') id: string) {
return this.userService.getUserById(id);
}

// ----------------- Get User by Email --------------------- \\
@Get('email/:email')
// @UseGuards(AuthGuard())
async getUserByEmail(@Param('email') email: string) {
return await this.userService.getUserByEmail(email);
}

// ----------------- Update User --------------------------- \\
@Patch('update/:id')
// @UseGuards(AuthGuard())
async updateUser(
@Param('id') id: string,
@Body('name') name: string,
@Body('email') email: string,
@Body('role') role: Role,
) {
await this.userService.updateUser(id, name, email, role);
}

// ----------------- Delete User --------------------------- //
@Delete('remove/:id')
// @UseGuards(AuthGuard())
async adminDeleteUser(@Param('id') id: string, @Req() req: any) {
await this.userService.removeUser(id);
}

// ================== End Admin routes ======================== \\
}
9 changes: 7 additions & 2 deletions src/user/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Role } from '../../auth/schemas/userAuthSchema';
import { Role } from '../../auth/schemas/userAuth.model';
import {
IsAlpha,
IsEmail,
Expand All @@ -21,9 +21,14 @@ export class CreateUserDto {
@IsNotEmpty()
@IsString()
@IsAlpha()
@MinLength(2, { message: 'Must be equal to or longer than 2 letters' })
@MinLength(2, { message: 'Name must be longer than 2 letters.' })
name: string;

@IsNotEmpty()
@IsString()
@MinLength(8, { message: 'Password must contain 8 characters or more.' })
password: string;

@IsNotEmpty()
@IsEnum(Role)
role: Role;
Expand Down
Loading