Skip to content

Commit

Permalink
[#7] feat: add new models and dto for user
Browse files Browse the repository at this point in the history
  • Loading branch information
glemenneo committed Sep 18, 2024
1 parent 3baa4dc commit c575df8
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 1 deletion.
47 changes: 47 additions & 0 deletions backend/user-service/src/models/user.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Schema, model } from 'mongoose'
import { IUser } from '../types/IUser'
import { Proficiency } from '../types/Proficiency'
import { Role } from '../types/Role'

const UserSchema = new Schema<IUser>({
username: {
type: String,
required: true,
unique: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: Object.values(Role),
required: true,
},
proficiency: {
type: String,
enum: Object.values(Proficiency),
required: false,
},
createdAt: {
type: Date,
required: false,
},
updatedAt: {
type: Date,
required: false,
default: null,
},
deletedAt: {
type: Date,
required: false,
default: null,
},
})

export default model<IUser>('User', UserSchema)
56 changes: 56 additions & 0 deletions backend/user-service/src/types/CreateUserDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
IsEmail,
IsEnum,
IsNotEmpty,
IsOptional,
IsString,
IsStrongPassword,
validate,
ValidationError,
} from 'class-validator'
import { Proficiency } from './Proficiency'
import { Role } from './Role'
import { TypedRequest } from './TypedRequest'

export class CreateUserDto {
@IsString()
@IsNotEmpty()
username: string

@IsStrongPassword({ minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1 })
password: string

@IsEmail()
email: string

@IsEnum(Role)
role: Role

@IsOptional()
@IsEnum(Proficiency)
proficiency?: Proficiency

constructor(username: string, email: string, password: string, role: Role, proficiency?: Proficiency) {
this.username = username
this.email = email
this.password = password
this.role = role
this.proficiency = proficiency
}

static fromRequest({
body: { username, email, password, role, proficiency },
}: TypedRequest<{
username: string
password: string
email: string
role: Role
proficiency: Proficiency | undefined
}>): CreateUserDto {
return new CreateUserDto(username, email, password, role, proficiency)
}

async validate(): Promise<ValidationError[]> {
return validate(this)
}
}
14 changes: 14 additions & 0 deletions backend/user-service/src/types/IUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Proficiency } from './Proficiency'
import { Role } from './Role'

export interface IUser {
id: string
username: string
email: string
password: string
role: Role
proficiency?: Proficiency
createdAt?: Date
updatedAt?: Date
deletedAt?: Date
}
6 changes: 6 additions & 0 deletions backend/user-service/src/types/Proficiency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum Proficiency {
BEGINNER = 'BEGINNER',
INTERMEDIATE = 'INTERMEDIATE',
ADVANCED = 'ADVANCED',
EXPERT = 'EXPERT',
}
4 changes: 4 additions & 0 deletions backend/user-service/src/types/Role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum Role {
USER = 'USER',
ADMIN = 'ADMIN',
}
5 changes: 5 additions & 0 deletions backend/user-service/src/types/TypedRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Request } from 'express'

export interface TypedRequest<T> extends Request {
body: T
}
53 changes: 53 additions & 0 deletions backend/user-service/src/types/UserDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { IsEmail, IsEnum, IsNotEmpty, IsOptional, IsString, validate, ValidationError } from 'class-validator'
import { IUser } from './IUser'
import { Proficiency } from './Proficiency'
import { Role } from './Role'
import { TypedRequest } from './TypedRequest'

export class UserDto {
@IsString()
@IsNotEmpty()
id: string

@IsString()
@IsNotEmpty()
username: string

@IsEmail()
email: string

@IsEnum(Role)
role: Role

@IsOptional()
@IsEnum(Proficiency)
proficiency?: Proficiency

constructor(id: string, username: string, email: string, role: Role, proficiency?: Proficiency) {
this.id = id
this.username = username
this.email = email
this.role = role
this.proficiency = proficiency
}

static fromModel({ id, username, email, role, proficiency }: IUser): UserDto {
return new UserDto(id, username, email, role, proficiency)
}

static fromRequest({
body: { id, username, email, role, proficiency },
}: TypedRequest<{
id: string
username: string
email: string
role: Role
proficiency: Proficiency | undefined
}>): UserDto {
return new UserDto(id, username, email, role, proficiency)
}

async validate(): Promise<ValidationError[]> {
return validate(this)
}
}
2 changes: 1 addition & 1 deletion backend/user-service/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
"experimentalDecorators": true /* Enable experimental support for legacy experimental decorators. */,
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
Expand Down

0 comments on commit c575df8

Please sign in to comment.