diff --git a/README.md b/README.md
index fdc754d..1da497b 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Le code source est publié sous licence libre [GNU GPL-3.0-or-later](LICENSE) et
Vous pouvez librement utiliser le service en vous inscrivant sur [https://www.musictopus.fr/](https://www.musictopus.fr/).
-Une fois inscrit vous pourrez saisir vos CDs et Vinyles sur votre espace personnel le tout gratuitement, sans tracker et sans utilisation de vos données personnelles !
+Une fois inscrit vous pourrez saisir vos CDs et Vinyles sur votre espace personnel le tout gratuitement, sans tracker (en dehors de statistiques web via [Matomo](https://fr.matomo.org/)) et sans utilisation de vos données personnelles !
## Auto hébergement
@@ -195,9 +195,13 @@ MONGODB_URI # Url du serveur mongo (par défaut mongodb://musictopus-db/musictop
SECRET # Hash utilisé pour pour sauvegardé les dessions (par défaut waemaeMe5ahc6ce1chaeKohKa6Io8Eik)
DISCOGS_TOKEN # Token Discogs (vous devez créer un compte sur discogs afin d'en obtenir un gratuitement)
FORMSPREE_ID # Id du formulaire formspree pour la page "nous-contacter"
+MATOMO_URL # Url vers l'instance matomo (exemple: https://analytics.darkou.fr/)
+MATOMO_ID # Id du site sur votre instance matomo (exemple: 1)
+SITE_NAME # Nom du site (utilisé dans le titre des pages)
```
## Contributeurs
- Damien Broqua (développeur principal du projet)
-- Brunus (Logo et fournisseur d'idées :wink: )
\ No newline at end of file
+- Brunus (Logo et fournisseur d'idées :wink: )
+
diff --git a/docker-compose.yml.dev b/docker-compose.yml.dev
index b14864f..9391624 100644
--- a/docker-compose.yml.dev
+++ b/docker-compose.yml.dev
@@ -25,6 +25,9 @@ services:
SECRET: ${SECRET}
DISCOGS_TOKEN: ${DISCOGS_TOKEN}
FORMSPREE_ID: ${FORMSPREE_ID}
+ MATOMO_URL: ${MATOMO_URL}
+ MATOMO_ID: ${MATOMO_ID}
+ SITE_NAME: ${SITE_NAME}
networks:
- musictopus
musictopus-db:
diff --git a/docker-compose.yml.prod b/docker-compose.yml.prod
index d314748..9077877 100644
--- a/docker-compose.yml.prod
+++ b/docker-compose.yml.prod
@@ -25,6 +25,9 @@ services:
SECRET: ${SECRET}
DISCOGS_TOKEN: ${DISCOGS_TOKEN}
FORMSPREE_ID: ${FORMSPREE_ID}
+ MATOMO_URL: ${MATOMO_URL}
+ MATOMO_ID: ${MATOMO_ID}
+ SITE_NAME: ${SITE_NAME}
networks:
- musictopus
musictopus-db:
diff --git a/package.json b/package.json
index 8c53d5a..b5aea27 100644
--- a/package.json
+++ b/package.json
@@ -27,9 +27,6 @@
},
"license": "GPL-3.0-or-later",
"devDependencies": {
- "@babel/cli": "^7.17.0",
- "@babel/core": "^7.17.2",
- "@babel/preset-env": "^7.16.11",
"eslint": "^8.9.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.3.0",
@@ -38,11 +35,12 @@
"husky": "^7.0.4",
"lint-staged": "^12.3.3",
"nodemon": "^2.0.15",
- "npm-run-all": "^4.1.5",
- "prettier": "^2.5.1",
- "rimraf": "^3.0.2"
+ "prettier": "^2.5.1"
},
"dependencies": {
+ "@babel/cli": "^7.17.0",
+ "@babel/core": "^7.17.2",
+ "@babel/preset-env": "^7.16.11",
"axios": "^0.26.0",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
@@ -54,14 +52,17 @@
"excel4node": "^1.7.2",
"express": "^4.17.2",
"express-session": "^1.17.2",
+ "joi": "^17.6.0",
"knacss": "^8.0.4",
"moment": "^2.29.1",
"moment-timezone": "^0.5.34",
"mongoose": "^6.2.1",
"mongoose-unique-validator": "^3.0.0",
+ "npm-run-all": "^4.1.5",
"passport": "^0.5.2",
"passport-http": "^0.3.0",
"passport-local": "^1.0.0",
+ "rimraf": "^3.0.2",
"sass": "^1.49.7",
"vue": "^3.2.31"
},
diff --git a/public/500.html b/public/500.html
index 072dfd0..76eb123 100644
--- a/public/500.html
+++ b/public/500.html
@@ -4,7 +4,7 @@
-
Site en maintenance
+ MusicTopus - Erreur applicative
@@ -17,37 +17,10 @@
-
-
-
-
-
- Site inaccessible
-
-
- Pas de panique on revient très vite !
-
-
-
-
+
+
+ Nous sommes désolé mais quelque chose a mal tourné de notre côté.
+
+ On devrait revenir très vite ! 😅
diff --git a/public/font/icon.eot b/public/font/icon.eot
index 5a5d395..a17c0f6 100644
Binary files a/public/font/icon.eot and b/public/font/icon.eot differ
diff --git a/public/font/icon.svg b/public/font/icon.svg
index 51f7015..d5ac2f6 100644
--- a/public/font/icon.svg
+++ b/public/font/icon.svg
@@ -34,6 +34,8 @@
+
+
diff --git a/public/font/icon.ttf b/public/font/icon.ttf
index 488fa0b..4ccfa6d 100644
Binary files a/public/font/icon.ttf and b/public/font/icon.ttf differ
diff --git a/public/font/icon.woff b/public/font/icon.woff
index 7c3262d..3262198 100644
Binary files a/public/font/icon.woff and b/public/font/icon.woff differ
diff --git a/public/font/icon.woff2 b/public/font/icon.woff2
index ac6af3a..f73baf4 100644
Binary files a/public/font/icon.woff2 and b/public/font/icon.woff2 differ
diff --git a/public/img/404.svg b/public/img/404.svg
index c963bb6..b4dbe78 100644
--- a/public/img/404.svg
+++ b/public/img/404.svg
@@ -1 +1,343 @@
-
\ No newline at end of file
+
+
diff --git a/public/img/logo.svg b/public/img/logo.svg
deleted file mode 100644
index 7ceed9f..0000000
--- a/public/img/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/js/main.js b/public/js/main.js
index 994b2ae..895683a 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -2,13 +2,16 @@
* Fonction permettant d'afficher un message dans un toastr
* @param {String} message
*/
- function showToastr(message) {
+ function showToastr(message, success = false) {
let x = document.getElementById("toastr");
if ( message ) {
x.getElementsByTagName("SPAN")[0].innerHTML = message;
}
- x.className = `${x.className} show`;
+ x.className = `${x.className} show`.replace("sucess", "");
+ if ( success ) {
+ x.className = `${x.className} success`;
+ }
setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);
};
diff --git a/public/mstile-310x150.png b/public/mstile-310x150.png
deleted file mode 100644
index ed34b0c..0000000
Binary files a/public/mstile-310x150.png and /dev/null differ
diff --git a/sass/500.scss b/sass/500.scss
new file mode 100644
index 0000000..910f8dd
--- /dev/null
+++ b/sass/500.scss
@@ -0,0 +1,22 @@
+.body-500 {
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ font-weight: 400;
+ font-size: larger;
+ line-height: 200%;
+
+ text-align: center;
+
+ img {
+ max-width: 60%;
+ margin-bottom: 32px;
+
+ @include respond-to("small-up") {
+ max-width: 30%;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sass/button.scss b/sass/button.scss
index 1d8c946..1fd0e5d 100644
--- a/sass/button.scss
+++ b/sass/button.scss
@@ -54,7 +54,7 @@
&.is-link {
background-color: transparent;
border-color: $nord9;
- color: $nord9;
+ color: var(--button-link-text-color);
&:hover {
border-color: darken($nord9, $hoverAmount);
diff --git a/sass/ma-collection.scss b/sass/collection.scss
similarity index 90%
rename from sass/ma-collection.scss
rename to sass/collection.scss
index af22f2a..6412fe1 100644
--- a/sass/ma-collection.scss
+++ b/sass/collection.scss
@@ -1,4 +1,9 @@
-.ma-collection {
+.collection {
+ h1 {
+ i {
+ cursor: pointer;
+ }
+ }
.filters {
display: flex;
justify-content: end;
diff --git a/sass/colors.scss b/sass/colors.scss
index 5759f90..441062c 100644
--- a/sass/colors.scss
+++ b/sass/colors.scss
@@ -29,7 +29,7 @@ $danger-color-hl: darken($danger-color, $hoverAmount);
$warning-color-hl: darken($warning-color, $hoverAmount);
$success-color-hl: darken($success-color, $hoverAmount);
-$button-font-color: $nord1;
+$button-font-color: #2C364A;
$button-alternate-color: #01103C;
$pagination-border-color: $nord3;
@@ -38,6 +38,7 @@ $pagination-hover-color: rgb(115, 151, 186);
:root {
--default-color: #{$white};
--bg-color: #{darken($white, 5%)};
+ --bg-alternate-color: #{darken($white, 8%)};
--font-color: #{$nord3};
--footer-color: #{$darken-white};
--link-color: #{$nord1};
@@ -45,18 +46,38 @@ $pagination-hover-color: rgb(115, 151, 186);
--input-font-color: #{$nord3};
--input-color: #{$white};
--input-active-color: #{$nord5};
-
+
--navbar-color: #{darken($white, 5%)};
--box-bg-color: #F8F9FB;
--box-shadow-color: #{rgba($nord4, 0.35)};
--border-color: #{$nord4};
+
+ --button-link-text-color: #2C364A;
+
+ --nord0: #{$nord0};
+ --nord1: #{$nord1};
+ --nord2: #{$nord2};
+ --nord3: #{$nord3};
+ --nord4: #{$nord4};
+ --nord5: #{$nord5};
+ --nord6: #{$nord6};
+ --nord7: #{$nord7};
+ --nord8: #{$nord8};
+ --nord9: #{$nord9};
+ --nord10: #{$nord10};
+ --nord11: #{$nord11};
+ --nord12: #{$nord12};
+ --nord13: #{$nord13};
+ --nord14: #{$nord14};
+ --nord15: #{$nord15};
}
[data-theme="dark"] {
--default-color: #{$nord3};
--bg-color: #{lighten($nord0, 2%)};
+ --bg-alternate-color: #{lighten($nord3, 8%)};
--font-color: #{$nord6};
--footer-color: #{$nord1};
--link-color: #{$nord4};
@@ -71,4 +92,6 @@ $pagination-hover-color: rgb(115, 151, 186);
--box-shadow-color: #{rgba($nord4, 0.2)};
--border-color: #{$nord1};
+
+ --button-link-text-color: #{$white};
}
\ No newline at end of file
diff --git a/sass/composants.scss b/sass/composants.scss
new file mode 100644
index 0000000..b9d4e65
--- /dev/null
+++ b/sass/composants.scss
@@ -0,0 +1,13 @@
+.composants {
+ .couleur {
+ margin-bottom: 1rem;
+ text-align: center;
+
+ border: 1px solid var(--input-active-color);
+ box-shadow: var(--box-shadow-color) 0px 3px 6px 0px;
+
+ div {
+ height: 56px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sass/global.scss b/sass/global.scss
index 491b9ca..454cd14 100644
--- a/sass/global.scss
+++ b/sass/global.scss
@@ -82,4 +82,8 @@ html {
@include respond-to("small-up") {
display: initial;
}
+}
+
+.is-danger {
+ color: $nord12;
}
\ No newline at end of file
diff --git a/sass/icons.scss b/sass/icons.scss
index ca297ea..4250307 100644
--- a/sass/icons.scss
+++ b/sass/icons.scss
@@ -46,6 +46,7 @@
.icon-link-ext:before { content: '\f08e'; } /* '' */
.icon-sun:before { content: '\f185'; } /* '' */
.icon-moon:before { content: '\f186'; } /* '' */
+.icon-share:before { content: '\f1e0'; } /* '' */
.icon-trash:before { content: '\f1f8'; } /* '' */
.icon-blind:before { content: '\f29d'; } /* '' */
@@ -61,4 +62,4 @@
100% {
transform: rotate(359deg);
}
-}
\ No newline at end of file
+}
diff --git a/sass/index.scss b/sass/index.scss
index aa7557a..3a53fd2 100644
--- a/sass/index.scss
+++ b/sass/index.scss
@@ -41,7 +41,9 @@
@import './box';
@import './error';
+@import './500';
@import './home';
@import './ajouter-un-album';
-@import './ma-collection';
-@import './ma-collection-details';
\ No newline at end of file
+@import './collection';
+@import './ma-collection-details';
+@import './composants';
\ No newline at end of file
diff --git a/sass/list.scss b/sass/list.scss
index 7c479ff..9dbd03a 100644
--- a/sass/list.scss
+++ b/sass/list.scss
@@ -3,30 +3,35 @@
.item{
padding: 0.5rem 0.75rem;
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 2px solid var(--border-color);
+ background-color: var(--bg-alternate-color);
@include transition() {}
@include respond-to("medium") {
&:nth-child(2n) {
background-color: var(--default-color);
}
+ border: none;
}
+
@include respond-to("medium-up") {
- border-left: 1px solid var(--border-color);
+ border-left: 2px solid var(--border-color);
+
+ &:nth-child(4n),
+ &:nth-child(4n-1)
+ {
+ background-color: var(--default-color);
+ }
&:first-child,
&:nth-child(2) {
- border-top: 1px solid var(--border-color);
+ border-top: 2px solid var(--border-color);
}
&:nth-child(2n),
&:last-child {
- border-right: 1px solid var(--border-color);
- margin-right: -1px;
- }
-
- &:hover {
- background-color: var(--default-color);
+ border-right: 2px solid var(--border-color);
+ margin-right: -2px;
}
}
@@ -44,4 +49,10 @@
max-width: 90%;
}
}
+
+ &.hover {
+ .item:hover {
+ background-color: var(--border-color);
+ }
+ }
}
\ No newline at end of file
diff --git a/sass/ma-collection-details.scss b/sass/ma-collection-details.scss
index 6d4ba32..952a026 100644
--- a/sass/ma-collection-details.scss
+++ b/sass/ma-collection-details.scss
@@ -16,6 +16,7 @@
img {
max-width: 90%;
+ max-height: 90%;
}
}
}
diff --git a/sass/toast.scss b/sass/toast.scss
index 21d1730..46777e7 100644
--- a/sass/toast.scss
+++ b/sass/toast.scss
@@ -13,6 +13,11 @@
color: $button-alternate-color;
border-radius: 6px;
+ &.success {
+ background-color: $success-color;
+ color: $button-font-color;
+ }
+
&.show {
visibility: visible;
animation: toastrFadein 0.5s, toastrFadeout 0.5s 2.5s;
diff --git a/src/app.js b/src/app.js
index 0b32d82..6d1e507 100644
--- a/src/app.js
+++ b/src/app.js
@@ -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,
diff --git a/src/config/index.js b/src/config/index.js
index 43158f5..19f16ea 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -5,4 +5,7 @@ module.exports = {
secret: process.env.SECRET || "waemaeMe5ahc6ce1chaeKohKa6Io8Eik",
discogsToken: process.env.DISCOGS_TOKEN,
formspreeId: process.env.FORMSPREE_ID,
+ matomoUrl: process.env.MATOMO_URL || "",
+ matomoId: process.env.MATOMO_ID || "",
+ siteName: process.env.SITE_NAME || "MusicTopus",
};
diff --git a/src/libs/error.js b/src/libs/error.js
index 562265f..13470f2 100644
--- a/src/libs/error.js
+++ b/src/libs/error.js
@@ -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();
}
}
diff --git a/src/middleware/Albums.js b/src/middleware/Albums.js
index 4796207..6caa29b 100644
--- a/src/middleware/Albums.js
+++ b/src/middleware/Albums.js
@@ -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,
},
[],
@@ -604,6 +641,7 @@ class Albums extends Pages {
this.setPageContent("artists", artists);
this.setPageContent("formats", formats);
+ this.setPageTitle("Ma collection");
}
/**
@@ -618,6 +656,33 @@ class Albums extends Pages {
});
this.setPageContent("item", item);
+ this.setPageTitle(
+ `Détails de l'album ${item.title} de ${item.artists_sort}`
+ );
+ }
+
+ /**
+ * 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.setPageTitle(`Collection publique de ${user.username}`);
+ this.setPageContent("artists", artists);
+ this.setPageContent("formats", formats);
}
}
diff --git a/src/middleware/Me.js b/src/middleware/Me.js
new file mode 100644
index 0000000..ae2712c
--- /dev/null
+++ b/src/middleware/Me.js
@@ -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;
diff --git a/src/middleware/Pages.js b/src/middleware/Pages.js
index e5a59af..eb3ea75 100644
--- a/src/middleware/Pages.js
+++ b/src/middleware/Pages.js
@@ -34,6 +34,10 @@ class Pages {
}
}
+ setPageTitle(title) {
+ this.pageContent.page.title = title;
+ }
+
setPageContent(field, value) {
this.pageContent.page[field] = value;
}
diff --git a/src/models/users.js b/src/models/users.js
index 0807ccb..96629c0 100644
--- a/src/models/users.js
+++ b/src/models/users.js
@@ -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é" });
diff --git a/src/routes/api/v1/albums.js b/src/routes/api/v1/albums.js
index 164ea40..e1caa1f 100644
--- a/src/routes/api/v1/albums.js
+++ b/src/routes/api/v1/albums.js
@@ -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();
@@ -19,9 +19,11 @@ router
case "csv":
case "musictopus":
res.header("Content-Type", "text/csv");
+ res.attachment("export-musictopus.csv");
return res.status(200).send(data);
case "xml":
res.header("Content-type", "text/xml");
+ res.attachment("export-musictopus.xml");
return res.status(200).send(data);
case "xls":
return data.write("musictopus.xls", res);
diff --git a/src/routes/api/v1/me.js b/src/routes/api/v1/me.js
new file mode 100644
index 0000000..42c46b9
--- /dev/null
+++ b/src/routes/api/v1/me.js
@@ -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;
diff --git a/src/routes/collection.js b/src/routes/collection.js
new file mode 100644
index 0000000..6584992
--- /dev/null
+++ b/src/routes/collection.js
@@ -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;
diff --git a/src/routes/index.js b/src/routes/index.js
index 95c9a45..ac43a51 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -14,6 +14,8 @@ router.route("/").get((req, res, next) => {
try {
const page = new Pages(req, "home");
+ page.setPageTitle("Présentation du projet");
+
render(res, page);
} catch (err) {
next(err);
@@ -26,6 +28,8 @@ router
try {
const page = new Pages(req, "connexion");
+ page.setPageTitle("Connexion");
+
render(res, page);
} catch (err) {
next(err);
@@ -61,6 +65,8 @@ router
try {
const page = new Pages(req, "inscription");
+ page.setPageTitle("Inscription");
+
render(res, page);
} catch (err) {
next(err);
@@ -82,6 +88,8 @@ router
try {
const page = new Pages(req, "ajouter-un-album");
+ page.setPageTitle("Ajouter un album");
+
render(res, page);
} catch (err) {
next(err);
@@ -92,6 +100,8 @@ router.route("/nous-contacter").get(async (req, res, next) => {
try {
const page = new Pages(req, "nous-contacter");
+ page.setPageTitle("Nous contacter");
+
render(res, page);
} catch (err) {
next(err);
@@ -102,6 +112,8 @@ router.route("/composants").get(async (req, res, next) => {
try {
const page = new Pages(req, "composants");
+ page.setPageTitle("Les composants");
+
render(res, page);
} catch (err) {
next(err);
diff --git a/src/routes/ma-collection.js b/src/routes/ma-collection.js
index 51ff0ee..9c217bf 100644
--- a/src/routes/ma-collection.js
+++ b/src/routes/ma-collection.js
@@ -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();
@@ -30,6 +30,8 @@ router
try {
const page = new Albums(req, "mon-compte/ma-collection/exporter");
+ page.setPageTitle("Exporter ma collection");
+
render(res, page);
} catch (err) {
next(err);
diff --git a/views/error.ejs b/views/error.ejs
index b0e5112..8f80430 100644
--- a/views/error.ejs
+++ b/views/error.ejs
@@ -5,7 +5,9 @@
<% } %>
+ <% if ( process.env.NODE_ENV !== 'production' ) { %>
+ <% } %>
\ No newline at end of file
diff --git a/views/index.ejs b/views/index.ejs
index ddf0b8c..a2a98b5 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -4,7 +4,7 @@
- <% if (page.title) { %><%= page.title %> <% } else { %> DarKou - MusicTopus <% } %>
+ <%= config.siteName %> :: <%= page.title %>
@@ -19,6 +19,24 @@
+
+ <% if ( config.matomoUrl ) { %>
+
+
+
+ <% } %>