Merge pull request #147 from ets-cfuhrman-pfe/backend-tests

Backend tests and refactorings
This commit is contained in:
Christopher (Cris) Fuhrman 2024-10-15 21:09:29 -04:00 committed by GitHub
commit b1e9489ba9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 1509 additions and 481 deletions

View file

@ -1,4 +1,4 @@
name: Frontend Tests
name: Tests
on:
pull_request:
@ -9,7 +9,7 @@ on:
- main
jobs:
frontend-test:
tests:
runs-on: ubuntu-latest
steps:
@ -19,12 +19,14 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '18'
- name: Install Dependencies
run: npm ci
working-directory: ./client
- name: Install Dependencies and Run Tests
run: |
npm ci
npm test
working-directory: ${{ matrix.directory }}
- name: Run Tests
run: npm test
working-directory: ./client
strategy:
matrix:
directory: [client, server]

1
.gitignore vendored
View file

@ -128,3 +128,4 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
db-backup/

View file

@ -98,8 +98,9 @@ const Dashboard: React.FC = () => {
setQuizzes(quizzes as QuizType[]);
}
else {
console.log("show some quizes")
console.log("show some quizzes")
const folderQuizzes = await ApiService.getFolderContent(selectedFolder);
console.log("folderQuizzes: ", folderQuizzes);
setQuizzes(folderQuizzes as QuizType[]);
}
@ -147,7 +148,7 @@ const Dashboard: React.FC = () => {
setQuizzes(quizzes as QuizType[]);
}
else {
console.log("show some quizes")
console.log("show some quizzes")
const folderQuizzes = await ApiService.getFolderContent(selectedFolder);
setQuizzes(folderQuizzes as QuizType[]);
@ -292,7 +293,7 @@ const Dashboard: React.FC = () => {
}
setQuizzes(quizzes as QuizType[]);
setSelectedFolder('');
} catch (error) {
console.error('Error deleting folder:', error);
@ -317,9 +318,11 @@ const Dashboard: React.FC = () => {
try {
// folderId: string GET THIS FROM CURRENT FOLDER
await ApiService.duplicateFolder(selectedFolder);
// TODO set the selected folder to be the duplicated folder
const userFolders = await ApiService.getUserFolders();
setFolders(userFolders as FolderType[]);
const newlyCreatedFolder = userFolders[userFolders.length - 1] as FolderType;
setSelectedFolder(newlyCreatedFolder._id);
} catch (error) {
console.error('Error duplicating folder:', error);
}
@ -401,7 +404,6 @@ const Dashboard: React.FC = () => {
</div>
<div className='actions'>
<Tooltip title="Ajouter dossier" placement="top">
<IconButton
color="primary"
@ -425,7 +427,7 @@ const Dashboard: React.FC = () => {
> <ContentCopy /> </IconButton>
</Tooltip>
<Tooltip title="Suprimer dossier" placement="top">
<Tooltip title="Supprimer dossier" placement="top">
<IconButton
aria-label="delete"
color="primary"

View file

@ -0,0 +1,8 @@
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
module.exports = AppError;

View file

@ -0,0 +1,6 @@
const mockBcrypt = {
hash: jest.fn().mockResolvedValue('hashedPassword'),
compare: jest.fn().mockResolvedValue(true),
};
module.exports = mockBcrypt;

20
server/__mocks__/db.js Normal file
View file

@ -0,0 +1,20 @@
class MockDBConnection {
constructor() {
this.db = jest.fn().mockReturnThis();
this.collection = jest.fn().mockReturnThis();
this.insertOne = jest.fn();
this.findOne = jest.fn();
this.updateOne = jest.fn();
this.deleteOne = jest.fn();
}
async connect() {
// Simulate successful connection
}
getConnection() {
return this;
}
}
module.exports = MockDBConnection;

View file

@ -0,0 +1,8 @@
const mockFolders = {
create: jest.fn(),
find: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
};
module.exports = mockFolders;

View file

@ -0,0 +1,441 @@
const { create } = require('../middleware/jwtToken');
const Folders = require('../models/folders');
const ObjectId = require('mongodb').ObjectId;
const Quizzes = require('../models/quiz');
describe('Folders', () => {
let folders;
let db;
let collection;
let quizzes;
beforeEach(() => {
jest.clearAllMocks(); // Clear any previous mock calls
// Mock the collection object
collection = {
findOne: jest.fn(),
insertOne: jest.fn(),
find: jest.fn().mockReturnValue({ toArray: jest.fn() }), // Mock the find method
deleteOne: jest.fn(),
deleteMany: jest.fn(),
updateOne: jest.fn(),
};
// Mock the database connection
db = {
connect: jest.fn(),
getConnection: jest.fn().mockReturnThis(), // Add getConnection method
collection: jest.fn().mockReturnValue(collection),
};
quizzes = new Quizzes(db);
folders = new Folders(db, quizzes);
});
// create
describe('create', () => {
it('should create a new folder and return the new folder ID', async () => {
const title = 'Test Folder';
// Mock the database response
collection.findOne.mockResolvedValue(null);
collection.insertOne.mockResolvedValue({ insertedId: new ObjectId() });
const result = await folders.create(title, '12345');
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ title, userId: '12345' });
expect(collection.insertOne).toHaveBeenCalledWith(expect.objectContaining({ title, userId: '12345' }));
expect(result).toBeDefined();
});
// throw an error if userId is undefined
it('should throw an error if userId is undefined', async () => {
const title = 'Test Folder';
await expect(folders.create(title, undefined)).rejects.toThrow('Missing required parameter(s)');
expect(db.connect).not.toHaveBeenCalled();
});
it('should throw an error if the folder already exists', async () => {
const title = 'Existing Folder';
const userId = '66fc70bea1b9e87655cf17c9';
// Mock the database response of a found folder
collection.findOne.mockResolvedValue(
// real result from mongosh
{
_id: ObjectId.createFromHexString('66fd33fd81758a882ce99aae'),
userId: userId,
title: title,
created_at: new Date('2024-10-02T11:52:29.797Z')
}
);
await expect(folders.create(title, userId)).rejects.toThrow('Folder already exists');
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ title, userId: userId });
});
});
// getUserFolders
describe('getUserFolders', () => {
it('should return all folders for a user', async () => {
const userId = '12345';
const userFolders = [
{ title: 'Folder 1', userId },
{ title: 'Folder 2', userId },
];
// Mock the database response
collection.find().toArray.mockResolvedValue(userFolders);
const result = await folders.getUserFolders(userId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.find).toHaveBeenCalledWith({ userId });
expect(result).toEqual(userFolders);
});
});
// getOwner
describe('getOwner', () => {
it('should return the owner of a folder', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue({ userId });
const result = await folders.getOwner(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
expect(result).toBe(userId);
});
});
// write a test for getContent
describe('getContent', () => {
it('should return the content of a folder', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const content = [
{ title: 'Quiz 1', content: [] },
{ title: 'Quiz 2', content: [] },
];
// Mock the database response
collection.find().toArray.mockResolvedValue(content);
const result = await folders.getContent(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('files');
expect(collection.find).toHaveBeenCalledWith({ folderId });
expect(result).toEqual(content);
});
it('should return an empty array if the folder has no content', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.find().toArray.mockResolvedValue([]);
const result = await folders.getContent(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('files');
expect(collection.find).toHaveBeenCalledWith({ folderId });
expect(result).toEqual([]);
});
});
// delete
describe('delete', () => {
it('should delete a folder and return true', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteOne.mockResolvedValue({ deletedCount: 1 });
// Mock the folders.quizModel.deleteQuizzesByFolderId()
jest.spyOn(quizzes, 'deleteQuizzesByFolderId').mockResolvedValue(true);
const result = await folders.delete(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.deleteOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
expect(result).toBe(true);
});
it('should return false if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteOne.mockResolvedValue({ deletedCount: 0 });
const result = await folders.delete(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.deleteOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
expect(result).toBe(false);
});
});
// rename
describe('rename', () => {
it('should rename a folder and return true', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const newTitle = 'New Folder Name';
// Mock the database response
collection.updateOne.mockResolvedValue({ modifiedCount: 1 });
const result = await folders.rename(folderId, newTitle);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.updateOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) }, { $set: { title: newTitle } });
expect(result).toBe(true);
});
it('should return false if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const newTitle = 'New Folder Name';
// Mock the database response
collection.updateOne.mockResolvedValue({ modifiedCount: 0 });
const result = await folders.rename(folderId, newTitle);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.updateOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) }, { $set: { title: newTitle } });
expect(result).toBe(false);
});
});
// duplicate
describe('duplicate', () => {
it('should duplicate a folder and return the new folder ID', async () => {
const userId = '12345';
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const sourceFolder = {title: 'SourceFolder', userId: userId, content: []};
const duplicatedFolder = {title: 'SourceFolder (1)', userId: userId, created_at: expect.any(Date), content: []};
// Mock the database responses for the folder and the new folder (first one is found, second one is null)
// mock the findOne method
jest.spyOn(collection, 'findOne')
.mockResolvedValueOnce(sourceFolder) // source file exists
.mockResolvedValueOnce(null); // new name is not found
// Mock the folder create method
const createSpy = jest.spyOn(folders, 'create').mockResolvedValue(new ObjectId());
// mock the folder.getContent method
jest.spyOn(folders, 'getContent').mockResolvedValue([{ title: 'Quiz 1', content: [] }]);
// Mock the quizzes.create method
jest.spyOn(quizzes, 'create').mockResolvedValue(new ObjectId());
const result = await folders.duplicate(folderId, userId);
expect(db.collection).toHaveBeenCalledWith('folders');
// expect folders.create method was called
expect(createSpy).toHaveBeenCalledWith(duplicatedFolder.title, userId);
// expect the getContent method was called
expect(folders.getContent).toHaveBeenCalledWith(folderId);
// expect the quizzes.create method was called
expect(quizzes.create).toHaveBeenCalledWith('Quiz 1', [], expect.any(String), userId);
expect(result).toBeDefined();
});
it('should throw an error if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response for the source
collection.findOne.mockResolvedValue(null);
await expect(folders.duplicate(folderId, '54321')).rejects.toThrow(`Folder ${folderId} not found`);
// expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId), userId: '54321' });
});
});
describe('folderExists', () => {
it('should return true if folder exists', async () => {
const title = 'Test Folder';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue({ title, userId });
const result = await folders.folderExists(title, userId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ title, userId });
expect(result).toBe(true);
});
it('should return false if folder does not exist', async () => {
const title = 'Nonexistent Folder';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue(null);
const result = await folders.folderExists(title, userId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ title, userId });
expect(result).toBe(false);
});
});
describe('copy', () => {
it('should copy a folder and return the new folder ID', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
const newFolderId = new ObjectId();
// Mock some quizzes that are in folder.content
const sourceFolder = {
title: 'Test Folder',
content: [
{ title: 'Quiz 1', content: [] },
{ title: 'Quiz 2', content: [] },
],
};
// Mock the response from getFolderWithContent
jest.spyOn(folders, 'getFolderWithContent').mockResolvedValue(sourceFolder);
jest.spyOn(folders, 'create').mockResolvedValue(newFolderId);
// Mock the response from Quiz.createQuiz
jest.spyOn(quizzes, 'create').mockImplementation(() => {});
const result = await folders.copy(folderId, userId);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection).toHaveBeenCalledWith('folders');
// expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
// expect(collection.insertOne).toHaveBeenCalledWith(expect.objectContaining({ userId }));
expect(result).toBe(newFolderId);
});
it('should throw an error if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
// Mock the response from getFolderWithContent
jest.spyOn(folders, 'getFolderWithContent').mockImplementation(() => {
throw new Error(`Folder ${folderId} not found`);
});
await expect(folders.copy(folderId, userId)).rejects.toThrow(`Folder ${folderId} not found`);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection).toHaveBeenCalledWith('folders');
// expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
});
});
// write a test for getFolderWithContent
describe('getFolderWithContent', () => {
it('should return a folder with content', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const folder = {
_id: new ObjectId(folderId),
title: 'Test Folder',
};
const content = {
content : [
{ title: 'Quiz 1', content: [] },
{ title: 'Quiz 2', content: [] },
]};
// Mock the response from getFolderById
jest.spyOn(folders, 'getFolderById').mockResolvedValue(folder);
// Mock the response from getContent
jest.spyOn(folders, 'getContent').mockResolvedValue(content);
const result = await folders.getFolderWithContent(folderId);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection).toHaveBeenCalledWith('folders');
// expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
expect(result).toEqual({
...folder,
content: content
});
});
it('should throw an error if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// // Mock the database response
// collection.findOne.mockResolvedValue(null);
// Mock getFolderById to throw an error
jest.spyOn(folders, 'getFolderById').mockImplementation(() => {
throw new Error(`Folder ${folderId} not found`);
});
await expect(folders.getFolderWithContent(folderId)).rejects.toThrow(`Folder ${folderId} not found`);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection).toHaveBeenCalledWith('folders');
// expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
});
});
// write a test for getFolderById
describe('getFolderById', () => {
it('should return a folder by ID', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
const folder = {
_id: new ObjectId(folderId),
title: 'Test Folder',
};
// Mock the database response
collection.findOne.mockResolvedValue(folder);
const result = await folders.getFolderById(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
expect(result).toEqual(folder);
});
it('should throw an error if the folder does not exist', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.findOne.mockResolvedValue(null);
await expect(folders.getFolderById(folderId)).resolves.toThrow(`Folder ${folderId} not found`);
expect(db.connect).toHaveBeenCalled();
expect(db.collection).toHaveBeenCalledWith('folders');
expect(collection.findOne).toHaveBeenCalledWith({ _id: new ObjectId(folderId) });
});
});
});

View file

@ -1,11 +1,11 @@
const request = require('supertest');
const app = require('../app.js');
// const app = require('../routers/images.js');
const { response } = require('express');
// const request = require('supertest');
// const app = require('../app.js');
// // const app = require('../routers/images.js');
// const { response } = require('express');
const BASE_URL = '/image'
// const BASE_URL = '/image'
describe("POST /upload", () => {
describe.skip("POST /upload", () => {
describe("when the jwt is not sent", () => {
@ -44,7 +44,7 @@ describe("POST /upload", () => {
})
describe("GET /get", () => {
describe.skip("GET /get", () => {
describe("when not give id", () => {
@ -61,4 +61,4 @@ describe("GET /get", () => {
})
})
})

View file

@ -0,0 +1,347 @@
const { ObjectId } = require('mongodb');
const Quizzes = require('../models/quiz'); // Adjust the path as necessary
describe('Quizzes', () => {
let db;
let quizzes;
let collection;
beforeEach(() => {
jest.clearAllMocks(); // Clear any previous mock calls
// Mock the collection object
collection = {
findOne: jest.fn(),
insertOne: jest.fn(),
find: jest.fn().mockReturnValue({ toArray: jest.fn() }), // Mock the find method
deleteOne: jest.fn(),
deleteMany: jest.fn(),
updateOne: jest.fn(),
getContent: jest.fn(),
};
// Mock the database connection
db = {
connect: jest.fn(),
getConnection: jest.fn().mockReturnValue({
collection: jest.fn().mockReturnValue(collection),
}),
};
// Initialize the Quiz model with the mocked db
quizzes = new Quizzes(db);
});
describe('create', () => {
it('should create a new quiz if it does not exist', async () => {
const title = 'Test Quiz';
const content = 'This is a test quiz.';
const folderId = '507f1f77bcf86cd799439011';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue(null);
collection.insertOne.mockResolvedValue({ insertedId: new ObjectId() });
const result = await quizzes.create(title, content, folderId, userId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.findOne).toHaveBeenCalledWith({ title, folderId, userId });
expect(collection.insertOne).toHaveBeenCalledWith(expect.objectContaining({
folderId,
userId,
title,
content,
created_at: expect.any(Date),
updated_at: expect.any(Date),
}));
expect(result).not.toBeNull();
});
it('should throw exception if the quiz already exists', async () => {
const title = 'Test Quiz';
const content = 'This is a test quiz.';
const folderId = '507f1f77bcf86cd799439011';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue({ title });
await expect(quizzes.create(title, content, folderId, userId)).rejects.toThrow(`Quiz already exists with title: ${title}, folderId: ${folderId}, userId: ${userId}`);
});
});
describe('getOwner', () => {
it('should return the owner of the quiz', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
// Mock the database response
collection.findOne.mockResolvedValue({ userId });
const result = await quizzes.getOwner(quizId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.findOne).toHaveBeenCalledWith({ _id: ObjectId.createFromHexString(quizId) });
expect(result).toBe(userId);
});
});
describe('getContent', () => {
it('should return the content of the quiz', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const content = 'This is a test quiz.';
// Mock the database response
collection.findOne.mockResolvedValue({ content });
const result = await quizzes.getContent(quizId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.findOne).toHaveBeenCalledWith({ _id: ObjectId.createFromHexString(quizId) });
expect(result).toEqual({ content });
});
});
describe('delete', () => {
it('should delete the quiz', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteOne.mockResolvedValue({deletedCount: 1});
await quizzes.delete(quizId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.deleteOne).toHaveBeenCalledWith({ _id: ObjectId.createFromHexString(quizId) });
});
it('should return false if the quiz does not exist', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteOne.mockResolvedValue({deletedCount: 0});
const result = await quizzes.delete(quizId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.deleteOne).toHaveBeenCalledWith({ _id: ObjectId.createFromHexString(quizId) });
expect(result).toBe(false);
});
});
// deleteQuizzesByFolderId
describe('deleteQuizzesByFolderId', () => {
it('should delete all quizzes in a folder', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteMany.mockResolvedValue({deletedCount: 2});
await quizzes.deleteQuizzesByFolderId(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.deleteMany).toHaveBeenCalledWith({ folderId });
});
it('should return false if no quizzes are deleted', async () => {
const folderId = '60c72b2f9b1d8b3a4c8e4d3b';
// Mock the database response
collection.deleteMany.mockResolvedValue({deletedCount: 0});
const result = await quizzes.deleteQuizzesByFolderId(folderId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.deleteMany).toHaveBeenCalledWith({ folderId });
expect(result).toBe(false);
});
});
// update
describe('update', () => {
it('should update the title and content of the quiz', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const newTitle = 'Updated Quiz';
const newContent = 'This is an updated quiz.';
// Mock the database response
collection.updateOne.mockResolvedValue({modifiedCount: 1});
await quizzes.update(quizId, newTitle, newContent);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.updateOne).toHaveBeenCalledWith(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { title: newTitle, content: newContent, updated_at: expect.any(Date) } }
);
});
it('should return false if the quiz does not exist', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const newTitle = 'Updated Quiz';
const newContent = 'This is an updated quiz.';
// Mock the database response
collection.updateOne.mockResolvedValue({modifiedCount: 0});
const result = await quizzes.update(quizId, newTitle, newContent);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.updateOne).toHaveBeenCalledWith(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { title: newTitle, content: newContent, updated_at: expect.any(Date) } }
);
expect(result).toBe(false);
});
});
// move
describe('move', () => {
it('should move the quiz to a new folder', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const newFolderId = '507f1f77bcf86cd799439011';
// Mock the database response
collection.updateOne.mockResolvedValue({modifiedCount: 1});
await quizzes.move(quizId, newFolderId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.updateOne).toHaveBeenCalledWith(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { folderId: newFolderId } }
);
});
it('should return false if the quiz does not exist', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const newFolderId = '507f1f77bcf86cd799439011';
// Mock the database response
collection.updateOne.mockResolvedValue({modifiedCount: 0});
const result = await quizzes.move(quizId, newFolderId);
expect(db.connect).toHaveBeenCalled();
expect(db.getConnection).toHaveBeenCalled();
expect(collection.updateOne).toHaveBeenCalledWith(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { folderId: newFolderId } }
);
expect(result).toBe(false);
});
});
// duplicate
describe('duplicate', () => {
it('should duplicate the quiz and return the new quiz ID', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
const newQuizId = ObjectId.createFromTime(Math.floor(Date.now() / 1000)); // Corrected ObjectId creation
const sourceQuiz = {
title: 'Test Quiz',
content: 'This is a test quiz.',
};
const createMock = jest.spyOn(quizzes, 'create').mockResolvedValue(newQuizId);
// mock the findOne method
jest.spyOn(collection, 'findOne')
.mockResolvedValueOnce(sourceQuiz) // source quiz exists
.mockResolvedValueOnce(null); // new name is not found
const result = await quizzes.duplicate(quizId, userId);
expect(result).toBe(newQuizId);
// Ensure mocks were called correctly
expect(createMock).toHaveBeenCalledWith(
sourceQuiz.title + ' (1)',
sourceQuiz.content,
undefined,
userId
);
});
// Add test case for quizExists (name with number in parentheses)
it('should create a new title if the quiz title already exists and ends with " (1)"', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
const newQuizId = ObjectId.createFromTime(Math.floor(Date.now() / 1000));
const sourceQuiz = {
title: 'Test Quiz (1)',
content: 'This is a test quiz.',
};
const createMock = jest.spyOn(quizzes, 'create').mockResolvedValue(newQuizId);
// mock the findOne method
jest.spyOn(collection, 'findOne')
.mockResolvedValueOnce(sourceQuiz) // source quiz exists
.mockResolvedValueOnce(null); // new name is not found
const result = await quizzes.duplicate(quizId, userId);
expect(result).toBe(newQuizId);
// Ensure mocks were called correctly
expect(createMock).toHaveBeenCalledWith(
'Test Quiz (2)',
sourceQuiz.content,
undefined,
userId
);
});
// test case for duplication of "C (1)" but "C (2)" already exists, so it should create "C (3)"
it('should create a new title if the quiz title already exists and ends with " (n)" but the incremented n also exists', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
const newQuizId = ObjectId.createFromTime(Math.floor(Date.now() / 1000));
const sourceQuiz = {
title: 'Test Quiz (1)',
content: 'This is a test quiz.',
};
const createMock = jest.spyOn(quizzes, 'create').mockResolvedValue(newQuizId);
// mock the findOne method
jest.spyOn(collection, 'findOne')
.mockResolvedValueOnce(sourceQuiz) // source quiz exists
.mockResolvedValueOnce({ title: 'Test Quiz (2)' }) // new name collision
.mockResolvedValueOnce(null); // final new name is not found
const result = await quizzes.duplicate(quizId, userId);
expect(result).toBe(newQuizId);
// Ensure mocks were called correctly
expect(createMock).toHaveBeenCalledWith(
'Test Quiz (3)',
sourceQuiz.content,
undefined,
userId
);
});
it('should throw an error if the quiz does not exist', async () => {
const quizId = '60c72b2f9b1d8b3a4c8e4d3b';
const userId = '12345';
// Mock the response from getContent
jest.spyOn(quizzes, 'getContent').mockResolvedValue(null);
await expect(quizzes.duplicate(quizId, userId)).rejects.toThrow();
});
});
});

View file

@ -5,7 +5,8 @@ const { setupWebsocket } = require("../socket/socket");
process.env.NODE_ENV = "test";
const BACKEND_PORT = 4400;
// pick a random port number for testing
const BACKEND_PORT = Math.ceil(Math.random() * 1000 + 3000);
const BACKEND_URL = "http://localhost";
const BACKEND_API = `${BACKEND_URL}:${BACKEND_PORT}`;

View file

@ -0,0 +1,86 @@
const Users = require('../models/users');
const bcrypt = require('bcrypt');
const Quizzes = require('../models/quiz');
const Folders = require('../models/folders');
const AppError = require('../middleware/AppError');
const { ObjectId } = require('mongodb');
jest.mock('bcrypt');
jest.mock('../middleware/AppError');
jest.mock('../models/folders');
describe('Users', () => {
let users;
let db;
beforeEach(() => {
jest.clearAllMocks(); // Clear any previous mock calls
// Mock the database connection
db = {
connect: jest.fn(),
getConnection: jest.fn().mockReturnThis(), // Add getConnection method
collection: jest.fn().mockReturnThis(),
findOne: jest.fn(),
insertOne: jest.fn().mockResolvedValue({ insertedId: new ObjectId() }), // Mock insertOne to return an ObjectId
updateOne: jest.fn(),
deleteOne: jest.fn(),
};
const quizModel = new Quizzes(db);
const foldersModel = new Folders(db, quizModel);
users = new Users(db, foldersModel);
});
it('should register a new user', async () => {
db.collection().findOne.mockResolvedValue(null); // No user found
db.collection().insertOne.mockResolvedValue({ insertedId: new ObjectId() });
bcrypt.hash.mockResolvedValue('hashedPassword');
users.folders.create.mockResolvedValue(true);
const email = 'test@example.com';
const password = 'password123';
const result = await users.register(email, password);
expect(db.connect).toHaveBeenCalled();
expect(db.collection().findOne).toHaveBeenCalledWith({ email });
expect(bcrypt.hash).toHaveBeenCalledWith(password, 10);
expect(db.collection().insertOne).toHaveBeenCalledWith({
email,
password: 'hashedPassword',
created_at: expect.any(Date),
});
expect(users.folders.create).toHaveBeenCalledWith('Dossier par Défaut', expect.any(String));
expect(result.insertedId).toBeDefined(); // Ensure result has insertedId
});
// it('should update the user password', async () => {
// db.collection().updateOne.mockResolvedValue({ modifiedCount: 1 });
// bcrypt.hash.mockResolvedValue('hashedPassword');
// const email = 'test@example.com';
// const newPassword = 'newPassword123';
// const result = await users.updatePassword(email, newPassword);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection().updateOne).toHaveBeenCalledWith(
// { email },
// { $set: { password: 'hashedPassword' } }
// );
// expect(result).toEqual(newPassword);
// });
// it('should delete a user', async () => {
// db.collection().deleteOne.mockResolvedValue({ deletedCount: 1 });
// const email = 'test@example.com';
// const result = await users.delete(email);
// expect(db.connect).toHaveBeenCalled();
// expect(db.collection().deleteOne).toHaveBeenCalledWith({ email });
// expect(result).toBe(true);
// });
// Add more tests as needed
});

View file

@ -7,7 +7,35 @@ const dotenv = require('dotenv')
const { setupWebsocket } = require("./socket/socket");
const { Server } = require("socket.io");
//import routers
// instantiate the db
const db = require('./config/db.js');
// instantiate the models
const quiz = require('./models/quiz.js');
const quizModel = new quiz(db);
const folders = require('./models/folders.js');
const foldersModel = new folders(db, quizModel);
const users = require('./models/users.js');
const userModel = new users(db, foldersModel);
const images = require('./models/images.js');
const imageModel = new images(db);
// instantiate the controllers
const usersController = require('./controllers/users.js');
const usersControllerInstance = new usersController(userModel);
const foldersController = require('./controllers/folders.js');
const foldersControllerInstance = new foldersController(foldersModel);
const quizController = require('./controllers/quiz.js');
const quizControllerInstance = new quizController(quizModel, foldersModel);
const imagesController = require('./controllers/images.js');
const imagesControllerInstance = new imagesController(imageModel);
// export the controllers
module.exports.users = usersControllerInstance;
module.exports.folders = foldersControllerInstance;
module.exports.quizzes = quizControllerInstance;
module.exports.images = imagesControllerInstance;
//import routers (instantiate controllers as side effect)
const userRouter = require('./routers/users.js');
const folderRouter = require('./routers/folders.js');
const quizRouter = require('./routers/quiz.js');
@ -15,7 +43,6 @@ const imagesRouter = require('./routers/images.js')
// Setup environement
dotenv.config();
const db = require('./config/db.js');
const errorHandler = require("./middleware/errorHandler.js");
// Start app

View file

@ -1,174 +1,170 @@
//controller
const model = require('../models/folders.js');
const AppError = require('../middleware/AppError.js');
const { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, FOLDER_NOT_FOUND, FOLDER_ALREADY_EXISTS, GETTING_FOLDER_ERROR, DELETE_FOLDER_ERROR, UPDATE_FOLDER_ERROR, MOVING_FOLDER_ERROR, DUPLICATE_FOLDER_ERROR, COPY_FOLDER_ERROR } = require('../constants/errorCodes');
// controllers must use arrow functions to bind 'this' to the class instance in order to access class properties as callbacks in Express
class FoldersController {
constructor(foldersModel) {
this.folders = foldersModel;
}
/***
* Basic queries
*/
async create(req, res, next) {
create = async (req, res, next) => {
try {
const { title } = req.body;
if (!title) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const result = await model.create(title, req.user.userId);
const result = await this.folders.create(title, req.user.userId);
if (!result) {
throw new AppError(FOLDER_ALREADY_EXISTS);
}
return res.status(200).json({
message: 'Dossier créé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async getUserFolders(req, res, next) {
getUserFolders = async (req, res, next) => {
try {
const folders = await model.getUserFolders(req.user.userId);
const folders = await this.folders.getUserFolders(req.user.userId);
if (!folders) {
throw new AppError(FOLDER_NOT_FOUND);
}
return res.status(200).json({
data: folders
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async getFolderContent(req, res, next) {
getFolderContent = async (req, res, next) => {
try {
const { folderId } = req.params;
if (!folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const content = await model.getContent(folderId);
const content = await this.folders.getContent(folderId);
if (!content) {
throw new AppError(GETTING_FOLDER_ERROR);
}
return res.status(200).json({
data: content
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async delete(req, res, next) {
delete = async (req, res, next) => {
try {
const { folderId } = req.params;
if (!folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const result = await model.delete(folderId);
const result = await this.folders.delete(folderId);
if (!result) {
throw new AppError(DELETE_FOLDER_ERROR);
}
return res.status(200).json({
message: 'Dossier supprimé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async rename(req, res, next) {
rename = async (req, res, next) => {
try {
const { folderId, newTitle } = req.body;
if (!folderId || !newTitle) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const result = await model.rename(folderId, newTitle);
const result = await this.folders.rename(folderId, newTitle);
if (!result) {
throw new AppError(UPDATE_FOLDER_ERROR);
}
return res.status(200).json({
message: 'Dossier mis à jours avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async duplicate(req, res, next) {
duplicate = async (req, res, next) => {
try {
const { folderId, } = req.body;
if (!folderId ) {
const { folderId } = req.body;
if (!folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const userId = req.user.userId;
const newFolderId = await model.duplicate(folderId, userId);
const userId = req.user.userId;
const newFolderId = await this.folders.duplicate(folderId, userId);
if (!newFolderId) {
throw new AppError(DUPLICATE_FOLDER_ERROR);
}
return res.status(200).json({
message: 'Dossier dupliqué avec succès.',
newFolderId: newFolderId
@ -177,30 +173,30 @@ class FoldersController {
return next(error);
}
}
async copy(req, res, next) {
copy = async (req, res, next) => {
try {
const { folderId, newTitle } = req.body;
if (!folderId || !newTitle) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const userId = req.user.userId; // Assuming userId is obtained from authentication
const newFolderId = await model.copy(folderId, userId);
const newFolderId = await this.folders.copy(folderId, userId);
if (!newFolderId) {
throw new AppError(COPY_FOLDER_ERROR);
}
return res.status(200).json({
message: 'Dossier copié avec succès.',
newFolderId: newFolderId
@ -210,27 +206,27 @@ class FoldersController {
}
}
async getFolderById(req, res, next) {
getFolderById = async (req, res, next) => {
try {
const { folderId } = req.params;
if (!folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await model.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const folder = await model.getFolderById(folderId);
const folder = await this.folders.getFolderById(folderId);
if (!folder) {
throw new AppError(FOLDER_NOT_FOUND);
}
return res.status(200).json({
data: folder
});
@ -238,8 +234,8 @@ class FoldersController {
return next(error);
}
}
async folderExists(req, res, next) {
folderExists = async (req, res, next) => {
try {
const { title } = req.body;
@ -247,10 +243,10 @@ class FoldersController {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const userId = req.user.userId;
const userId = req.user.userId;
// Vérifie si le dossier existe pour l'utilisateur donné
const exists = await model.folderExists(title, userId);
const exists = await this.folders.folderExists(title, userId);
return res.status(200).json({
exists: exists
@ -260,9 +256,8 @@ class FoldersController {
}
}
}
module.exports = new FoldersController;
module.exports = FoldersController;

View file

@ -1,56 +1,55 @@
const model = require('../models/images.js');
const AppError = require('../middleware/AppError.js');
const { MISSING_REQUIRED_PARAMETER, IMAGE_NOT_FOUND } = require('../constants/errorCodes');
class ImagesController {
async upload(req, res, next) {
constructor(imagesModel) {
this.images = imagesModel;
}
upload = async (req, res, next) => {
try {
const file = req.file;
if (!file) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const id = await model.upload(file, req.user.userId);
const id = await this.images.upload(file, req.user.userId);
return res.status(200).json({
id: id
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async get(req, res, next) {
};
get = async (req, res, next) => {
try {
const { id } = req.params;
if (!id) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const image = await model.get(id);
const image = await this.images.get(id);
if (!image) {
throw new AppError(IMAGE_NOT_FOUND)
throw new AppError(IMAGE_NOT_FOUND);
}
// Set Headers for display in browser
res.setHeader('Content-Type', image.mime_type);
res.setHeader('Content-Disposition', 'inline; filename=' + image.file_name);
res.setHeader('Accept-Ranges', 'bytes');
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
return res.send(image.file_content);
}
catch (error) {
} catch (error) {
return next(error);
}
}
};
}
module.exports = new ImagesController;
module.exports = ImagesController;

View file

@ -1,5 +1,3 @@
const model = require('../models/quiz.js');
const folderModel = require('../models/folders.js');
const emailer = require('../config/email.js');
const AppError = require('../middleware/AppError.js');
@ -7,184 +5,181 @@ const { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, QUIZ_NOT_FOUND, FOLDER_NOT_
class QuizController {
async create(req, res, next) {
constructor(quizModel, foldersModel) {
this.folders = foldersModel;
this.quizzes = quizModel;
}
create = async (req, res, next) => {
try {
const { title, content, folderId } = req.body;
if (!title || !content || !folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this folder mine
const owner = await folderModel.getOwner(folderId);
const owner = await this.folders.getOwner(folderId);
if (owner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const result = await model.create(title, content, folderId, req.user.userId);
const result = await this.quizzes.create(title, content, folderId, req.user.userId);
if (!result) {
throw new AppError(QUIZ_ALREADY_EXISTS);
}
return res.status(200).json({
message: 'Quiz créé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async get(req, res, next) {
};
get = async (req, res, next) => {
try {
const { quizId } = req.params;
if (!quizId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const content = await model.getContent(quizId);
const content = await this.quizzes.getContent(quizId);
if (!content) {
throw new AppError(GETTING_QUIZ_ERROR);
}
// Is this quiz mine
if (content.userId != req.user.userId) {
throw new AppError(QUIZ_NOT_FOUND);
}
return res.status(200).json({
data: content
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async delete(req, res, next) {
};
delete = async (req, res, next) => {
try {
const { quizId } = req.params;
if (!quizId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this quiz mine
const owner = await model.getOwner(quizId);
const owner = await this.quizzes.getOwner(quizId);
if (owner != req.user.userId) {
throw new AppError(QUIZ_NOT_FOUND);
}
const result = await model.delete(quizId);
const result = await this.quizzes.delete(quizId);
if (!result) {
throw new AppError(DELETE_QUIZ_ERROR);
}
return res.status(200).json({
message: 'Quiz supprimé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async update(req, res, next) {
};
update = async (req, res, next) => {
try {
const { quizId, newTitle, newContent } = req.body;
if (!newTitle || !newContent || !quizId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this quiz mine
const owner = await model.getOwner(quizId);
const owner = await this.quizzes.getOwner(quizId);
if (owner != req.user.userId) {
throw new AppError(QUIZ_NOT_FOUND);
}
const result = await model.update(quizId, newTitle, newContent);
const result = await this.quizzes.update(quizId, newTitle, newContent);
if (!result) {
throw new AppError(UPDATE_QUIZ_ERROR);
}
return res.status(200).json({
message: 'Quiz mis à jours avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async move(req, res, next) {
};
move = async (req, res, next) => {
try {
const { quizId, newFolderId } = req.body;
if (!quizId || !newFolderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Is this quiz mine
const quizOwner = await model.getOwner(quizId);
const quizOwner = await this.quizzes.getOwner(quizId);
if (quizOwner != req.user.userId) {
throw new AppError(QUIZ_NOT_FOUND);
}
// Is this folder mine
const folderOwner = await folderModel.getOwner(newFolderId);
const folderOwner = await this.folders.getOwner(newFolderId);
if (folderOwner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const result = await model.move(quizId, newFolderId);
const result = await this.quizzes.move(quizId, newFolderId);
if (!result) {
throw new AppError(MOVING_QUIZ_ERROR);
}
return res.status(200).json({
message: 'Utilisateur déplacé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
};
async copy(req, res, next) {
copy = async (req, res, next) => {
const { quizId, newTitle, folderId } = req.body;
if (!quizId || !newTitle || !folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
throw new AppError(NOT_IMPLEMENTED);
// const { quizId } = req.params;
// const { newUserId } = req.body;
// try {
// //Trouver le quiz a dupliquer
// const conn = db.getConnection();
// const quiztoduplicate = await conn.collection('quiz').findOne({ _id: new ObjectId(quizId) });
// const quiztoduplicate = await conn.collection('quiz').findOne({ _id: ObjectId.createFromHexString(quizId) });
// if (!quiztoduplicate) {
// throw new Error("Quiz non trouvé");
// }
@ -192,121 +187,119 @@ class QuizController {
// //Suppression du id du quiz pour ne pas le répliquer
// delete quiztoduplicate._id;
// //Ajout du duplicata
// await conn.collection('quiz').insertOne({ ...quiztoduplicate, userId: new ObjectId(newUserId) });
// await conn.collection('quiz').insertOne({ ...quiztoduplicate, userId: ObjectId.createFromHexString(newUserId) });
// res.json(Response.ok("Dossier dupliqué avec succès pour un autre utilisateur"));
// } catch (error) {
// if (error.message.startsWith("Quiz non trouvé")) {
// return res.status(404).json(Response.badRequest(error.message));
// }
// res.status(500).json(Response.serverError(error.message));
// }
}
async deleteQuizzesByFolderId(req, res, next) {
};
deleteQuizzesByFolderId = async (req, res, next) => {
try {
const { folderId } = req.body;
if (!folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// Call the method from the Quiz model to delete quizzes by folder ID
await Quiz.deleteQuizzesByFolderId(folderId);
return res.status(200).json({
message: 'Quizzes deleted successfully.'
});
} catch (error) {
return next(error);
}
}
async duplicate(req, res, next) {
const { quizId } = req.body;
};
duplicate = async (req, res, next) => {
const { quizId } = req.body;
try {
const newQuizId = await model.duplicate(quizId,req.user.userId);
const newQuizId = await this.quizzes.duplicate(quizId, req.user.userId);
res.status(200).json({ success: true, newQuizId });
} catch (error) {
return next(error);
}
}
async quizExists(title, userId) {
};
quizExists = async (title, userId) => {
try {
const existingFile = await model.quizExists(title, userId);
const existingFile = await this.quizzes.quizExists(title, userId);
return existingFile !== null;
} catch (error) {
throw new AppError(GETTING_QUIZ_ERROR);
}
}
async Share(req, res, next) {
};
share = async (req, res, next) => {
try {
const { quizId, email } = req.body;
if ( !quizId || !email) {
if (!quizId || !email) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
}
const link = `${process.env.FRONTEND_URL}/teacher/Share/${quizId}`;
emailer.quizShare(email, link);
return res.status(200).json({
message: 'Quiz partagé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
};
async getShare(req, res, next) {
getShare = async (req, res, next) => {
try {
const { quizId } = req.params;
if ( !quizId ) {
if (!quizId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const content = await model.getContent(quizId);
}
const content = await this.quizzes.getContent(quizId);
if (!content) {
throw new AppError(GETTING_QUIZ_ERROR);
}
return res.status(200).json({
data: content.title
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async receiveShare(req, res, next) {
};
receiveShare = async (req, res, next) => {
try {
const { quizId, folderId } = req.body;
if (!quizId || !folderId) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const folderOwner = await folderModel.getOwner(folderId);
const folderOwner = await this.folders.getOwner(folderId);
if (folderOwner != req.user.userId) {
throw new AppError(FOLDER_NOT_FOUND);
}
const content = await model.getContent(quizId);
const content = await this.quizzes.getContent(quizId);
if (!content) {
throw new AppError(GETTING_QUIZ_ERROR);
}
const result = await model.create(content.title, content.content, folderId, req.user.userId);
const result = await this.quizzes.create(content.title, content.content, folderId, req.user.userId);
if (!result) {
throw new AppError(QUIZ_ALREADY_EXISTS);
}
@ -314,13 +307,11 @@ class QuizController {
return res.status(200).json({
message: 'Quiz partagé reçu.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
};
}
module.exports = new QuizController;
module.exports = QuizController;

View file

@ -1,35 +1,40 @@
const emailer = require('../config/email.js');
const model = require('../models/users.js');
const jwt = require('../middleware/jwtToken.js');
const AppError = require('../middleware/AppError.js');
const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR, DELETE_USER_ERROR } = require('../constants/errorCodes');
// controllers must use arrow functions to bind 'this' to the class instance in order to access class properties as callbacks in Express
class UsersController {
async register(req, res, next) {
constructor(userModel) {
this.users = userModel;
}
register = async (req, res, next) => {
try {
const { email, password } = req.body;
if (!email || !password) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
await model.register(email, password);
emailer.registerConfirmation(email)
if (!this.users) {
throw new AppError('Users model not found');
}
await this.users.register(email, password);
emailer.registerConfirmation(email);
return res.status(200).json({
message: 'Utilisateur créé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async login(req, res, next) {
login = async (req, res, next) => {
try {
const { email, password } = req.body;
@ -37,7 +42,11 @@ class UsersController {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const user = await model.login(email, password);
if (!this) {
throw new AppError('UsersController not initialized');
}
const user = await this.users.login(email, password);
if (!user) {
throw new AppError(LOGIN_CREDENTIALS_ERROR);
@ -45,102 +54,93 @@ class UsersController {
const token = jwt.create(user.email, user._id);
return res.status(200).json({
token: token,
id: user.email
});
}
catch (error) {
return next(error);
return res.status(200).json({ token });
} catch (error) {
next(error);
}
}
async resetPassword(req, res, next) {
resetPassword = async (req, res, next) => {
try {
const { email } = req.body;
if (!email) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
const newPassword = await model.resetPassword(email);
const newPassword = await this.users.resetPassword(email);
if (!newPassword) {
throw new AppError(GENERATE_PASSWORD_ERROR);
}
emailer.newPasswordConfirmation(email, newPassword);
return res.status(200).json({
message: 'Nouveau mot de passe envoyé par courriel.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async changePassword(req, res, next) {
changePassword = async (req, res, next) => {
try {
const { email, oldPassword, newPassword } = req.body;
if (!email || !oldPassword || !newPassword) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// verify creds first
const user = await model.login(email, oldPassword);
const user = await this.users.login(email, oldPassword);
if (!user) {
throw new AppError(LOGIN_CREDENTIALS_ERROR);
}
const password = await model.changePassword(email, newPassword)
const password = await this.users.changePassword(email, newPassword);
if (!password) {
throw new AppError(UPDATE_PASSWORD_ERROR);
}
return res.status(200).json({
message: 'Mot de passe changé avec succès.'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
async delete(req, res, next) {
delete = async (req, res, next) => {
try {
const { email, password } = req.body;
if (!email || !password) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
// verify creds first
const user = await model.login(email, password);
const user = await this.users.login(email, password);
if (!user) {
throw new AppError(LOGIN_CREDENTIALS_ERROR);
}
const result = await model.delete(email)
const result = await this.users.delete(email);
if (!result) {
throw new AppError(DELETE_USER_ERROR)
throw new AppError(DELETE_USER_ERROR);
}
return res.status(200).json({
message: 'Utilisateur supprimé avec succès'
});
}
catch (error) {
} catch (error) {
return next(error);
}
}
}
module.exports = new UsersController;
module.exports = UsersController;

View file

@ -1,19 +1,31 @@
//model
const db = require('../config/db.js')
const { ObjectId } = require('mongodb');
const Quiz = require('./quiz.js');
const ObjectId = require('mongodb').ObjectId;
const { generateUniqueTitle } = require('./utils');
class Folders {
constructor(db, quizModel) {
this.db = db;
this.quizModel = quizModel;
}
async create(title, userId) {
await db.connect()
const conn = db.getConnection();
console.log("LOG: create", title, userId);
if (!title || !userId) {
throw new Error('Missing required parameter(s)');
}
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const existingFolder = await foldersCollection.findOne({ title: title, userId: userId });
if (existingFolder) return new Error('Folder already exists');
if (existingFolder) {
throw new Error('Folder already exists');
}
const newFolder = {
userId: userId,
@ -27,8 +39,8 @@ class Folders {
}
async getUserFolders(userId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
@ -38,19 +50,20 @@ class Folders {
}
async getOwner(folderId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folder = await foldersCollection.findOne({ _id: new ObjectId(folderId) });
const folder = await foldersCollection.findOne({ _id: ObjectId.createFromHexString(folderId) });
return folder.userId;
}
// finds all quizzes in a folder
async getContent(folderId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const filesCollection = conn.collection('files');
@ -60,26 +73,26 @@ class Folders {
}
async delete(folderId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folderResult = await foldersCollection.deleteOne({ _id: new ObjectId(folderId) });
const folderResult = await foldersCollection.deleteOne({ _id: ObjectId.createFromHexString(folderId) });
if (folderResult.deletedCount != 1) return false;
await Quiz.deleteQuizzesByFolderId(folderId);
await this.quizModel.deleteQuizzesByFolderId(folderId);
return true;
}
async rename(folderId, newTitle) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const result = await foldersCollection.updateOne({ _id: new ObjectId(folderId) }, { $set: { title: newTitle } })
const result = await foldersCollection.updateOne({ _id: ObjectId.createFromHexString(folderId) }, { $set: { title: newTitle } })
if (result.modifiedCount != 1) return false;
@ -87,69 +100,77 @@ class Folders {
}
async duplicate(folderId, userId) {
console.log("LOG: duplicate", folderId, userId);
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const sourceFolder = await this.getFolderWithContent(folderId);
// Check if the new title already exists
let newFolderTitle = sourceFolder.title + "-copie";
let counter = 1;
while (await this.folderExists(newFolderTitle, userId)) {
newFolderTitle = `${sourceFolder.title}-copie(${counter})`;
counter++;
const sourceFolder = await foldersCollection.findOne({ _id: ObjectId.createFromHexString(folderId), userId: userId });
if (!sourceFolder) {
throw new Error(`Folder ${folderId} not found`);
}
const theUserId = userId;
// Use the utility function to generate a unique title
const newFolderTitle = await generateUniqueTitle(sourceFolder.title, async (title) => {
console.log(`generateUniqueTitle(${title}): userId`, theUserId);
return await foldersCollection.findOne({ title: title, userId: theUserId });
});
const newFolderId = await this.create(newFolderTitle, userId);
if (!newFolderId) {
throw new Error('Failed to create a duplicate folder.');
throw new Error('Failed to create duplicate folder');
}
for (const quiz of sourceFolder.content) {
const { title, content } = quiz;
//console.log(title);
//console.log(content);
await Quiz.create(title, content, newFolderId.toString(), userId);
// copy the quizzes from source folder to destination folder
const content = await this.getContent(folderId);
console.log("folders.duplicate: found content", content);
for (const quiz of content) {
console.log("folders.duplicate: creating quiz (copy)", quiz);
const result = await this.quizModel.create(quiz.title, quiz.content, newFolderId.toString(), userId);
if (!result) {
throw new Error('Failed to create duplicate quiz');
}
}
return newFolderId;
}
async folderExists(title, userId) {
await db.connect();
const conn = db.getConnection();
console.log("LOG: folderExists", title, userId);
await this.db.connect();
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const existingFolder = await foldersCollection.findOne({ title: title, userId: userId });
return existingFolder !== null;
return !!existingFolder;
}
async copy(folderId, userId) {
const sourceFolder = await this.getFolderWithContent(folderId);
const newFolderId = await this.create(sourceFolder.title, userId);
if (!newFolderId) {
throw new Error('Failed to create a new folder.');
}
for (const quiz of sourceFolder.content) {
await this.createQuiz(quiz.title, quiz.content, newFolderId, userId);
await this.quizModel.create(quiz.title, quiz.content, newFolderId, userId);
}
return newFolderId;
}
async getFolderById(folderId) {
await db.connect();
const conn = db.getConnection();
await this.db.connect();
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folder = await foldersCollection.findOne({ _id: new ObjectId(folderId) });
const folder = await foldersCollection.findOne({ _id: ObjectId.createFromHexString(folderId) });
if (!folder) return new Error(`Folder ${folderId} not found`);
return folder;
}
@ -171,4 +192,4 @@ class Folders {
}
module.exports = new Folders;
module.exports = Folders;

View file

@ -1,8 +1,12 @@
const db = require('../config/db.js')
//const db = require('../config/db.js')
const { ObjectId } = require('mongodb');
class Images {
constructor(db) {
this.db = db;
}
async upload(file, userId) {
await db.connect()
const conn = db.getConnection();
@ -28,7 +32,7 @@ class Images {
const imagesCollection = conn.collection('images');
const result = await imagesCollection.findOne({ _id: new ObjectId(id) });
const result = await imagesCollection.findOne({ _id: ObjectId.createFromHexString(id) });
if (!result) return null;
@ -41,4 +45,4 @@ class Images {
}
module.exports = new Images;
module.exports = Images;

View file

@ -1,17 +1,25 @@
const db = require('../config/db.js')
const { ObjectId } = require('mongodb');
const { generateUniqueTitle } = require('./utils');
class Quiz {
constructor(db) {
// console.log("Quiz constructor: db", db)
this.db = db;
}
async create(title, content, folderId, userId) {
await db.connect()
const conn = db.getConnection();
console.log(`quizzes: create title: ${title}, folderId: ${folderId}, userId: ${userId}`);
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const existingQuiz = await quizCollection.findOne({ title: title, folderId: folderId, userId: userId })
if (existingQuiz) return null;
if (existingQuiz) {
throw new Error(`Quiz already exists with title: ${title}, folderId: ${folderId}, userId: ${userId}`);
}
const newQuiz = {
folderId: folderId,
@ -23,74 +31,86 @@ class Quiz {
}
const result = await quizCollection.insertOne(newQuiz);
console.log("quizzes: create insertOne result", result);
return result.insertedId;
}
async getOwner(quizId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const quiz = await quizCollection.findOne({ _id: new ObjectId(quizId) });
const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) });
return quiz.userId;
}
async getContent(quizId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const quiz = await quizCollection.findOne({ _id: new ObjectId(quizId) });
const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) });
return quiz;
}
async delete(quizId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.deleteOne({ _id: new ObjectId(quizId) });
const result = await quizCollection.deleteOne({ _id: ObjectId.createFromHexString(quizId) });
if (result.deletedCount != 1) return false;
return true;
}
async deleteQuizzesByFolderId(folderId) {
await db.connect();
const conn = db.getConnection();
await this.db.connect();
const conn = this.db.getConnection();
const quizzesCollection = conn.collection('files');
// Delete all quizzes with the specified folderId
await quizzesCollection.deleteMany({ folderId: folderId });
const result = await quizzesCollection.deleteMany({ folderId: folderId });
return result.deletedCount > 0;
}
async update(quizId, newTitle, newContent) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.updateOne({ _id: new ObjectId(quizId) }, { $set: { title: newTitle, content: newContent } });
//Ne fonctionne pas si rien n'est chngé dans le quiz
//if (result.modifiedCount != 1) return false;
const result = await quizCollection.updateOne(
{ _id: ObjectId.createFromHexString(quizId) },
{
$set: {
title: newTitle,
content: newContent,
updated_at: new Date()
}
}
);
return true
return result.modifiedCount === 1;
}
async move(quizId, newFolderId) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.updateOne({ _id: new ObjectId(quizId) }, { $set: { folderId: newFolderId } });
const result = await quizCollection.updateOne(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { folderId: newFolderId } }
);
if (result.modifiedCount != 1) return false;
@ -98,29 +118,31 @@ class Quiz {
}
async duplicate(quizId, userId) {
const sourceQuiz = await this.getContent(quizId);
let newQuizTitle = `${sourceQuiz.title}-copy`;
let counter = 1;
while (await this.quizExists(newQuizTitle, userId)) {
newQuizTitle = `${sourceQuiz.title}-copy(${counter})`;
counter++;
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const sourceQuiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId), userId: userId });
if (!sourceQuiz) {
throw new Error('Quiz not found for quizId: ' + quizId);
}
//console.log(newQuizTitle);
const newQuizId = await this.create(newQuizTitle, sourceQuiz.content,sourceQuiz.folderId, userId);
// Use the utility function to generate a unique title
const newQuizTitle = await generateUniqueTitle(sourceQuiz.title, async (title) => {
return await quizCollection.findOne({ title: title, folderId: sourceQuiz.folderId, userId: userId });
});
const newQuizId = await this.create(newQuizTitle, sourceQuiz.content, sourceQuiz.folderId, userId);
if (!newQuizId) {
throw new Error('Failed to create a duplicate quiz.');
throw new Error('Failed to create duplicate quiz');
}
return newQuizId;
}
async quizExists(title, userId) {
await db.connect();
const conn = db.getConnection();
await this.db.connect();
const conn = this.db.getConnection();
const filesCollection = conn.collection('files');
const existingFolder = await filesCollection.findOne({ title: title, userId: userId });
@ -130,4 +152,4 @@ class Quiz {
}
module.exports = new Quiz;
module.exports = Quiz;

View file

@ -1,11 +1,14 @@
//user
const db = require('../config/db.js');
const bcrypt = require('bcrypt');
const AppError = require('../middleware/AppError.js');
const { USER_ALREADY_EXISTS } = require('../constants/errorCodes');
const Folders = require('../models/folders.js');
class Users {
constructor(db, foldersModel) {
// console.log("Users constructor: db", db)
this.db = db;
this.folders = foldersModel;
}
async hashPassword(password) {
return await bcrypt.hash(password, 10)
@ -20,8 +23,8 @@ class Users {
}
async register(email, password) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
@ -37,18 +40,19 @@ class Users {
created_at: new Date()
};
await userCollection.insertOne(newUser);
const result = await userCollection.insertOne(newUser);
// console.log("userCollection.insertOne() result", result);
const userId = result.insertedId.toString();
const folderTitle = 'Dossier par Défaut';
const userId = newUser._id.toString();
await Folders.create(folderTitle, userId);
await this.folders.create(folderTitle, userId);
// TODO: verif if inserted properly...
return result;
}
async login(email, password) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
@ -74,8 +78,8 @@ class Users {
}
async changePassword(email, newPassword) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
@ -89,8 +93,8 @@ class Users {
}
async delete(email) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
@ -102,8 +106,8 @@ class Users {
}
async getId(email) {
await db.connect()
const conn = db.getConnection();
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
@ -118,4 +122,4 @@ class Users {
}
module.exports = new Users;
module.exports = Users;

35
server/models/utils.js Normal file
View file

@ -0,0 +1,35 @@
// utils.js
async function generateUniqueTitle(baseTitle, existsCallback) {
console.log(`generateUniqueTitle(${baseTitle})`);
let newTitle = baseTitle;
let counter = 1;
const titleRegex = /(.*?)(\((\d+)\))?$/;
const match = baseTitle.match(titleRegex);
if (match) {
baseTitle = match[1].trim();
counter = match[3] ? parseInt(match[3], 10) + 1 : 1;
}
// If the base title does not end with a parentheses expression, start with "(1)"
if (!match[2]) {
newTitle = `${baseTitle} (${counter})`;
} else {
// else increment the counter in the parentheses expression as a first try
newTitle = `${baseTitle} (${counter})`;
}
console.log(`first check of newTitle: ${newTitle}`);
while (await existsCallback(newTitle)) {
counter++;
newTitle = `${baseTitle} (${counter})`;
console.log(`trying newTitle: ${newTitle}`);
}
return newTitle;
}
module.exports = {
generateUniqueTitle
};

View file

@ -22,6 +22,7 @@
},
"devDependencies": {
"jest": "^29.7.0",
"jest-mock": "^29.7.0",
"nodemon": "^3.0.1",
"supertest": "^6.3.4"
},

View file

@ -7,7 +7,7 @@
"build": "webpack --config webpack.config.js",
"start": "node app.js",
"dev": "nodemon app.js",
"test": "jest"
"test": "jest --colors"
},
"keywords": [],
"author": "",
@ -26,6 +26,7 @@
},
"devDependencies": {
"jest": "^29.7.0",
"jest-mock": "^29.7.0",
"nodemon": "^3.0.1",
"supertest": "^6.3.4"
},

View file

@ -1,18 +1,22 @@
const express = require('express');
const router = express.Router();
const jwt = require('../middleware/jwtToken.js');
const folders = require('../app.js').folders;
const foldersController = require('../controllers/folders.js')
router.post("/create", jwt.authenticate, foldersController.create);
router.get("/getUserFolders", jwt.authenticate, foldersController.getUserFolders);
router.get("/getFolderContent/:folderId", jwt.authenticate, foldersController.getFolderContent);
router.delete("/delete/:folderId", jwt.authenticate, foldersController.delete);
router.put("/rename", jwt.authenticate, foldersController.rename);
router.post("/create", jwt.authenticate, folders.create);
router.get("/getUserFolders", jwt.authenticate, folders.getUserFolders);
router.get("/getFolderContent/:folderId", jwt.authenticate, folders.getFolderContent);
router.delete("/delete/:folderId", jwt.authenticate, folders.delete);
router.put("/rename", jwt.authenticate, folders.rename);
//router.post("/duplicate", jwt.authenticate, foldersController.duplicate);
router.post("/duplicate", jwt.authenticate, foldersController.duplicate);
router.post("/duplicate", jwt.authenticate, folders.duplicate);
router.post("/copy/:folderId", jwt.authenticate, foldersController.copy);
router.post("/copy/:folderId", jwt.authenticate, folders.copy);
module.exports = router;
module.exports = router;
// export also folders (the controller)
module.exports.folders = folders;
// Refer to folders using: const folders = require('../controllers/folders.js').folders;

View file

@ -1,15 +1,15 @@
const express = require('express');
const router = express.Router();
const images = require('../app.js').images;
const jwt = require('../middleware/jwtToken.js');
const imagesController = require('../controllers/images.js')
// For getting the image out of the form data
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
router.post("/upload", jwt.authenticate, upload.single('image'), imagesController.upload);
router.get("/get/:id", imagesController.get);
router.post("/upload", jwt.authenticate, upload.single('image'), images.upload);
router.get("/get/:id", images.get);
module.exports = router;
module.exports = router;

View file

@ -1,19 +1,22 @@
const express = require('express');
const router = express.Router();
const quizzes = require('../app.js').quizzes;
const jwt = require('../middleware/jwtToken.js');
const quizController = require('../controllers/quiz.js')
router.post("/create", jwt.authenticate, quizController.create);
router.get("/get/:quizId", jwt.authenticate, quizController.get);
router.delete("/delete/:quizId", jwt.authenticate, quizController.delete);
router.put("/update", jwt.authenticate, quizController.update);
router.put("/move", jwt.authenticate, quizController.move);
if (!quizzes) {
console.error("quizzes is not defined");
}
router.post("/duplicate", jwt.authenticate, quizController.duplicate);
router.post("/copy/:quizId", jwt.authenticate, quizController.copy);
router.put("/Share", jwt.authenticate, quizController.Share);
router.get("/getShare/:quizId", jwt.authenticate, quizController.getShare);
router.post("/receiveShare", jwt.authenticate, quizController.receiveShare);
router.post("/create", jwt.authenticate, quizzes.create);
router.get("/get/:quizId", jwt.authenticate, quizzes.get);
router.delete("/delete/:quizId", jwt.authenticate, quizzes.delete);
router.put("/update", jwt.authenticate, quizzes.update);
router.put("/move", jwt.authenticate, quizzes.move);
module.exports = router;
router.post("/duplicate", jwt.authenticate, quizzes.duplicate);
router.post("/copy/:quizId", jwt.authenticate, quizzes.copy);
router.put("/Share", jwt.authenticate, quizzes.share);
router.get("/getShare/:quizId", jwt.authenticate, quizzes.getShare);
router.post("/receiveShare", jwt.authenticate, quizzes.receiveShare);
module.exports = router;

View file

@ -1,13 +1,12 @@
const express = require('express');
const router = express.Router();
const users = require('../app.js').users;
const jwt = require('../middleware/jwtToken.js');
const usersController = require('../controllers/users.js')
router.post("/register", usersController.register);
router.post("/login", usersController.login);
router.post("/reset-password", usersController.resetPassword);
router.post("/change-password", jwt.authenticate, usersController.changePassword);
router.post("/delete-user", jwt.authenticate, usersController.delete);
router.post("/register", users.register);
router.post("/login", users.login);
router.post("/reset-password", users.resetPassword);
router.post("/change-password", jwt.authenticate, users.changePassword);
router.post("/delete-user", jwt.authenticate, users.delete);
module.exports = router;
module.exports = router;

View file

@ -9,7 +9,7 @@ const setupWebsocket = (io) => {
console.log("Connection limit reached. Disconnecting client.");
socket.emit(
"join-failure",
"Le nombre maximum de connexion a été atteint"
"Le nombre maximum de connexions a été atteint"
);
socket.disconnect(true);
return;