transfert to ts

This commit is contained in:
Gabriel Matte 2024-11-10 10:19:05 -05:00
parent 55fe6003c6
commit 9740a80335
34 changed files with 222 additions and 639 deletions

View file

@ -4,7 +4,6 @@ import dotenv from 'dotenv';
import cors from 'cors';
import bodyParser from 'body-parser';
import { ServerOptions, Server as SocketIOServer } from 'socket.io';
import { GlideClient } from '@valkey/valkey-glide';
// Set app defaults
const environment: string = process.env.NODE_ENV ?? "production";
@ -14,12 +13,12 @@ const isDev: boolean = environment === "development";
import setupWebsocket from "./socket/socket";
// Import Database
import db from './config/db';
import db from './config/db-connection';
// Import Models
import Quiz from './models/quiz';
import Folders from './models/folders';
import Users from './models/users';
import Users from './models/user-model';
import Images from './models/images';
// Instantiate models
@ -29,28 +28,28 @@ const userModel = new Users(db, foldersModel);
const imageModel = new Images(db);
// Initialize cache
/*
const valkey = await GlideClient.createClient({
addresses: [{
host: process.env.VALKEY_HOST ?? 'localhost',
port: Number(process.env.VALKEY_PORT) ?? 6379
}]
});
*/
// Import Controllers
import UsersController from './controllers/users';
import FoldersController from './controllers/folders';
import QuizController from './controllers/quiz';
import ImagesController from './controllers/images';
import { RoomManager as RoomsController } from './controllers/rooms';
import UsersController from './controllers/user-controller';
import FoldersController from './controllers/folder-controller';
import QuizController from './controllers/quiz-controller';
import ImagesController from './controllers/image-controller';
//import { RoomManager as RoomsController } from './controllers/rooms';
// Instantiate Controllers
const usersControllerInstance = new UsersController(userModel);
const foldersControllerInstance = new FoldersController(foldersModel);
const quizControllerInstance = new QuizController(quizModel, foldersModel);
const imagesControllerInstance = new ImagesController(imageModel);
// Initialize valkey before creating rooms controller
const roomsControllerInstance = new RoomsController({}, valkey);
//const roomsControllerInstance = new RoomsController({}, valkey);
// Export Controllers
@ -59,18 +58,18 @@ export const controllers = {
folders: foldersControllerInstance,
quizzes: quizControllerInstance,
images: imagesControllerInstance,
rooms: roomsControllerInstance
//rooms: roomsControllerInstance
};
// Import Routers
import userRouter from './routers/users';
import folderRouter from './routers/folders';
import quizRouter from './routers/quiz';
import imagesRouter from './routers/images';
import userRouter from './routers/user-router';
import folderRouter from './routers/folder-router';
import quizRouter from './routers/quiz-router';
import imagesRouter from './routers/image-router';
// Setup environment
dotenv.config();
import errorHandler from "./middleware/errorHandler";
import errorHandler from "./middleware/error-handler";
// Start app
const app: Application = express();

View file

@ -22,4 +22,4 @@ export class DBConnection {
}
}
export default new DBConnection();
export default DBConnection

View file

@ -43,4 +43,4 @@ class Emailer {
}
export default new Emailer()
export default Emailer

View file

@ -1,4 +1,4 @@
import type { AppErrorInfos } from "../middleware/AppError";
import type { AppErrorInfos } from "../middleware/app-error";
import { HttpStatusCode } from "../utils/http-status-codes";
export const UNAUTHORIZED_NO_TOKEN_GIVEN:AppErrorInfos = {

View file

@ -1,41 +1,16 @@
//controller
import AppError from '../middleware/AppError.js';
import { 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 } from '../constants/errorCodes';
import Folders from '../models/folders.js';
import AppError from '../middleware/app-error.js';
import { 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 } from '../constants/error-codes.js';
import FolderRepository from '../repository/folder-repository.js';
import Folder from '../models/folder-model.js';
// controllers must use arrow functions to bind 'this' to the class instance in order to access class properties as callbacks in Express
class FoldersController {
folders:Folders
constructor(foldersModel) {
this.folders = foldersModel;
}
class FolderController{
/***
* Basic queries
*/
create = async (req, res, next) => {
try {
const { title } = req.body;
if (!title) {
throw new AppError(MISSING_REQUIRED_PARAMETER);
}
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) {
return next(error);
}
}
getUserFolders = async (req, res, next) => {
try {
@ -260,4 +235,4 @@ class FoldersController {
}
export default FoldersController
export default FolderController

View file

@ -1,8 +1,8 @@
import AppError from '../middleware/AppError.js';
import { MISSING_REQUIRED_PARAMETER, IMAGE_NOT_FOUND } from '../constants/errorCodes.js';
import AppError from '../middleware/app-error.js';
import { MISSING_REQUIRED_PARAMETER, IMAGE_NOT_FOUND } from '../constants/error-codes.js';
import Images from '../models/images.js';
class ImagesController {
class ImageController {
images:Images
constructor(imagesModel) {
@ -54,4 +54,4 @@ class ImagesController {
}
export default ImagesController
export default ImageController

View file

@ -1,7 +1,7 @@
import emailer from '../config/email.js';
import emailer from '../config/emailer.js';
import AppError from'../middleware/AppError.js';
import { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, QUIZ_NOT_FOUND, FOLDER_NOT_FOUND, QUIZ_ALREADY_EXISTS, GETTING_QUIZ_ERROR, DELETE_QUIZ_ERROR, UPDATE_QUIZ_ERROR, MOVING_QUIZ_ERROR, DUPLICATE_QUIZ_ERROR, COPY_QUIZ_ERROR } from'../constants/errorCodes.js';
import AppError from'../middleware/app-error.js';
import { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, QUIZ_NOT_FOUND, FOLDER_NOT_FOUND, QUIZ_ALREADY_EXISTS, GETTING_QUIZ_ERROR, DELETE_QUIZ_ERROR, UPDATE_QUIZ_ERROR, MOVING_QUIZ_ERROR, DUPLICATE_QUIZ_ERROR, COPY_QUIZ_ERROR } from'../constants/error-codes.js';
import Folders from '../models/folders.js';
import Quiz from '../models/quiz.js';

View file

@ -15,7 +15,7 @@ interface RoomManagerOptions {
providerOptions?: ProviderConfig;
}
export class RoomManager {
export class RoomController {
private valkey: GlideClient;
private provider: BaseRoomProvider<RoomInfo>;
@ -75,4 +75,4 @@ export class RoomManager {
}
}
module.exports = RoomManager;
export default RoomController;

View file

@ -1,9 +1,8 @@
import emailer from'../config/email.js';
import jwt from'../middleware/jwtToken.js';
import emailer from'../config/emailer.js';
import jwt from'../middleware/jwt-token.js';
import AppError from'../middleware/AppError.js';
import { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR, DELETE_USER_ERROR, USER_NOT_FOUND,USER_CONTROLLER_NOT_INITIALIZED } from'../constants/errorCodes';
import Users from '../models/users.js'
import AppError from'../middleware/app-error.js';
import { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR, DELETE_USER_ERROR, USER_NOT_FOUND,USER_CONTROLLER_NOT_INITIALIZED } from'../constants/error-codes.js';
// controllers must use arrow functions to bind 'this' to the class instance in order to access class properties as callbacks in Express
class UsersController {

View file

@ -1,4 +1,4 @@
import AppError from './AppError'
import AppError from './app-error'
import fs from 'fs';
import { HttpStatusCode } from '../utils/http-status-codes';

View file

@ -1,7 +1,7 @@
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'
import AppError from './AppError.ts';
import { UNAUTHORIZED_NO_TOKEN_GIVEN, UNAUTHORIZED_INVALID_TOKEN } from '../constants/errorCodes';
import AppError from './app-error.ts';
import { UNAUTHORIZED_NO_TOKEN_GIVEN, UNAUTHORIZED_INVALID_TOKEN } from '../constants/error-codes.ts';
dotenv.config();

View file

@ -0,0 +1,8 @@
import { ObjectId } from "mongodb";
abstract class BaseModel {
id: ObjectId;
abstract validate(): boolean;
}
export default BaseModel;

View file

@ -0,0 +1,8 @@
import BaseModel from './base-model'
export default class Folder extends BaseModel{
title:string
validate(): boolean {
return true
}
}

View file

@ -1,202 +0,0 @@
//model
import type { DBConnection } from '../config/db';
import type {Quiz} from './quiz'
import {ObjectId} from 'mongodb'
import { generateUniqueTitle } from '../utils/models-utils';
class Folders {
db: DBConnection
quizModel:Quiz
constructor(db, quizModel) {
this.db = db;
this.quizModel = quizModel;
}
async create(title, userId) {
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) {
throw new Error('Folder already exists');
}
const newFolder = {
userId: userId,
title: title,
created_at: new Date()
}
const result = await foldersCollection.insertOne(newFolder);
return result.insertedId;
}
async getUserFolders(userId) {
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const result = await foldersCollection.find({ userId: userId }).toArray();
return result;
}
async getOwner(folderId) {
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folder = await foldersCollection.findOne({ _id: ObjectId.createFromHexString(folderId) });
return folder?.userId;
}
// finds all quizzes in a folder
async getContent(folderId) {
await this.db.connect()
const conn = this.db.getConnection();
const filesCollection = conn.collection('files');
const result = await filesCollection.find({ folderId: folderId }).toArray();
return result;
}
async delete(folderId) {
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folderResult = await foldersCollection.deleteOne({ _id: ObjectId.createFromHexString(folderId) });
if (folderResult.deletedCount != 1) return false;
await this.quizModel.deleteQuizzesByFolderId(folderId);
return true;
}
async rename(folderId, newTitle) {
await this.db.connect()
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const result = await foldersCollection.updateOne({ _id: ObjectId.createFromHexString(folderId) }, { $set: { title: newTitle } })
if (result.modifiedCount != 1) return false;
return true
}
async duplicate(folderId, userId) {
console.log("LOG: duplicate", folderId, userId);
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
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 duplicate folder');
}
// 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) {
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;
}
async copy(folderId, userId) {
const sourceFolder = await this.getFolderWithContent(folderId);
const newFolderId = await this.create(sourceFolder[0].title, userId);
if (!newFolderId) {
throw new Error('Failed to create a new folder.');
}
for (const quiz of sourceFolder.content) {
await this.quizModel.create(quiz.title, quiz.content, newFolderId, userId);
}
return newFolderId;
}
async getFolderById(folderId) {
await this.db.connect();
const conn = this.db.getConnection();
const foldersCollection = conn.collection('folders');
const folder = await foldersCollection.findOne({ _id: ObjectId.createFromHexString(folderId) });
if (!folder) return new Error(`Folder ${folderId} not found`);
return folder;
}
async getFolderWithContent(folderId) {
const folder = await this.getFolderById(folderId);
const content = await this.getContent(folderId);
return {
...folder,
content: content
};
}
}
export default Folders

View file

@ -0,0 +1,9 @@
import BaseModel from './base-model'
class Image extends BaseModel{
validate(): boolean {
return true
}
}
export default Image;

View file

@ -1,49 +0,0 @@
import type {DBConnection} from '../config/db.js'
import { ObjectId } from 'mongodb';
class Images {
db:DBConnection
constructor(db) {
this.db = db;
}
async upload(file, userId) {
await this.db.connect()
const conn = this.db.getConnection();
const imagesCollection = conn.collection('images');
const newImage = {
userId: userId,
file_name: file.originalname,
file_content: file.buffer.toString('base64'),
mime_type: file.mimetype,
created_at: new Date()
};
const result = await imagesCollection.insertOne(newImage);
return result.insertedId;
}
async get(id) {
await this.db.connect()
const conn = this.db.getConnection();
const imagesCollection = conn.collection('images');
const result = await imagesCollection.findOne({ _id: ObjectId.createFromHexString(id) });
if (!result) return null;
return {
file_name: result.file_name,
file_content: Buffer.from(result.file_content, 'base64'),
mime_type: result.mime_type
};
}
}
export default Images

View file

@ -0,0 +1,9 @@
import BaseModel from './base-model'
class Quiz extends BaseModel{
validate(): boolean {
return true
}
}
export default Quiz;

View file

@ -1,157 +0,0 @@
import type { DBConnection } from '../config/db';
import { ObjectId } from 'mongodb';
import { generateUniqueTitle } from '../utils/models-utils'
export class Quiz {
db: DBConnection
constructor(db) {
// console.log("Quiz constructor: db", db)
this.db = db;
}
async create(title, content, folderId, userId) {
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) {
throw new Error(`Quiz already exists with title: ${title}, folderId: ${folderId}, userId: ${userId}`);
}
const newQuiz = {
folderId: folderId,
userId: userId,
title: title,
content: content,
created_at: new Date(),
updated_at: new Date()
}
const result = await quizCollection.insertOne(newQuiz);
console.log("quizzes: create insertOne result", result);
return result.insertedId;
}
async getOwner(quizId) {
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) });
return quiz?.userId;
}
async getContent(quizId) {
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) });
return quiz;
}
async delete(quizId) {
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.deleteOne({ _id: ObjectId.createFromHexString(quizId) });
if (result.deletedCount != 1) return false;
return true;
}
async deleteQuizzesByFolderId(folderId) {
await this.db.connect();
const conn = this.db.getConnection();
const quizzesCollection = conn.collection('files');
// Delete all quizzes with the specified folderId
const result = await quizzesCollection.deleteMany({ folderId: folderId });
return result.deletedCount > 0;
}
async update(quizId, newTitle, newContent) {
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.updateOne(
{ _id: ObjectId.createFromHexString(quizId) },
{
$set: {
title: newTitle,
content: newContent,
updated_at: new Date()
}
}
);
return result.modifiedCount === 1;
}
async move(quizId, newFolderId) {
await this.db.connect()
const conn = this.db.getConnection();
const quizCollection = conn.collection('files');
const result = await quizCollection.updateOne(
{ _id: ObjectId.createFromHexString(quizId) },
{ $set: { folderId: newFolderId } }
);
if (result.modifiedCount != 1) return false;
return true
}
async duplicate(quizId, userId) {
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);
}
// 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 duplicate quiz');
}
return newQuizId;
}
async quizExists(title, userId) {
await this.db.connect();
const conn = this.db.getConnection();
const filesCollection = conn.collection('files');
const existingFolder = await filesCollection.findOne({ title: title, userId: userId });
return existingFolder !== null;
}
}
export default Quiz;

View file

@ -0,0 +1,8 @@
import BaseModel from './base-model'
export default class User extends BaseModel{
username:string
validate(): boolean {
return true
}
}

View file

@ -1,130 +0,0 @@
//user
import bcrypt from 'bcrypt';
import AppError from '../middleware/AppError.js'
import { USER_ALREADY_EXISTS } from '../constants/errorCodes.js';
import type { DBConnection } from '../config/db.js';
import Folders from './folders.js';
class Users {
db:DBConnection
folders:Folders
constructor(db, foldersModel) {
// console.log("Users constructor: db", db)
this.db = db;
this.folders = foldersModel;
}
async hashPassword(password) {
return await bcrypt.hash(password, 10)
}
generatePassword() {
return Math.random().toString(36).slice(-8);
}
async verify(password, hash) {
return await bcrypt.compare(password, hash)
}
async register(email, password) {
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
const existingUser = await userCollection.findOne({ email: email });
if (existingUser) {
throw new AppError(USER_ALREADY_EXISTS);
}
const newUser = {
email: email,
password: await this.hashPassword(password),
created_at: new Date()
};
const result = await userCollection.insertOne(newUser);
// console.log("userCollection.insertOne() result", result);
const userId = result.insertedId.toString();
const folderTitle = 'Dossier par Défaut';
await this.folders.create(folderTitle, userId);
return result;
}
async login(email, password) {
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
const user = await userCollection.findOne({ email: email });
if (!user) {
return false;
}
const passwordMatch = await this.verify(password, user.password);
if (!passwordMatch) {
return false;
}
return user;
}
async resetPassword(email) {
const newPassword = this.generatePassword();
return await this.changePassword(email, newPassword);
}
async changePassword(email, newPassword) {
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
const hashedPassword = await this.hashPassword(newPassword);
const result = await userCollection.updateOne({ email }, { $set: { password: hashedPassword } });
if (result.modifiedCount != 1) return null;
return newPassword
}
async delete(email) {
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
const result = await userCollection.deleteOne({ email });
if (result.deletedCount != 1) return false;
return true;
}
async getId(email) {
await this.db.connect()
const conn = this.db.getConnection();
const userCollection = conn.collection('users');
const user = await userCollection.findOne({ email: email });
if (!user) {
return false;
}
return user._id;
}
}
export default Users

View file

@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@valkey-ts/client": "^1.5.14",
"@valkey/valkey-glide": "^1.1.0",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
@ -1433,6 +1434,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/@valkey-ts/client": {
"version": "1.5.14",
"resolved": "https://registry.npmjs.org/@valkey-ts/client/-/client-1.5.14.tgz",
"integrity": "sha512-2gPi24bPweUvfUbRsoI8pXOJZQ3fuUghHNxgi7CdAfeEiH0ysIm76jl2F+/Zf4LKkSDTNezmBW0YH359ZPBKXQ==",
"license": "MIT",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@valkey-ts/client/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
},
"node_modules/@valkey/valkey-glide": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@valkey/valkey-glide/-/valkey-glide-1.1.0.tgz",
@ -2252,6 +2273,15 @@
"node": ">=12"
}
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -3148,6 +3178,15 @@
"node": ">=10"
}
},
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",

View file

@ -15,7 +15,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"@valkey/valkey-glide": "^1.1.0",
"@valkey-ts/client": "^1.5.14",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.4",

View file

@ -0,0 +1,44 @@
import { Collection, Document } from 'mongodb';
import type { DBConnection } from '../config/db-connection';
export default class BaseRepository<T extends Document>{
protected db: DBConnection
protected collection: Collection
constructor(db:DBConnection,collectionName:string) {
db= db;
db.connect();
this.collection = db.getConnection().collection(collectionName);
}
async create(item: T|Object): Promise<T | null> {
const objectToInsert = item as T;
if(!objectToInsert.validate()) return null;
const result = await this.collection.insertOne(objectToInsert);
return result.insertedId ? objectToInsert : null;
}
async getAll(): Promise<T[]> {
const result = await this.collection.find().toArray();
return result as Object[] as T[];
}
async get(id: string): Promise<T | null> {
const result = await this.collection.findOne({ id: id });
return result?._id ? result as object as T : null;
}
async update(id: string, item: T|Object): Promise<T | null> {
const objectToInsert = item as T;
if(!objectToInsert.validate()) return null;
const result = await this.collection.updateOne({ id: id }, { $set: objectToInsert });
return result.modifiedCount ? objectToInsert : null;
}
async delete(id: string): Promise<boolean> {
const result = await this.collection.deleteOne({ id: id });
return result.deletedCount > 0;
}
}

View file

@ -0,0 +1,10 @@
import Folder from '../models/folder-model';
import BaseRepository from './base-repository';
class FolderRepository extends BaseRepository<Folder> {
constructor(db) {
super(db,'folders');
}
}
export default FolderRepository;

View file

@ -0,0 +1,10 @@
import Image from '../models/image-model';
import BaseRepository from './base-repository';
class ImageRepository extends BaseRepository<Image> {
constructor(db) {
super(db,'images');
}
}
export default ImageRepository;

View file

@ -0,0 +1,10 @@
import Quiz from '../models/quiz-model';
import BaseRepository from './base-repository';
class QuizRepository extends BaseRepository<Quiz> {
constructor(db) {
super(db,'quizzes');
}
}
export default QuizRepository;

View file

@ -0,0 +1,10 @@
import User from "../models/user-model";
import BaseRepository from "./base-repository";
class UserRepository extends BaseRepository<User> {
constructor(db) {
super(db, "users");
}
}
export default UserRepository;

View file

@ -1,5 +1,5 @@
import express, { Response, Request } from "express";
import jwt from '../middleware/jwtToken.js';
import express from "express";
import jwt from '../middleware/jwt-token.js';
import {controllers} from '../app.js'
const folders = controllers.folders

View file

@ -1,5 +1,5 @@
import express, { Response, Request } from "express";
import jwt from '../middleware/jwtToken.js';
import jwt from '../middleware/jwt-token.js';
import {controllers} from '../app.js'
import multer from 'multer';

View file

@ -1,5 +1,5 @@
import express, { Response, Request } from "express";
import jwt from '../middleware/jwtToken.js';
import jwt from '../middleware/jwt-token.js';
import {controllers} from '../app.js'
const quizzes = controllers.quizzes

View file

@ -1,5 +1,5 @@
import express, { Response, Request } from "express";
import jwt from '../middleware/jwtToken.js';
import jwt from '../middleware/jwt-token.js';
import {controllers} from '../app.js'
const roomsController = controllers.rooms

View file

@ -1,5 +1,5 @@
import express, { Response, Request } from "express";
import jwt from '../middleware/jwtToken.js';
import jwt from '../middleware/jwt-token.js';
import {controllers} from '../app.js'
const users = controllers.users

View file

@ -1,29 +1,12 @@
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"lib": ["es2017", "esnext.asynciterable"],
"skipLibCheck": true,
"sourceMap": true,
"outDir": "./dist",
"moduleResolution": "node",
"removeComments": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"baseUrl": ".",
"rootDir": "."
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"exclude": ["node_modules"],
"include": ["./**/*.ts"]
"include": ["server/**/*.ts"],
"exclude": ["node_modules"]
}