From 1f63c74ac343d3492c469a5e571d7449a31f5be1 Mon Sep 17 00:00:00 2001 From: dbroqua Date: Fri, 4 Mar 2022 14:25:42 +0100 Subject: [PATCH] #2 {menu, csv, xls} --- package.json | 2 + public/font/icon.eot | Bin 9408 -> 9752 bytes public/font/icon.svg | 2 + public/font/icon.ttf | Bin 9256 -> 9600 bytes public/font/icon.woff | Bin 5844 -> 6060 bytes public/font/icon.woff2 | Bin 4860 -> 5052 bytes sass/forms.scss | 26 +++ sass/icons.scss | 1 + sass/index.scss | 4 +- src/app.js | 2 + src/middleware/Albums.js | 169 ++++++++++++++++-- src/routes/api/v1/albums.js | 14 +- src/routes/index.js | 33 ---- src/routes/ma-collection.js | 53 ++++++ views/index.ejs | 3 + .../mon-compte/ma-collection/exporter.ejs | 68 +++++++ 16 files changed, 325 insertions(+), 52 deletions(-) create mode 100644 src/routes/ma-collection.js create mode 100644 views/pages/mon-compte/ma-collection/exporter.ejs 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 8664abe7c3bb927c5503dbfc1ac1e0ec80045291..5a5d395769630de6dfb612635456a30fcfc3b97b 100644 GIT binary patch delta 849 zcmXw1OH30{6uoag?{(VJp+lJ>7AS=Rm5&XSR=y#iF+}i(kq}L>A{2$%2C5<|paEBE zz;R(P5Jh)xNQf+S0f`G;8CJwkG@7{Rf(4M6Kw`iS0ohsYkby^d>(+i(se!VL>(XXBMz3HSU7UAYDD!;QSAaCHZis}2V#H^eM}7vm^J*y4tqpCKB9G$+XJXO8_)^ui z_qYKY=3mDKx?>}YHH*0Pw>C-6kzs9(L_O0$FbnVm_`O*PMk6*k4FdF{ZUF;uKogQS z&Xr0|&|eq0w6|QYn2J97@)t)GG@A7)u(CH|-`YAKZIb{J2)$sUDhV(FtUpRZU$Zfh z1f*cRp9FpsHnx%g8DMiJ3H>w|UJ2jnCok+dfy)DcAl1nNR39_T%X6r~mP>5+GLX zkm4cFwV>j)31(qH*b;AxKj{Njz4wz?7v_|29J)r*op}4&YYHhRQ@XGZy(xZ{|;QsIG5dU|i{&P^Q5oVU-Wm&%(pNz-y6_ znwTQrt-F+gLC^&#ZWs>0txATlP-`C^aa!0g8br=y0fvT7#Kv30Oc1I6r~o_ zZL{9Sz@XeSc>-fJW5wh*jQN@~7#M-F3=ESPn87R^Ak78z#=dx}0(hAgI8gFnJe~B2WX{=7&s7i~&Zsq>YF3P5AXp1X$*QP diff --git a/public/font/icon.svg b/public/font/icon.svg index 9370b56..51f7015 100644 --- a/public/font/icon.svg +++ b/public/font/icon.svg @@ -24,6 +24,8 @@ + + diff --git a/public/font/icon.ttf b/public/font/icon.ttf index 1f0de7e581f6d9e5e42b4de9768222fc8c0c1ce2..488fa0b950dfb203d41f048e34aa311fcb6ee045 100644 GIT binary patch delta 862 zcmXw0OH30%82)Excc!~ty0nyn$fFbrR9+2~Havr%QG=)m5s9Wy5n6=W2C5=4fJQti z!K^0?20fX0At7?{fQgBEGMtFfXgsLlz(Gh%ATi>`oy6h*S-S#^R`_B7cq66dt)b z*gBl@4nWLCe@J;i2?$SjKumwSr>CY z0i=12fM{quPJEUn)Jqh{whftF_nO-~e{?zle_x#3xtkS1|Sa z!<`FcLhm9m&pZ%x0z3k`e=0+(;2q~dgb3;uFo6JUL)JG*d8HGK<-&y_s8fuRfC0xS z8S~7bLJH<+#=QyCJA@s*PcUn$(E`@?cYG85JdJhA02>IS+eU2?m=C{ZlfX)_HIoF^ zgspo?V0GBqNdo)8_CgXy$7NOg!lnd(yWjHkAsw5S(*w@4Z)ioGXU6n^1c4`Z@ z{`Iy7gRQe%C0c2oBsRHy#9v6(+&(2$GiBUeS2WHYJujPE4hSh+mQ?1q_qO4<*d9b2FZm^=b{jL8BYSANzXj$%p?|k5~i5sxMkS zWKn->_1Z;M92Iw@ThcdnpV#550$7(7+h+lze%hS^vFR+mp0k1Rcx*JGA5Je`9!g)e F`~&E-t6l&A delta 518 zcmXv}OK1~O6g~6FB+)dJCUwA2Y-kHw$P__LwRIt)BDiTmMA8;Brui&7oxw(lA~Bn~ zsfhYEAy}1y;IcF&>nvOe?%au`%Pc}M0in9lGY;OznLFp)bMJe%e)HpvmlIFxfHV&v zm$xmqxt)GXz5~ch`G=Jhb;b#opJ>r7+4rV@JtnV{MoQMYr^m?4%%RfiqvDxahy7{< z7`jj{SSw?j<_BQ-D(jgth2U8wNB)F-vTRqXGaI-6^eDWiaCz0qTgjxcM1DX%Zd+AX zIv3pm;wpJ+&9V!kIxxv6`M@pLS+CT-EPn<@KC!;--Y>Yd_FNm7c>d~WQL2htk~7tS z#3Jw-%D=xf^D*w&fQlmZC_<2-bwi>jndT{YC&fbxb%m|~Gz94iv+p<}7-EmkvL+Vf z-y$c6b?(dX9^r*9vWj!&wOwq`bR!E8-pz$&|9PGcdd0k zlGjGx^>)YZ>X&{(SGwLU`_~@?{%5flpOIps7oQR*6XuBWRn4mVfh&PS?F}v7{;^gz W@lB>DW2D3#V@@=U)2)utiT(vP^m7mZ diff --git a/public/font/icon.woff b/public/font/icon.woff index 6474d86873d5600e7ce9e3cfcd9dd17133cfb3d1..7c3262dd2702cebd300972a85c85e47075a2dd86 100644 GIT binary patch delta 3533 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 S!>haXIZX>+@S6g2<^TY&bBksG literal 4860 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 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/icons.scss b/sass/icons.scss index 05250a2..ca297ea 100644 --- a/sass/icons.scss +++ b/sass/icons.scss @@ -41,6 +41,7 @@ .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 7ff8d31..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"; 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 7e4d5d7..9afbbc8 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,126 @@ import ErrorEvent from "../libs/error"; * Classe permettant la gestion des albums d'un utilisateur */ class Albums extends Pages { + /** + * Méthode permettant de convertir les rows en csv + * @param {Array} rows + * + * @return {string} + */ + static async convertToCsv(rows) { + let data = ""; + + 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 {string} + */ + 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 d'ajouter un album dans une collection * @param {Object} req @@ -59,16 +181,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 +204,43 @@ 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 "json": + default: + return { + rows, + count, + }; + } } /** diff --git a/src/routes/api/v1/albums.js b/src/routes/api/v1/albums.js index 5d0c68c..df1b5c6 100644 --- a/src/routes/api/v1/albums.js +++ b/src/routes/api/v1/albums.js @@ -13,10 +13,20 @@ 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": + res.header("Content-Type", "text/csv"); + 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 fca9847..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,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) => { 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/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. +

+
+ Choisir le format d'export + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+ + \ No newline at end of file