diff --git a/README.md b/README.md
index 1da497b..4e40c47 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ Le site est accessible sur [http://localhost:PORT](http://localhost:PORT).
#### Standalone
-Pour la version standalone je vous conseille de faire un script embarquant les variables d'environnement que vous souhaitez modifier :
+Pour la version standalone je vous conseille de faire un script embarquant les variables d'environnement que vous souhaitez modifier ([voir à la fin pour la liste des variables](#env-file)) :
```bash
#! /bin/bash
@@ -198,10 +198,15 @@ 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)
+AWS_ACCESS_KEY_ID # Clé d'accès AWS
+AWS_SECRET_ACCESS_KEY # Clé secrète AWS
+S3_ENDPOINT # Url de l'instance aws (s3.fr-par.scw.cloud pour scaleway france par exemple)
+S3_SIGNATURE # Version de la signature AWS (s3v4 pour scaleway par exemple)
+S3_BASEFOLDER # Nom du sous dossier dans lequel seront mis les pochettes des albums
+S3_BUCKET # Nom du bucket
```
## Contributeurs
- Damien Broqua (développeur principal du projet)
- Brunus (Logo et fournisseur d'idées :wink: )
-
diff --git a/docker-compose.yml.dev b/docker-compose.yml.dev
index 9391624..2f7e80e 100644
--- a/docker-compose.yml.dev
+++ b/docker-compose.yml.dev
@@ -28,6 +28,12 @@ services:
MATOMO_URL: ${MATOMO_URL}
MATOMO_ID: ${MATOMO_ID}
SITE_NAME: ${SITE_NAME}
+ AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
+ AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
+ S3_BASEFOLDER: ${S3_BASEFOLDER}
+ S3_BUCKET: ${S3_BUCKET}
+ S3_ENDPOINT: ${S3_ENDPOINT}
+ S3_SIGNATURE: ${S3_SIGNATURE}
networks:
- musictopus
musictopus-db:
diff --git a/docker-compose.yml.prod b/docker-compose.yml.prod
index 9077877..59823cb 100644
--- a/docker-compose.yml.prod
+++ b/docker-compose.yml.prod
@@ -28,6 +28,12 @@ services:
MATOMO_URL: ${MATOMO_URL}
MATOMO_ID: ${MATOMO_ID}
SITE_NAME: ${SITE_NAME}
+ AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
+ AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
+ S3_BASEFOLDER: ${S3_BASEFOLDER}
+ S3_BUCKET: ${S3_BUCKET}
+ S3_ENDPOINT: ${S3_ENDPOINT}
+ S3_SIGNATURE: ${S3_SIGNATURE}
networks:
- musictopus
musictopus-db:
diff --git a/package.json b/package.json
index b5aea27..d346f25 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"@babel/cli": "^7.17.0",
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
+ "aws-sdk": "^2.1110.0",
"axios": "^0.26.0",
"connect-ensure-login": "^0.1.1",
"connect-flash": "^0.1.1",
@@ -64,6 +65,7 @@
"passport-local": "^1.0.0",
"rimraf": "^3.0.2",
"sass": "^1.49.7",
+ "uuid": "^8.3.2",
"vue": "^3.2.31"
},
"nodemonConfig": {
diff --git a/src/app.js b/src/app.js
index 6d1e507..a3e80bd 100644
--- a/src/app.js
+++ b/src/app.js
@@ -46,10 +46,10 @@ const sess = {
const app = express();
-app.use(express.json());
-app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(flash());
+app.use(express.json({ limit: "50mb" }));
+app.use(express.urlencoded({ extended: false, limit: "50mb" }));
app.use(session(sess));
diff --git a/src/config/index.js b/src/config/index.js
index 19f16ea..8070698 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -8,4 +8,10 @@ module.exports = {
matomoUrl: process.env.MATOMO_URL || "",
matomoId: process.env.MATOMO_ID || "",
siteName: process.env.SITE_NAME || "MusicTopus",
+ awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
+ awsSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
+ s3BaseFolder: process.env.S3_BASEFOLDER || "dev",
+ s3Bucket: process.env.S3_BUCKET || "musictopus",
+ s3Endpoint: process.env.S3_ENDPOINT || "s3.fr-par.scw.cloud",
+ s3Signature: process.env.S3_SIGNATURE || "s3v4",
};
diff --git a/src/libs/aws.js b/src/libs/aws.js
new file mode 100644
index 0000000..f65521b
--- /dev/null
+++ b/src/libs/aws.js
@@ -0,0 +1,72 @@
+import AWS from "aws-sdk";
+import fs from "fs";
+import path from "path";
+import axios from "axios";
+import { v4 as uuid } from "uuid";
+
+import {
+ awsAccessKeyId,
+ awsSecretAccessKey,
+ s3BaseFolder,
+ s3Endpoint,
+ s3Bucket,
+ s3Signature,
+} from "../config";
+
+AWS.config.update({
+ accessKeyId: awsAccessKeyId,
+ secretAccessKey: awsSecretAccessKey,
+});
+/**
+ * Fonction permettant de stocker un fichier local sur S3
+ * @param {String} filename
+ * @param {String} file
+ * @param {Boolean} deleteFile
+ *
+ * @return {String}
+ */
+export const uploadFromFile = async (filename, file, deleteFile = false) => {
+ const data = await fs.readFileSync(file);
+
+ const base64data = Buffer.from(data, "binary");
+ const dest = path.join(s3BaseFolder, filename);
+
+ const s3 = new AWS.S3({
+ endpoint: s3Endpoint,
+ signatureVersion: s3Signature,
+ });
+
+ await s3
+ .putObject({
+ Bucket: s3Bucket,
+ Key: dest,
+ Body: base64data,
+ ACL: "public-read",
+ })
+ .promise();
+
+ if (deleteFile) {
+ fs.unlinkSync(file);
+ }
+
+ return `https://${s3Bucket}.${s3Endpoint}/${dest}`;
+};
+
+/**
+ * Fonction permettant de stocker un fichier provenant d'une URL sur S3
+ * @param {String} url
+ *
+ * @return {String}
+ */
+export const uploadFromUrl = async (url) => {
+ const filename = `${uuid()}.jpg`;
+ const file = `/tmp/${filename}`;
+
+ const { data } = await axios.get(url, { responseType: "arraybuffer" });
+
+ fs.writeFileSync(file, data);
+
+ return uploadFromFile(filename, file, true);
+
+ // return s3Object;
+};
diff --git a/src/middleware/Albums.js b/src/middleware/Albums.js
index 6caa29b..a0ead43 100644
--- a/src/middleware/Albums.js
+++ b/src/middleware/Albums.js
@@ -1,468 +1,19 @@
+/* eslint-disable no-await-in-loop */
import moment from "moment";
-import momenttz from "moment-timezone";
-import xl from "excel4node";
import Pages from "./Pages";
+import Export from "./Export";
import AlbumsModel from "../models/albums";
+import CronModel from "../models/cron";
import UsersModel from "../models/users";
import ErrorEvent from "../libs/error";
+// import { uploadFromUrl } from "../libs/aws";
/**
* 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 "";
- }
- 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 += `
- `;
- }
-
- 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 += `
- `;
- }
-
- 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
@@ -480,9 +31,36 @@ class Albums extends Pages {
: null;
delete data.id;
+ // INFO: {POC} Pour chaque image on récupère une version que l'on stocke localement
+ // Utiliser un cron qui check la librairie pour mettre à jour les urls des images
+ // Mettre en cron l'id du nouvel élément créé pour me pas parser toute la bibliothèque à chaque fois
+ // if (data.thumb) {
+ // data.thumb = await uploadFromUrl(data.thumb);
+ // data.thumbType = "local";
+ // }
+ // if (data.images && data.images.length > 0) {
+ // for (let i = 0; i < data.images.length; i += 1) {
+ // data.images[i].uri150 = await uploadFromUrl(
+ // data.images[i].uri150
+ // );
+ // data.images[i].uri = await uploadFromUrl(data.images[i].uri);
+ // }
+ // }
+
const album = new AlbumsModel(data);
- return album.save();
+ await album.save();
+
+ const cronData = {
+ model: "Albums",
+ id: album._id,
+ };
+
+ const cron = new CronModel(cronData);
+
+ cron.save();
+
+ return album;
}
/**
@@ -593,13 +171,13 @@ class Albums extends Pages {
switch (exportFormat) {
case "csv":
- return Albums.convertToCsv(rows);
+ return Export.convertToCsv(rows);
case "xls":
- return Albums.convertToXls(rows);
+ return Export.convertToXls(rows);
case "xml":
- return Albums.convertToXml(rows);
+ return Export.convertToXml(rows);
case "musictopus":
- return Albums.convertToMusicTopus(rows);
+ return Export.convertToMusicTopus(rows);
case "json":
default:
return {
diff --git a/src/middleware/Export.js b/src/middleware/Export.js
new file mode 100644
index 0000000..380f025
--- /dev/null
+++ b/src/middleware/Export.js
@@ -0,0 +1,453 @@
+import momenttz from "moment-timezone";
+import xl from "excel4node";
+
+class Export {
+ /**
+ * Méthode permettant de remplacer certains cartactères par leur équivalents html
+ * @param {String} str
+ *
+ * @return {String}
+ */
+ 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 += `
+ ${Export.replaceSpecialChars(artists[j].name)}
+ ${Export.replaceSpecialChars(artists[j].anv)}
+ ${Export.replaceSpecialChars(artists[j].join)}
+ ${Export.replaceSpecialChars(artists[j].role)}
+ ${Export.replaceSpecialChars(artists[j].tracks)}
+ ${Export.replaceSpecialChars(artists[j].id)}
+ ${Export.replaceSpecialChars(
+ artists[j].resource_url
+ )}
+ ${Export.replaceSpecialChars(
+ artists[j].thumbnail_url
+ )}
+ `;
+ }
+
+ for (let j = 0; j < labels.length; j += 1) {
+ labelList += `
+ `;
+ }
+
+ for (let j = 0; j < series.length; j += 1) {
+ serieList += `
+ ${Export.replaceSpecialChars(series[j].name)}
+ ${Export.replaceSpecialChars(series[j].catno)}
+ ${Export.replaceSpecialChars(
+ series[j].entity_type
+ )}
+ ${Export.replaceSpecialChars(
+ series[j].entity_type_name
+ )}
+ ${Export.replaceSpecialChars(series[j].id)}
+ ${Export.replaceSpecialChars(
+ series[j].resource_url
+ )}
+ ${Export.replaceSpecialChars(
+ series[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < companies.length; j += 1) {
+ companiesList += `
+ ${Export.replaceSpecialChars(companies[j].name)}
+ ${Export.replaceSpecialChars(companies[j].catno)}
+ ${Export.replaceSpecialChars(
+ companies[j].entity_type
+ )}
+ ${Export.replaceSpecialChars(
+ companies[j].entity_type_name
+ )}
+ ${Export.replaceSpecialChars(companies[j].id)}
+ ${Export.replaceSpecialChars(
+ companies[j].resource_url
+ )}
+ ${Export.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 += `
+ ${Export.replaceSpecialChars(formats[j].name)}
+ ${Export.replaceSpecialChars(formats[j].qty)}
+ ${Export.replaceSpecialChars(formats[j].text)}
+
+ ${descriptions}
+
+
+ `;
+ }
+
+ for (let j = 0; j < identifiers.length; j += 1) {
+ identifiersList += `
+ ${Export.replaceSpecialChars(identifiers[j].type)}
+ ${Export.replaceSpecialChars(identifiers[j].value)}
+ ${Export.replaceSpecialChars(
+ identifiers[j].description
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < videos.length; j += 1) {
+ videosList += `
+ `;
+ }
+
+ for (let j = 0; j < genres.length; j += 1) {
+ genresList += `${Export.replaceSpecialChars(
+ genres[j]
+ )}
+ `;
+ }
+
+ for (let j = 0; j < styles.length; j += 1) {
+ stylesList += `
+ `;
+ }
+
+ for (let j = 0; j < tracklist.length; j += 1) {
+ tracklistList += `
+ ${Export.replaceSpecialChars(tracklist[j].title)}
+
+ `;
+ }
+
+ for (let j = 0; j < extraartists.length; j += 1) {
+ extraartistsList += `
+ ${Export.replaceSpecialChars(extraartists[j].name)}
+ ${Export.replaceSpecialChars(extraartists[j].anv)}
+ ${Export.replaceSpecialChars(extraartists[j].join)}
+ ${Export.replaceSpecialChars(extraartists[j].role)}
+ ${Export.replaceSpecialChars(
+ extraartists[j].tracks
+ )}
+ ${Export.replaceSpecialChars(extraartists[j].id)}
+ ${Export.replaceSpecialChars(
+ extraartists[j].resource_url
+ )}
+ ${Export.replaceSpecialChars(
+ extraartists[j].thumbnail_url
+ )}
+
+ `;
+ }
+
+ for (let j = 0; j < images.length; j += 1) {
+ imagesList += `
+ ${Export.replaceSpecialChars(images[j].uri)}
+ ${Export.replaceSpecialChars(
+ images[j].resource_url
+ )}
+ ${Export.replaceSpecialChars(
+ images[j].resource_url
+ )}
+
+ `;
+ }
+
+ data += `
+
+ ${discogsId}
+ ${Export.replaceSpecialChars(title)}
+ ${Export.replaceSpecialChars(artists_sort)}
+
+ ${artistsList}
+
+ ${year}
+ ${Export.replaceSpecialChars(country)}
+ ${released}
+ ${uri}
+ ${thumb}
+
+ ${labelList}
+
+
+ ${serieList}
+
+
+ ${companiesList}
+
+
+ ${formatsList}
+
+ ${Export.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;
+ }
+}
+
+export default Export;
diff --git a/src/models/albums.js b/src/models/albums.js
index 0180dad..e08b7ad 100644
--- a/src/models/albums.js
+++ b/src/models/albums.js
@@ -29,6 +29,7 @@ const AlbumSchema = new mongoose.Schema(
extraartists: Array,
images: Array,
thumb: String,
+ thumbType: String,
},
{ timestamps: true }
);
diff --git a/src/models/cron.js b/src/models/cron.js
new file mode 100644
index 0000000..6e782cc
--- /dev/null
+++ b/src/models/cron.js
@@ -0,0 +1,24 @@
+import mongoose from "mongoose";
+
+const { Schema } = mongoose;
+
+const CronSchema = new mongoose.Schema(
+ {
+ model: String,
+ id: Schema.Types.ObjectId,
+ state: {
+ type: String,
+ enum: ["NEW", "ERROR", "SUCCESS"],
+ default: "NEW",
+ },
+ lastTry: Date,
+ lastErrorMessage: String,
+ tries: {
+ type: Number,
+ default: 0,
+ },
+ },
+ { timestamps: true }
+);
+
+export default mongoose.model("Cron", CronSchema);