Skip to content
Snippets Groups Projects
Unverified Commit d4bdf5cc authored by Nabilsenko's avatar Nabilsenko Committed by GitHub
Browse files

Merge branch 'master' into login

parents d936324f b64f7ddf
No related branches found
No related tags found
1 merge request!6feat: added login to people
Showing
with 18138 additions and 14 deletions
......@@ -103,8 +103,5 @@ dist
# TernJS port file
.tern-port
# package-lock.json file
package-lock.json
# config files
config.json
This diff is collapsed.
......@@ -13,10 +13,10 @@
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"start": "cross-env NODE_ENV=dev nest start",
"start:dev": "cross-env NODE_ENV=dev nest start --watch",
"start:debug": "cross-env NODE_ENV=dev nest start --debug --watch",
"start:prod": "cross-env NODE_ENV=prod node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
......@@ -55,6 +55,7 @@
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
......
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { mongodb } from './config';
import config from './config';
import { PeopleModule } from './people/people.module';
import { GroupsModule } from './groups/groups.module';
import { LoginModule } from './login/login.module';
import { InternshipsModule } from './internships/internships.module';
@Module({
imports: [PeopleModule, GroupsModule, MongooseModule.forRoot(mongodb.uri), LoginModule],
imports: [
PeopleModule,
GroupsModule,
InternshipsModule,
MongooseModule.forRoot(config.mongodb.uri),
LoginModule
],
})
export class AppModule {}
{
"server": {
"uri": "localhost",
"port": 3001
},
"mongodb": {
"uri": "mongodb://localhost:27017/internship-manager"
}
}
import * as _config from './config.template.json';
import { IConfig } from './config.model';
import { readFileSync } from 'fs';
import * as path from 'path';
import { exit } from 'process';
const config = _config as IConfig;
// Store file local path in var for lisibility
const CONFIG_DEV = 'config.json';
const CONFIG_PROD = 'config.prod.json';
export const server = config.server;
export const mongodb = config.mongodb;
let config;
// Load config based on env
switch (process.env.NODE_ENV) {
case 'dev':
// Load 'dev' config
config = JSON.parse(
readFileSync(path.join(__dirname, CONFIG_DEV), 'utf-8'),
) as IConfig;
break;
case 'prod':
// Load 'prod' config
config = JSON.parse(
readFileSync(path.join(__dirname, CONFIG_PROD), 'utf-8'),
) as IConfig;
break;
default:
// This happens when the environment isn't set
console.log(
'\x1b[31mFATAL: Cannot load config.\nInvalid application environment. Did you read the \x1b[4mREADME\x1b[0m\x1b[31m ?\x1b[0m',
);
exit(-1);
}
// Export config
export default config;
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { BAD_REQUEST, CONFLICT } from 'src/shared/HttpError';
import {
isStateValid,
STATE_COMPANY_SIGNS_INTERNSHIP_AGREEMENT,
STATE_DEAN_SIGNS_INTERNSHIP_AGREEMENT,
STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION,
STATE_RESPONSIBLE_SIGNS_INTERNSHIP_AGREEMENT,
STATE_SECRETARY_ESTABLISHES_INTERNSHIP_AGREEMENT,
STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION,
STATE_STUDENT_SIGNS_INTERNSHIP_AGREEMENT,
} from 'src/shared/InternshipState';
import { CreateInternshipDto } from '../dto/create-internship.dto';
import { InternshipDto } from '../dto/internship.dto';
import { Internship } from '../schemas/internship.schema';
@Injectable()
export class InternshipDao {
constructor(
@InjectModel(Internship.name)
private readonly _internshipModel: Model<Internship>,
) {}
find = (): Promise<Internship[]> =>
new Promise((resolve, reject) => {
this._internshipModel.find({}, {}, {}, (err, value) => {
if (err) reject(err.message);
if (!value) reject('No values');
resolve(value);
});
});
findByStudentId = (studentId: string): Promise<Internship | void> =>
new Promise((resolve, reject) => {
this._internshipModel.findOne({ studentId }, {}, {}, (err, value) => {
if (err) reject(err.message);
if (!value) reject(new NotFoundException());
resolve(value);
});
});
save = (internship: CreateInternshipDto): Promise<Internship> =>
new Promise((resolve, reject) => {
// Use updateOne with `upsert: true` to only insert when no other document has the same studentId to prevent duplicata
const decoratedInternship = this.toInternshipDtoWithTracking(internship);
this._internshipModel.updateOne(
{ studentId: internship.studentId },
{ $setOnInsert: decoratedInternship },
{
upsert: true,
runValidators: true,
},
(err, value) => {
const { upsertedCount } = value;
if (err) reject(err.message);
if (upsertedCount === 0) reject(CONFLICT);
resolve(decoratedInternship as Internship);
},
);
});
findByStudentIdAndUpdate = (
studentId: string,
internship: CreateInternshipDto,
): Promise<Internship | void> =>
new Promise((resolve, reject) => {
// Check if information modification is allowed -> current state is information input by student and updating is allowed
if (studentId !== internship.studentId) reject(BAD_REQUEST);
const decoratedInternship = this.toInternshipDtoWithTracking(internship);
this._internshipModel.findOneAndReplace(
{
studentId,
'tracking.state': STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION,
},
decoratedInternship,
{
new: true,
runValidators: true,
},
(err, value) => {
if (err) reject(err.message);
// if (typeof value !== typeof Internship) reject(INTERNAL);
resolve(value as Internship);
},
);
});
private updateTrackingState = (
studentId: string,
state: string,
nextState: string,
contentHolder: string,
content: string | boolean,
callback: (err: any, value: any) => void,
) => {
this._internshipModel.findOneAndUpdate(
{
studentId,
'tracking.state': state,
},
{
$set: {
'tracking.state': nextState,
[contentHolder]: content,
},
},
{
new: true,
runValidators: true,
},
callback,
);
};
findByStudentIdAndUpdateTracking = (
studentId: string,
state: string,
content: string | boolean,
): Promise<Internship | void> =>
new Promise((resolve, reject) => {
if (!isStateValid(state)) reject(BAD_REQUEST);
console.log(typeof content);
let nextState: string, contentHolder: string;
let valid = false;
switch (state) {
case STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION: {
if (typeof content === 'boolean' && content === true) {
nextState = STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION;
contentHolder = 'tracking.studentEntersInternshipInformation';
valid = true;
} else reject(BAD_REQUEST);
break;
}
case STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION: {
if (typeof content === 'boolean' && content === true) {
// content === true -> Responsible agrees with internship
nextState = STATE_SECRETARY_ESTABLISHES_INTERNSHIP_AGREEMENT;
contentHolder = 'tracking.responsibleAcceptsInternshipInformation';
valid = true;
} else if (typeof content === 'boolean' && content === false) {
// content === false -> Responsible did not agree with internship, go back to student entering information
nextState = STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION;
contentHolder = 'tracking.responsibleAcceptsInternshipInformation';
valid = true;
} else reject(BAD_REQUEST);
break;
}
case STATE_SECRETARY_ESTABLISHES_INTERNSHIP_AGREEMENT: {
if (typeof content !== 'string') reject(BAD_REQUEST);
else {
nextState = STATE_STUDENT_SIGNS_INTERNSHIP_AGREEMENT;
contentHolder = 'tracking.secretaryEstablishesInternshipAgreement';
valid = true;
}
break;
}
case STATE_STUDENT_SIGNS_INTERNSHIP_AGREEMENT: {
if (typeof content !== 'string') reject(BAD_REQUEST);
else {
nextState = STATE_RESPONSIBLE_SIGNS_INTERNSHIP_AGREEMENT;
contentHolder = 'tracking.studentSignsInternshipAgreement';
valid = true;
}
break;
}
case STATE_RESPONSIBLE_SIGNS_INTERNSHIP_AGREEMENT: {
if (typeof content !== 'string') reject(BAD_REQUEST);
else {
nextState = STATE_COMPANY_SIGNS_INTERNSHIP_AGREEMENT;
contentHolder = 'tracking.responsibleSignsInternshipAgreement';
valid = true;
}
break;
}
case STATE_COMPANY_SIGNS_INTERNSHIP_AGREEMENT: {
if (typeof content !== 'string') reject(BAD_REQUEST);
else {
nextState = STATE_DEAN_SIGNS_INTERNSHIP_AGREEMENT;
contentHolder = 'tracking.companySignsInternshipAgreement';
valid = true;
}
break;
}
case STATE_DEAN_SIGNS_INTERNSHIP_AGREEMENT: {
if (typeof content !== 'string') reject(BAD_REQUEST);
else {
nextState = '/';
contentHolder = 'tracking.deanSignsInternshipAgreement';
valid = true;
}
break;
}
}
if (valid) {
this.updateTrackingState(
studentId,
state,
nextState,
contentHolder,
content,
(err, value) => {
if (err) reject(err);
else if (!value) reject(BAD_REQUEST);
else resolve(value);
},
);
}
});
findByStudentIdAndRemove = (studentId: string): Promise<Internship | void> =>
new Promise((resolve, reject) => {
this._internshipModel.findOneAndDelete({ studentId }, {}, (err) => {
if (err) reject(err.message);
resolve();
});
});
toInternshipDtoWithTracking = (
createInternshipDto: CreateInternshipDto,
): InternshipDto => {
return {
...createInternshipDto,
tracking: {
state: STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION,
},
};
};
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDefined,
IsNotEmptyObject,
ValidateNested,
} from 'class-validator';
import { InformationDto } from './nested-create/information.dto';
export class CreateInternshipDto {
@IsString()
@IsNotEmpty()
studentId: string;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => InformationDto)
information: InformationDto;
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDefined,
IsNotEmptyObject,
ValidateNested,
} from 'class-validator';
import { InformationDto } from './nested-create/information.dto';
import { TrackingDto } from './nested-create/tracking.dto';
export class InternshipDto {
@IsString()
@IsNotEmpty()
studentId: string;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => InformationDto)
information: InformationDto;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => TrackingDto)
tracking: TrackingDto;
}
import { IsString, IsNotEmpty } from 'class-validator';
export class AddressDto {
@IsString()
@IsNotEmpty()
street: string;
@IsString()
@IsNotEmpty()
city: string;
@IsString()
@IsNotEmpty()
postalCode: string;
@IsString()
@IsNotEmpty()
country: string;
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDateString,
IsDefined,
IsNotEmptyObject,
ValidateNested,
} from 'class-validator';
import { AddressDto } from './address.dto';
export class AffectationDto {
@IsString()
@IsNotEmpty()
service: string;
@IsString()
@IsNotEmpty()
responsibleName: string;
@IsString()
@IsNotEmpty()
responsibleEmail: string;
@IsString()
@IsNotEmpty()
responsiblePhone: string;
@IsString()
@IsNotEmpty()
responsibleFunction: string;
@IsDateString()
@IsNotEmpty()
dateStart: Date;
@IsDateString()
@IsNotEmpty()
dateEnd: Date;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto;
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDefined,
IsNotEmptyObject,
ValidateNested,
} from 'class-validator';
import { AddressDto } from './address.dto';
export class CompanyDto {
@IsString()
@IsNotEmpty()
ceoName: string;
@IsString()
@IsNotEmpty()
companyName: string;
@IsString()
@IsNotEmpty()
hrContactName: string;
@IsString()
@IsNotEmpty()
hrContactEmail: string;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto;
}
import { IsString, IsNotEmpty } from 'class-validator';
export class CompensationDto {
@IsString()
@IsNotEmpty()
gratificationAmount: string;
@IsString()
@IsNotEmpty()
modalities: string;
@IsString()
@IsNotEmpty()
othersAdvantages: string;
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDefined,
IsNotEmptyObject,
ValidateNested,
} from 'class-validator';
import { AffectationDto } from './affectation.dto';
import { CompanyDto } from './company.dto';
import { CompensationDto } from './compensation.dto';
import { StudentDto } from './student.dto';
export class InformationDto {
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => StudentDto)
student: StudentDto;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => CompanyDto)
company: CompanyDto;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => AffectationDto)
affectation: AffectationDto;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => CompensationDto)
compensation: CompensationDto;
@IsString()
@IsNotEmpty()
internshipDescription: string;
}
import { Type } from 'class-transformer';
import {
IsString,
IsNotEmpty,
IsDateString,
IsDefined,
IsNotEmptyObject,
ValidateNested,
IsEmail,
IsAlphanumeric,
IsPhoneNumber,
} from 'class-validator';
import { AddressDto } from './address.dto';
export class StudentDto {
@IsString()
@IsNotEmpty()
completeName: string;
@IsString()
@IsPhoneNumber()
@IsNotEmpty()
phone: string;
@IsDateString()
@IsNotEmpty()
birthDate: Date;
@IsDefined()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto;
@IsString()
@IsNotEmpty()
FormationAndSpecialty: string;
@IsString()
@IsEmail()
@IsNotEmpty()
email: string;
@IsString()
@IsAlphanumeric()
@IsNotEmpty()
socialSecurityNumber: string;
}
import { IsString, IsNotEmpty, IsBoolean, IsOptional } from 'class-validator';
export class TrackingDto {
@IsString()
@IsNotEmpty()
state: string;
@IsBoolean()
@IsOptional()
studentEntersInternshipInformation?: boolean;
@IsBoolean()
@IsOptional()
responsibleAcceptsInternshipInformation?: boolean;
@IsString()
@IsOptional()
secretaryEstablishesInternshipAgreement?: string;
@IsString()
@IsOptional()
studentSignsInternshipAgreement?: string;
@IsString()
@IsOptional()
responsibleSignsInternshipAgreement?: string;
@IsString()
@IsOptional()
companySignsInternshipAgreement?: string;
@IsString()
@IsOptional()
deanSignsInternshipAgreement?: string;
}
import { InformationEntity } from './nested-entities/information.entity';
import { TrackingEntity } from './nested-entities/tracking.entity';
export class InternshipEntity {
studentId: string;
information: InformationEntity;
tracking: TrackingEntity;
constructor(partial: Partial<InternshipEntity>) {
Object.assign(this, partial);
}
}
export class AddressEntity {
street: string;
postalCode: string;
city: string;
country: string;
constructor(partial: Partial<AddressEntity>) {
Object.assign(this, partial);
}
}
import { AddressEntity } from './address.entity';
export class AffectationEntity {
service: string;
responsibleName: string;
responsibleEmail: string;
responsiblePhone: string;
responsibleFunction: string;
dateStart: Date;
dateEnd: Date;
address: AddressEntity;
constructor(partial: Partial<AffectationEntity>) {
Object.assign(this, partial);
}
}
import { AddressEntity } from './address.entity';
export class CompanyEntity {
ceoName: string;
companyName: string;
hrContactName: string;
hrContactEmail: string;
address: AddressEntity;
constructor(partial: Partial<CompanyEntity>) {
Object.assign(this, partial);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment