Compare commits
2 commits
0b8b4b21bd
...
95ab6f5f42
Author | SHA1 | Date | |
---|---|---|---|
95ab6f5f42 | |||
b27a81a0b6 |
13 changed files with 660 additions and 54 deletions
|
@ -16,7 +16,7 @@ module.exports = {
|
||||||
'no-underscore-dangle': [
|
'no-underscore-dangle': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
allow: ['_id', 'artists_sort'],
|
allow: ['_id', 'artists_sort', 'type_'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'camelcase': [
|
'camelcase': [
|
||||||
|
|
|
@ -51,10 +51,12 @@
|
||||||
"debug": "^4.3.3",
|
"debug": "^4.3.3",
|
||||||
"disconnect": "^1.2.2",
|
"disconnect": "^1.2.2",
|
||||||
"ejs": "^3.1.6",
|
"ejs": "^3.1.6",
|
||||||
|
"excel4node": "^1.7.2",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
"express-session": "^1.17.2",
|
"express-session": "^1.17.2",
|
||||||
"knacss": "^8.0.4",
|
"knacss": "^8.0.4",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
"moment-timezone": "^0.5.34",
|
||||||
"mongoose": "^6.2.1",
|
"mongoose": "^6.2.1",
|
||||||
"mongoose-unique-validator": "^3.0.0",
|
"mongoose-unique-validator": "^3.0.0",
|
||||||
"passport": "^0.5.2",
|
"passport": "^0.5.2",
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
<glyph glyph-name="right-open" unicode="" d="M618 361l-414-415q-11-10-25-10t-25 10l-93 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l93 93q10 11 25 11t25-11l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
|
<glyph glyph-name="right-open" unicode="" d="M618 361l-414-415q-11-10-25-10t-25 10l-93 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l93 93q10 11 25 11t25-11l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
|
||||||
|
|
||||||
|
<glyph glyph-name="export" unicode="" d="M786 298v-144q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h142q7 0 13-6t5-12q0-15-15-18-43-15-74-34-5-2-9-2h-62q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v119q0 11 10 16 16 7 31 21 8 9 19 4 12-5 12-16z m132 277l-214-214q-10-11-25-11-7 0-14 3-22 9-22 33v107h-89q-181 0-245-73-66-77-41-264 2-13-11-19-5-1-7-1-9 0-14 7-6 8-12 17t-22 39-28 55-21 64-10 68q0 27 2 51t8 50 15 49 27 45 38 42 52 34 70 27 89 17 110 6h89v107q0 24 22 33 7 3 14 3 14 0 25-11l214-214q11-10 11-25t-11-25z" horiz-adv-x="928.6" />
|
||||||
|
|
||||||
<glyph glyph-name="spin" unicode="" d="M855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
|
<glyph glyph-name="spin" unicode="" d="M855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="link-ext" unicode="" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
|
<glyph glyph-name="link-ext" unicode="" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
|
||||||
|
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 7.2 KiB |
|
@ -3,6 +3,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.inline {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
&.has-addons {
|
&.has-addons {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
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 {
|
select {
|
||||||
appearance: none;
|
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");
|
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");
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
.icon-eye:before { content: '\e806'; } /* '' */
|
.icon-eye:before { content: '\e806'; } /* '' */
|
||||||
.icon-left-open:before { content: '\e807'; } /* '' */
|
.icon-left-open:before { content: '\e807'; } /* '' */
|
||||||
.icon-right-open:before { content: '\e808'; } /* '' */
|
.icon-right-open:before { content: '\e808'; } /* '' */
|
||||||
|
.icon-export:before { content: '\e809'; } /* '' */
|
||||||
.icon-spin:before { content: '\e839'; } /* '' */
|
.icon-spin:before { content: '\e839'; } /* '' */
|
||||||
.icon-link-ext:before { content: '\f08e'; } /* '' */
|
.icon-link-ext:before { content: '\f08e'; } /* '' */
|
||||||
.icon-sun:before { content: '\f185'; } /* '' */
|
.icon-sun:before { content: '\f185'; } /* '' */
|
||||||
|
@ -60,4 +61,4 @@
|
||||||
100% {
|
100% {
|
||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
// COMPOSANTS (à ajouter au besoin)
|
// COMPOSANTS (à ajouter au besoin)
|
||||||
// @import "../node_modules/knacss/sass/components/button";
|
// @import "../node_modules/knacss/sass/components/button";
|
||||||
// @import "components/burger";
|
// @import "components/burger";
|
||||||
// @import "components/checkbox";
|
// @import "../node_modules/knacss/sass/components/checkbox";
|
||||||
// @import "components/radio";
|
@import "../node_modules/knacss/sass/components/radio";
|
||||||
// @import "../node_modules/knacss/sass/components/select";
|
// @import "../node_modules/knacss/sass/components/select";
|
||||||
// @import "components/quote";
|
// @import "components/quote";
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import config, { env, mongoDbUri, secret } from "./config";
|
||||||
import { isXhr } from "./helpers";
|
import { isXhr } from "./helpers";
|
||||||
|
|
||||||
import indexRouter from "./routes";
|
import indexRouter from "./routes";
|
||||||
|
import maCollectionRouter from "./routes/ma-collection";
|
||||||
|
|
||||||
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
|
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
|
||||||
import importSearchRouterApiV1 from "./routes/api/v1/search";
|
import importSearchRouterApiV1 from "./routes/api/v1/search";
|
||||||
|
@ -80,6 +81,7 @@ app.use(
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
|
app.use("/ma-collection", maCollectionRouter);
|
||||||
app.use("/api/v1/albums", importAlbumRouterApiV1);
|
app.use("/api/v1/albums", importAlbumRouterApiV1);
|
||||||
app.use("/api/v1/search", importSearchRouterApiV1);
|
app.use("/api/v1/search", importSearchRouterApiV1);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import momenttz from "moment-timezone";
|
||||||
|
import xl from "excel4node";
|
||||||
|
|
||||||
import Pages from "./Pages";
|
import Pages from "./Pages";
|
||||||
|
|
||||||
|
@ -9,6 +11,451 @@ import ErrorEvent from "../libs/error";
|
||||||
* Classe permettant la gestion des albums d'un utilisateur
|
* Classe permettant la gestion des albums d'un utilisateur
|
||||||
*/
|
*/
|
||||||
class Albums extends Pages {
|
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 = '<?xml version="1.0" encoding="UTF-8"?>\n\r<albums>';
|
||||||
|
|
||||||
|
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 += `<artist>
|
||||||
|
<name>${Albums.replaceSpecialChars(artists[j].name)}</name>
|
||||||
|
<anv>${Albums.replaceSpecialChars(artists[j].anv)}</anv>
|
||||||
|
<join>${Albums.replaceSpecialChars(artists[j].join)}</join>
|
||||||
|
<role>${Albums.replaceSpecialChars(artists[j].role)}</role>
|
||||||
|
<tracks>${Albums.replaceSpecialChars(
|
||||||
|
artists[j].tracks
|
||||||
|
)}</tracks>
|
||||||
|
<id>${Albums.replaceSpecialChars(artists[j].id)}</id>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
artists[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<thumbnail_url>${Albums.replaceSpecialChars(
|
||||||
|
artists[j].thumbnail_url
|
||||||
|
)}</thumbnail_url>
|
||||||
|
</artist>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < labels.length; j += 1) {
|
||||||
|
labelList += `<label>
|
||||||
|
<name>${Albums.replaceSpecialChars(labels[j].name)}</name>
|
||||||
|
<catno>${Albums.replaceSpecialChars(labels[j].catno)}</catno>
|
||||||
|
<entity_type>${Albums.replaceSpecialChars(
|
||||||
|
labels[j].entity_type
|
||||||
|
)}</entity_type>
|
||||||
|
<entity_type_name>${Albums.replaceSpecialChars(
|
||||||
|
labels[j].entity_type
|
||||||
|
)}</entity_type_name>
|
||||||
|
<id>${Albums.replaceSpecialChars(labels[j].id)}</id>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
labels[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<thumbnail_url>${Albums.replaceSpecialChars(
|
||||||
|
labels[j].thumbnail_url
|
||||||
|
)}</thumbnail_url>
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < series.length; j += 1) {
|
||||||
|
serieList += `<serie>
|
||||||
|
<name>${Albums.replaceSpecialChars(series[j].name)}</name>
|
||||||
|
<catno>${Albums.replaceSpecialChars(series[j].catno)}</catno>
|
||||||
|
<entity_type>${Albums.replaceSpecialChars(
|
||||||
|
series[j].entity_type
|
||||||
|
)}</entity_type>
|
||||||
|
<entity_type_name>${Albums.replaceSpecialChars(
|
||||||
|
series[j].entity_type_name
|
||||||
|
)}</entity_type_name>
|
||||||
|
<id>${Albums.replaceSpecialChars(series[j].id)}</id>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
series[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<thumbnail_url>${Albums.replaceSpecialChars(
|
||||||
|
series[j].thumbnail_url
|
||||||
|
)}</thumbnail_url>
|
||||||
|
</serie>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < companies.length; j += 1) {
|
||||||
|
companiesList += `<company>
|
||||||
|
<name>${Albums.replaceSpecialChars(companies[j].name)}</name>
|
||||||
|
<catno>${Albums.replaceSpecialChars(companies[j].catno)}</catno>
|
||||||
|
<entity_type>${Albums.replaceSpecialChars(
|
||||||
|
companies[j].entity_type
|
||||||
|
)}</entity_type>
|
||||||
|
<entity_type_name>${Albums.replaceSpecialChars(
|
||||||
|
companies[j].entity_type_name
|
||||||
|
)}</entity_type_name>
|
||||||
|
<id>${Albums.replaceSpecialChars(companies[j].id)}</id>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
companies[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<thumbnail_url>${Albums.replaceSpecialChars(
|
||||||
|
companies[j].thumbnail_url
|
||||||
|
)}</thumbnail_url>
|
||||||
|
</company>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 += `<description>${formats[j].descriptions[k]}</description>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatsList += `<format>
|
||||||
|
<name>${Albums.replaceSpecialChars(formats[j].name)}</name>
|
||||||
|
<qte>${Albums.replaceSpecialChars(formats[j].qty)}</qte>
|
||||||
|
<text>${Albums.replaceSpecialChars(formats[j].text)}</text>
|
||||||
|
<descriptions>
|
||||||
|
${descriptions}
|
||||||
|
</descriptions>
|
||||||
|
</format>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < identifiers.length; j += 1) {
|
||||||
|
identifiersList += `<identifier>
|
||||||
|
<type>${Albums.replaceSpecialChars(identifiers[j].type)}</type>
|
||||||
|
<value>${Albums.replaceSpecialChars(
|
||||||
|
identifiers[j].value
|
||||||
|
)}</value>
|
||||||
|
<description>${Albums.replaceSpecialChars(
|
||||||
|
identifiers[j].description
|
||||||
|
)}</description>
|
||||||
|
</identifier>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < videos.length; j += 1) {
|
||||||
|
videosList += `<video embed="${videos[j].embed}">
|
||||||
|
<uri>${Albums.replaceSpecialChars(videos[j].uri)}</uri>
|
||||||
|
<title>${Albums.replaceSpecialChars(videos[j].title)}</title>
|
||||||
|
<description>${Albums.replaceSpecialChars(
|
||||||
|
videos[j].description
|
||||||
|
)}</description>
|
||||||
|
<duration>${Albums.replaceSpecialChars(
|
||||||
|
videos[j].duration
|
||||||
|
)}</duration>
|
||||||
|
</video>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < genres.length; j += 1) {
|
||||||
|
genresList += `<genre>${Albums.replaceSpecialChars(
|
||||||
|
genres[j]
|
||||||
|
)}</genre>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < styles.length; j += 1) {
|
||||||
|
stylesList += `<style>${Albums.replaceSpecialChars(
|
||||||
|
styles[j]
|
||||||
|
)}</style>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < tracklist.length; j += 1) {
|
||||||
|
tracklistList += `<tracklist position="${
|
||||||
|
tracklist[j].position
|
||||||
|
}" type="${tracklist[j].type_}" duration="${
|
||||||
|
tracklist[j].duration
|
||||||
|
}">
|
||||||
|
${Albums.replaceSpecialChars(tracklist[j].title)}
|
||||||
|
</tracklist>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < extraartists.length; j += 1) {
|
||||||
|
extraartistsList += `<extraartist>
|
||||||
|
<name>${Albums.replaceSpecialChars(extraartists[j].name)}</name>
|
||||||
|
<anv>${Albums.replaceSpecialChars(extraartists[j].anv)}</anv>
|
||||||
|
<join>${Albums.replaceSpecialChars(extraartists[j].join)}</join>
|
||||||
|
<role>${Albums.replaceSpecialChars(extraartists[j].role)}</role>
|
||||||
|
<tracks>${Albums.replaceSpecialChars(
|
||||||
|
extraartists[j].tracks
|
||||||
|
)}</tracks>
|
||||||
|
<id>${Albums.replaceSpecialChars(extraartists[j].id)}</id>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
extraartists[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<thumbnail_url>${Albums.replaceSpecialChars(
|
||||||
|
extraartists[j].thumbnail_url
|
||||||
|
)}</thumbnail_url>
|
||||||
|
</extraartist>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < images.length; j += 1) {
|
||||||
|
imagesList += `<image type="${images[j].type}" width="${
|
||||||
|
images[j].width
|
||||||
|
}" height="${images[j].height}">
|
||||||
|
<uri>${Albums.replaceSpecialChars(images[j].uri)}</uri>
|
||||||
|
<resource_url>${Albums.replaceSpecialChars(
|
||||||
|
images[j].resource_url
|
||||||
|
)}</resource_url>
|
||||||
|
<uri150>${Albums.replaceSpecialChars(
|
||||||
|
images[j].resource_url
|
||||||
|
)}</uri150>
|
||||||
|
</image>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += `
|
||||||
|
<album>
|
||||||
|
<discogId>${discogsId}</discogId>
|
||||||
|
<title>${Albums.replaceSpecialChars(title)}</title>
|
||||||
|
<artists_sort>${Albums.replaceSpecialChars(artists_sort)}</artists_sort>
|
||||||
|
<artists>
|
||||||
|
${artistsList}
|
||||||
|
</artists>
|
||||||
|
<year>${year}</year>
|
||||||
|
<country>${Albums.replaceSpecialChars(country)}</country>
|
||||||
|
<released>${released}</released>
|
||||||
|
<uri>${uri}</uri>
|
||||||
|
<thumb>${thumb}</thumb>
|
||||||
|
<labels>
|
||||||
|
${labelList}
|
||||||
|
</labels>
|
||||||
|
<series>
|
||||||
|
${serieList}
|
||||||
|
</series>
|
||||||
|
<companies>
|
||||||
|
${companiesList}
|
||||||
|
</companies>
|
||||||
|
<formats>
|
||||||
|
${formatsList}
|
||||||
|
</formats>
|
||||||
|
<notes>${Albums.replaceSpecialChars(notes)}</notes>
|
||||||
|
<identifiers>
|
||||||
|
${identifiersList}
|
||||||
|
</identifiers>
|
||||||
|
<videos>
|
||||||
|
${videosList}
|
||||||
|
</videos>
|
||||||
|
<genres>
|
||||||
|
${genresList}
|
||||||
|
</genres>
|
||||||
|
<styles>
|
||||||
|
${stylesList}
|
||||||
|
</styles>
|
||||||
|
<tracklist>
|
||||||
|
${tracklistList}
|
||||||
|
</tracklist>
|
||||||
|
<extraartists>
|
||||||
|
${extraartistsList}
|
||||||
|
</extraartists>
|
||||||
|
<images>
|
||||||
|
${imagesList}
|
||||||
|
</images>
|
||||||
|
</album>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${data}</albums>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Méthode permettant d'ajouter un album dans une collection
|
||||||
* @param {Object} req
|
* @param {Object} req
|
||||||
|
@ -59,16 +506,15 @@ class Albums extends Pages {
|
||||||
*/
|
*/
|
||||||
async getAll() {
|
async getAll() {
|
||||||
const {
|
const {
|
||||||
page = 1,
|
page,
|
||||||
limit = 4,
|
limit,
|
||||||
|
exportFormat = "json",
|
||||||
sort = "artists_sort",
|
sort = "artists_sort",
|
||||||
order = "asc",
|
order = "asc",
|
||||||
artists_sort,
|
artists_sort,
|
||||||
format,
|
format,
|
||||||
} = this.req.query;
|
} = this.req.query;
|
||||||
|
|
||||||
const skip = (page - 1) * limit;
|
|
||||||
|
|
||||||
const where = {};
|
const where = {};
|
||||||
|
|
||||||
if (artists_sort) {
|
if (artists_sort) {
|
||||||
|
@ -83,25 +529,47 @@ class Albums extends Pages {
|
||||||
...where,
|
...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(
|
const rows = await AlbumsModel.find(
|
||||||
{
|
{
|
||||||
user: this.req.user._id,
|
user: this.req.user._id,
|
||||||
...where,
|
...where,
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
{
|
params
|
||||||
skip,
|
|
||||||
limit,
|
|
||||||
sort: {
|
|
||||||
[sort]: order.toLowerCase() === "asc" ? 1 : -1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
switch (exportFormat) {
|
||||||
rows,
|
case "csv":
|
||||||
count,
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,10 +13,24 @@ router
|
||||||
try {
|
try {
|
||||||
const albums = new Albums(req);
|
const albums = new Albums(req);
|
||||||
const data = await albums.getAll();
|
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) {
|
} catch (err) {
|
||||||
next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
.post(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { ensureLoggedIn } from "connect-ensure-login";
|
||||||
|
|
||||||
import Pages from "../middleware/Pages";
|
import Pages from "../middleware/Pages";
|
||||||
import Auth from "../middleware/Auth";
|
import Auth from "../middleware/Auth";
|
||||||
import Albums from "../middleware/Albums";
|
|
||||||
|
|
||||||
import render from "../libs/format";
|
import render from "../libs/format";
|
||||||
|
|
||||||
|
@ -89,38 +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("/ma-collection/: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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.route("/nous-contacter").get(async (req, res, next) => {
|
router.route("/nous-contacter").get(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const page = new Pages(req, "nous-contacter");
|
const page = new Pages(req, "nous-contacter");
|
||||||
|
|
53
src/routes/ma-collection.js
Normal file
53
src/routes/ma-collection.js
Normal file
|
@ -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;
|
|
@ -68,6 +68,9 @@
|
||||||
<a class="navbar-item" href="/ma-collection">
|
<a class="navbar-item" href="/ma-collection">
|
||||||
Ma collection
|
Ma collection
|
||||||
</a>
|
</a>
|
||||||
|
<a class="navbar-item" href="/ma-collection/exporter">
|
||||||
|
Exporter ma collection
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
68
views/pages/mon-compte/ma-collection/exporter.ejs
Normal file
68
views/pages/mon-compte/ma-collection/exporter.ejs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<main class="layout-maxed ma-collection-exporter" id="app">
|
||||||
|
<h1>Exporter ma collection</h1>
|
||||||
|
<p>
|
||||||
|
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 :
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Nom de l'artiste</li>
|
||||||
|
<li>Nom de l'album</li>
|
||||||
|
<li>Liste des genres</li>
|
||||||
|
<li>Liste des styles</li>
|
||||||
|
<li>Pays (ou région) de distribution</li>
|
||||||
|
<li>Année de sortie</li>
|
||||||
|
<li>Date de sortie</li>
|
||||||
|
<li>Format de l'album</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Enfin le dernier format, MusicTopus, vous permettra d'exporter votre collection afin de l'importer ensuite sur une autre instance MusicTopus.
|
||||||
|
</p>
|
||||||
|
<form @submit="exportCollection">
|
||||||
|
<strong>Choisir le format d'export</strong>
|
||||||
|
|
||||||
|
<div class="field inline">
|
||||||
|
<input type="radio" name="format" v-model="format" value="csv" id="csv">
|
||||||
|
<label for="csv">CSV</label>
|
||||||
|
</div>
|
||||||
|
<div class="field inline">
|
||||||
|
<input type="radio" name="format" v-model="format" value="xls" id="xls">
|
||||||
|
<label for="xls">Excel</label>
|
||||||
|
</div>
|
||||||
|
<div class="field inline">
|
||||||
|
<input type="radio" name="format" v-model="format" value="xml" id="xml">
|
||||||
|
<label for="xml">XML</label>
|
||||||
|
</div>
|
||||||
|
<div class="field inline">
|
||||||
|
<input type="radio" name="format" v-model="format" value="musictopus" id="musictopus">
|
||||||
|
<label for="musictopus">MusicTopus</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="button is-primary my-16">
|
||||||
|
<i class="icon-export"></i>
|
||||||
|
Exporter
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
format: 'xml',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
exportCollection(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
window.open(`/api/v1/albums?exportFormat=${this.format}`, '_blank');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).mount('#app');
|
||||||
|
</script>
|
Loading…
Reference in a new issue