diff --git a/gulpfile.js b/gulpfile.js
index 8e76f38..fe1fe6f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -10,6 +10,7 @@ const babel = require("gulp-babel");
const sourceJs = "javascripts/**/*.js";
const sourceRemoteJS = [
"./node_modules/vue/dist/vue.global.prod.js",
+ "./node_modules/chart.js/dist/chart.umd.js",
"./node_modules/axios/dist/axios.min.js",
];
diff --git a/javascripts/mon-compte/index.js b/javascripts/mon-compte/index.js
index 2fb6f0f..6faa615 100644
--- a/javascripts/mon-compte/index.js
+++ b/javascripts/mon-compte/index.js
@@ -1,4 +1,3 @@
-
if (typeof email !== "undefined" && typeof username !== "undefined") {
Vue.createApp({
data() {
diff --git a/package-lock.json b/package-lock.json
index 1a49ca9..64fdc92 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"axios": "^0.26.0",
+ "chart.js": "^4.4.1",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
"connect-mongo": "^4.6.0",
@@ -5257,6 +5258,11 @@
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"license": "MIT"
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+ },
"node_modules/@mongodb-js/saslprep": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz",
@@ -7913,6 +7919,17 @@
"node": ">=4"
}
},
+ "node_modules/chart.js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz",
+ "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=7"
+ }
+ },
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
diff --git a/package.json b/package.json
index e8815fb..690739a 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"axios": "^0.26.0",
+ "chart.js": "^4.4.1",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
"connect-mongo": "^4.6.0",
diff --git a/src/app.js b/src/app.js
index b293a37..e9fcc0b 100644
--- a/src/app.js
+++ b/src/app.js
@@ -150,4 +150,6 @@ app.use((error, req, res, next) => {
}
});
+console.log("Server ready!");
+
export default app;
diff --git a/src/middleware/Albums.js b/src/middleware/Albums.js
index 59d6c5c..749de9a 100644
--- a/src/middleware/Albums.js
+++ b/src/middleware/Albums.js
@@ -162,6 +162,29 @@ Publié automatiquement via #musictopus`;
return distincts;
}
+ constructor(req, viewname) {
+ super(req, viewname);
+
+ this.colors = {
+ nord0: "#2e3440",
+ nord1: "#3b4252",
+ nord2: "#434c5e",
+ nord3: "#4C566A",
+ nord4: "#d8dee9",
+ nord5: "#e5e9f0",
+ nord6: "#eceff4",
+ nord7: "#8fbcbb",
+ nord8: "#88c0d0",
+ nord9: "#81a1c1",
+ nord10: "#5e81ac",
+ nord11: "#d08770",
+ nord12: "#bf616a",
+ nord13: "#ebcb8b",
+ nord14: "#a3be8c",
+ nord15: "#b48ead",
+ };
+ }
+
/**
* Méthode permettant de récupérer la liste des albums d'une collection
* @return {Object}
@@ -500,6 +523,106 @@ Publié automatiquement via #musictopus`;
await this.loadItem();
}
+ /**
+ * Méthode permettant d'afficher des statistiques au sujet de ma collection
+ */
+ async statistics() {
+ const { _id: User } = this.req.user;
+ const top = {};
+ const byGenres = {};
+ const byStyles = {};
+ const byFormats = {};
+ const top10 = [];
+
+ const albums = await AlbumsModel.find({
+ User,
+ artists: { $exists: true, $not: { $size: 0 } },
+ });
+
+ for (let i = 0; i < albums.length; i += 1) {
+ const currentFormats = [];
+ const { artists, genres, styles, formats } = albums[i];
+
+ // INFO: On regroupe les artistes par nom pour en faire le top10
+ for (let j = 0; j < artists.length; j += 1) {
+ const { name } = artists[j];
+ if (!top[name]) {
+ top[name] = {
+ name,
+ count: 0,
+ };
+ }
+ top[name].count += 1;
+ }
+
+ // INFO: On regroupe les genres
+ for (let j = 0; j < genres.length; j += 1) {
+ const name = genres[j];
+ if (!byGenres[name]) {
+ byGenres[name] = {
+ name,
+ count: 0,
+ color: this.colors[
+ `nord${Object.keys(byGenres).length % 15}`
+ ],
+ };
+ }
+
+ byGenres[name].count += 1;
+ }
+
+ // INFO: On regroupe les styles
+ for (let j = 0; j < styles.length; j += 1) {
+ const name = styles[j];
+ if (!byStyles[name]) {
+ byStyles[name] = {
+ name,
+ count: 0,
+ color: this.colors[
+ `nord${Object.keys(byStyles).length % 15}`
+ ],
+ };
+ }
+
+ byStyles[name].count += 1;
+ }
+
+ // INFO: On regroupe les formats
+ for (let j = 0; j < formats.length; j += 1) {
+ const { name } = formats[j];
+ // INFO: On évite qu'un album avec 2 vinyles soit compté 2x
+ if (!currentFormats.includes(name)) {
+ if (!byFormats[name]) {
+ byFormats[name] = {
+ name,
+ count: 0,
+ color: this.colors[
+ `nord${Object.keys(byFormats).length % 15}`
+ ],
+ };
+ }
+
+ byFormats[name].count += 1;
+ currentFormats.push(name);
+ }
+ }
+ }
+
+ // INFO: On convertit le top en tableau
+ Object.keys(top).forEach((index) => {
+ top10.push(top[index]);
+ });
+
+ // INFO: On ordonne par quantité pour on récupère le top 10
+ top10.sort((a, b) => (a.count > b.count ? -1 : 1));
+
+ this.setPageTitle("Mes statistiques");
+ this.setPageContent("top10", top10.splice(0, 10));
+ this.setPageContent("byGenres", byGenres);
+ this.setPageContent("byStyles", byStyles);
+ this.setPageContent("byFormats", byFormats);
+ }
+
/**
* Méthode permettant de créer la page "collection/:userId"
*/
@@ -522,8 +645,8 @@ Publié automatiquement via #musictopus`;
const genres = await Albums.getAllDistincts("genres", userId);
const styles = await Albums.getAllDistincts("styles", userId);
- this.setPageContent("username", user.username);
this.setPageTitle(`Collection publique de ${user.username}`);
+ this.setPageContent("username", user.username);
this.setPageContent("artists", artists);
this.setPageContent("formats", formats);
this.setPageContent("years", years);
diff --git a/src/routes/ma-collection.js b/src/routes/ma-collection.js
index 1100bd9..f7a4084 100644
--- a/src/routes/ma-collection.js
+++ b/src/routes/ma-collection.js
@@ -38,6 +38,23 @@ router
}
});
+router
+ .route("/statistiques")
+ .get(ensureLoggedIn("/connexion"), async (req, res, next) => {
+ try {
+ const page = new Albums(
+ req,
+ "mon-compte/ma-collection/statistiques"
+ );
+
+ await page.statistics();
+
+ render(res, page);
+ } catch (err) {
+ next(err);
+ }
+ });
+
router
.route("/exporter")
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
diff --git a/views/index.ejs b/views/index.ejs
index 2fca1a8..f8048b4 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -16,6 +16,9 @@
+
+
+
<% if ( config.matomoUrl ) { %>
-