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

Merge pull request #8 from ivanalglave/pdfback

Pdfback
parents ceefad6e 2eb4afa9
No related branches found
No related tags found
No related merge requests found
......@@ -105,3 +105,6 @@ dist
# config files
config.json
# file where we store pdf
files/*
......@@ -20,6 +20,7 @@
"eslint-import-resolver-typescript": "^3.5.2",
"fastify": "^4.9.2",
"mongoose": "^6.7.2",
"multer": "^1.4.5-lts.1",
"passport": "^0.6.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
......@@ -37,6 +38,7 @@
"@types/passport-jwt": "^3.0.8",
"@types/passport-local": "^1.0.34",
"@types/supertest": "^2.0.11",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"cross-env": "^7.0.3",
......@@ -2683,6 +2685,23 @@
"@nestjs/core": "^9.0.0"
}
},
"node_modules/@nestjs/platform-express/node_modules/multer": {
"version": "1.4.4-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/@nestjs/schematics": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz",
......@@ -3232,6 +3251,12 @@
"@types/superagent": "*"
}
},
"node_modules/@types/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
"dev": true
},
"node_modules/@types/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
......@@ -8255,9 +8280,9 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/multer": {
"version": "1.4.4-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
......@@ -12979,6 +13004,22 @@
"express": "4.18.2",
"multer": "1.4.4-lts.1",
"tslib": "2.4.1"
},
"dependencies": {
"multer": {
"version": "1.4.4-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
}
}
}
},
"@nestjs/schematics": {
......@@ -13468,6 +13509,12 @@
"@types/superagent": "*"
}
},
"@types/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
"dev": true
},
"@types/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
......@@ -17223,9 +17270,9 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"multer": {
"version": "1.4.4-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
"integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
......
......@@ -5,12 +5,14 @@ import { PeopleModule } from './people/people.module';
import { GroupsModule } from './groups/groups.module';
import { LoginModule } from './login/login.module';
import { InternshipsModule } from './internships/internships.module';
import { ResourcesModule } from './resources/resources.module';
@Module({
imports: [
PeopleModule,
GroupsModule,
InternshipsModule,
ResourcesModule,
MongooseModule.forRoot(config.mongodb.uri),
LoginModule
],
......
export interface IServerConfig {
interface IServerConfig {
uri: string;
port: number;
}
export interface IMongodbConfig {
interface IResources {
root: string;
agreements: string;
}
interface IMongodbConfig {
uri: string;
}
export interface IConfig {
server: IServerConfig;
resources: IResources;
mongodb: IMongodbConfig;
}
......@@ -3,6 +3,9 @@
"uri": "localhost",
"port": 3001
},
"resources": {
"internshipAgreements": "internship-agreements"
},
"mongodb": {
"uri": "mongodb://localhost:27017/internship-manager"
}
......
{
"server": {
"uri": "localhost",
"port": 3001
},
"resources": {
"internshipAgreements": "internship-agreements"
},
"mongodb": {
"uri": "mongodb://localhost:27017/internship-manager"
}
......
......@@ -7,7 +7,8 @@ import { exit } from 'process';
const CONFIG_DEV = 'config.json';
const CONFIG_PROD = 'config.prod.json';
let config;
let config: IConfig;
console.log(process.env.NODE_ENV);
// Load config based on env
switch (process.env.NODE_ENV) {
case 'dev':
......@@ -30,5 +31,7 @@ switch (process.env.NODE_ENV) {
exit(-1);
}
console.log(config);
// Export config
export default config;
......@@ -120,8 +120,9 @@ export class InternshipDao {
content: string | boolean,
): Promise<Internship | void> =>
new Promise((resolve, reject) => {
console.log('%s/%s: {%s}', studentId, state, content);
if (!isStateValid(state)) reject(BAD_REQUEST);
console.log(typeof content);
console.log(content);
let nextState: string, contentHolder: string;
let valid = false;
switch (state) {
......
......@@ -7,13 +7,23 @@ import {
Param,
Body,
UseInterceptors,
UploadedFile,
} from '@nestjs/common';
import { BAD_TRACKING_STATE } from 'src/shared/HttpError';
import { BAD_REQUEST, BAD_TRACKING_STATE } from 'src/shared/HttpError';
import * as InternshipStates from 'src/shared/InternshipState';
import { HttpInterceptor } from '../interceptors/http.interceptor';
import { CreateInternshipDto } from './dto/create-internship.dto';
import { InternshipEntity } from './entities/internship.entity';
import { InternshipService } from './internships.service';
import { FileInterceptor } from '@nestjs/platform-express';
import {
STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION,
STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION,
} from 'src/shared/InternshipState';
import config from 'src/config';
import { Optional } from '@nestjs/common/decorators';
import { v4 } from 'uuid';
import { diskStorage } from 'multer';
@Controller('internships')
@UseInterceptors(HttpInterceptor)
......@@ -47,18 +57,43 @@ export class InternshipsController {
return this._internshipsService.update(params.studentId, internshipDto);
}
@Put(':studentId/tracking')
// uploads even if invalid state...
@Put(':studentId/:state')
@UseInterceptors(
FileInterceptor('pdf', {
storage: diskStorage({
destination: './files',
filename: (_req, _file, cb) => {
return cb(null, `${v4()}.pdf`);
},
}),
}),
)
updateState(
@Param() params: { studentId: string },
@Body() body: { state: string; content?: string | boolean },
@Param() params: { studentId: string; state: string },
@Optional() @Body() body: { content?: boolean },
@Optional() @UploadedFile() file,
): Promise<InternshipEntity | void> {
if (!InternshipStates.isStateValid(body.state))
throw BAD_TRACKING_STATE(body.state);
// AMINE : Handle PDF file upload -> save file in /pdf/ folder and set content as local file URL. In case of step with no file, set content as true/false
if (!InternshipStates.isStateValid(params.state))
throw BAD_TRACKING_STATE(params.state);
if (
params.state === STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION ||
params.state === STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION
) {
if (!body) throw BAD_REQUEST;
return this._internshipsService.updateTracking(
params.studentId,
params.state,
body.content,
);
}
if (!file) throw BAD_REQUEST;
console.log(params.state);
return this._internshipsService.updateTracking(
params.studentId,
body.state,
body.content,
params.state,
`${config.server.uri}:${config.server.port}/resources/agreements/${file.filename}`,
);
}
......
import config from './config';
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import config from './config';
async function bootstrap() {
const env = process.env.NODE_ENV;
......
import {
Controller,
Get,
Param,
UseInterceptors,
Res,
StreamableFile,
} from '@nestjs/common';
import { NOT_FOUND } from 'src/shared/HttpError';
import { HttpInterceptor } from '../interceptors/http.interceptor';
import { Response } from 'express';
import { createReadStream, existsSync } from 'fs';
@Controller('resources')
@UseInterceptors(HttpInterceptor)
export class ResourcesController {
@Get('agreements/:filename')
serveAgreement(
@Param('filename') filename,
@Res({ passthrough: true }) res: Response,
): StreamableFile {
const filepath = `files\\${filename}`;
if (!existsSync(filepath)) throw NOT_FOUND;
const file = createReadStream(filepath);
res.set({
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="agreement.pdf"',
});
return new StreamableFile(file);
}
}
import { Module, Logger } from '@nestjs/common';
import { ResourcesController } from './resources.controller';
@Module({
controllers: [ResourcesController],
providers: [Logger],
})
export class ResourcesModule {}
......@@ -11,6 +11,7 @@ export const NOT_FOUND = new NotFoundException();
export const CONFLICT = new ConflictException();
export const BAD_REQUEST = new BadRequestException();
export const INTERNAL = new InternalServerErrorException();
export const UNPROCESSABLE_ENTITY = new UnprocessableEntityException();
export const BAD_TRACKING_STATE = (badState: string) =>
new UnprocessableEntityException(`Unknown state [${badState}]`);
export const CUSTOM = (reason: string, errorStatus: number) =>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment