diff --git a/backend/jest.config.json b/backend/jest.config.json index 42bbce4a3..1e1fc6414 100644 --- a/backend/jest.config.json +++ b/backend/jest.config.json @@ -12,14 +12,13 @@ "coverageDirectory": "report", "collectCoverageFrom": ["src/**/*.{ts,tsx}", "!node_modules/", "!src/database/migrations/**/*.{ts,tsx}"], "transform": { - "\\.ts$": ["ts-jest"] + "\\.ts$": [ + "ts-jest", { + "tsconfig": "/tsconfig.json" + } + ] }, "testEnvironment": "node", "preset": "ts-jest", - "globals": { - "ts-jest": { - "tsconfig": "/tsconfig.json" - } - }, "testTimeout": 30000 } \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 54a63e74d..08a00f87f 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -17,7 +17,7 @@ "@nestjs/core": "^9.0.0", "@nestjs/jwt": "^9.0.0", "@nestjs/mapped-types": "^1.0.1", - "@nestjs/mongoose": "^9.0.3", + "@nestjs/mongoose": "^9.2.1", "@nestjs/passport": "^9.0.0", "@nestjs/platform-express": "^9.0.0", "@nestjs/platform-socket.io": "^9.0.0", @@ -41,7 +41,7 @@ "moment": "^2.29.4", "moment-business-days": "^1.2.0", "mongodb": "4.5.0", - "mongoose": "^6.7.0", + "mongoose": "^6.7.4", "mongoose-lean-virtuals": "0.9.0", "nodemailer": "^6.7.5", "passport": "^0.6.0", @@ -84,7 +84,7 @@ "ts-loader": "^9.2.8", "ts-node": "^10.7.0", "tsconfig-paths": "^4.0.0", - "typescript": "^4.6.3" + "typescript": "^4.9.3" } }, "node_modules/@ampproject/remapping": { @@ -2972,6 +2972,19 @@ "strip-bom": "^3.0.0" } }, + "node_modules/@nestjs/cli/node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@nestjs/cli/node_modules/webpack": { "version": "5.73.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", @@ -3137,9 +3150,9 @@ } }, "node_modules/@nestjs/mongoose": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-9.2.0.tgz", - "integrity": "sha512-fC33b8nwR7C3y6hlTyKjiHQVU57SFOd3Dwa6alWj3BOhK5bHt8Ld6qOK2G35/XXPHjtSIk3LIKEqwyK5xGcmBA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-9.2.1.tgz", + "integrity": "sha512-tMK5kKFjQnNVhqJDw1wa352z+VsODOFznTn74xSzrziof03qS+O6rLU4q1kMx0B4AmFbADf03GOdpvBc9bMWqw==", "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0", "@nestjs/core": "^8.0.0 || ^9.0.0", @@ -12270,17 +12283,17 @@ } }, "node_modules/mongoose": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.0.tgz", - "integrity": "sha512-Jt6NSiSpgcrSBzRb9+YwkpjjVuq4H532c4jbf+5Nu0wd/nIPHSOKhr8jnQZ8gQTdPjubF+szR5r6KMSqaY4/Wg==", + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.4.tgz", + "integrity": "sha512-0LWMrOa5U43cR3I/iRPnmyedoa6T8+QPxmFYdPgx4WAS0CdbSbOzAFSKeU6bndUY6cs4VkxKZGcuDM0twystCg==", "dependencies": { - "bson": "^4.6.5", + "bson": "^4.7.0", "kareem": "2.4.1", "mongodb": "4.11.0", "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.1" }, "engines": { "node": ">=12.0.0" @@ -14288,9 +14301,9 @@ } }, "node_modules/sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "node_modules/sigmund": { "version": "1.0.1", @@ -15436,9 +15449,9 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -18435,6 +18448,12 @@ "strip-bom": "^3.0.0" } }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, "webpack": { "version": "5.73.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", @@ -18520,9 +18539,9 @@ "requires": {} }, "@nestjs/mongoose": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-9.2.0.tgz", - "integrity": "sha512-fC33b8nwR7C3y6hlTyKjiHQVU57SFOd3Dwa6alWj3BOhK5bHt8Ld6qOK2G35/XXPHjtSIk3LIKEqwyK5xGcmBA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-9.2.1.tgz", + "integrity": "sha512-tMK5kKFjQnNVhqJDw1wa352z+VsODOFznTn74xSzrziof03qS+O6rLU4q1kMx0B4AmFbADf03GOdpvBc9bMWqw==", "requires": {} }, "@nestjs/passport": { @@ -25551,17 +25570,17 @@ } }, "mongoose": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.0.tgz", - "integrity": "sha512-Jt6NSiSpgcrSBzRb9+YwkpjjVuq4H532c4jbf+5Nu0wd/nIPHSOKhr8jnQZ8gQTdPjubF+szR5r6KMSqaY4/Wg==", + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.4.tgz", + "integrity": "sha512-0LWMrOa5U43cR3I/iRPnmyedoa6T8+QPxmFYdPgx4WAS0CdbSbOzAFSKeU6bndUY6cs4VkxKZGcuDM0twystCg==", "requires": { - "bson": "^4.6.5", + "bson": "^4.7.0", "kareem": "2.4.1", "mongodb": "4.11.0", "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.1" }, "dependencies": { "denque": { @@ -27088,9 +27107,9 @@ } }, "sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "sigmund": { "version": "1.0.1", @@ -27934,9 +27953,9 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true }, "uc.micro": { diff --git a/backend/package.json b/backend/package.json index 2fa4ed5c5..5419de642 100644 --- a/backend/package.json +++ b/backend/package.json @@ -31,7 +31,7 @@ "@nestjs/core": "^9.0.0", "@nestjs/jwt": "^9.0.0", "@nestjs/mapped-types": "^1.0.1", - "@nestjs/mongoose": "^9.0.3", + "@nestjs/mongoose": "^9.2.1", "@nestjs/passport": "^9.0.0", "@nestjs/platform-express": "^9.0.0", "@nestjs/platform-socket.io": "^9.0.0", @@ -55,7 +55,7 @@ "moment": "^2.29.4", "moment-business-days": "^1.2.0", "mongodb": "4.5.0", - "mongoose": "^6.7.0", + "mongoose": "^6.7.4", "mongoose-lean-virtuals": "0.9.0", "nodemailer": "^6.7.5", "passport": "^0.6.0", @@ -98,7 +98,7 @@ "ts-loader": "^9.2.8", "ts-node": "^10.7.0", "tsconfig-paths": "^4.0.0", - "typescript": "^4.6.3" + "typescript": "^4.9.3" }, "lint-staged": { "*.{js,ts,tsx}": [ diff --git a/backend/src/infrastructure/database/mongoose.module.ts b/backend/src/infrastructure/database/mongoose.module.ts index 519b8cd8f..73e2ed80d 100644 --- a/backend/src/infrastructure/database/mongoose.module.ts +++ b/backend/src/infrastructure/database/mongoose.module.ts @@ -5,7 +5,7 @@ import BoardUser, { BoardUserSchema } from 'src/modules/boards/schemas/board.use import Schedules, { SchedulesSchema } from 'src/modules/schedules/schemas/schedules.schema'; import TeamUser, { TeamUserSchema } from 'src/modules/teams/schemas/team.user.schema'; import Team, { TeamSchema } from 'src/modules/teams/schemas/teams.schema'; -import User, { UserSchema } from 'src/modules/users/schemas/user.schema'; +import User, { UserSchema } from 'src/modules/users/entities/user.schema'; export const mongooseBoardModule = MongooseModule.forFeature([ { name: Board.name, schema: BoardSchema } diff --git a/backend/src/libs/repositories/interfaces/base.repository.interface.ts b/backend/src/libs/repositories/interfaces/base.repository.interface.ts new file mode 100644 index 000000000..6fdca55fb --- /dev/null +++ b/backend/src/libs/repositories/interfaces/base.repository.interface.ts @@ -0,0 +1,18 @@ +import { UpdateQuery } from 'mongoose'; +import { ModelProps, SelectedValues } from '../types'; + +export interface BaseInterfaceRepository { + getAll(selectedValues?: SelectedValues): Promise; + + get(id: string, selectedValues?: SelectedValues): Promise; + + create(item: T): Promise; + + update(id: string, item: T); + + getByProp(value: ModelProps): Promise; + + countDocuments(): Promise; + + findOneByFieldAndUpdate(value: ModelProps, query: UpdateQuery): Promise; +} diff --git a/backend/src/libs/repositories/mongo/mongo-generic.repository.ts b/backend/src/libs/repositories/mongo/mongo-generic.repository.ts new file mode 100644 index 000000000..8d08af18a --- /dev/null +++ b/backend/src/libs/repositories/mongo/mongo-generic.repository.ts @@ -0,0 +1,45 @@ +import { Model, UpdateQuery } from 'mongoose'; +import { BaseInterfaceRepository } from '../interfaces/base.repository.interface'; +import { ModelProps, SelectedValues } from '../types'; + +export class MongoGenericRepository implements BaseInterfaceRepository { + private _repository: Model; + private _populateOnFind: string[]; + + constructor(repository: Model, populateOnFind: string[] = []) { + this._repository = repository; + this._populateOnFind = populateOnFind; + } + + getAll(selectedValues?: SelectedValues): Promise { + return this._repository.find().select(selectedValues).populate(this._populateOnFind).exec(); + } + + get(id: any, selectedValues?: SelectedValues): Promise { + return this._repository + .findById(id) + .select(selectedValues) + .populate(this._populateOnFind) + .exec() as Promise; + } + + getByProp(value: ModelProps): Promise { + return this._repository.findOne(value).exec(); + } + + create(item: T): Promise { + return this._repository.create(item); + } + + update(id: string, item: T) { + return this._repository.findByIdAndUpdate(id, item); + } + + countDocuments(): Promise { + return this._repository.countDocuments().exec(); + } + + findOneByFieldAndUpdate(value: ModelProps, query: UpdateQuery): Promise { + return this._repository.findOneAndUpdate(value, query).exec(); + } +} diff --git a/backend/src/libs/repositories/types/index.ts b/backend/src/libs/repositories/types/index.ts new file mode 100644 index 000000000..d80f4d8a6 --- /dev/null +++ b/backend/src/libs/repositories/types/index.ts @@ -0,0 +1,9 @@ +export type SelectedValues = + | string // maintain compatibility with existing code + | { + [K in keyof T]?: 1 | 0; + }; + +export type ModelProps = { + [K in keyof T]?: T[K]; +}; diff --git a/backend/src/modules/auth/controller/auth.controller.spec.ts b/backend/src/modules/auth/controller/auth.controller.spec.ts index 3f0759f0d..db290bd61 100644 --- a/backend/src/modules/auth/controller/auth.controller.spec.ts +++ b/backend/src/modules/auth/controller/auth.controller.spec.ts @@ -24,7 +24,8 @@ import { getUserApplication, getUserService, updateUserApplication, - updateUserService + updateUserService, + userRepository } from 'src/modules/users/users.providers'; describe('AuthController', () => { @@ -56,6 +57,7 @@ describe('AuthController', () => { createUserService, getUserApplication, getUserService, + userRepository, ConfigService, { provide: ConfigService, diff --git a/backend/src/modules/auth/interfaces/applications/register.auth.application.interface.ts b/backend/src/modules/auth/interfaces/applications/register.auth.application.interface.ts index 64e22a671..091f1f7fb 100644 --- a/backend/src/modules/auth/interfaces/applications/register.auth.application.interface.ts +++ b/backend/src/modules/auth/interfaces/applications/register.auth.application.interface.ts @@ -1,7 +1,6 @@ -import { LeanDocument } from 'mongoose'; import CreateUserDto from 'src/modules/users/dto/create.user.dto'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; export interface RegisterAuthApplication { - register(registrationData: CreateUserDto): Promise>; + register(registrationData: CreateUserDto): Promise; } diff --git a/backend/src/modules/auth/interfaces/services/register.auth.service.interface.ts b/backend/src/modules/auth/interfaces/services/register.auth.service.interface.ts index 562169970..1aad683a1 100644 --- a/backend/src/modules/auth/interfaces/services/register.auth.service.interface.ts +++ b/backend/src/modules/auth/interfaces/services/register.auth.service.interface.ts @@ -1,7 +1,6 @@ -import { LeanDocument } from 'mongoose'; import CreateUserDto from 'src/modules/users/dto/create.user.dto'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; export interface RegisterAuthService { - register(registrationData: CreateUserDto): Promise>; + register(registrationData: CreateUserDto): Promise; } diff --git a/backend/src/modules/auth/interfaces/services/validate-user.auth.service.interface.ts b/backend/src/modules/auth/interfaces/services/validate-user.auth.service.interface.ts index 5f98edc91..8dc65c00c 100644 --- a/backend/src/modules/auth/interfaces/services/validate-user.auth.service.interface.ts +++ b/backend/src/modules/auth/interfaces/services/validate-user.auth.service.interface.ts @@ -1,16 +1,9 @@ -import { LeanDocument } from 'mongoose'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; export interface ValidateUserAuthService { - validateUserWithCredentials( - email: string, - plainTextPassword: string - ): Promise | null>; + validateUserWithCredentials(email: string, plainTextPassword: string): Promise; - validateUserById(userId: string): Promise | null>; + validateUserById(userId: string): Promise; - validateUserByRefreshToken( - authorization: string, - userId: string - ): Promise>; + validateUserByRefreshToken(authorization: string, userId: string): Promise; } diff --git a/backend/src/modules/auth/services/get-token.auth.service.spec.ts b/backend/src/modules/auth/services/get-token.auth.service.spec.ts index c5a2964ab..f0a6e1c30 100644 --- a/backend/src/modules/auth/services/get-token.auth.service.spec.ts +++ b/backend/src/modules/auth/services/get-token.auth.service.spec.ts @@ -5,7 +5,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import configService from 'src/libs/test-utils/mocks/configService.mock'; import jwtService from 'src/libs/test-utils/mocks/jwtService.mock'; import GetTokenAuthServiceImpl from 'src/modules/auth/services/get-token.auth.service'; -import { updateUserService } from 'src/modules/users/users.providers'; +import { updateUserService, userRepository } from 'src/modules/users/users.providers'; describe('AuthService', () => { let service: GetTokenAuthServiceImpl; @@ -15,6 +15,7 @@ describe('AuthService', () => { providers: [ GetTokenAuthServiceImpl, updateUserService, + userRepository, { provide: ConfigService, useValue: configService diff --git a/backend/src/modules/auth/services/validate-user.auth.service.spec.ts b/backend/src/modules/auth/services/validate-user.auth.service.spec.ts index 334c61873..ac9425988 100644 --- a/backend/src/modules/auth/services/validate-user.auth.service.spec.ts +++ b/backend/src/modules/auth/services/validate-user.auth.service.spec.ts @@ -10,7 +10,7 @@ import ValidateUserAuthServiceImpl from 'src/modules/auth/services/validate-user import { getTeamService } from 'src/modules/teams/providers'; import { GetUserService } from 'src/modules/users/interfaces/services/get.user.service.interface'; import { TYPES } from 'src/modules/users/interfaces/types'; -import { getUserService } from 'src/modules/users/users.providers'; +import { getUserService, userRepository } from 'src/modules/users/users.providers'; jest.mock('bcrypt'); jest.mock('src/modules/schedules/services/create.schedules.service.ts'); @@ -23,9 +23,7 @@ describe('The AuthenticationService', () => { let findUser: jest.Mock; beforeEach(async () => { findUser = jest.fn().mockImplementation(() => ({ - lean: jest.fn().mockImplementation(() => ({ - exec: jest.fn().mockReturnValue(mockedUser) - })) + exec: jest.fn().mockReturnValue(mockedUser) })); const usersRepository = { findOne: findUser @@ -39,6 +37,7 @@ describe('The AuthenticationService', () => { ValidateUserAuthServiceImpl, getUserService, getTeamService, + userRepository, { provide: ConfigService, useValue: configService @@ -99,9 +98,7 @@ describe('The AuthenticationService', () => { describe('and the user is not found in the database', () => { beforeEach(() => { findUser.mockImplementation(() => ({ - lean: jest.fn().mockImplementation(() => ({ - exec: jest.fn().mockReturnValue(undefined) - })) + exec: jest.fn().mockReturnValue(undefined) })); }); it('should throw an error', async () => { diff --git a/backend/src/modules/auth/shared/login.auth.ts b/backend/src/modules/auth/shared/login.auth.ts index dd5cc6d53..d82666a83 100644 --- a/backend/src/modules/auth/shared/login.auth.ts +++ b/backend/src/modules/auth/shared/login.auth.ts @@ -1,11 +1,10 @@ -import { LeanDocument } from 'mongoose'; import UserDto from 'src/modules/users/dto/user.dto'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import { GetTokenAuthApplication } from '../interfaces/applications/get-token.auth.application.interface'; import { GetTokenAuthService } from '../interfaces/services/get-token.auth.service.interface'; export const signIn = async ( - user: LeanDocument | UserDto, + user: User | UserDto, getTokenService: GetTokenAuthService | GetTokenAuthApplication, strategy: string ) => { @@ -14,5 +13,5 @@ export const signIn = async ( if (!jwt) return null; - return { ...jwt, email, firstName, lastName, strategy, id: _id, isSAdmin }; + return { ...jwt, email, firstName, lastName, strategy, _id, isSAdmin }; }; diff --git a/backend/src/modules/auth/strategy/local.strategy.ts b/backend/src/modules/auth/strategy/local.strategy.ts index 028890593..8fef7654b 100644 --- a/backend/src/modules/auth/strategy/local.strategy.ts +++ b/backend/src/modules/auth/strategy/local.strategy.ts @@ -3,7 +3,7 @@ import { PassportStrategy } from '@nestjs/passport'; import { LeanDocument } from 'mongoose'; import { Strategy } from 'passport-local'; import { INVALID_CREDENTIALS } from 'src/libs/exceptions/messages'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import { UserDocument } from 'src/modules/users/entities/user.schema'; import { ValidateUserAuthService } from '../interfaces/services/validate-user.auth.service.interface'; import { TYPES } from '../interfaces/types'; diff --git a/backend/src/modules/boards/schemas/board.schema.ts b/backend/src/modules/boards/schemas/board.schema.ts index df9dc6abb..6b27beb94 100644 --- a/backend/src/modules/boards/schemas/board.schema.ts +++ b/backend/src/modules/boards/schemas/board.schema.ts @@ -2,7 +2,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, ObjectId, SchemaTypes } from 'mongoose'; import * as leanVirtualsPlugin from 'mongoose-lean-virtuals'; import Team from 'src/modules/teams/schemas/teams.schema'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import { ColumnDocument, ColumnSchema } from './column.schema'; export type BoardDocument = Board & Document; diff --git a/backend/src/modules/boards/schemas/board.user.schema.ts b/backend/src/modules/boards/schemas/board.user.schema.ts index cc638fa2c..990132672 100644 --- a/backend/src/modules/boards/schemas/board.user.schema.ts +++ b/backend/src/modules/boards/schemas/board.user.schema.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, ObjectId, SchemaTypes } from 'mongoose'; import { BoardRoles } from 'src/libs/enum/board.roles'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; export type BoardUserDocument = BoardUser & Document; diff --git a/backend/src/modules/boards/services/create.board.service.ts b/backend/src/modules/boards/services/create.board.service.ts index ffdb43ade..72bf6b385 100644 --- a/backend/src/modules/boards/services/create.board.service.ts +++ b/backend/src/modules/boards/services/create.board.service.ts @@ -21,7 +21,7 @@ import * as SchedulesType from 'src/modules/schedules/interfaces/types'; import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface'; import { TYPES as TeamType } from 'src/modules/teams/interfaces/types'; import TeamUser, { TeamUserDocument } from 'src/modules/teams/schemas/team.user.schema'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import { UserDocument } from 'src/modules/users/entities/user.schema'; import BoardDto from '../dto/board.dto'; import BoardUserDto from '../dto/board.user.dto'; import { Configs, CreateBoardService } from '../interfaces/services/create.board.service.interface'; diff --git a/backend/src/modules/boards/services/delete.board.service.ts b/backend/src/modules/boards/services/delete.board.service.ts index 2c5695cb0..c56d8944e 100644 --- a/backend/src/modules/boards/services/delete.board.service.ts +++ b/backend/src/modules/boards/services/delete.board.service.ts @@ -9,7 +9,7 @@ import * as Schedules from 'src/modules/schedules/interfaces/types'; import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface'; import * as Teams from 'src/modules/teams/interfaces/types'; import { TeamUserDocument } from 'src/modules/teams/schemas/team.user.schema'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import { UserDocument } from 'src/modules/users/entities/user.schema'; import { DeleteBoardService } from '../interfaces/services/delete.board.service.interface'; import Board, { BoardDocument } from '../schemas/board.schema'; import BoardUser, { BoardUserDocument } from '../schemas/board.user.schema'; diff --git a/backend/src/modules/boards/services/get.board.service.ts b/backend/src/modules/boards/services/get.board.service.ts index 063fefad8..3e5e3ee94 100644 --- a/backend/src/modules/boards/services/get.board.service.ts +++ b/backend/src/modules/boards/services/get.board.service.ts @@ -10,7 +10,7 @@ import { CardDocument } from 'src/modules/cards/schemas/card.schema'; import { CommentDocument } from 'src/modules/comments/schemas/comment.schema'; import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface'; import * as Team from 'src/modules/teams/interfaces/types'; -import { UserDocument } from 'src/modules/users/schemas/user.schema'; +import { UserDocument } from 'src/modules/users/entities/user.schema'; import { QueryType } from '../interfaces/findQuery'; import { GetBoardServiceInterface } from '../interfaces/services/get.board.service.interface'; import Board, { BoardDocument } from '../schemas/board.schema'; diff --git a/backend/src/modules/boards/services/update.board.service.ts b/backend/src/modules/boards/services/update.board.service.ts index 8b0a109fa..bfbc6b4f4 100644 --- a/backend/src/modules/boards/services/update.board.service.ts +++ b/backend/src/modules/boards/services/update.board.service.ts @@ -19,7 +19,7 @@ import * as CommunicationsType from 'src/modules/communication/interfaces/types' import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface'; import * as Teams from 'src/modules/teams/interfaces/types'; import { TeamUserDocument } from 'src/modules/teams/schemas/team.user.schema'; -import User, { UserDocument } from 'src/modules/users/schemas/user.schema'; +import User, { UserDocument } from 'src/modules/users/entities/user.schema'; import { UpdateBoardDto } from '../dto/update-board.dto'; import { ResponsibleType } from '../interfaces/responsible.interface'; import { UpdateBoardServiceInterface } from '../interfaces/services/update.board.service.interface'; diff --git a/backend/src/modules/cards/schemas/card.item.schema.ts b/backend/src/modules/cards/schemas/card.item.schema.ts index 14d07a150..b9eb7363c 100644 --- a/backend/src/modules/cards/schemas/card.item.schema.ts +++ b/backend/src/modules/cards/schemas/card.item.schema.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, ObjectId, SchemaTypes } from 'mongoose'; import * as leanVirtualsPlugin from 'mongoose-lean-virtuals'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import { CommentDocument, CommentSchema } from '../../comments/schemas/comment.schema'; export type CardItemDocument = CardItem & Document; diff --git a/backend/src/modules/cards/schemas/card.schema.ts b/backend/src/modules/cards/schemas/card.schema.ts index faf590a9e..9a06ebbfc 100644 --- a/backend/src/modules/cards/schemas/card.schema.ts +++ b/backend/src/modules/cards/schemas/card.schema.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, ObjectId, SchemaTypes } from 'mongoose'; import * as leanVirtualsPlugin from 'mongoose-lean-virtuals'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import { CommentDocument, CommentSchema } from '../../comments/schemas/comment.schema'; import { CardItemDocument, CardItemSchema } from './card.item.schema'; diff --git a/backend/src/modules/cards/services/delete.card.service.ts b/backend/src/modules/cards/services/delete.card.service.ts index 371c51c17..7117169ba 100644 --- a/backend/src/modules/cards/services/delete.card.service.ts +++ b/backend/src/modules/cards/services/delete.card.service.ts @@ -5,7 +5,7 @@ import { UPDATE_FAILED } from 'src/libs/exceptions/messages'; import Board, { BoardDocument } from 'src/modules/boards/schemas/board.schema'; import { BoardUserDocument } from 'src/modules/boards/schemas/board.user.schema'; import { CommentDocument } from 'src/modules/comments/schemas/comment.schema'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import { DeleteVoteService } from 'src/modules/votes/interfaces/services/delete.vote.service.interface'; import * as Votes from 'src/modules/votes/interfaces/types'; import { DeleteCardService } from '../interfaces/services/delete.card.service.interface'; diff --git a/backend/src/modules/comments/schemas/comment.schema.ts b/backend/src/modules/comments/schemas/comment.schema.ts index 040c4dc24..827632d97 100644 --- a/backend/src/modules/comments/schemas/comment.schema.ts +++ b/backend/src/modules/comments/schemas/comment.schema.ts @@ -1,6 +1,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import * as mongoose from 'mongoose'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; export type CommentDocument = Comment & mongoose.Document; diff --git a/backend/src/modules/teams/schemas/team.user.schema.ts b/backend/src/modules/teams/schemas/team.user.schema.ts index d9b269520..6f30149ff 100644 --- a/backend/src/modules/teams/schemas/team.user.schema.ts +++ b/backend/src/modules/teams/schemas/team.user.schema.ts @@ -2,7 +2,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, ObjectId, SchemaTypes } from 'mongoose'; import * as leanVirtualsPlugin from 'mongoose-lean-virtuals'; import { TeamRoles } from 'src/libs/enum/team.roles'; -import User from 'src/modules/users/schemas/user.schema'; +import User from 'src/modules/users/entities/user.schema'; import Team from './teams.schema'; export type TeamUserDocument = TeamUser & Document; diff --git a/backend/src/modules/teams/services/get.team.service.ts b/backend/src/modules/teams/services/get.team.service.ts index 4271e8491..d0f44b213 100644 --- a/backend/src/modules/teams/services/get.team.service.ts +++ b/backend/src/modules/teams/services/get.team.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { LeanDocument, Model } from 'mongoose'; -import { TeamQueryParams } from '../../../libs/dto/param/team.query.params'; import { GetTeamServiceInterface } from '../interfaces/services/get.team.service.interface'; import { UserWithTeams } from '../../users/interfaces/type-user-with-teams'; import TeamUser, { TeamUserDocument } from '../schemas/team.user.schema'; @@ -22,30 +21,8 @@ export default class GetTeamService implements GetTeamServiceInterface { return this.teamModel.countDocuments().exec(); } - getTeam(teamId: string, teamQueryParams: TeamQueryParams = {}) { - const { loadUsers, teamUserRole } = teamQueryParams; + getTeam(teamId: string) { const teamModel = this.teamModel.findById(teamId); - let teamUserRoleFilter = {}; - - if (teamUserRole) { - teamUserRoleFilter = { match: { role: { $eq: teamUserRole } } }; - } - - if (loadUsers || teamUserRole) { - teamModel - .populate({ - path: 'users', - select: 'user role isNewJoiner', - ...teamUserRoleFilter, - populate: { - path: 'user', - select: '_id firstName lastName email joinedAt' - } - }) - .lean({ virtuals: true }); - } else { - teamModel.lean(); - } return teamModel .select('_id name') @@ -57,14 +34,13 @@ export default class GetTeamService implements GetTeamServiceInterface { select: '_id firstName lastName email joinedAt' } }) - .lean() .exec(); } async getTeamsOfUser(userId: string) { const teamsUser = await this.teamUserModel.find({ user: userId }).distinct('team'); - const teams: LeanDocument[] = await this.teamModel + const teams: LeanDocument = await this.teamModel .find({ _id: { $in: teamsUser } }) .select('_id name') .populate({ @@ -79,7 +55,7 @@ export default class GetTeamService implements GetTeamServiceInterface { path: 'boards', select: '_id' }) - .lean() + .lean({ virtuals: true }) .exec(); return teams.map((team) => { @@ -166,7 +142,6 @@ export default class GetTeamService implements GetTeamServiceInterface { path: 'user', select: '_id firstName lastName email isSAdmin' }) - .lean() .exec(); } } diff --git a/backend/src/modules/users/dto/logged.user.dto.ts b/backend/src/modules/users/dto/logged.user.dto.ts index 807c74c19..e88fd0937 100644 --- a/backend/src/modules/users/dto/logged.user.dto.ts +++ b/backend/src/modules/users/dto/logged.user.dto.ts @@ -5,7 +5,7 @@ export default class LoggedUserDto { @IsNotEmpty() @IsMongoId() @IsString() - id!: string; + _id!: string; @IsNotEmpty() @IsString() diff --git a/backend/src/modules/users/schemas/user.schema.ts b/backend/src/modules/users/entities/user.schema.ts similarity index 98% rename from backend/src/modules/users/schemas/user.schema.ts rename to backend/src/modules/users/entities/user.schema.ts index 15be3bb01..cdd3e9803 100644 --- a/backend/src/modules/users/schemas/user.schema.ts +++ b/backend/src/modules/users/entities/user.schema.ts @@ -9,6 +9,8 @@ export type UserDocument = User & mongoose.Document; } }) export default class User { + _id?: string; + @Prop({ nullable: false }) firstName!: string; diff --git a/backend/src/modules/users/interfaces/applications/get.user.application.interface.ts b/backend/src/modules/users/interfaces/applications/get.user.application.interface.ts index 307e625ee..7720fc684 100644 --- a/backend/src/modules/users/interfaces/applications/get.user.application.interface.ts +++ b/backend/src/modules/users/interfaces/applications/get.user.application.interface.ts @@ -1,5 +1,5 @@ import { LeanDocument } from 'mongoose'; -import { UserDocument } from '../../schemas/user.schema'; +import { UserDocument } from '../../entities/user.schema'; import { UserWithTeams } from '../type-user-with-teams'; export interface GetUserApplication { diff --git a/backend/src/modules/users/interfaces/applications/update.user.service.interface.ts b/backend/src/modules/users/interfaces/applications/update.user.service.interface.ts index dcbc846c8..7dbe6b55a 100644 --- a/backend/src/modules/users/interfaces/applications/update.user.service.interface.ts +++ b/backend/src/modules/users/interfaces/applications/update.user.service.interface.ts @@ -1,5 +1,5 @@ import { LeanDocument } from 'mongoose'; -import { UserDocument } from '../../schemas/user.schema'; +import User, { UserDocument } from '../../entities/user.schema'; export interface UpdateUserApplication { setCurrentRefreshToken( @@ -11,7 +11,7 @@ export interface UpdateUserApplication { userEmail: string, newPassword: string, newPasswordConf: string - ): Promise; + ): Promise; checkEmail(token: string): Promise; } diff --git a/backend/src/modules/users/interfaces/services/create.user.service.interface.ts b/backend/src/modules/users/interfaces/services/create.user.service.interface.ts index e31b1b1e4..3d102618f 100644 --- a/backend/src/modules/users/interfaces/services/create.user.service.interface.ts +++ b/backend/src/modules/users/interfaces/services/create.user.service.interface.ts @@ -1,8 +1,7 @@ -import { LeanDocument } from 'mongoose'; import CreateUserAzureDto from '../../dto/create.user.azure.dto'; import CreateUserDto from '../../dto/create.user.dto'; -import { UserDocument } from '../../schemas/user.schema'; +import User from '../../entities/user.schema'; export interface CreateUserService { - create(user: CreateUserDto | CreateUserAzureDto): Promise>; + create(user: CreateUserDto | CreateUserAzureDto): Promise; } diff --git a/backend/src/modules/users/interfaces/services/get.user.service.interface.ts b/backend/src/modules/users/interfaces/services/get.user.service.interface.ts index be28bcd3b..a1a379f29 100644 --- a/backend/src/modules/users/interfaces/services/get.user.service.interface.ts +++ b/backend/src/modules/users/interfaces/services/get.user.service.interface.ts @@ -1,5 +1,5 @@ import { LeanDocument } from 'mongoose'; -import { UserDocument } from '../../schemas/user.schema'; +import { UserDocument } from '../../entities/user.schema'; import { UserWithTeams } from '../type-user-with-teams'; export interface GetUserService { diff --git a/backend/src/modules/users/interfaces/services/update.user.service.interface.ts b/backend/src/modules/users/interfaces/services/update.user.service.interface.ts index 778e86523..088193869 100644 --- a/backend/src/modules/users/interfaces/services/update.user.service.interface.ts +++ b/backend/src/modules/users/interfaces/services/update.user.service.interface.ts @@ -1,17 +1,13 @@ -import { LeanDocument } from 'mongoose'; -import { UserDocument } from '../../schemas/user.schema'; +import User from '../../entities/user.schema'; export interface UpdateUserService { - setCurrentRefreshToken( - refreshToken: string, - userId: string - ): Promise | null>; + setCurrentRefreshToken(refreshToken: string, userId: string): Promise; setPassword( userEmail: string, newPassword: string, newPasswordConf: string - ): Promise; + ): Promise; checkEmail(token: string): Promise; } diff --git a/backend/src/modules/users/interfaces/type-user-with-teams.ts b/backend/src/modules/users/interfaces/type-user-with-teams.ts index c21c63cea..73bd5beeb 100644 --- a/backend/src/modules/users/interfaces/type-user-with-teams.ts +++ b/backend/src/modules/users/interfaces/type-user-with-teams.ts @@ -1,6 +1,6 @@ -import UserDto from '../dto/user.dto'; +import User from '../entities/user.schema'; export type UserWithTeams = { - user: UserDto; + user: User; teams?: string[]; }; diff --git a/backend/src/modules/users/interfaces/types.ts b/backend/src/modules/users/interfaces/types.ts index a3728734c..a8db34af4 100644 --- a/backend/src/modules/users/interfaces/types.ts +++ b/backend/src/modules/users/interfaces/types.ts @@ -7,5 +7,6 @@ export const TYPES = { applications: { GetUserApplication: 'GetUserApplication', UpdateUserApplication: 'UpdateUserApplication' - } + }, + repository: 'UserRepository' }; diff --git a/backend/src/modules/users/repository/user.repository.interface.ts b/backend/src/modules/users/repository/user.repository.interface.ts new file mode 100644 index 000000000..90e125a15 --- /dev/null +++ b/backend/src/modules/users/repository/user.repository.interface.ts @@ -0,0 +1,8 @@ +import { BaseInterfaceRepository } from 'src/libs/repositories/interfaces/base.repository.interface'; +import User from '../entities/user.schema'; + +export interface UserRepositoryInterface extends BaseInterfaceRepository { + getById(userId: string): Promise; + updateUserWithRefreshToken(refreshToken: string, userId: string): Promise; + updateUserPassword(email: string, password: string): Promise; +} diff --git a/backend/src/modules/users/repository/user.repository.ts b/backend/src/modules/users/repository/user.repository.ts new file mode 100644 index 000000000..464141cfd --- /dev/null +++ b/backend/src/modules/users/repository/user.repository.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { Model } from 'mongoose'; +import { MongoGenericRepository } from 'src/libs/repositories/mongo/mongo-generic.repository'; +import User, { UserDocument } from '../entities/user.schema'; +import { UserRepositoryInterface } from './user.repository.interface'; + +@Injectable() +export class UserRepository + extends MongoGenericRepository + implements UserRepositoryInterface +{ + constructor(@InjectModel(User.name) private model: Model) { + super(model); + } + + getById(userId: string) { + return this.get(userId, { + password: 0, + currentHashedRefreshToken: 0 + }); + } + + updateUserWithRefreshToken(refreshToken: string, userId: string) { + return this.findOneByFieldAndUpdate({ _id: userId }, { $set: { refreshToken } }); + } + + updateUserPassword(email: string, password: string) { + return this.findOneByFieldAndUpdate( + { email }, + { + $set: { password } + } + ); + } +} diff --git a/backend/src/modules/users/services/create.user.service.ts b/backend/src/modules/users/services/create.user.service.ts index 3041e2e4b..18b4200cf 100644 --- a/backend/src/modules/users/services/create.user.service.ts +++ b/backend/src/modules/users/services/create.user.service.ts @@ -1,15 +1,26 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; +import { Inject, Injectable } from '@nestjs/common'; import CreateUserDto from '../dto/create.user.dto'; +import User from '../entities/user.schema'; import { CreateUserService } from '../interfaces/services/create.user.service.interface'; -import User, { UserDocument } from '../schemas/user.schema'; +import { TYPES } from '../interfaces/types'; +import { UserRepositoryInterface } from '../repository/user.repository.interface'; @Injectable() export default class CreateUserServiceImpl implements CreateUserService { - constructor(@InjectModel(User.name) private userModel: Model) {} + constructor( + @Inject(TYPES.repository) + private readonly userRepository: UserRepositoryInterface + ) {} create(userData: CreateUserDto) { - return this.userModel.create(userData); + const user: User = { + ...userData, + strategy: '', + isSAdmin: false, + isDeleted: false, + joinedAt: new Date() + }; + + return this.userRepository.create(user); } } diff --git a/backend/src/modules/users/services/get.user.service.ts b/backend/src/modules/users/services/get.user.service.ts index 324a64afc..4d6e70364 100644 --- a/backend/src/modules/users/services/get.user.service.ts +++ b/backend/src/modules/users/services/get.user.service.ts @@ -1,32 +1,27 @@ import { Inject, Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; import { compare } from 'src/libs/utils/bcrypt'; import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface'; -import { TYPES } from 'src/modules/teams/interfaces/types'; -import UserDto from '../dto/user.dto'; +import * as Team from 'src/modules/teams/interfaces/types'; import { GetUserService } from '../interfaces/services/get.user.service.interface'; import { UserWithTeams } from '../interfaces/type-user-with-teams'; -import User, { UserDocument } from '../schemas/user.schema'; +import { TYPES } from '../interfaces/types'; +import { UserRepositoryInterface } from '../repository/user.repository.interface'; @Injectable() export default class GetUserServiceImpl implements GetUserService { constructor( - @InjectModel(User.name) private userModel: Model, - @Inject(TYPES.services.GetTeamService) + @Inject(TYPES.repository) + private readonly userRepository: UserRepositoryInterface, + @Inject(Team.TYPES.services.GetTeamService) private getTeamService: GetTeamServiceInterface ) {} getByEmail(email: string) { - return this.userModel.findOne({ email }).lean().exec(); + return this.userRepository.getByProp({ email }); } getById(_id: string) { - return this.userModel - .findById(_id) - .select(['-password -currentHashedRefreshToken']) - .lean() - .exec(); + return this.userRepository.getById(_id); } async getUserIfRefreshTokenMatches(refreshToken: string, userId: string) { @@ -40,18 +35,18 @@ export default class GetUserServiceImpl implements GetUserService { } countUsers() { - return this.userModel.countDocuments().exec(); + return this.userRepository.countDocuments(); } getAllUsers() { - return this.userModel.find().select('-password -currentHashedRefreshToken').lean().exec(); + return this.userRepository.getAll({ password: 0, currentHashedRefreshToken: 0 }); } async getAllUsersWithTeams() { const users = await this.getAllUsers(); const mappedUsers: UserWithTeams[] = users.map((userFound) => { return { - user: userFound as UserDto, + user: userFound, teams: [] }; }); diff --git a/backend/src/modules/users/services/update.user.service.ts b/backend/src/modules/users/services/update.user.service.ts index 9fdf2ade2..13cafed72 100644 --- a/backend/src/modules/users/services/update.user.service.ts +++ b/backend/src/modules/users/services/update.user.service.ts @@ -1,4 +1,4 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { encrypt } from 'src/libs/utils/bcrypt'; @@ -6,12 +6,14 @@ import ResetPassword, { ResetPasswordDocument } from 'src/modules/auth/schemas/reset-password.schema'; import { UpdateUserService } from '../interfaces/services/update.user.service.interface'; -import User, { UserDocument } from '../schemas/user.schema'; +import { TYPES } from '../interfaces/types'; +import { UserRepositoryInterface } from '../repository/user.repository.interface'; @Injectable() export default class updateUserServiceImpl implements UpdateUserService { constructor( - @InjectModel(User.name) private userModel: Model, + @Inject(TYPES.repository) + private readonly userRepository: UserRepositoryInterface, @InjectModel(ResetPassword.name) private resetModel: Model ) {} @@ -19,15 +21,7 @@ export default class updateUserServiceImpl implements UpdateUserService { async setCurrentRefreshToken(refreshToken: string, userId: string) { const currentHashedRefreshToken = await encrypt(refreshToken); - return this.userModel - .findOneAndUpdate( - { _id: userId }, - { - $set: { currentHashedRefreshToken } - } - ) - .lean() - .exec(); + return this.userRepository.updateUserWithRefreshToken(currentHashedRefreshToken, userId); } async setPassword(userEmail: string, newPassword: string, newPasswordConf: string) { @@ -35,12 +29,7 @@ export default class updateUserServiceImpl implements UpdateUserService { if (newPassword !== newPasswordConf) throw new HttpException('PASSWORDS_DO_NOT_MATCH', HttpStatus.BAD_REQUEST); - const user = await this.userModel.findOneAndUpdate( - { email: userEmail }, - { - $set: { password } - } - ); + const user = this.userRepository.updateUserPassword(userEmail, password); if (!user) throw new HttpException('USER_NOT_FOUND', HttpStatus.NOT_FOUND); @@ -52,9 +41,7 @@ export default class updateUserServiceImpl implements UpdateUserService { if (!userFromDb) throw new HttpException('USER_FROM_TOKEN_NOT_FOUND', HttpStatus.NOT_FOUND); this.tokenValidator(userFromDb.updatedAt); - const user = await this.userModel.findOne({ - email: userFromDb.emailAddress - }); + const user = await this.userRepository.getByProp({ email: userFromDb.emailAddress }); if (!user) throw new HttpException('USER_NOT_FOUND', HttpStatus.NOT_FOUND); diff --git a/backend/src/modules/users/users.module.ts b/backend/src/modules/users/users.module.ts index 9a2debfbb..2b45b108e 100644 --- a/backend/src/modules/users/users.module.ts +++ b/backend/src/modules/users/users.module.ts @@ -10,17 +10,19 @@ import { getUserApplication, getUserService, updateUserApplication, - updateUserService + updateUserService, + userRepository } from './users.providers'; @Module({ - imports: [mongooseUserModule, mongooseResetModule, TeamsModule], + imports: [mongooseUserModule, TeamsModule, mongooseResetModule], providers: [ createUserService, getUserService, updateUserService, updateUserApplication, - getUserApplication + getUserApplication, + userRepository ], controllers: [UsersController], exports: [ diff --git a/backend/src/modules/users/users.providers.ts b/backend/src/modules/users/users.providers.ts index bbcfa189c..46abf18ce 100644 --- a/backend/src/modules/users/users.providers.ts +++ b/backend/src/modules/users/users.providers.ts @@ -1,6 +1,7 @@ import { GetUserApplicationImpl } from './applications/get.user.application'; import { UpdateUserApplicationImpl } from './applications/update.user.application'; import { TYPES } from './interfaces/types'; +import { UserRepository } from './repository/user.repository'; import CreateUserServiceImpl from './services/create.user.service'; import GetUserServiceImpl from './services/get.user.service'; import UpdateUserServiceImpl from './services/update.user.service'; @@ -29,3 +30,8 @@ export const getUserApplication = { provide: TYPES.applications.GetUserApplication, useClass: GetUserApplicationImpl }; + +export const userRepository = { + provide: TYPES.repository, + useClass: UserRepository +}; diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 7f70ab728..e716599bb 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -27,6 +27,7 @@ "no-underscore-dangle": "off", "react/display-name": "off", "no-plusplus": "off", + "@typescript-eslint/naming-convention": "off", "import/no-extraneous-dependencies": [ "error", { diff --git a/frontend/src/pages/api/auth/[...nextauth].tsx b/frontend/src/pages/api/auth/[...nextauth].tsx index e9ae3d473..83b65b129 100644 --- a/frontend/src/pages/api/auth/[...nextauth].tsx +++ b/frontend/src/pages/api/auth/[...nextauth].tsx @@ -49,8 +49,8 @@ export default NextAuth({ password: credentials?.password, }; const data = await login(loginUser); - const { firstName, lastName, isSAdmin, accessToken, refreshToken, id } = data || {}; - if (!id || !accessToken || !refreshToken) return null; + const { firstName, lastName, isSAdmin, accessToken, refreshToken, _id, email } = data || {}; + if (!_id || !accessToken || !refreshToken) return null; const token = { firstName, @@ -58,7 +58,8 @@ export default NextAuth({ isSAdmin, accessToken, refreshToken, - id, + id: _id, + email, strategy: 'local', }; return token; @@ -81,14 +82,14 @@ export default NextAuth({ const data = await createOrLoginUserAzure(azureAccessToken ?? ''); if (!data) return false; - const { firstName, lastName, accessToken, refreshToken, email, id, isSAdmin } = data; + const { firstName, lastName, accessToken, refreshToken, email, _id, isSAdmin } = data; user.firstName = firstName; user.lastName = lastName; user.accessToken = accessToken; user.refreshToken = refreshToken; user.email = email; user.strategy = 'azure'; - user.id = id; + user.id = _id; user.isSAdmin = isSAdmin; } @@ -124,9 +125,11 @@ export default NextAuth({ }, async session({ session, token }) { let newSession: Session = { ...session }; + if (token) { newSession = { ...token, expires: token.user.accessToken.expiresIn }; } + return newSession; }, redirect({ url, baseUrl }) { diff --git a/frontend/src/pages/boards/[boardId].tsx b/frontend/src/pages/boards/[boardId].tsx index cd68159e7..67f73b283 100644 --- a/frontend/src/pages/boards/[boardId].tsx +++ b/frontend/src/pages/boards/[boardId].tsx @@ -24,11 +24,17 @@ import { TeamUserRoles } from '@/utils/enums/team.user.roles'; import isEmpty from '@/utils/isEmpty'; export const getServerSideProps: GetServerSideProps = async (context) => { - const { boardId } = context.query; + const boardId = String(context.query.boardId); const queryClient = new QueryClient(); + + if (boardId.includes('.map')) + return { + props: {}, + }; + try { await queryClient.fetchQuery(['board', { id: boardId }], () => - getBoardRequest(boardId as string, context), + getBoardRequest(boardId, context), ); } catch (e) { return { @@ -40,10 +46,10 @@ export const getServerSideProps: GetServerSideProps = async (context) => { } return { props: { - key: context.query.boardId, + key: boardId, dehydratedState: dehydrate(queryClient), mainBoardId: context.query.mainBoardId ?? null, - boardId: context.query.boardId, + boardId, }, }; }; diff --git a/frontend/src/pages/boards/new.tsx b/frontend/src/pages/boards/new.tsx index 628ade589..e834b9fcc 100644 --- a/frontend/src/pages/boards/new.tsx +++ b/frontend/src/pages/boards/new.tsx @@ -120,12 +120,13 @@ const NewBoard: NextPage = () => { useEffect(() => { const isAdminOrStakeHolder = teams - ? teams[0].users.find( + ? !!teams[0].users.find( (teamUser) => teamUser.user._id === session?.user.id && [TeamUserRoles.ADMIN, TeamUserRoles.STAKEHOLDER].includes(teamUser.role), ) || session?.user.isSAdmin : false; + if (!isAdminOrStakeHolder && !haveError) { setHaveError(!isAdminOrStakeHolder); } diff --git a/frontend/src/pages/teams/[teamId].tsx b/frontend/src/pages/teams/[teamId].tsx index fb7853323..c766807b8 100644 --- a/frontend/src/pages/teams/[teamId].tsx +++ b/frontend/src/pages/teams/[teamId].tsx @@ -67,11 +67,14 @@ const Team = () => { export const getServerSideProps: GetServerSideProps = async (context) => { const teamId = String(context.query.teamId); + if (teamId.includes('.map')) + return { + props: {}, + }; + const queryClient = new QueryClient(); try { - await queryClient.prefetchQuery(['team', teamId], () => - getTeamRequest(teamId as string, context), - ); + await queryClient.prefetchQuery(['team', teamId], () => getTeamRequest(teamId, context)); await queryClient.prefetchQuery('users', () => getAllUsers(context)); } catch (e) { return { diff --git a/frontend/src/types/card/card.ts b/frontend/src/types/card/card.ts index 3af855c00..e0577a8d5 100644 --- a/frontend/src/types/card/card.ts +++ b/frontend/src/types/card/card.ts @@ -1,5 +1,6 @@ import CommentType from '../comment/comment'; import { User } from '../user/user'; + import { CardItemToAdd, CardItemType } from './cardItem'; export default interface CardType { diff --git a/frontend/src/types/user/create-login.user.ts b/frontend/src/types/user/create-login.user.ts index 8dc13888e..acf118986 100644 --- a/frontend/src/types/user/create-login.user.ts +++ b/frontend/src/types/user/create-login.user.ts @@ -3,7 +3,7 @@ import { Token } from '../token'; export interface CreateOrLogin { strategy?: string; email: string; - id: string; + _id: string; accessToken: Token; refreshToken: Token; firstName: string; diff --git a/frontend/src/types/user/user.ts b/frontend/src/types/user/user.ts index d8c1b69f9..f7c02c5bf 100644 --- a/frontend/src/types/user/user.ts +++ b/frontend/src/types/user/user.ts @@ -5,7 +5,6 @@ import { Nullable } from '../common'; import { Token } from '../token'; export interface User { - id?: string; _id: string; firstName: string; lastName: string;