Co-authored-by: dbroqua <contact@darkou.fr>
Reviewed-on: https://git.darkou.fr/dbroqua/MusicTopus/pulls/31
This commit is contained in:
Damien Broqua 2022-03-06 14:38:26 +01:00
parent ac72c1c13c
commit aeb5df067c
28 changed files with 630 additions and 66 deletions

View file

@ -13,9 +13,11 @@ import { isXhr } from "./helpers";
import indexRouter from "./routes";
import maCollectionRouter from "./routes/ma-collection";
import collectionRouter from "./routes/collection";
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
import importSearchRouterApiV1 from "./routes/api/v1/search";
import importMeRouterApiV1 from "./routes/api/v1/me";
// Mongoose schema init
require("./models/users");
@ -82,8 +84,10 @@ app.use(
app.use("/", indexRouter);
app.use("/ma-collection", maCollectionRouter);
app.use("/collection", collectionRouter);
app.use("/api/v1/albums", importAlbumRouterApiV1);
app.use("/api/v1/search", importSearchRouterApiV1);
app.use("/api/v1/me", importMeRouterApiV1);
// Handle 404
app.use((req, res) => {
@ -113,7 +117,10 @@ app.use((error, req, res, next) => {
} else {
res.status(error.errorCode || 500);
res.render("index", {
page: { title: "500: Oups… le serveur a crashé !", error },
page: {
title: error.title || "500: Oups… le serveur a crashé !",
error,
},
errorCode: error.errorCode || 500,
viewname: "error",
user: req.user || null,

View file

@ -4,9 +4,10 @@
class ErrorEvent extends Error {
/**
* @param {Number} errorCode
* @param {String} title
* @param {Mixed} ...params
*/
constructor(errorCode, ...params) {
constructor(errorCode, title, ...params) {
super(...params);
if (Error.captureStackTrace) {
@ -14,6 +15,7 @@ class ErrorEvent extends Error {
}
this.errorCode = parseInt(errorCode, 10);
this.title = title;
this.date = new Date();
}
}

View file

@ -5,12 +5,19 @@ import xl from "excel4node";
import Pages from "./Pages";
import AlbumsModel from "../models/albums";
import UsersModel from "../models/users";
import ErrorEvent from "../libs/error";
/**
* Classe permettant la gestion des albums d'un utilisateur
*/
class Albums extends Pages {
/**
* Méthode permettant de remplacer certains cartactères par leur équivalents html
* @param {String} str
*
* @return {String}
*/
static replaceSpecialChars(str) {
if (!str) {
return "";
@ -487,7 +494,7 @@ class Albums extends Pages {
static async getAllDistincts(field, user) {
const distincts = await AlbumsModel.find(
{
user,
User: user,
},
[],
{
@ -513,8 +520,11 @@ class Albums extends Pages {
order = "asc",
artists_sort,
format,
userId: collectionUserId,
} = this.req.query;
let userId = this.req.user?._id;
const where = {};
if (artists_sort) {
@ -524,8 +534,35 @@ class Albums extends Pages {
where["formats.name"] = format;
}
if (!this.req.user && !collectionUserId) {
throw new ErrorEvent(
401,
"Cette collection n'est pas publique",
"Cette collection n'est pas publique"
);
}
if (collectionUserId) {
const userIsSharingCollection = await UsersModel.findById(
collectionUserId
);
if (
!userIsSharingCollection ||
!userIsSharingCollection.isPublicCollection
) {
throw new ErrorEvent(
401,
"Cette collection n'est pas publique",
"Cette collection n'est pas publique"
);
}
userId = userIsSharingCollection._id;
}
const count = await AlbumsModel.count({
user: this.req.user._id,
User: userId,
...where,
});
@ -547,7 +584,7 @@ class Albums extends Pages {
const rows = await AlbumsModel.find(
{
user: this.req.user._id,
User: userId,
...where,
},
[],
@ -619,6 +656,29 @@ class Albums extends Pages {
this.setPageContent("item", item);
}
/**
* Méthode permettant de créer la page "collection/:userId"
*/
async loadPublicCollection() {
const { userId } = this.req.params;
const user = await UsersModel.findById(userId);
if (!user || !user.isPublicCollection) {
throw new ErrorEvent(
401,
"Cet utilisateur ne souhaite pas partager sa collection"
);
}
const artists = await Albums.getAllDistincts("artists_sort", userId);
const formats = await Albums.getAllDistincts("formats.name", userId);
this.setPageContent("username", user.username);
this.setPageContent("artists", artists);
this.setPageContent("formats", formats);
}
}
export default Albums;

45
src/middleware/Me.js Normal file
View file

@ -0,0 +1,45 @@
import Joi from "joi";
import UsersModel from "../models/users";
/**
* Classe permettant la gestion de l'utilisateur connecté
*/
class Me {
constructor(req) {
this.req = req;
}
/**
* Méthode permettant de modifier le profil d'un utilisateur
* @return {Object}
*/
async patchMe() {
const { body, user } = this.req;
const schema = Joi.object({
isPublicCollection: Joi.boolean(),
});
const value = await schema.validateAsync(body);
const update = await UsersModel.findByIdAndUpdate(
user._id,
{ $set: value },
{ new: true }
);
await new Promise((resolve, reject) => {
this.req.login(update, (err) => {
if (err) {
return reject(err);
}
return resolve(null);
});
});
return update;
}
}
export default Me;

View file

@ -1,5 +1,7 @@
/* eslint-disable func-names */
/* eslint-disable no-invalid-this */
/* eslint-disable no-param-reassign */
import mongoose from "mongoose";
import uniqueValidator from "mongoose-unique-validator";
import crypto from "crypto";
@ -23,8 +25,20 @@ const UserSchema = new mongoose.Schema(
},
hash: String,
salt: String,
isPublicCollection: {
type: Boolean,
default: false,
},
},
{ timestamps: true }
{
timestamps: true,
toJSON: {
transform(doc, ret) {
delete ret.hash;
delete ret.salt;
},
},
}
);
UserSchema.plugin(uniqueValidator, { message: "est déjà utilisé" });

View file

@ -9,7 +9,7 @@ const router = express.Router();
router
.route("/")
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
.get(async (req, res, next) => {
try {
const albums = new Albums(req);
const data = await albums.getAll();

24
src/routes/api/v1/me.js Normal file
View file

@ -0,0 +1,24 @@
import express from "express";
import { ensureLoggedIn } from "connect-ensure-login";
import { sendResponse } from "../../../libs/format";
import Me from "../../../middleware/Me";
// eslint-disable-next-line new-cap
const router = express.Router();
router
.route("/")
.patch(ensureLoggedIn("/connexion"), async (req, res, next) => {
try {
const me = new Me(req);
const data = await me.patchMe();
return sendResponse(req, res, data);
} catch (err) {
return next(err);
}
});
export default router;

22
src/routes/collection.js Normal file
View file

@ -0,0 +1,22 @@
import express from "express";
import Albums from "../middleware/Albums";
import render from "../libs/format";
// eslint-disable-next-line new-cap
const router = express.Router();
router.route("/:userId").get(async (req, res, next) => {
try {
const page = new Albums(req, "collection");
await page.loadPublicCollection();
render(res, page);
} catch (err) {
next(err);
}
});
export default router;

View file

@ -10,7 +10,7 @@ const router = express.Router();
router.route("/").get(ensureLoggedIn("/connexion"), async (req, res, next) => {
try {
const page = new Albums(req, "mon-compte/ma-collection");
const page = new Albums(req, "mon-compte/ma-collection/index");
await page.loadMyCollection();