forked from dbroqua/MusicTopus
Some changes in structure + add album
This commit is contained in:
parent
3ebdc9c06a
commit
f08e70eb7c
36 changed files with 883 additions and 165 deletions
44
src/app.js
44
src/app.js
|
@ -9,10 +9,14 @@ import MongoStore from "connect-mongo";
|
|||
|
||||
import config, { env, mongoDbUri, secret } from "./config";
|
||||
|
||||
import indexRouter from "./routes/index";
|
||||
import indexRouter from "./routes";
|
||||
import addAlbumRouter from "./routes/addAlbum";
|
||||
import importRouterApiV1 from "./routes/api/v1";
|
||||
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
|
||||
|
||||
// Mongoose schema init
|
||||
require("./models/users");
|
||||
require("./models/albums");
|
||||
|
||||
require("./libs/passport")(passport);
|
||||
|
||||
|
@ -60,7 +64,7 @@ if (["production"].indexOf(env) !== -1) {
|
|||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
app.set("views", path.join(__dirname, "../views"));
|
||||
app.set("view engine", "ejs");
|
||||
|
||||
app.use(express.static(path.join(__dirname, "../public")));
|
||||
|
@ -69,45 +73,65 @@ app.use(
|
|||
express.static(path.join(__dirname, "../node_modules/jquery/dist/"))
|
||||
);
|
||||
app.use(
|
||||
"/libs/mdbootstrap",
|
||||
express.static(path.join(__dirname, "../node_modules/mdbootstrap"))
|
||||
"/libs/mdb-ui-kit/css",
|
||||
express.static(path.join(__dirname, "../node_modules/mdb-ui-kit/css"))
|
||||
);
|
||||
app.use(
|
||||
"/libs/mdb-ui-kit/js",
|
||||
express.static(path.join(__dirname, "../node_modules/mdb-ui-kit/js"))
|
||||
);
|
||||
app.use(
|
||||
"/libs/vue",
|
||||
express.static(path.join(__dirname, "../node_modules/vue/dist"))
|
||||
);
|
||||
app.use(
|
||||
"/libs/axios",
|
||||
express.static(path.join(__dirname, "../node_modules/axios/dist"))
|
||||
);
|
||||
|
||||
app.use("/", indexRouter);
|
||||
app.use("/ajouter-un-album", addAlbumRouter);
|
||||
app.use("/api/v1", importRouterApiV1);
|
||||
app.use("/api/v1/albums", importAlbumRouterApiV1);
|
||||
|
||||
// Handle 404
|
||||
app.use((req, res) => {
|
||||
if (req.xhr) {
|
||||
if (req.xhr || req.rawHeaders.indexOf("application/json") !== -1) {
|
||||
res.status(404).send({ message: "404: Not found" });
|
||||
} else {
|
||||
res.status(404).render("error", {
|
||||
res.status(404).render("index", {
|
||||
page: { title: `404: Cette page n'existe pas.` },
|
||||
errorCode: 404,
|
||||
viewname: "error",
|
||||
user: req.user || null,
|
||||
config,
|
||||
session: req.session || null,
|
||||
flashInfo: null,
|
||||
query: null,
|
||||
params: null,
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Handle 500
|
||||
app.use((error, req, res, next) => {
|
||||
if (req.xhr) {
|
||||
res.status(error.errorCode || 500).send({ message: error.message });
|
||||
if (req.xhr || req.rawHeaders.indexOf("application/json") !== -1) {
|
||||
const { message, errorCode, date } = error;
|
||||
res.status(error.errorCode || 500).send({ message, errorCode, date });
|
||||
} else {
|
||||
res.status(500);
|
||||
res.render("error", {
|
||||
res.status(error.errorCode || 500);
|
||||
res.render("index", {
|
||||
page: { title: "500: Oups… le serveur a crashé !", error },
|
||||
errorCode: error.errorCode || 500,
|
||||
viewname: "error",
|
||||
user: req.user || null,
|
||||
config,
|
||||
session: req.session || null,
|
||||
flashInfo: null,
|
||||
query: null,
|
||||
params: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
next();
|
||||
|
|
|
@ -3,4 +3,5 @@ module.exports = {
|
|||
port: parseInt(process.env.PORT || "3001", 10),
|
||||
mongoDbUri: process.env.MONGODB_URI || "mongodb://nodecdtheque-db/cdtheque",
|
||||
secret: process.env.SECRET || "waemaeMe5ahc6ce1chaeKohKa6Io8Eik",
|
||||
discogsToken: process.env.DISCOGS_TOKEN,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/* eslint-disable import/prefer-default-export */
|
||||
import { Client as Discogs } from "disconnect";
|
||||
|
||||
import { discogsToken } from "../config";
|
||||
|
||||
export const getBaseUrl = (req) => `${req.protocol}://${req.get("host")}`;
|
||||
|
||||
export const searchSong = async (q) => {
|
||||
const dis = new Discogs({ userToken: discogsToken }).database();
|
||||
|
||||
const res = await dis.search({
|
||||
q,
|
||||
type: "release",
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getAlbumDetails = async (id) => {
|
||||
const dis = new Discogs({ userToken: discogsToken }).database();
|
||||
|
||||
const res = await dis.getRelease(id);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
|
21
src/libs/error.js
Normal file
21
src/libs/error.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Classe permettant la gestion des erreurs personilisées
|
||||
*/
|
||||
class ErrorEvent extends Error {
|
||||
/**
|
||||
* @param {Number} errorCode
|
||||
* @param {Mixed} ...params
|
||||
*/
|
||||
constructor(errorCode, ...params) {
|
||||
super(...params);
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, ErrorEvent);
|
||||
}
|
||||
|
||||
this.errorCode = parseInt(errorCode, 10);
|
||||
this.date = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorEvent;
|
|
@ -1,3 +1,39 @@
|
|||
/**
|
||||
* Fonction permettant de formater une réponse basée sur la méthode utilisée
|
||||
* @param {Object} req
|
||||
* @param {Object} res
|
||||
* @param {Object} data
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
export const sendResponse = (req, res, data) => {
|
||||
let status = 200;
|
||||
const path = req.route.path.split("/");
|
||||
|
||||
switch (req.method) {
|
||||
case "GET":
|
||||
// INFO: On regarde de quel type de get il s'agit (liste ou item)
|
||||
if (path[path.length - 1].indexOf(":") === 0) {
|
||||
// INFO: Cas d'un item
|
||||
status = !data ? 404 : 200;
|
||||
} else {
|
||||
// INFO: Cas d'une liste
|
||||
status =
|
||||
data.rows === undefined || data.rows.length > 0 ? 200 : 204;
|
||||
}
|
||||
|
||||
return res.status(status).json(data).end();
|
||||
case "PATCH":
|
||||
return res.status(200).json(data).end();
|
||||
case "DELETE":
|
||||
return res.status(200).json(data).end();
|
||||
case "POST":
|
||||
return res.status(201).json(data).end();
|
||||
default:
|
||||
return res.status(500).json({ message: "Not implemented" });
|
||||
}
|
||||
};
|
||||
|
||||
export default (res, page) => {
|
||||
res.status(200).render("index", page.render());
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names */
|
||||
const mongoose = require("mongoose");
|
||||
const LocalStrategy = require("passport-local").Strategy;
|
||||
const { BasicStrategy } = require("passport-http");
|
||||
|
||||
const Users = mongoose.model("Users");
|
||||
|
||||
|
@ -36,4 +37,22 @@ module.exports = function (passport) {
|
|||
}
|
||||
)
|
||||
);
|
||||
passport.use(
|
||||
"basic",
|
||||
new BasicStrategy((email, password, done) => {
|
||||
Users.findOne({ email })
|
||||
.then((user) => {
|
||||
if (!user || !user.validPassword(password)) {
|
||||
return done(
|
||||
null,
|
||||
false,
|
||||
"Oops! Identifiants incorrects"
|
||||
);
|
||||
}
|
||||
|
||||
return done(null, user);
|
||||
})
|
||||
.catch(done);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
85
src/middleware/Albums.js
Normal file
85
src/middleware/Albums.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
import moment from "moment";
|
||||
|
||||
import Pages from "./Pages";
|
||||
|
||||
import { getAlbumDetails } from "../helpers";
|
||||
|
||||
import AlbumsModel from "../models/albums";
|
||||
|
||||
/**
|
||||
* Classe permettant la gestion des albums d'un utilisateur
|
||||
*/
|
||||
class Albums extends Pages {
|
||||
async getFormAddOne() {
|
||||
const data = await getAlbumDetails(this.req.params.discogsId);
|
||||
|
||||
const {
|
||||
id, // Integer
|
||||
year, // - Integer
|
||||
uri, // String
|
||||
artists, // - Array<Object>
|
||||
artists_sort, // String
|
||||
labels, // - Array<Object>
|
||||
series, // Array
|
||||
companies, // - Array<Object>
|
||||
formats, // - Array<Object>
|
||||
title, // - String
|
||||
country, // - String
|
||||
released, // - Date
|
||||
notes, // - String
|
||||
identifiers, // - Array<Object>
|
||||
videos, // - Array<Object>
|
||||
genres, // - Array<String>
|
||||
styles, // - Array<String>
|
||||
tracklist, // - Array<Object>
|
||||
extraartists, // - Array<Object>
|
||||
images, // - Array<Object
|
||||
thumb, // - String
|
||||
} = data;
|
||||
|
||||
this.pageContent.page.values = "test";
|
||||
|
||||
this.setPageContent("values", {
|
||||
id,
|
||||
year,
|
||||
uri,
|
||||
artists,
|
||||
artists_sort,
|
||||
labels,
|
||||
series,
|
||||
companies,
|
||||
formats,
|
||||
title,
|
||||
country,
|
||||
released,
|
||||
notes,
|
||||
identifiers,
|
||||
videos,
|
||||
genres,
|
||||
styles,
|
||||
tracklist,
|
||||
extraartists,
|
||||
images,
|
||||
thumb,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static async postAddOne(req) {
|
||||
const { body, user } = req;
|
||||
const data = {
|
||||
...body,
|
||||
discogsId: body.id,
|
||||
User: user._id,
|
||||
};
|
||||
data.released = moment(data.released.replace("-00", "-01"));
|
||||
delete data.id;
|
||||
|
||||
const album = new AlbumsModel(data);
|
||||
|
||||
return album.save();
|
||||
}
|
||||
}
|
||||
|
||||
export default Albums;
|
|
@ -34,6 +34,10 @@ class Pages {
|
|||
}
|
||||
}
|
||||
|
||||
setPageContent(field, value) {
|
||||
this.pageContent.page[field] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendu de la page
|
||||
* @return {Object}
|
||||
|
@ -46,7 +50,7 @@ class Pages {
|
|||
this.pageContent.params = this.req.params;
|
||||
this.pageContent.user = this.user;
|
||||
this.pageContent.config = config;
|
||||
this.pageContent.getBaseUrl = getBaseUrl();
|
||||
this.pageContent.getBaseUrl = getBaseUrl(this.req);
|
||||
|
||||
if (this.req.session.flash && this.req.session.flash.error) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
|
|
36
src/models/albums.js
Normal file
36
src/models/albums.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import mongoose from "mongoose";
|
||||
|
||||
const { Schema } = mongoose;
|
||||
|
||||
const AlbumSchema = new mongoose.Schema(
|
||||
{
|
||||
User: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Users",
|
||||
},
|
||||
discogsId: Number,
|
||||
year: Number,
|
||||
released: Date,
|
||||
uri: String,
|
||||
artists: Array,
|
||||
artists_sort: String,
|
||||
labels: Array,
|
||||
series: Array,
|
||||
companies: Array,
|
||||
formats: Array,
|
||||
title: String,
|
||||
country: String,
|
||||
notes: String,
|
||||
identifiers: Array,
|
||||
videos: Array,
|
||||
genres: Array,
|
||||
styles: Array,
|
||||
tracklist: Array,
|
||||
extraartists: Array,
|
||||
images: Array,
|
||||
thumb: String,
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export default mongoose.model("Albums", AlbumSchema);
|
35
src/routes/addAlbum.js
Normal file
35
src/routes/addAlbum.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import express from "express";
|
||||
import { ensureLoggedIn } from "connect-ensure-login";
|
||||
|
||||
import Pages from "../middleware/Albums";
|
||||
|
||||
import render from "../libs/format";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const router = express.Router();
|
||||
|
||||
router.route("/").get(ensureLoggedIn("/connexion"), (req, res, next) => {
|
||||
try {
|
||||
const page = new Pages(req, "ajouter-un-album/search");
|
||||
|
||||
render(res, page);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
router
|
||||
.route("/:discogsId")
|
||||
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||
try {
|
||||
const page = new Pages(req, "ajouter-un-album/form");
|
||||
|
||||
await page.getFormAddOne();
|
||||
|
||||
render(res, page);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
20
src/routes/api/v1/albums.js
Normal file
20
src/routes/api/v1/albums.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import express from "express";
|
||||
import { ensureLoggedIn } from "connect-ensure-login";
|
||||
|
||||
import { sendResponse } from "../../../libs/format";
|
||||
import Albums from "../../../middleware/Albums";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const router = express.Router();
|
||||
|
||||
router.route("/").post(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||
try {
|
||||
const data = await Albums.postAddOne(req);
|
||||
|
||||
sendResponse(req, res, data);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
22
src/routes/api/v1/index.js
Normal file
22
src/routes/api/v1/index.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import express from "express";
|
||||
import { ensureLoggedIn } from "connect-ensure-login";
|
||||
|
||||
import { sendResponse } from "../../../libs/format";
|
||||
import { searchSong } from "../../../helpers";
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const router = express.Router();
|
||||
|
||||
router
|
||||
.route("/search")
|
||||
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||
try {
|
||||
const data = await searchSong(req.query.q);
|
||||
|
||||
sendResponse(req, res, data);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<%- include('partials/head', {page: page, user: user}); %>
|
||||
|
||||
<body class="error">
|
||||
<%- include('partials/header'); %>
|
||||
<main class="mt-4">
|
||||
<div class="container">
|
||||
<section class="px-md-5 mx-md-5 dark-grey-text mb-4">
|
||||
<h1><%= page.title %></h1>
|
||||
<% if ( errorCode && errorCode === 404 ) { %>
|
||||
<img src="/img/404.svg" alt="Erreur 404" style="max-height: 400px;" />
|
||||
<% } %>
|
||||
<p class="lead">
|
||||
<%= page.error %>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<%- include('partials/footer', {page: page, user: user, blog: null}); %>
|
||||
</body>
|
||||
</html>
|
|
@ -1,27 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<%- include('partials/head'); %>
|
||||
<body>
|
||||
<%- include('partials/header'); %>
|
||||
|
||||
<% if ( page.failureFlash ) {%>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= page.failureFlash %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<%
|
||||
if (error && error.length > 0) {
|
||||
for( let i = 0 ; i < error.length ; i += 1 ) {
|
||||
%>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= error %>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
<%- include(viewname) %>
|
||||
<%- include('partials/footer'); %>
|
||||
</body>
|
||||
</html>
|
|
@ -1,24 +0,0 @@
|
|||
<div class="container">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="p-2">
|
||||
<form class="text-center border border-light p-5" method="POST">
|
||||
<img class="mb-4" src="/img/logo.png" alt="DarKou">
|
||||
<p class="h4 mb-4">Connexion</p>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="email" id="email" name="email" class="form-control" required>
|
||||
<label for="email">Adresse e-mail</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="password" id="password" name="password" class="form-control" required>
|
||||
<label for="password">Mot de passe</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-block my-4" type="submit">Connexion</button>
|
||||
|
||||
<p>Pas encore inscrit ? <a href="/inscription">Inscrivez-vous</a></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,29 +0,0 @@
|
|||
<div class="container">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="p-2">
|
||||
<form class="text-center border border-light p-5" method="POST">
|
||||
<img class="mb-4" src="/img/logo.png" alt="DarKou">
|
||||
<p class="h4 mb-4">Inscription</p>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="text" id="username" name="username" class="form-control" required>
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="email" id="email" name="email" class="form-control" required>
|
||||
<label for="email">Adresse e-mail</label>
|
||||
</div>
|
||||
|
||||
<div class="md-form">
|
||||
<input type="password" id="password" name="password" class="form-control" required>
|
||||
<label for="password">Mot de passe</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-block my-4" type="submit">Inscription</button>
|
||||
|
||||
<p>Déjà inscrit ? <a href="/connexion">Connectez-vous</a></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<script type="text/javascript" src="/libs/mdbootstrap/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/popper.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/libs/mdbootstrap/js/mdb.min.js"></script>
|
||||
<script type="text/javascript" src="/js/main.js"></script>
|
|
@ -1,17 +0,0 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title><% if (page.title) { %><%= page.title %> <% } else { %> DarKou - Ma CDThèque <% } %></title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.11.2/css/all.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/mdb.min.css">
|
||||
<link rel="stylesheet" href="/libs/mdbootstrap/css/style.css">
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css" />
|
||||
</head>
|
|
@ -1,24 +0,0 @@
|
|||
<nav class="navbar navbar-expand-md navbar-dark primary-color sticky-top">
|
||||
<a class="navbar-brand" href="/">CDThèque</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<% if ( user ) { %>
|
||||
<div class="navbar-collapse collapse w-100 order-1 dual-collapse2">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/upload">Ajouter une image</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Mon compte</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="/gallery">Mes images</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/se-deconnecter">Déconnexion</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</nav>
|
Loading…
Add table
Add a link
Reference in a new issue