diff --git a/.eslintrc.js b/.eslintrc.js
index c8f8a9d..143bf10 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -16,7 +16,7 @@ module.exports = {
'no-underscore-dangle': [
'error',
{
- allow: ['_id', 'artists_sort'],
+ allow: ['_id', 'artists_sort', 'type_'],
},
],
'camelcase': [
diff --git a/README.md b/README.md
index c787da0..fdc754d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# MusicTopus
+
+
MusicTopus est une application Web (que vous pouvez auto-héberger) et un site Web (sur lequel vous pouvez créer un compte) permettant de gérer votre liste des CDs et Vinyles et de l'utiliser facilement n'importe où.
Le code source est publié sous licence libre [GNU GPL-3.0-or-later](LICENSE) et est disponible sur [git.darkou.fr](https://git.darkou.fr/dbroqua/MusicTopus).
diff --git a/package.json b/package.json
index 77f10de..8c53d5a 100644
--- a/package.json
+++ b/package.json
@@ -51,10 +51,12 @@
"debug": "^4.3.3",
"disconnect": "^1.2.2",
"ejs": "^3.1.6",
+ "excel4node": "^1.7.2",
"express": "^4.17.2",
"express-session": "^1.17.2",
"knacss": "^8.0.4",
"moment": "^2.29.1",
+ "moment-timezone": "^0.5.34",
"mongoose": "^6.2.1",
"mongoose-unique-validator": "^3.0.0",
"passport": "^0.5.2",
diff --git a/public/font/icon.eot b/public/font/icon.eot
index 1609d73..5a5d395 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 67c8d09..51f7015 100644
--- a/public/font/icon.svg
+++ b/public/font/icon.svg
@@ -20,6 +20,12 @@
+
+
+
+
+
+
diff --git a/public/font/icon.ttf b/public/font/icon.ttf
index cbdbe4d..488fa0b 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 4bed225..7c3262d 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 b39dcc9..ac6af3a 100644
Binary files a/public/font/icon.woff2 and b/public/font/icon.woff2 differ
diff --git a/public/js/main.js b/public/js/main.js
index 710d84b..994b2ae 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -1,7 +1,7 @@
/**
- * Fonction permettant d'afficher un message dans un toastr
- * @param {String} message
- */
+ * Fonction permettant d'afficher un message dans un toastr
+ * @param {String} message
+ */
function showToastr(message) {
let x = document.getElementById("toastr");
if ( message ) {
@@ -114,17 +114,22 @@ document.addEventListener('DOMContentLoaded', () => {
}
const switchAriaThemeBtn = document.querySelector("#switchAriaTheme");
- switchAriaThemeBtn.addEventListener("click", switchAriaTheme);
+ if ( switchAriaThemeBtn ) {
+ switchAriaThemeBtn.addEventListener("click", switchAriaTheme);
+ }
setAriaTheme(getCookie('ariatheme'));
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
- toggleSwitch.addEventListener('change', switchTheme, false);
+ if ( toggleSwitch ) {
+ toggleSwitch.addEventListener('change', switchTheme, false);
+ }
let currentThemeIsDark = getCookie('theme');
if ( currentThemeIsDark === 'false' && window.matchMedia ) {
currentThemeIsDark = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
- console.log('currentThemeIsDark:', currentThemeIsDark);
switchTheme({target: {checked: currentThemeIsDark === 'dark'}});
- toggleSwitch.checked = currentThemeIsDark === 'dark';
+ if ( toggleSwitch) {
+ toggleSwitch.checked = currentThemeIsDark === 'dark';
+ }
});
\ No newline at end of file
diff --git a/sass/forms.scss b/sass/forms.scss
index 0f4aab7..fd302e0 100644
--- a/sass/forms.scss
+++ b/sass/forms.scss
@@ -3,6 +3,10 @@
display: flex;
flex-direction: column;
+ &.inline {
+ flex-direction: row;
+ }
+
&.has-addons {
display: flex;
justify-content: flex-start;
@@ -40,6 +44,28 @@
}
}
+ input[type="radio"] {
+ border-radius: 50%;
+ appearance: none;
+ width: 1.2rem;
+ height: 1.2rem;
+ vertical-align: text-bottom;
+ outline: 0;
+ box-shadow: inset 0 0 0 1px var(--input-active-color);
+ background-color: #fff;
+ transition: background-size .15s;
+ cursor: pointer;
+
+ &:checked {
+ box-shadow: inset 0 0 0 4px var(--input-active-color);
+ }
+ }
+
+ input[type="radio"] + label,
+ label + input[type="radio"] {
+ margin-left: 12px;
+ }
+
select {
appearance: none;
background-image: url("data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20style%3D%22isolation%3Aisolate%22%20viewBox%3D%220%200%2020%2020%22%20width%3D%2220%22%20height%3D%2220%22%3E%3Cpath%20d%3D%22%20M%209.96%2011.966%20L%203.523%205.589%20C%202.464%204.627%200.495%206.842%201.505%207.771%20L%201.505%207.771%20L%208.494%2014.763%20C%209.138%2015.35%2010.655%2015.369%2011.29%2014.763%20L%2011.29%2014.763%20L%2018.49%207.771%20C%2019.557%206.752%2017.364%204.68%2016.262%205.725%20L%2016.262%205.725%20L%209.96%2011.966%20Z%20%22%20fill%3D%22inherit%22/%3E%3C/svg%3E");
diff --git a/sass/global.scss b/sass/global.scss
index 2165147..491b9ca 100644
--- a/sass/global.scss
+++ b/sass/global.scss
@@ -1,5 +1,6 @@
html {
min-height: 100vh;
+ scroll-behavior: smooth;
body {
background-color: var(--bg-color);
@@ -69,4 +70,16 @@ html {
.is-hidden {
display: none;
+}
+
+.ml-4 {
+ margin-left: 1rem;
+}
+
+.sm-hidden {
+ display: none;
+
+ @include respond-to("small-up") {
+ display: initial;
+ }
}
\ No newline at end of file
diff --git a/sass/icons.scss b/sass/icons.scss
index ec219a8..ca297ea 100644
--- a/sass/icons.scss
+++ b/sass/icons.scss
@@ -39,6 +39,9 @@
.icon-link:before { content: '\e804'; } /* '' */
.icon-heart:before { content: '\e805'; } /* '' */
.icon-eye:before { content: '\e806'; } /* '' */
+.icon-left-open:before { content: '\e807'; } /* '' */
+.icon-right-open:before { content: '\e808'; } /* '' */
+.icon-export:before { content: '\e809'; } /* '' */
.icon-spin:before { content: '\e839'; } /* '' */
.icon-link-ext:before { content: '\f08e'; } /* '' */
.icon-sun:before { content: '\f185'; } /* '' */
diff --git a/sass/index.scss b/sass/index.scss
index a2d268e..aa7557a 100644
--- a/sass/index.scss
+++ b/sass/index.scss
@@ -19,8 +19,8 @@
// COMPOSANTS (à ajouter au besoin)
// @import "../node_modules/knacss/sass/components/button";
// @import "components/burger";
-// @import "components/checkbox";
-// @import "components/radio";
+// @import "../node_modules/knacss/sass/components/checkbox";
+@import "../node_modules/knacss/sass/components/radio";
// @import "../node_modules/knacss/sass/components/select";
// @import "components/quote";
@@ -43,4 +43,5 @@
@import './error';
@import './home';
@import './ajouter-un-album';
-@import './ma-collection';
\ No newline at end of file
+@import './ma-collection';
+@import './ma-collection-details';
\ No newline at end of file
diff --git a/sass/ma-collection-details.scss b/sass/ma-collection-details.scss
new file mode 100644
index 0000000..6d4ba32
--- /dev/null
+++ b/sass/ma-collection-details.scss
@@ -0,0 +1,55 @@
+.ma-collection-details {
+ .galerie {
+ display: flex;
+ flex-wrap: wrap;
+
+ div {
+ width: 80px;
+ height: 80px;
+ margin: 0.25rem;
+ padding: 0.25rem;
+ border: 2px solid var(--font-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+
+ img {
+ max-width: 90%;
+ }
+ }
+ }
+
+ .modal {
+ button.close {
+ height: 36px;
+ max-height: 36px;
+ max-width: 36px;
+ min-height: 36px;
+ min-width: 36px;
+ width: 36px;
+ position: absolute;
+ background-color: rgba(10,10,10,.6);
+ right: 12px;
+ top: 12px;
+ }
+
+ .navigation {
+ position: absolute;
+ top: 50%;
+ cursor: pointer;
+ z-index: 10;
+
+ &.previous {
+ left: 12px;
+ }
+ &.next {
+ right: 12px;
+ }
+ i {
+ font-size: 2rem;
+ color: $nord4;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sass/modal.scss b/sass/modal.scss
index ffe0571..e44de67 100644
--- a/sass/modal.scss
+++ b/sass/modal.scss
@@ -24,6 +24,47 @@
top: 0;
}
+ button.close {
+ user-select: none;
+ background-color: rgba(10,10,10,.2);
+ border: none;
+ border-radius: 9999px;
+ cursor: pointer;
+ pointer-events: auto;
+ display: inline-block;
+ flex-grow: 0;
+ flex-shrink: 0;
+ font-size: 0;
+ height: 20px;
+ max-height: 20px;
+ max-width: 20px;
+ min-height: 20px;
+ min-width: 20px;
+ outline: none;
+ position: relative;
+ width: 20px;
+
+ &::before,
+ &::after {
+ background-color: var(--default-color);
+ content: "";
+ display: block;
+ left: 50%;
+ position: absolute;
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%) rotate(45deg);
+ transform-origin: center center;
+ }
+ &::before {
+ height: 2px;
+ width: 50%;
+ }
+ &::after {
+ height: 50%;
+ width: 2px;
+ }
+ }
+
.modal-card {
position: relative;
width: 300px;
@@ -62,47 +103,6 @@
justify-content: space-between;
font-size: 1.5rem;
@include transition() {}
-
- button {
- user-select: none;
- background-color: rgba(10,10,10,.2);
- border: none;
- border-radius: 9999px;
- cursor: pointer;
- pointer-events: auto;
- display: inline-block;
- flex-grow: 0;
- flex-shrink: 0;
- font-size: 0;
- height: 20px;
- max-height: 20px;
- max-width: 20px;
- min-height: 20px;
- min-width: 20px;
- outline: none;
- position: relative;
- width: 20px;
-
- &::before,
- &::after {
- background-color: var(--default-color);
- content: "";
- display: block;
- left: 50%;
- position: absolute;
- top: 50%;
- transform: translateX(-50%) translateY(-50%) rotate(45deg);
- transform-origin: center center;
- }
- &::before {
- height: 2px;
- width: 50%;
- }
- &::after {
- height: 50%;
- width: 2px;
- }
- }
}
section {
background-color: var(--default-color);
diff --git a/src/app.js b/src/app.js
index d64e63c..0b32d82 100644
--- a/src/app.js
+++ b/src/app.js
@@ -12,6 +12,7 @@ import config, { env, mongoDbUri, secret } from "./config";
import { isXhr } from "./helpers";
import indexRouter from "./routes";
+import maCollectionRouter from "./routes/ma-collection";
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
import importSearchRouterApiV1 from "./routes/api/v1/search";
@@ -80,6 +81,7 @@ app.use(
);
app.use("/", indexRouter);
+app.use("/ma-collection", maCollectionRouter);
app.use("/api/v1/albums", importAlbumRouterApiV1);
app.use("/api/v1/search", importSearchRouterApiV1);
diff --git a/src/middleware/Albums.js b/src/middleware/Albums.js
index fe795c3..4796207 100644
--- a/src/middleware/Albums.js
+++ b/src/middleware/Albums.js
@@ -1,4 +1,6 @@
import moment from "moment";
+import momenttz from "moment-timezone";
+import xl from "excel4node";
import Pages from "./Pages";
@@ -9,6 +11,451 @@ import ErrorEvent from "../libs/error";
* Classe permettant la gestion des albums d'un utilisateur
*/
class Albums extends Pages {
+ static replaceSpecialChars(str) {
+ if (!str) {
+ return "";
+ }
+ let final = str.toString();
+ const find = ["&", "<", ">"];
+ const replace = ["&", "<", ">"];
+
+ for (let i = 0; i < find.length; i += 1) {
+ final = final.replace(new RegExp(find[i], "g"), replace[i]);
+ }
+
+ return final;
+ }
+
+ /**
+ * Méthode permettant de convertir les rows en csv
+ * @param {Array} rows
+ *
+ * @return {string}
+ */
+ static async convertToCsv(rows) {
+ let data =
+ "Artiste;Titre;Genre;Styles;Pays;Année;Date de sortie;Format\n\r";
+
+ for (let i = 0; i < rows.length; i += 1) {
+ const {
+ artists_sort,
+ title,
+ genres,
+ styles,
+ country,
+ year,
+ released,
+ formats,
+ } = rows[i];
+
+ let format = "";
+ for (let j = 0; j < formats.length; j += 1) {
+ format += `${format !== "" ? ", " : ""}${formats[j].name}`;
+ }
+
+ data += `${artists_sort};${title};${genres.join()};${styles.join()};${country};${year};${released};${format}\n\r`;
+ }
+
+ return data;
+ }
+
+ /**
+ * Méthode permettant de convertir les rows en fichier xls
+ * @param {Array} rows
+ *
+ * @return {Object}
+ */
+ static async convertToXls(rows) {
+ const wb = new xl.Workbook();
+ const ws = wb.addWorksheet("MusicTopus");
+
+ const headerStyle = wb.createStyle({
+ font: {
+ color: "#FFFFFF",
+ size: 11,
+ },
+ fill: {
+ type: "pattern",
+ patternType: "solid",
+ bgColor: "#595959",
+ fgColor: "#595959",
+ },
+ });
+ const style = wb.createStyle({
+ font: {
+ color: "#000000",
+ size: 11,
+ },
+ numberFormat: "0000",
+ });
+
+ const header = [
+ "Artiste",
+ "Titre",
+ "Genre",
+ "Styles",
+ "Pays",
+ "Année",
+ "Date de sortie",
+ "Format",
+ ];
+ for (let i = 0; i < header.length; i += 1) {
+ ws.cell(1, i + 1)
+ .string(header[i])
+ .style(headerStyle);
+ }
+
+ for (let i = 0; i < rows.length; i += 1) {
+ const currentRow = i + 2;
+ const {
+ artists_sort,
+ title,
+ genres,
+ styles,
+ country,
+ year,
+ released,
+ formats,
+ } = rows[i];
+
+ let format = "";
+ for (let j = 0; j < formats.length; j += 1) {
+ format += `${format !== "" ? ", " : ""}${formats[j].name}`;
+ }
+
+ ws.cell(currentRow, 1).string(artists_sort).style(style);
+ ws.cell(currentRow, 2).string(title).style(style);
+ ws.cell(currentRow, 3).string(genres.join()).style(style);
+ ws.cell(currentRow, 4).string(styles.join()).style(style);
+ if (country) {
+ ws.cell(currentRow, 5).string(country).style(style);
+ }
+ if (year) {
+ ws.cell(currentRow, 6).number(year).style(style);
+ }
+ if (released) {
+ ws.cell(currentRow, 7)
+ .date(momenttz.tz(released, "Europe/Paris").hour(12))
+ .style({ numberFormat: "dd/mm/yyyy" });
+ }
+ ws.cell(currentRow, 8).string(format).style(style);
+ }
+
+ return wb;
+ }
+
+ /**
+ * Méthode permettant de convertir les rows en csv pour importer dans MusicTopus
+ * @param {Array} rows
+ *
+ * @return {string}
+ */
+ static async convertToXml(rows) {
+ let data = '\n\r';
+
+ for (let i = 0; i < rows.length; i += 1) {
+ const {
+ discogsId,
+ year,
+ released,
+ uri,
+ artists,
+ artists_sort,
+ labels,
+ series,
+ companies,
+ formats,
+ title,
+ country,
+ notes,
+ identifiers,
+ videos,
+ genres,
+ styles,
+ tracklist,
+ extraartists,
+ images,
+ thumb,
+ } = rows[i];
+
+ let artistsList = "";
+ let labelList = "";
+ let serieList = "";
+ let companiesList = "";
+ let formatsList = "";
+ let identifiersList = "";
+ let videosList = "";
+ let genresList = "";
+ let stylesList = "";
+ let tracklistList = "";
+ let extraartistsList = "";
+ let imagesList = "";
+
+ for (let j = 0; j < artists.length; j += 1) {
+ artistsList += `
+ ${Albums.replaceSpecialChars(artists[j].name)}
+ ${Albums.replaceSpecialChars(artists[j].anv)}
+ ${Albums.replaceSpecialChars(artists[j].join)}
+ ${Albums.replaceSpecialChars(artists[j].role)}
+ ${Albums.replaceSpecialChars(
+ artists[j].tracks
+ )}
+ ${Albums.replaceSpecialChars(artists[j].id)}
+ ${Albums.replaceSpecialChars(
+ artists[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ artists[j].thumbnail_url
+ )}
+ `;
+ }
+
+ for (let j = 0; j < labels.length; j += 1) {
+ labelList += `
+ ${Albums.replaceSpecialChars(labels[j].name)}
+ ${Albums.replaceSpecialChars(labels[j].catno)}
+ ${Albums.replaceSpecialChars(
+ labels[j].entity_type
+ )}
+ ${Albums.replaceSpecialChars(
+ labels[j].entity_type
+ )}
+ ${Albums.replaceSpecialChars(labels[j].id)}
+ ${Albums.replaceSpecialChars(
+ labels[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ labels[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < series.length; j += 1) {
+ serieList += `
+ ${Albums.replaceSpecialChars(series[j].name)}
+ ${Albums.replaceSpecialChars(series[j].catno)}
+ ${Albums.replaceSpecialChars(
+ series[j].entity_type
+ )}
+ ${Albums.replaceSpecialChars(
+ series[j].entity_type_name
+ )}
+ ${Albums.replaceSpecialChars(series[j].id)}
+ ${Albums.replaceSpecialChars(
+ series[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ series[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < companies.length; j += 1) {
+ companiesList += `
+ ${Albums.replaceSpecialChars(companies[j].name)}
+ ${Albums.replaceSpecialChars(companies[j].catno)}
+ ${Albums.replaceSpecialChars(
+ companies[j].entity_type
+ )}
+ ${Albums.replaceSpecialChars(
+ companies[j].entity_type_name
+ )}
+ ${Albums.replaceSpecialChars(companies[j].id)}
+ ${Albums.replaceSpecialChars(
+ companies[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ companies[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < formats.length; j += 1) {
+ let descriptions = "";
+ if (formats[j].descriptions) {
+ for (
+ let k = 0;
+ k < formats[j].descriptions.length;
+ k += 1
+ ) {
+ descriptions += `${formats[j].descriptions[k]}
+ `;
+ }
+ }
+ formatsList += `
+ ${Albums.replaceSpecialChars(formats[j].name)}
+ ${Albums.replaceSpecialChars(formats[j].qty)}
+ ${Albums.replaceSpecialChars(formats[j].text)}
+
+ ${descriptions}
+
+
+ `;
+ }
+
+ for (let j = 0; j < identifiers.length; j += 1) {
+ identifiersList += `
+ ${Albums.replaceSpecialChars(identifiers[j].type)}
+ ${Albums.replaceSpecialChars(
+ identifiers[j].value
+ )}
+ ${Albums.replaceSpecialChars(
+ identifiers[j].description
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < videos.length; j += 1) {
+ videosList += `
+ ${Albums.replaceSpecialChars(videos[j].uri)}
+ ${Albums.replaceSpecialChars(videos[j].title)}
+ ${Albums.replaceSpecialChars(
+ videos[j].description
+ )}
+ ${Albums.replaceSpecialChars(
+ videos[j].duration
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < genres.length; j += 1) {
+ genresList += `${Albums.replaceSpecialChars(
+ genres[j]
+ )}
+ `;
+ }
+
+ for (let j = 0; j < styles.length; j += 1) {
+ stylesList += `
+ `;
+ }
+
+ for (let j = 0; j < tracklist.length; j += 1) {
+ tracklistList += `
+ ${Albums.replaceSpecialChars(tracklist[j].title)}
+
+ `;
+ }
+
+ for (let j = 0; j < extraartists.length; j += 1) {
+ extraartistsList += `
+ ${Albums.replaceSpecialChars(extraartists[j].name)}
+ ${Albums.replaceSpecialChars(extraartists[j].anv)}
+ ${Albums.replaceSpecialChars(extraartists[j].join)}
+ ${Albums.replaceSpecialChars(extraartists[j].role)}
+ ${Albums.replaceSpecialChars(
+ extraartists[j].tracks
+ )}
+ ${Albums.replaceSpecialChars(extraartists[j].id)}
+ ${Albums.replaceSpecialChars(
+ extraartists[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ extraartists[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < images.length; j += 1) {
+ imagesList += `
+ ${Albums.replaceSpecialChars(images[j].uri)}
+ ${Albums.replaceSpecialChars(
+ images[j].resource_url
+ )}
+ ${Albums.replaceSpecialChars(
+ images[j].resource_url
+ )}
+
+ `;
+ }
+
+ data += `
+
+ ${discogsId}
+ ${Albums.replaceSpecialChars(title)}
+ ${Albums.replaceSpecialChars(artists_sort)}
+
+ ${artistsList}
+
+ ${year}
+ ${Albums.replaceSpecialChars(country)}
+ ${released}
+ ${uri}
+ ${thumb}
+
+ ${labelList}
+
+
+ ${serieList}
+
+
+ ${companiesList}
+
+
+ ${formatsList}
+
+ ${Albums.replaceSpecialChars(notes)}
+
+ ${identifiersList}
+
+
+ ${videosList}
+
+
+ ${genresList}
+
+
+ ${stylesList}
+
+
+ ${tracklistList}
+
+
+ ${extraartistsList}
+
+
+ ${imagesList}
+
+ `;
+ }
+
+ return `${data} `;
+ }
+
+ /**
+ * Méthode permettant de convertir les rows en csv pour importer dans MusicTopus
+ * @param {Array} rows
+ *
+ * @return {string}
+ */
+ static async convertToMusicTopus(rows) {
+ let data = "itemId;createdAt;updatedAt\n\r";
+
+ for (let i = 0; i < rows.length; i += 1) {
+ const { discogsId, createdAt, updatedAt } = rows[i];
+
+ data += `${discogsId};${createdAt};${updatedAt}\n\r`;
+ }
+
+ data += "v1.0";
+
+ return data;
+ }
+
/**
* Méthode permettant d'ajouter un album dans une collection
* @param {Object} req
@@ -59,16 +506,15 @@ class Albums extends Pages {
*/
async getAll() {
const {
- page = 1,
- limit = 4,
+ page,
+ limit,
+ exportFormat = "json",
sort = "artists_sort",
order = "asc",
artists_sort,
format,
} = this.req.query;
- const skip = (page - 1) * limit;
-
const where = {};
if (artists_sort) {
@@ -83,25 +529,47 @@ class Albums extends Pages {
...where,
});
+ let params = {
+ sort: {
+ [sort]: order.toLowerCase() === "asc" ? 1 : -1,
+ },
+ };
+
+ if (page && limit) {
+ const skip = (page - 1) * limit;
+
+ params = {
+ ...params,
+ skip,
+ limit,
+ };
+ }
+
const rows = await AlbumsModel.find(
{
user: this.req.user._id,
...where,
},
[],
- {
- skip,
- limit,
- sort: {
- [sort]: order.toLowerCase() === "asc" ? 1 : -1,
- },
- }
+ params
);
- return {
- rows,
- count,
- };
+ switch (exportFormat) {
+ case "csv":
+ return Albums.convertToCsv(rows);
+ case "xls":
+ return Albums.convertToXls(rows);
+ case "xml":
+ return Albums.convertToXml(rows);
+ case "musictopus":
+ return Albums.convertToMusicTopus(rows);
+ case "json":
+ default:
+ return {
+ rows,
+ count,
+ };
+ }
}
/**
@@ -137,6 +605,20 @@ class Albums extends Pages {
this.setPageContent("artists", artists);
this.setPageContent("formats", formats);
}
+
+ /**
+ * Méthode permettant d'afficher le détails d'un album
+ */
+ async loadItem() {
+ const { itemId: _id } = this.req.params;
+ const { _id: User } = this.req.user;
+ const item = await AlbumsModel.findOne({
+ _id,
+ User,
+ });
+
+ this.setPageContent("item", item);
+ }
}
export default Albums;
diff --git a/src/routes/api/v1/albums.js b/src/routes/api/v1/albums.js
index 5d0c68c..164ea40 100644
--- a/src/routes/api/v1/albums.js
+++ b/src/routes/api/v1/albums.js
@@ -13,10 +13,24 @@ router
try {
const albums = new Albums(req);
const data = await albums.getAll();
+ const { exportFormat = "json" } = req.query;
- sendResponse(req, res, data);
+ switch (exportFormat) {
+ case "csv":
+ case "musictopus":
+ res.header("Content-Type", "text/csv");
+ return res.status(200).send(data);
+ case "xml":
+ res.header("Content-type", "text/xml");
+ return res.status(200).send(data);
+ case "xls":
+ return data.write("musictopus.xls", res);
+ case "json":
+ default:
+ return sendResponse(req, res, data);
+ }
} catch (err) {
- next(err);
+ return next(err);
}
})
.post(ensureLoggedIn("/connexion"), async (req, res, next) => {
diff --git a/src/routes/index.js b/src/routes/index.js
index 8a340a0..95c9a45 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -4,7 +4,6 @@ import { ensureLoggedIn } from "connect-ensure-login";
import Pages from "../middleware/Pages";
import Auth from "../middleware/Auth";
-import Albums from "../middleware/Albums";
import render from "../libs/format";
@@ -89,24 +88,6 @@ router
}
});
-router
- .route("/ma-collection")
- .get(ensureLoggedIn("/connexion"), async (req, res, next) => {
- try {
- const page = new Albums(req, "mon-compte/ma-collection");
-
- await page.loadMyCollection();
-
- if (page.getPageContent("artists").length > 0) {
- render(res, page);
- } else {
- res.redirect("/ajouter-un-album");
- }
- } catch (err) {
- next(err);
- }
- });
-
router.route("/nous-contacter").get(async (req, res, next) => {
try {
const page = new Pages(req, "nous-contacter");
diff --git a/src/routes/ma-collection.js b/src/routes/ma-collection.js
new file mode 100644
index 0000000..51ff0ee
--- /dev/null
+++ b/src/routes/ma-collection.js
@@ -0,0 +1,53 @@
+import express from "express";
+import { ensureLoggedIn } from "connect-ensure-login";
+
+import Albums from "../middleware/Albums";
+
+import render from "../libs/format";
+
+// eslint-disable-next-line new-cap
+const router = express.Router();
+
+router.route("/").get(ensureLoggedIn("/connexion"), async (req, res, next) => {
+ try {
+ const page = new Albums(req, "mon-compte/ma-collection");
+
+ await page.loadMyCollection();
+
+ if (page.getPageContent("artists").length > 0) {
+ render(res, page);
+ } else {
+ res.redirect("/ajouter-un-album");
+ }
+ } catch (err) {
+ next(err);
+ }
+});
+
+router
+ .route("/exporter")
+ .get(ensureLoggedIn("/connexion"), async (req, res, next) => {
+ try {
+ const page = new Albums(req, "mon-compte/ma-collection/exporter");
+
+ render(res, page);
+ } catch (err) {
+ next(err);
+ }
+ });
+
+router
+ .route("/:itemId")
+ .get(ensureLoggedIn("/connexion"), async (req, res, next) => {
+ try {
+ const page = new Albums(req, "mon-compte/ma-collection/details");
+
+ await page.loadItem();
+
+ render(res, page);
+ } catch (err) {
+ next(err);
+ }
+ });
+
+export default router;
diff --git a/views/index.ejs b/views/index.ejs
index 8d2364f..ddf0b8c 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -68,6 +68,9 @@
Ma collection
+
+ Exporter ma collection
+
<% } %>
diff --git a/views/pages/ajouter-un-album.ejs b/views/pages/ajouter-un-album.ejs
index 8a26488..bdebb4e 100644
--- a/views/pages/ajouter-un-album.ejs
+++ b/views/pages/ajouter-un-album.ejs
@@ -52,12 +52,12 @@
-
+
@@ -217,8 +217,6 @@
this.modalIsVisible = !this.modalIsVisible;
},
loadDetails(discogsId) {
- console.log('discogsId:', discogsId);
-
axios.get(`/api/v1/search/${discogsId}`)
.then( response => {
const {
@@ -245,5 +243,5 @@
});
},
}
- }).mount('#app')
+ }).mount('#app');
diff --git a/views/pages/composants.ejs b/views/pages/composants.ejs
index 2362206..7c17b38 100644
--- a/views/pages/composants.ejs
+++ b/views/pages/composants.ejs
@@ -230,6 +230,8 @@
.icon-moon
.icon-trash
.icon-blind
+
.icon-left-open
+
.icon-right-open
Les listes
diff --git a/views/pages/mon-compte/ma-collection.ejs b/views/pages/mon-compte/ma-collection.ejs
index ed03634..b754ccf 100644
--- a/views/pages/mon-compte/ma-collection.ejs
+++ b/views/pages/mon-compte/ma-collection.ejs
@@ -40,12 +40,12 @@
- {{ item.artists_sort}} - {{ item.title }}
+ {{ item.artists_sort}} - {{ item.title }}
-
+
Année : {{ item.year }}
@@ -175,7 +175,6 @@
this.fetch();
},
changeSort() {
- console.log('TEST:', this.sortOrder);
const [sort,order] = this.sortOrder.split('-');
this.sort = sort;
this.order = order;
@@ -208,5 +207,5 @@
});
}
}
- }).mount('#app')
+ }).mount('#app');
diff --git a/views/pages/mon-compte/ma-collection/details.ejs b/views/pages/mon-compte/ma-collection/details.ejs
new file mode 100644
index 0000000..12490c0
--- /dev/null
+++ b/views/pages/mon-compte/ma-collection/details.ejs
@@ -0,0 +1,282 @@
+
+
+ {{item.artists_sort}} - {{item.title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{album.title}}
+
+
+ {{ track.title }} ({{track.duration}})
+
+
+ {{extra.role}} : {{extra.name}}
+
+
+
+
+
+
+
+
+
+ Genres
+
+
+ {{genre}},
+
+
+
+ Styles
+
+
+ {{style}},
+
+
+
+
+
+
+ Pays
+
+ {{item.country}}
+
+
+ Année
+
+ {{item.year}}
+
+
+ Date de sortie
+
+ {{item.released}}
+
+
+
+
+
+
Format
+
+
+ {{format.name}}
+
+ (
+ {{description}},
+ )
+
+
+
+
+
+
+
+
+
Codes barres
+
+
+ {{identifier.value}} ({{identifier.type}})
+
+
+
+
+ Voir la suite
+
+
+ Voir moins
+
+
+
+
+ Label
+
+
+ {{label.name}} {{label.catno}}
+
+
+
+ Sociétés
+
+
+ {{company.entity_type_name}} : {{company.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/pages/mon-compte/ma-collection/exporter.ejs b/views/pages/mon-compte/ma-collection/exporter.ejs
new file mode 100644
index 0000000..dc1de77
--- /dev/null
+++ b/views/pages/mon-compte/ma-collection/exporter.ejs
@@ -0,0 +1,68 @@
+
+ Exporter ma collection
+
+ Les formats CSV et Excel sont facilement lisiblent par un humain. Dans ces 2 formats vous trouverez seulement les informations principales de vos albums, à savoir :
+
+
+ Nom de l'artiste
+ Nom de l'album
+ Liste des genres
+ Liste des styles
+ Pays (ou région) de distribution
+ Année de sortie
+ Date de sortie
+ Format de l'album
+
+
+ Le format XML quand a lui est un peu moins lisible par un humain, même s'il reste un fichier texte. Dans ce format vous retrouverez toute les informations de vos albums.
+
+
+ Enfin le dernier format, MusicTopus, vous permettra d'exporter votre collection afin de l'importer ensuite sur une autre instance MusicTopus.
+
+
+
+
+
\ No newline at end of file