From 702cdfef8f59f1198234ac6e43094523968f8e47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Chanon?=
<95433353+MaelChanon@users.noreply.github.com>
Date: Thu, 16 Nov 2023 21:20:01 +0100
Subject: [PATCH 01/67] refactor User Model (#8)
---
.../use_cases/security/GetAccessToken.js | 1 +
lib/application/use_cases/user/CreateUser.js | 5 ++--
lib/domain/model/User.js | 8 +++---
lib/domain/model/utils/EtatsEnum.js | 4 ---
.../orm/sequelize/models/Etat.js | 19 --------------
.../orm/sequelize/models/Utilisateur.js | 6 +++++
lib/infrastructure/orm/sequelize/sequelize.js | 24 +----------------
.../repositories/UserRepository.js | 6 +++--
package-lock.json | 19 --------------
test/integration/users.test.js | 26 +++++++++++++++++--
.../usecase/fixtures/searchFixture.js | 4 ++-
.../application/usecase/user/user.test.js | 17 +++++++++---
12 files changed, 60 insertions(+), 79 deletions(-)
delete mode 100644 lib/domain/model/utils/EtatsEnum.js
delete mode 100644 lib/infrastructure/orm/sequelize/models/Etat.js
diff --git a/lib/application/use_cases/security/GetAccessToken.js b/lib/application/use_cases/security/GetAccessToken.js
index 09fdc08..cef3d32 100644
--- a/lib/application/use_cases/security/GetAccessToken.js
+++ b/lib/application/use_cases/security/GetAccessToken.js
@@ -6,6 +6,7 @@ module.exports = async (email, password, { userRepository, accessTokenManager })
if (!user || !await bcrypt.compare(password,user.password)) {
throwStatusCode(401,'Bad credentials')
}
+
return accessTokenManager.generate({
sub: 'my-sub', // needs to match definition above
value: user.id, // this is a custom key I used, it could be named anything. Value should be a way to authenticate the user
diff --git a/lib/application/use_cases/user/CreateUser.js b/lib/application/use_cases/user/CreateUser.js
index afccae1..d10dba7 100644
--- a/lib/application/use_cases/user/CreateUser.js
+++ b/lib/application/use_cases/user/CreateUser.js
@@ -2,7 +2,6 @@
const User = require('../../../domain/model/User');
const bcrypt = require("bcrypt");
-const etatsEnum = require('../../../domain/model/utils/EtatsEnum')
const rolesEnum = require('../../../domain/model/utils/RolesEnum')
const throwStatusCode = require("../utils/throwStatusCode")
module.exports = async (pseudo, email,alias, bio, password,spotifyToken, { userRepository }) => {
@@ -20,10 +19,12 @@ module.exports = async (pseudo, email,alias, bio, password,spotifyToken, { userR
email,
alias,
bio,
+ null,
+ null,
password,
spotifyToken,
rolesEnum.UTILISATEUR,
- etatsEnum.LIBRE);
+ null);
return userRepository.persist(user)
diff --git a/lib/domain/model/User.js b/lib/domain/model/User.js
index d5c2153..1293a12 100644
--- a/lib/domain/model/User.js
+++ b/lib/domain/model/User.js
@@ -2,16 +2,18 @@
module.exports = class {
- constructor(id = null, pseudo, email,alias, bio, password,spotifyToken,id_role, id_etat) {
+ constructor(id = null, pseudo, email,alias, bio, photo,tempPhoto, password,spotifyToken,id_role, banUntil) {
this.id = id;
this.pseudo = pseudo;
this.email = email;
this.alias = alias
- this.bio = bio
+ this.photo = photo
+ this.tempPhoto = tempPhoto
this.spotifyToken = spotifyToken
this.password = password;
+ this.password = password;
this.id_role = id_role;
- this.id_etat = id_etat
+ this.banUntil = banUntil
this.type = 'user'
}
diff --git a/lib/domain/model/utils/EtatsEnum.js b/lib/domain/model/utils/EtatsEnum.js
deleted file mode 100644
index 20f5d9c..0000000
--- a/lib/domain/model/utils/EtatsEnum.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- LIBRE : 1,
- BAN : 2,
-}
\ No newline at end of file
diff --git a/lib/infrastructure/orm/sequelize/models/Etat.js b/lib/infrastructure/orm/sequelize/models/Etat.js
deleted file mode 100644
index 0241add..0000000
--- a/lib/infrastructure/orm/sequelize/models/Etat.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const { DataTypes } = require('sequelize');
-module.exports = (sequelize) => {
-
- return sequelize.define('etat', {
-
- // attributes
- id_etat: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- libelle: {
- type: DataTypes.STRING(20),
- allowNull: false,
- },
- },
- { freezeTableName: true,});
-
-};
diff --git a/lib/infrastructure/orm/sequelize/models/Utilisateur.js b/lib/infrastructure/orm/sequelize/models/Utilisateur.js
index 84fac16..22ff063 100644
--- a/lib/infrastructure/orm/sequelize/models/Utilisateur.js
+++ b/lib/infrastructure/orm/sequelize/models/Utilisateur.js
@@ -38,6 +38,12 @@ module.exports = (sequelize) => {
photo: {
type: DataTypes.STRING(250),
},
+ photo_temporaire: {
+ type: DataTypes.STRING(250),
+ },
+ ban_until: {
+ type: DataTypes.DATE
+ },
bio: {
type: DataTypes.STRING(1500),
},
diff --git a/lib/infrastructure/orm/sequelize/sequelize.js b/lib/infrastructure/orm/sequelize/sequelize.js
index 35a6951..f828b62 100644
--- a/lib/infrastructure/orm/sequelize/sequelize.js
+++ b/lib/infrastructure/orm/sequelize/sequelize.js
@@ -9,8 +9,6 @@ const ArtisteModel = require('./models/Artiste')(sequelize)
const ReviewModel = require('./models/Review')(sequelize)
const TypeReviewModel = require('./models/TypeReview')(sequelize)
const CommentaireModel = require('./models/Commentaire')(sequelize)
-const EtatModel = require('./models/Etat')(sequelize)
-
require('./models/LikeOeuvre')(sequelize)
require('./models/OeuvreFavorite')(sequelize)
@@ -21,17 +19,8 @@ UserModel.belongsTo(RoleModel,
{foreignKey: 'id_role'})
//un utilisateur a un etat
-UserModel.belongsTo(EtatModel,
- {foreignKey: 'id_etat'})
-//un utilisateur peut avoir plusieurs amis
-UserModel.belongsToMany(UserModel,
- {
- as: 'amis_1',
- foreignKey: 'amis_1_id',
- through : AmisModel
- }
-)
+
UserModel.belongsToMany(UserModel,
{
as: 'amis_2',
@@ -117,15 +106,4 @@ RoleModel.sync()
console.error('Erreur dans la création des roles : '+error)
})
-EtatModel.sync()
- .then(()=>{
- return EtatModel.bulkCreate([
- {id_etat: 1, libelle : 'libre'},
- {id_etat: 2, libelle : 'ban'},
- ])
- })
- .then(() => console.log('Creation des etats réussi'))
- .catch((error) => {
- console.error('Erreur dans la création des etats : '+error)
- })
module.exports = sequelize;
\ No newline at end of file
diff --git a/lib/infrastructure/repositories/UserRepository.js b/lib/infrastructure/repositories/UserRepository.js
index e8e94ab..2ad0dd2 100644
--- a/lib/infrastructure/repositories/UserRepository.js
+++ b/lib/infrastructure/repositories/UserRepository.js
@@ -38,7 +38,7 @@ module.exports = class extends userRepository {
{ pseudo : ident},
{ email : ident}
]
- }
+ },
});
return this.createUser(seqUser)
}
@@ -53,10 +53,12 @@ module.exports = class extends userRepository {
seqUser.email,
seqUser.alias,
seqUser.bio,
+ seqUser.photo,
+ seqUser.photo_temporaire,
seqUser.password,
seqUser.token_spotify,
seqUser.id_role,
- seqUser.id_etat);
+ seqUser.ban_until);
}
async getByEmailOrPseudo(email, pseudo){
const seqUser = await this.model.findOne({
diff --git a/package-lock.json b/package-lock.json
index bd5d4df..8b62635 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -414,25 +414,6 @@
}
}
},
- "@hapi/basic": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/@hapi/basic/-/basic-5.1.1.tgz",
- "integrity": "sha512-fHyVvf2xurgGBJJaLpRMtDF4AaPSs679nGk8/FjBw3p8/Kj5fuPv5kD1+fJ4ZSdPt1rHHGvKIDK0aVysbbUDMg==",
- "requires": {
- "@hapi/boom": "7.x.x",
- "@hapi/hoek": "8.x.x"
- },
- "dependencies": {
- "@hapi/boom": {
- "version": "7.4.11",
- "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-7.4.11.tgz",
- "integrity": "sha512-VSU/Cnj1DXouukYxxkes4nNJonCnlogHvIff1v1RVoN4xzkKhMXX+GRmb3NyH1iar10I9WFPDv2JPwfH3GaV0A==",
- "requires": {
- "@hapi/hoek": "8.x.x"
- }
- }
- }
- },
"@hapi/boom": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.0.tgz",
diff --git a/test/integration/users.test.js b/test/integration/users.test.js
index 9d25b15..7af5362 100644
--- a/test/integration/users.test.js
+++ b/test/integration/users.test.js
@@ -220,7 +220,18 @@ describe('user route', () => {
it('should respond code 200', async () => {
const password = 'password'
- let fetchedUser = new User("id","pseudo","email","alias","bio",await bcrypt.hash(password,10),"token",1,1)
+ const fetchedUser = new User(
+ "id",
+ "pseudo",
+ "email",
+ "alias",
+ "bio",
+ "path/to/file",
+ "path/to/file",
+ await bcrypt.hash(password,10),
+ "token",
+ 1,
+ new Date("10-06-2003"))
mockUserRepository.getByIdent = jest.fn((ident) =>{
return fetchedUser
@@ -240,7 +251,18 @@ describe('user route', () => {
})
it('should respond code 401 bad password', async () => {
const password = 'password'
- let fetchedUser = new User("id","pseudo","email","alias","bio",await bcrypt.hash(password,10),"token",1,1)
+ const fetchedUser = new User(
+ "id",
+ "pseudo",
+ "email",
+ "alias",
+ "bio",
+ "path/to/file",
+ "path/to/file",
+ await bcrypt.hash(password,10),
+ "token",
+ 1,
+ new Date("10-06-2003"))
mockUserRepository.getByIdent = jest.fn((ident) =>{
return fetchedUser
diff --git a/test/unit/application/usecase/fixtures/searchFixture.js b/test/unit/application/usecase/fixtures/searchFixture.js
index 049588e..8b81274 100644
--- a/test/unit/application/usecase/fixtures/searchFixture.js
+++ b/test/unit/application/usecase/fixtures/searchFixture.js
@@ -25,10 +25,12 @@ const mockUser = new User(
'testEmail@gmail.com',
'test_alias',
'testbio',
+ 'path/to/photo',
+ 'path/to/photo',
'passwordtest',
'spotifyToken',
2,
- 1
+ new Date("10-06-2003")
)
const SpotifyRepositoryFixture = {
tracks : { items : [rawTrackWithOneArtistOneAlbum]},
diff --git a/test/unit/application/usecase/user/user.test.js b/test/unit/application/usecase/user/user.test.js
index 39572ad..938560d 100644
--- a/test/unit/application/usecase/user/user.test.js
+++ b/test/unit/application/usecase/user/user.test.js
@@ -11,10 +11,13 @@ const persistedUser = new User(
'testEmail@gmail.com',
'test_alias',
'testbio',
+ 'path/to/file',
+ 'path/to/file',
'passwordtest',
'spotifyToken',
2,
- 1)
+ new Date("10-06-2003")
+)
describe('createUser', () =>{
@@ -40,7 +43,9 @@ describe('createUser', () =>{
expect(mockResult.bio).toBe(persistedUser.bio)
expect(mockResult.spotifyToken).toBe(persistedUser.spotifyToken)
expect(mockResult.id_role).toBe(2)
- expect(mockResult.id_etat).toBe(1)
+ expect(mockResult.photo).toBe(null)
+ expect(mockResult.tempPhoto).toBe(null)
+ expect(mockResult.banUntil).toBe(null)
expect(mockResult.password).not.toBe(user.password)
})
it('should throw an error when an user with the same pseudo exists', async ()=>{
@@ -83,10 +88,12 @@ describe('getAccessToken', () =>{
'testEmail@gmail.com',
'test_alias',
'testbio',
+ 'path/to/file',
+ 'path/to/file',
await bcrypt.hash(passwordTest,10),
'spotifyToken',
2,
- 1)
+ new Date("10-06-2003"))
const mockUserRepository = new UserRepository();
const mockAccessTokenManager = {};
mockAccessTokenManager.generate = jest.fn((uid) => 1)
@@ -112,10 +119,12 @@ describe('getAccessToken', () =>{
'testEmail@gmail.com',
'test_alias',
'testbio',
+ 'path/to/file',
+ 'path/to/file',
await bcrypt.hash(passwordTest,10),
'spotifyToken',
2,
- 1)
+ new Date("10-06-2003"))
const mockUserRepository = new UserRepository();
const mockAccessTokenManager = {};
mockUserRepository.getByIdent = jest.fn((ident) => persistedUserCrypted)
From aebd3cb56141a950ed47d9fed0303fb455e83c37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Chanon?=
<95433353+MaelChanon@users.noreply.github.com>
Date: Mon, 20 Nov 2023 13:36:04 +0100
Subject: [PATCH 02/67] =?UTF-8?q?refactor=20de=20la=20mise=20en=20place=20?=
=?UTF-8?q?de=20la=20strat=C3=A9gie=20(#9)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/infrastructure/config/strategy.js | 21 +++++++++++++++++++++
lib/infrastructure/webserver/server.js | 21 ++-------------------
test/integration/users.test.js | 7 +++++++
3 files changed, 30 insertions(+), 19 deletions(-)
create mode 100644 lib/infrastructure/config/strategy.js
diff --git a/lib/infrastructure/config/strategy.js b/lib/infrastructure/config/strategy.js
new file mode 100644
index 0000000..3250398
--- /dev/null
+++ b/lib/infrastructure/config/strategy.js
@@ -0,0 +1,21 @@
+module.exports = ({userRepository}) =>{
+ return {
+ keys: process.env.SECRET_ENCODER, // replace with your secret key for signing and verifying JWTs
+ verify: {
+ aud: 'urn:audience:test',
+ iss: 'urn:issuer:test',
+ sub: false,
+ nbf: true,
+ exp: true,
+ maxAgeSec: 14400, // 4 hours
+ timeSkewSec: 15
+ },
+ validate: async (artifacts, request, h) => {
+ const {userRepository} = server.app.serviceLocator
+ const isValid = !!await userRepository.getByUser(artifacts.decoded.payload.value)
+ return {
+ isValid,
+ };
+ },
+ }
+}
\ No newline at end of file
diff --git a/lib/infrastructure/webserver/server.js b/lib/infrastructure/webserver/server.js
index 9317bf7..6c779c7 100644
--- a/lib/infrastructure/webserver/server.js
+++ b/lib/infrastructure/webserver/server.js
@@ -10,6 +10,7 @@ const Package = require('../../../package');
const routes = require('../../interfaces/routes');
const serviceLocator = require('../../infrastructure/config/service-locator')
const Jwt = require('@hapi/jwt');
+const strategy = require("../config/strategy")
const createServer = async () => {
// Create a server with a host and port
@@ -64,25 +65,7 @@ const createServer = async () => {
- server.auth.strategy('jwt', 'jwt', {
- keys: process.env.SECRET_ENCODER, // replace with your secret key for signing and verifying JWTs
- verify: {
- aud: 'urn:audience:test',
- iss: 'urn:issuer:test',
- sub: false,
- nbf: true,
- exp: true,
- maxAgeSec: 14400, // 4 hours
- timeSkewSec: 15
- },
- validate: async (artifacts, request, h) => {
- const {userRepository} = server.app.serviceLocator
- const isValid = !!await userRepository.getByUser(artifacts.decoded.payload.value)
- return {
- isValid,
- };
- },
- });
+ server.auth.strategy('jwt', 'jwt', strategy(serviceLocator));
await server.register([
require('../../interfaces/routes/users'),
diff --git a/test/integration/users.test.js b/test/integration/users.test.js
index 7af5362..9a02199 100644
--- a/test/integration/users.test.js
+++ b/test/integration/users.test.js
@@ -2,9 +2,12 @@
const Hapi = require('@hapi/hapi');
const User = require("../../lib/domain/model/User")
const bcrypt = require("bcrypt");
+const strategy = require("../../lib/infrastructure/config/strategy");
+const Jwt = require("@hapi/jwt");
let server
const mockUserRepository = {}
const mockAccesTokenManager = {}
+require('dotenv').config()
mockUserRepository.getByEmailOrPseudo = jest.fn((email,pseudo) => {
return null
})
@@ -22,10 +25,14 @@ describe('user route', () => {
await server.register([
require('../../lib/interfaces/routes/users'),
]);
+ server.register(Jwt)
+
server.app.serviceLocator = {
userRepository: mockUserRepository,
accessTokenManager:mockAccesTokenManager
}
+ server.auth.strategy('jwt', 'jwt', strategy({userRepository: mockUserRepository}));
+
});
afterEach(async () => {
From 806bdacadef2bb9a847b661a24d3d28eed179605 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Chanon?=
<95433353+MaelChanon@users.noreply.github.com>
Date: Mon, 4 Dec 2023 12:18:44 +0100
Subject: [PATCH 03/67] Feature/profile upload (#11)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* first try upload image
* save
* Création de la route /users/uploadPreviewProfile
* save
* test & correction
---
.gitignore | 1 +
.../use_cases/image/uploadImage.js | 16 ++++
.../use_cases/user/uploadPreview.js | 16 ++++
lib/application/use_cases/utils/isImage.js | 5 ++
lib/infrastructure/config/service-locator.js | 2 +
lib/infrastructure/config/strategy.js | 1 -
.../repositories/DocumentRepository.js | 33 ++++++++
.../repositories/UserRepository.js | 23 ++++-
.../interfaces/DoucumentRepositoryAbstract.js | 16 ++++
.../interfaces/UserRepositoryAbstract.js | 7 +-
lib/interfaces/controllers/ImageController.js | 22 +++++
lib/interfaces/controllers/UsersController.js | 20 +++++
.../controllers/utils/handleError.js | 2 +-
lib/interfaces/routes/image.js | 47 ++++++++++
lib/interfaces/routes/users.js | 38 +++++++++
test/integration/fixture/imageTest.jpg | Bin 0 -> 127408 bytes
test/integration/users.test.js | 52 ++++++++++--
.../usecase/user/uploadPreview.test.js | 80 ++++++++++++++++++
.../repositories/DocumentRepository.test.js | 28 ++++++
.../1593d51b7bec762dc17fbc8833c18c7c.png | 1 +
20 files changed, 400 insertions(+), 10 deletions(-)
create mode 100644 lib/application/use_cases/image/uploadImage.js
create mode 100644 lib/application/use_cases/user/uploadPreview.js
create mode 100644 lib/application/use_cases/utils/isImage.js
create mode 100644 lib/infrastructure/repositories/DocumentRepository.js
create mode 100644 lib/infrastructure/repositories/interfaces/DoucumentRepositoryAbstract.js
create mode 100644 lib/interfaces/controllers/ImageController.js
create mode 100644 lib/interfaces/routes/image.js
create mode 100644 test/integration/fixture/imageTest.jpg
create mode 100644 test/unit/application/usecase/user/uploadPreview.test.js
create mode 100644 test/unit/infrastructure/repositories/DocumentRepository.test.js
create mode 100644 test/unit/infrastructure/repositories/testFolder/1593d51b7bec762dc17fbc8833c18c7c.png
diff --git a/.gitignore b/.gitignore
index 326bcde..cad71b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,6 @@ node_modules
.idea/
+upload
.env
diff --git a/lib/application/use_cases/image/uploadImage.js b/lib/application/use_cases/image/uploadImage.js
new file mode 100644
index 0000000..93d9d92
--- /dev/null
+++ b/lib/application/use_cases/image/uploadImage.js
@@ -0,0 +1,16 @@
+'use strict';
+const crypto = require('crypto');
+const {writeFile} = require("fs");
+module.exports = async (image) => {
+ return new Promise((resolve, reject) => {
+ const fileLabel = crypto.randomBytes(16).toString('hex')
+ const fileExt = image.hapi.filename.split(".")[1]
+ const path = `upload/${fileLabel}.${fileExt}`
+ writeFile(`./${path}`, image._data, err => {
+ if (err) {
+ reject(err)
+ }
+ resolve({ path })
+ })
+ })
+};
diff --git a/lib/application/use_cases/user/uploadPreview.js b/lib/application/use_cases/user/uploadPreview.js
new file mode 100644
index 0000000..fd4f604
--- /dev/null
+++ b/lib/application/use_cases/user/uploadPreview.js
@@ -0,0 +1,16 @@
+'use strict';
+const isImage = require("../utils/isImage")
+const throwStatusCode = require("../utils/throwStatusCode")
+module.exports = async (file,token,{accessTokenManager, userRepository,documentRepository}) => {
+ if(!isImage(file)) throwStatusCode('415',"le fichier fourni n'est pas une image")
+ const id = accessTokenManager.decode(token)?.value
+ if(! await userRepository.getByUser(id)) throwStatusCode('401',"votre token d'authentification n'est pas le bon")
+ const previewPath = await userRepository.getPreviewPath(id)
+ if(previewPath) {
+ documentRepository.deleteFile(previewPath)
+ }
+ const path = await documentRepository.uploadFile('upload',file)
+ if(! path) throwStatusCode(500, "internal server error")
+ userRepository.addPreviewPath(id,path)
+ return path
+};
\ No newline at end of file
diff --git a/lib/application/use_cases/utils/isImage.js b/lib/application/use_cases/utils/isImage.js
new file mode 100644
index 0000000..3df302c
--- /dev/null
+++ b/lib/application/use_cases/utils/isImage.js
@@ -0,0 +1,5 @@
+const acceptedHeaders = ['image/png','image/jpeg']
+module.exports = (file) => {
+ const header = file?.hapi?.headers['content-type']
+ return acceptedHeaders.includes(header) && file?.hapi?.filename && file._data
+}
\ No newline at end of file
diff --git a/lib/infrastructure/config/service-locator.js b/lib/infrastructure/config/service-locator.js
index de5db8a..01c17b7 100644
--- a/lib/infrastructure/config/service-locator.js
+++ b/lib/infrastructure/config/service-locator.js
@@ -5,12 +5,14 @@ const environment = require('./environment');
const UserRepository= require('../repositories/UserRepository');
const spotifyRepository= require('../repositories/SpotifyRepository');
const JwtAccessTokenManager = require('../security/JwtAccessTokenManager');
+const documentRepository= require('../repositories/DocumentRepository');
function buildBeans() {
return {
accessTokenManager: new JwtAccessTokenManager(),
userRepository: new UserRepository(),
spotifyRepository: new spotifyRepository(process.env.CLIENT_ID,process.env.CLIENT_SECRET),
+ documentRepository: new documentRepository()
};
}
diff --git a/lib/infrastructure/config/strategy.js b/lib/infrastructure/config/strategy.js
index 3250398..63867b4 100644
--- a/lib/infrastructure/config/strategy.js
+++ b/lib/infrastructure/config/strategy.js
@@ -11,7 +11,6 @@ module.exports = ({userRepository}) =>{
timeSkewSec: 15
},
validate: async (artifacts, request, h) => {
- const {userRepository} = server.app.serviceLocator
const isValid = !!await userRepository.getByUser(artifacts.decoded.payload.value)
return {
isValid,
diff --git a/lib/infrastructure/repositories/DocumentRepository.js b/lib/infrastructure/repositories/DocumentRepository.js
new file mode 100644
index 0000000..ae1b953
--- /dev/null
+++ b/lib/infrastructure/repositories/DocumentRepository.js
@@ -0,0 +1,33 @@
+'use strict';
+const documentRepositoryAbstract = require('./interfaces/DoucumentRepositoryAbstract')
+const {unlink, writeFile} = require("fs");
+const crypto = require("crypto");
+
+module.exports = class extends documentRepositoryAbstract{
+
+ uploadFile(folderPath,file) {
+ return new Promise((resolve, reject) => {
+ const fileLabel = crypto.randomBytes(16).toString('hex')
+ const fileExt = file.hapi.filename.split(".")[1]
+ const path = `${folderPath}/${fileLabel}.${fileExt}`
+ writeFile(`./${path}`, file._data, err => {
+ if (err) {
+ reject(err)
+ }
+ resolve(path)
+ })
+ })
+ }
+ deleteFile(path){
+ unlink(`./${path}`,err => {
+ if(err){
+ throw err
+ }
+ })
+ }
+
+
+
+
+
+};
diff --git a/lib/infrastructure/repositories/UserRepository.js b/lib/infrastructure/repositories/UserRepository.js
index 2ad0dd2..23f1d02 100644
--- a/lib/infrastructure/repositories/UserRepository.js
+++ b/lib/infrastructure/repositories/UserRepository.js
@@ -3,7 +3,7 @@
const sequelize = require('../orm/sequelize/sequelize');
const user = require('../../domain/model/User');
const userRepository = require('./interfaces/UserRepositoryAbstract');
-const { Op } = require('sequelize');
+const { Op,col,literal } = require('sequelize');
const {id} = require("../../domain/model/User");
const {create} = require("underscore");
module.exports = class extends userRepository {
@@ -87,4 +87,25 @@ module.exports = class extends userRepository {
});
return this.createUser(seqUser)
}
+ async getPreviewPath(id){
+ const url = await this.model.findOne({
+ where: {
+ [Op.and]: [
+ { id_utilisateur: id },
+ sequelize.literal('NOT `photo_temporaire` <=> `photo`'),
+ ]
+ },
+ attributes: ['photo_temporaire'],
+ raw:true
+ });
+ return url?.photo_temporaire
+ }
+ async addPreviewPath(id,path){
+ const [updatedRowsCount, updatedRows] = await this.model.update(
+ {photo_temporaire: path},
+ {where: {id_utilisateur: id}}
+ )
+ return updatedRowsCount
+ }
};
+
diff --git a/lib/infrastructure/repositories/interfaces/DoucumentRepositoryAbstract.js b/lib/infrastructure/repositories/interfaces/DoucumentRepositoryAbstract.js
new file mode 100644
index 0000000..3ff027f
--- /dev/null
+++ b/lib/infrastructure/repositories/interfaces/DoucumentRepositoryAbstract.js
@@ -0,0 +1,16 @@
+'use strict';
+
+module.exports = class {
+
+ uploadFile(path,file) {
+ throw new Error('ERR_METHOD_NOT_IMPLEMENTED');
+ }
+ deleteFile(path){
+ throw new Error('ERR_METHOD_NOT_IMPLEMENTED');
+ }
+
+
+
+
+
+};
diff --git a/lib/infrastructure/repositories/interfaces/UserRepositoryAbstract.js b/lib/infrastructure/repositories/interfaces/UserRepositoryAbstract.js
index 22f2528..44318ec 100644
--- a/lib/infrastructure/repositories/interfaces/UserRepositoryAbstract.js
+++ b/lib/infrastructure/repositories/interfaces/UserRepositoryAbstract.js
@@ -19,5 +19,10 @@ module.exports = class {
async getByUser(id){
throw new Error('ERR_METHOD_NOT_IMPLEMENTED');
}
-
+ async getPreviewPath(id){
+ throw new Error('ERR_METHOD_NOT_IMPLEMENTED');
+ }
+ async addPreviewPath(id,path){
+ throw new Error('ERR_METHOD_NOT_IMPLEMENTED');
+ }
};
diff --git a/lib/interfaces/controllers/ImageController.js b/lib/interfaces/controllers/ImageController.js
new file mode 100644
index 0000000..c74d821
--- /dev/null
+++ b/lib/interfaces/controllers/ImageController.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const uploadImage = require('../../application/use_cases/image/uploadImage');
+
+module.exports = {
+
+ async upload(request,handler){
+ const serviceLocator = request.server.app.serviceLocator;
+ const {image} = request.payload
+ const {path} = await uploadImage(image)
+ try{
+ return handler
+ .response({
+ url : `${request.server.info.uri}/${path}`,
+ })
+ }
+ catch (error){
+ console.log(error)
+ return handler.response(error).code(500)
+ }
+ }
+};
diff --git a/lib/interfaces/controllers/UsersController.js b/lib/interfaces/controllers/UsersController.js
index e572d16..c080570 100644
--- a/lib/interfaces/controllers/UsersController.js
+++ b/lib/interfaces/controllers/UsersController.js
@@ -3,6 +3,7 @@
const CreateUser = require('../../application/use_cases/user/CreateUser');
const GetAccessToken = require('../../application/use_cases/security/GetAccessToken');
const handleError = require("./utils/handleError")
+const uploadPreview = require("../../application/use_cases/user/uploadPreview")
module.exports = {
async createUser(request,handler) {
@@ -33,5 +34,24 @@ module.exports = {
catch (error){
return handleError(error)
}
+ },
+ async uploadPreviewProfile(request, handler){
+ const serviceLocator = request.server.app.serviceLocator;
+ const authorizationHeader = request.headers.authorization;
+ const [, token] = authorizationHeader.split(' ');
+ const {file} = request.payload
+ try{
+ return handler.response({
+ path: `${request.server.info.uri}/${await uploadPreview(file,token, serviceLocator)}`
+ })
+ }
+ catch (e){
+ return handleError(e)
+ }
+ // Now 'token' contains the bearer token
+
+ // Perform any necessary authentication logic here
+
+ return handler.response('Access granted!');
}
};
diff --git a/lib/interfaces/controllers/utils/handleError.js b/lib/interfaces/controllers/utils/handleError.js
index 2b19f3d..caa37d7 100644
--- a/lib/interfaces/controllers/utils/handleError.js
+++ b/lib/interfaces/controllers/utils/handleError.js
@@ -1,7 +1,7 @@
const Boom = require("@hapi/boom")
module.exports = (error) => {
- const statusCode = error.code ? error.code : 500
+ const statusCode = error?.code ? error.code : 500
console.log(error)
return Boom.boomify(error, {statusCode: statusCode})
}
\ No newline at end of file
diff --git a/lib/interfaces/routes/image.js b/lib/interfaces/routes/image.js
new file mode 100644
index 0000000..249bbe7
--- /dev/null
+++ b/lib/interfaces/routes/image.js
@@ -0,0 +1,47 @@
+'use strict';
+const Joi = require('@hapi/joi')
+const ImageController = require("../controllers/ImageController")
+const MAX_BYTE_SIZE =20971520
+module.exports = {
+ name: 'image',
+ version: '1.0.0',
+ register: async (server) => {
+ server.route([
+ {
+ method: 'POST',
+ path: '/image/upload',
+ handler: ImageController.upload,
+ options: {
+ payload: {
+ maxBytes: MAX_BYTE_SIZE, // Set your desired maximum payload size in bytes
+ output: 'stream',
+ parse: true,
+ allow: 'multipart/form-data',
+ multipart: true, // Set multipart to true for handling file uploads
+ },
+ description: 'upload an image',
+ tags: ['api'],
+ plugins: {
+ 'hapi-swagger': {
+ responses: {
+ 200: {description : 'Success'},
+ 204: {description : 'No content'},
+ 401: {description : 'Unauthorized'},
+ 403: {description : 'forbidden'},
+ 404: {description : 'Ressource not found'},
+ 500: {description : 'Internal server error'},
+ 502: {description : 'bad gateway'},
+ 503: {description : 'Service unavailable'},
+ }
+ }
+ },
+ validate: {
+ payload: Joi.object().keys({
+ image: Joi.any().required(),
+ })
+ }
+ },
+ },
+ ]);
+ }
+};
\ No newline at end of file
diff --git a/lib/interfaces/routes/users.js b/lib/interfaces/routes/users.js
index cd0415e..a01ccfb 100644
--- a/lib/interfaces/routes/users.js
+++ b/lib/interfaces/routes/users.js
@@ -1,6 +1,8 @@
'use strict';
const {userSignUp, userSignIn} = require('../../domain/entity/UserEntity')
const UsersController = require('../controllers/UsersController');
+const Joi = require('joi')
+const MAX_BYTE_SIZE =20971520
module.exports = {
name: 'users',
version: '1.0.0',
@@ -64,6 +66,42 @@ module.exports = {
}
},
},
+ {
+ method: 'POST',
+ path: '/users/uploadPreviewProfile',
+ handler: UsersController.uploadPreviewProfile,
+ options: {
+ payload: {
+ maxBytes: MAX_BYTE_SIZE, // Set your desired maximum payload size in bytes
+ output: 'stream',
+ parse: true,
+ allow: 'multipart/form-data',
+ multipart: true, // Set multipart to true for handling file uploads
+ },
+ auth: 'jwt',
+ description: 'allow to upload preview profile picture',
+ tags: ['api'],
+ plugins: {
+ 'hapi-swagger': {
+ responses: {
+ 200: {description : 'Success'},
+ 204: {description : 'No content'},
+ 401: {description : 'Unauthorized'},
+ 403: {description : 'forbidden'},
+ 404: {description : 'Ressource not found'},
+ 500: {description : 'Internal server error'},
+ 502: {description : 'bad gateway'},
+ 503: {description : 'Service unavailable'},
+ }
+ }
+ },
+ validate: {
+ payload: Joi.object().keys({
+ file: Joi.any()
+ })
+ }
+ },
+ }
]);
}
};
\ No newline at end of file
diff --git a/test/integration/fixture/imageTest.jpg b/test/integration/fixture/imageTest.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a723e0363e7a4459ea747e5c95754bcbdd247ec9
GIT binary patch
literal 127408
zcmb4q1ydY6*zMx(6nBcdyBBva4lVAo$YO=!?hcEy>|zBLx8kk~rBJ-sLZQW_w7u_l
z
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