Skip to content

Commit

Permalink
Merge pull request #72 from portableDD/sign-up-feature
Browse files Browse the repository at this point in the history
fix: sign-up functionality
  • Loading branch information
Xaxxoo authored Jan 23, 2025
2 parents 1518e3d + 92aa10a commit 8d57a3b
Show file tree
Hide file tree
Showing 10 changed files with 1,166 additions and 102 deletions.
1,009 changes: 928 additions & 81 deletions backend/package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@
"@nestjs/core": "^11.0.1",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.0.1",
"@nestjs/typeorm": "^11.0.0",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"pg": "^8.13.1",
"reflect-metadata": "^0.1.12",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"typeorm": "^0.3.20"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
15 changes: 14 additions & 1 deletion backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Body, Controller, Post } from '@nestjs/common';
import {
Body,
ClassSerializerInterceptor,
Controller,
Post,
UseInterceptors,
} from '@nestjs/common';
import { AuthService } from './providers/auth.service';
import { SignInDto } from './dtos/signIn.dto';
import { UserDTO } from 'src/user/dtos/create-user.dto';

@Controller('auth')
export class AuthController {
Expand All @@ -12,4 +19,10 @@ export class AuthController {

@Post('sign-in')
public async signIn(@Body() signInDto: SignInDto) {}

@Post('sign-up')
@UseInterceptors(ClassSerializerInterceptor)
public async createUser(@Body() userDTO: UserDTO) {
return await this.authService.signUp(userDTO);
}
}
5 changes: 5 additions & 0 deletions backend/src/auth/providers/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { UserService } from 'src/user/providers/user.service';
import { SignInDto } from '../dtos/signIn.dto';
import { UserDTO } from 'src/user/dtos/create-user.dto';

@Injectable()
export class AuthService {
Expand All @@ -16,4 +17,8 @@ export class AuthService {
//Compare the password
// Confirmation Message
}

public async signUp(userDto: UserDTO) {
return await this.userService.signUp(userDto);
}
}
66 changes: 66 additions & 0 deletions backend/src/user/dtos/create-user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
IsEmail,
IsNotEmpty,
IsOptional,
IsString,
IsNumber,
IsUUID,
Min,
MinLength,
} from 'class-validator';
import { Exclude, Expose } from 'class-transformer';

export class UserDTO {
@IsUUID()
@IsOptional()
@Expose()
id?: string; // Optional: Assigned automatically upon creation

@IsString()
@IsNotEmpty({ message: 'Username is required' })
@MinLength(3, { message: 'Username must be at least 3 characters long' })
@Expose()
username: string;

@IsEmail({}, { message: 'Invalid email address' })
@IsNotEmpty({ message: 'Email is required' })
@Expose()
email: string;

@IsString()
@IsNotEmpty({ message: 'Password is required' })
@MinLength(8, { message: 'Password must be at least 8 characters long' })
@Exclude({ toPlainOnly: true }) // Exclude password when converting the object to plain data
password: string;

@IsString()
@IsOptional()
@Expose()
avatar?: string; // Optional: Profile picture URL

@IsNumber()
@Min(0, { message: 'Tokens cannot be negative' })
@Expose()
tokens: number;

@IsNumber()
@Min(0, { message: 'Score cannot be negative' })
@Expose()
totalScore: number;

@IsNumber()
@Min(0, { message: 'Games played cannot be negative' })
@Expose()
gamesPlayed: number;

@IsNumber()
@Min(0, { message: 'Games won cannot be negative' })
@Expose()
gamesWon: number;

@Expose()
createdAt?: Date; // Optional: Automatically set on creation

@Expose()
updatedAt?: Date; // Optional: Automatically set on updates
}
58 changes: 58 additions & 0 deletions backend/src/user/providers/create-user.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
BadRequestException,
Injectable,
RequestTimeoutException,
} from '@nestjs/common';
import { HashingProvider } from './hashing.provider';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../user.entity';
import { Repository } from 'typeorm';
import { UserDTO } from '../dtos/create-user.dto';

@Injectable()
export class CreateUserProvider {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,

private readonly hashingProvider: HashingProvider,
) {}

public async createUsers(userDto: UserDTO) {
// check if user already exits
let existingUser: User;

try {
existingUser = await this.userRepository.findOne({
where: { email: userDto.email },
});
} catch (error) {
throw new RequestTimeoutException(
'Unable to process your request at the moment, Please try later',
{
description: 'Error processing your request',
},
);
}
// Handle Error
if (existingUser) {
throw new BadRequestException('User already exist');
}
// Create the user
let newUser = this.userRepository.create({
...userDto,
password: await this.hashingProvider.hashPassword(userDto.password),
});
try {
newUser = await this.userRepository.save(newUser);
} catch (error) {
throw new RequestTimeoutException(
'Unable to process your request at the moment, Please try later',
{
description: 'Error processing your request',
},
);
}
return [newUser];
}
}
11 changes: 11 additions & 0 deletions backend/src/user/providers/hashing.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';

@Injectable()
export class HashingProvider {
// hashing
public async hashPassword(data: string | Buffer): Promise<string> {
const salt = await bcrypt.genSalt();
return bcrypt.hash(data, salt);
}
}
39 changes: 22 additions & 17 deletions backend/src/user/providers/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { AuthService } from 'src/auth/providers/auth.service';
import { FindOneUserByEmailProvider } from './find-one-user-by-email.provider';
import { CreateUserProvider } from './create-user.services';
import { UserDTO } from '../dtos/create-user.dto';

// Service responsible for handling user operations.
@Injectable()
Expand All @@ -11,6 +13,9 @@ export class UserService {

//Inject findoneuserbyemailprovider
private readonly findOneUserByEmailProvider: FindOneUserByEmailProvider,

//Inject create user provider
private readonly createUserProvider: CreateUserProvider,
) {}

public async findUserByEmail(email: string) {
Expand All @@ -19,25 +24,25 @@ export class UserService {

// Placeholder for user-related business logic
// Sign up a user.
signUp() {
public async signUp(userDto: UserDTO) {
// Implement sign up logic
return 'userService: Sign-up logic placeholder';
}
return await this.createUserProvider.createUsers(userDto);
}

// Sign in a user.
signIn() {
// Sign in a user.
signIn() {
// Implement sign in logic
return 'userService: Sign-in logic placeholder';
}
return 'userService: Sign-in logic placeholder';
}

// Retrieve refresh token.
refreshToken() {
// Implement token refresh logic
return 'userService: Refresh token logic placeholder';
}
// Update user profile.
updateProfile() {
// Implement profile update logic
return 'userService: Update profile logic placeholder';
}
// Retrieve refresh token.
refreshToken() {
// Implement token refresh logic
return 'userService: Refresh token logic placeholder';
}
// Update user profile.
updateProfile() {
// Implement profile update logic
return 'userService: Update profile logic placeholder';
}
}
45 changes: 45 additions & 0 deletions backend/src/user/user.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Exclude } from 'class-transformer';
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';

@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string; // Unique identifier for the user

@Column({ unique: true })
username: string; // The username for the player

@Column({ unique: true })
email: string; // Player's email for account identification and recovery

@Exclude() // passwords should not be return when user is return
@Column()
password: string; // Hashed password for security

@Column({ nullable: true })
avatar: string; // Optional profile picture URL

@Column({ default: 0 })
tokens: number; // Amount of in-game tokens the player owns

@Column({ default: 0 })
totalScore: number; // Cumulative score across all games played

@Column({ default: 0 })
gamesPlayed: number; // Total number of games the user has participated in

@Column({ default: 0 })
gamesWon: number; // Number of games the user has won

@CreateDateColumn()
createdAt: Date; // Timestamp for when the account was created

@UpdateDateColumn()
updatedAt: Date; // Timestamp for the last account update
}
13 changes: 11 additions & 2 deletions backend/src/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ import { UserController } from './user.controller';
import { UserService } from './providers/user.service';
import { AuthModule } from 'src/auth/auth.module';
import { FindOneUserByEmailProvider } from './providers/find-one-user-by-email.provider';
import { CreateUserProvider } from './providers/create-user.services';
import { HashingProvider } from './providers/hashing.provider';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
controllers: [UserController],
providers: [UserService, FindOneUserByEmailProvider],
imports: [forwardRef(() => AuthModule)],
providers: [
UserService,
FindOneUserByEmailProvider,
CreateUserProvider,
HashingProvider,
],
imports: [TypeOrmModule.forFeature([User]), forwardRef(() => AuthModule)],
exports: [UserService, FindOneUserByEmailProvider],
})
export class UserModule {}

0 comments on commit 8d57a3b

Please sign in to comment.