@93 - Wantlist
This commit is contained in:
parent
bed5139a27
commit
a4a3933c6d
24 changed files with 1137 additions and 70 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
Vue.createApp({
|
Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -177,12 +178,15 @@ Vue.createApp({
|
||||||
this.submitting = true;
|
this.submitting = true;
|
||||||
|
|
||||||
return axios
|
return axios
|
||||||
.post("/api/v1/albums", {
|
.post(`/api/v1/${action}`, {
|
||||||
album: this.details,
|
album: this.details,
|
||||||
share: this.share,
|
share: this.share,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.href = "/ma-collection";
|
window.location.href =
|
||||||
|
action === "albums"
|
||||||
|
? "/ma-collection"
|
||||||
|
: "/ma-liste-de-souhaits";
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.submitting = false;
|
this.submitting = false;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
Vue.createApp({
|
Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -74,7 +75,7 @@ Vue.createApp({
|
||||||
|
|
||||||
this.sortOrder = `${sortOrder.sort}-${sortOrder.order}`;
|
this.sortOrder = `${sortOrder.sort}-${sortOrder.order}`;
|
||||||
|
|
||||||
let url = `/api/v1/albums?page=${this.page}&sort=${this.sort}&order=${this.order}`;
|
let url = `/api/v1/${action}?page=${this.page}&sort=${this.sort}&order=${this.order}`;
|
||||||
if (this.artist) {
|
if (this.artist) {
|
||||||
url += `&artist=${this.formatParams(this.artist)}`;
|
url += `&artist=${this.formatParams(this.artist)}`;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +187,7 @@ Vue.createApp({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return axios
|
return axios
|
||||||
.delete(`/api/v1/albums/${this.itemId}`)
|
.delete(`/api/v1/${action}/${this.itemId}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,6 +19,8 @@ if (typeof email !== "undefined" && typeof username !== "undefined") {
|
||||||
token: "",
|
token: "",
|
||||||
message:
|
message:
|
||||||
"Je viens d'ajouter {artist} - {album} à ma collection !",
|
"Je viens d'ajouter {artist} - {album} à ma collection !",
|
||||||
|
wantlist:
|
||||||
|
"Je viens d'ajouter {artist} - {album} à ma liste de souhaits !",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -58,8 +60,13 @@ if (typeof email !== "undefined" && typeof username !== "undefined") {
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
async updateProfil() {
|
async updateProfil() {
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
const { oldPassword, password, passwordConfirm, mastodon, pagination } =
|
const {
|
||||||
this.formData;
|
oldPassword,
|
||||||
|
password,
|
||||||
|
passwordConfirm,
|
||||||
|
mastodon,
|
||||||
|
pagination,
|
||||||
|
} = this.formData;
|
||||||
|
|
||||||
if (password && !oldPassword) {
|
if (password && !oldPassword) {
|
||||||
this.errors.push("emptyPassword");
|
this.errors.push("emptyPassword");
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
if (typeof item !== "undefined") {
|
if (typeof item !== "undefined") {
|
||||||
Vue.createApp({
|
Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
|
@ -196,7 +197,7 @@ if (typeof item !== "undefined") {
|
||||||
updateItem() {
|
updateItem() {
|
||||||
showToastr("Mise à jour en cours…", true);
|
showToastr("Mise à jour en cours…", true);
|
||||||
axios
|
axios
|
||||||
.patch(`/api/v1/albums/${this.item._id}`)
|
.patch(`/api/v1/${action}/${this.item._id}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
showToastr("Mise à jour réalisée avec succès", true);
|
showToastr("Mise à jour réalisée avec succès", true);
|
||||||
this.item = res.data;
|
this.item = res.data;
|
||||||
|
@ -215,9 +216,12 @@ if (typeof item !== "undefined") {
|
||||||
},
|
},
|
||||||
deleteItem() {
|
deleteItem() {
|
||||||
axios
|
axios
|
||||||
.delete(`/api/v1/albums/${this.item._id}`)
|
.delete(`/api/v1/${action}/${this.item._id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.href = "/ma-collection";
|
window.location.href =
|
||||||
|
action === "albums"
|
||||||
|
? "/ma-collection"
|
||||||
|
: "/ma-liste-de-souhaits";
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
showToastr(
|
showToastr(
|
||||||
|
@ -238,7 +242,7 @@ if (typeof item !== "undefined") {
|
||||||
}
|
}
|
||||||
this.shareSubmiting = true;
|
this.shareSubmiting = true;
|
||||||
axios
|
axios
|
||||||
.post(`/api/v1/albums/${this.item._id}/share`, {
|
.post(`/api/v1/${action}/${this.item._id}/share`, {
|
||||||
message: this.shareMessageTransformed,
|
message: this.shareMessageTransformed,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
Vue.createApp({
|
Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -10,7 +11,10 @@ Vue.createApp({
|
||||||
exportCollection(event) {
|
exportCollection(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
window.open(`/api/v1/albums?exportFormat=${this.format}`, "_blank");
|
window.open(
|
||||||
|
`/api/v1/${action}?exportFormat=${this.format}`,
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).mount("#exporter");
|
}).mount("#exporter");
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
Vue.createApp({
|
Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -66,11 +67,11 @@ Vue.createApp({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(
|
const res = await axios.get(
|
||||||
`/api/v1/albums?discogsId=${release_id}`
|
`/api/v1/${action}?discogsId=${release_id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status === 204) {
|
if (res.status === 204) {
|
||||||
await axios.post("/api/v1/albums", {
|
await axios.post(`/api/v1/${action}`, {
|
||||||
discogsId: release_id,
|
discogsId: release_id,
|
||||||
share: false,
|
share: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,12 +15,14 @@ import { isXhr } from "./helpers";
|
||||||
|
|
||||||
import indexRouter from "./routes";
|
import indexRouter from "./routes";
|
||||||
import maCollectionRouter from "./routes/ma-collection";
|
import maCollectionRouter from "./routes/ma-collection";
|
||||||
|
import wantlistRouter from "./routes/wantlist";
|
||||||
import monCompteRouter from "./routes/mon-compte";
|
import monCompteRouter from "./routes/mon-compte";
|
||||||
import collectionRouter from "./routes/collection";
|
import collectionRouter from "./routes/collection";
|
||||||
|
|
||||||
import importJobsRouter from "./routes/jobs";
|
import importJobsRouter from "./routes/jobs";
|
||||||
|
|
||||||
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
|
import importAlbumRouterApiV1 from "./routes/api/v1/albums";
|
||||||
|
import importWantlistRouterApiV1 from "./routes/api/v1/wantlist";
|
||||||
import importSearchRouterApiV1 from "./routes/api/v1/search";
|
import importSearchRouterApiV1 from "./routes/api/v1/search";
|
||||||
import importMastodonRouterApiV1 from "./routes/api/v1/mastodon";
|
import importMastodonRouterApiV1 from "./routes/api/v1/mastodon";
|
||||||
import importMeRouterApiV1 from "./routes/api/v1/me";
|
import importMeRouterApiV1 from "./routes/api/v1/me";
|
||||||
|
@ -81,9 +83,11 @@ app.use(express.static(path.join(__dirname, "../public")));
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
app.use("/mon-compte", monCompteRouter);
|
app.use("/mon-compte", monCompteRouter);
|
||||||
app.use("/ma-collection", maCollectionRouter);
|
app.use("/ma-collection", maCollectionRouter);
|
||||||
|
app.use("/ma-liste-de-souhaits", wantlistRouter);
|
||||||
app.use("/collection", collectionRouter);
|
app.use("/collection", collectionRouter);
|
||||||
app.use("/jobs", importJobsRouter);
|
app.use("/jobs", importJobsRouter);
|
||||||
app.use("/api/v1/albums", importAlbumRouterApiV1);
|
app.use("/api/v1/albums", importAlbumRouterApiV1);
|
||||||
|
app.use("/api/v1/wantlist", importWantlistRouterApiV1);
|
||||||
app.use("/api/v1/search", importSearchRouterApiV1);
|
app.use("/api/v1/search", importSearchRouterApiV1);
|
||||||
app.use("/api/v1/mastodon", importMastodonRouterApiV1);
|
app.use("/api/v1/mastodon", importMastodonRouterApiV1);
|
||||||
app.use("/api/v1/me", importMeRouterApiV1);
|
app.use("/api/v1/me", importMeRouterApiV1);
|
||||||
|
|
|
@ -53,3 +53,28 @@ export const isXhr = (req) => {
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de récupérer les éléments distincts d'une collection
|
||||||
|
* @param {Object} model
|
||||||
|
* @param {String} field
|
||||||
|
* @param {import("mongoose").ObjectId} user
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getAllDistincts = async (model, field, user) => {
|
||||||
|
const distincts = await model
|
||||||
|
.find(
|
||||||
|
{
|
||||||
|
User: user,
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
sort: {
|
||||||
|
[field]: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.distinct(field);
|
||||||
|
|
||||||
|
return distincts;
|
||||||
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ import JobsModel from "../models/jobs";
|
||||||
import UsersModel from "../models/users";
|
import UsersModel from "../models/users";
|
||||||
import ErrorEvent from "../libs/error";
|
import ErrorEvent from "../libs/error";
|
||||||
|
|
||||||
import { getAlbumDetails } from "../helpers";
|
import { getAlbumDetails, getAllDistincts } from "../helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classe permettant la gestion des albums d'un utilisateur
|
* Classe permettant la gestion des albums d'un utilisateur
|
||||||
|
@ -42,8 +42,11 @@ class Albums extends Pages {
|
||||||
discogsId: albumDetails.id,
|
discogsId: albumDetails.id,
|
||||||
User: user._id,
|
User: user._id,
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line no-nested-ternary
|
||||||
data.released = data.released
|
data.released = data.released
|
||||||
|
? typeof data.released === "string"
|
||||||
? new Date(data.released.replace("-00", "-01"))
|
? new Date(data.released.replace("-00", "-01"))
|
||||||
|
: data.released
|
||||||
: null;
|
: null;
|
||||||
delete data.id;
|
delete data.id;
|
||||||
|
|
||||||
|
@ -142,28 +145,6 @@ Publié automatiquement via #musictopus`;
|
||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Méthode permettant de récupérer les éléments distincts d'une collection
|
|
||||||
* @param {String} field
|
|
||||||
* @param {ObjectId} user
|
|
||||||
* @return {Array}
|
|
||||||
*/
|
|
||||||
static async getAllDistincts(field, user) {
|
|
||||||
const distincts = await AlbumsModel.find(
|
|
||||||
{
|
|
||||||
User: user,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
sort: {
|
|
||||||
[field]: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
).distinct(field);
|
|
||||||
|
|
||||||
return distincts;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(req, viewname) {
|
constructor(req, viewname) {
|
||||||
super(req, viewname);
|
super(req, viewname);
|
||||||
|
|
||||||
|
@ -178,6 +159,8 @@ Publié automatiquement via #musictopus`;
|
||||||
"#a3be8c",
|
"#a3be8c",
|
||||||
"#b48ead",
|
"#b48ead",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.setPageContent("action", "albums");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -457,20 +440,28 @@ Publié automatiquement via #musictopus`;
|
||||||
* Méthode permettant de créer la page "ma-collection"
|
* Méthode permettant de créer la page "ma-collection"
|
||||||
*/
|
*/
|
||||||
async loadMyCollection() {
|
async loadMyCollection() {
|
||||||
const artists = await Albums.getAllDistincts(
|
const artists = await getAllDistincts(
|
||||||
|
AlbumsModel,
|
||||||
"artists.name",
|
"artists.name",
|
||||||
this.req.user._id
|
this.req.user._id
|
||||||
);
|
);
|
||||||
const formats = await Albums.getAllDistincts(
|
const formats = await getAllDistincts(
|
||||||
|
AlbumsModel,
|
||||||
"formats.name",
|
"formats.name",
|
||||||
this.req.user._id
|
this.req.user._id
|
||||||
);
|
);
|
||||||
const years = await Albums.getAllDistincts("year", this.req.user._id);
|
const years = await getAllDistincts(
|
||||||
const genres = await Albums.getAllDistincts(
|
AlbumsModel,
|
||||||
|
"year",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
const genres = await getAllDistincts(
|
||||||
|
AlbumsModel,
|
||||||
"genres",
|
"genres",
|
||||||
this.req.user._id
|
this.req.user._id
|
||||||
);
|
);
|
||||||
const styles = await Albums.getAllDistincts(
|
const styles = await getAllDistincts(
|
||||||
|
AlbumsModel,
|
||||||
"styles",
|
"styles",
|
||||||
this.req.user._id
|
this.req.user._id
|
||||||
);
|
);
|
||||||
|
@ -669,11 +660,19 @@ Publié automatiquement via #musictopus`;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const artists = await Albums.getAllDistincts("artists.name", userId);
|
const artists = await getAllDistincts(
|
||||||
const formats = await Albums.getAllDistincts("formats.name", userId);
|
AlbumsModel,
|
||||||
const years = await Albums.getAllDistincts("year", userId);
|
"artists.name",
|
||||||
const genres = await Albums.getAllDistincts("genres", userId);
|
userId
|
||||||
const styles = await Albums.getAllDistincts("styles", userId);
|
);
|
||||||
|
const formats = await getAllDistincts(
|
||||||
|
AlbumsModel,
|
||||||
|
"formats.name",
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
const years = await getAllDistincts(AlbumsModel, "year", userId);
|
||||||
|
const genres = await getAllDistincts(AlbumsModel, "genres", userId);
|
||||||
|
const styles = await getAllDistincts(AlbumsModel, "styles", userId);
|
||||||
|
|
||||||
this.setPageTitle(`Collection publique de ${user.username}`);
|
this.setPageTitle(`Collection publique de ${user.username}`);
|
||||||
this.setPageContent("username", user.username);
|
this.setPageContent("username", user.username);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { getAlbumDetails } from "../helpers";
|
||||||
|
|
||||||
import JobsModel from "../models/jobs";
|
import JobsModel from "../models/jobs";
|
||||||
import AlbumsModel from "../models/albums";
|
import AlbumsModel from "../models/albums";
|
||||||
|
import WantListModel from "../models/wantlist";
|
||||||
|
|
||||||
class Jobs {
|
class Jobs {
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +52,50 @@ class Jobs {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de télécharger toute les images d'un album
|
||||||
|
* @param {ObjectId} itemId
|
||||||
|
*/
|
||||||
|
static async importAlbumForWantListAssets(itemId) {
|
||||||
|
const album = await WantListModel.findById(itemId);
|
||||||
|
|
||||||
|
if (!album) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
404,
|
||||||
|
"Item non trouvé",
|
||||||
|
`L'album avec l'id ${itemId} n'existe plus dans la collection`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = await getAlbumDetails(album.discogsId);
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
404,
|
||||||
|
"Erreur de communication",
|
||||||
|
"Erreur lors de la récupération des informations sur Discogs"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.thumb) {
|
||||||
|
album.thumb = await uploadFromUrl(item.thumb);
|
||||||
|
album.thumbType = "local";
|
||||||
|
}
|
||||||
|
const { images } = item;
|
||||||
|
if (images && images.length > 0) {
|
||||||
|
for (let i = 0; i < images.length; i += 1) {
|
||||||
|
images[i].uri150 = await uploadFromUrl(images[i].uri150);
|
||||||
|
images[i].uri = await uploadFromUrl(images[i].uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
album.images = images;
|
||||||
|
|
||||||
|
await album.save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Point d'entrée
|
* Point d'entrée
|
||||||
* @param {String} state
|
* @param {String} state
|
||||||
|
@ -78,6 +123,9 @@ class Jobs {
|
||||||
case "Albums":
|
case "Albums":
|
||||||
await Jobs.importAlbumAssets(job.id);
|
await Jobs.importAlbumAssets(job.id);
|
||||||
break;
|
break;
|
||||||
|
case "WantList":
|
||||||
|
await Jobs.importAlbumForWantListAssets(job.id);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ErrorEvent(
|
throw new ErrorEvent(
|
||||||
500,
|
500,
|
||||||
|
|
|
@ -26,6 +26,7 @@ class Me extends Pages {
|
||||||
url: Joi.string().uri().allow(null, ""),
|
url: Joi.string().uri().allow(null, ""),
|
||||||
token: Joi.string().allow(null, ""),
|
token: Joi.string().allow(null, ""),
|
||||||
message: Joi.string().allow(null, ""),
|
message: Joi.string().allow(null, ""),
|
||||||
|
wantlist: Joi.string().allow(null, ""),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
687
src/middleware/Wantlist.js
Normal file
687
src/middleware/Wantlist.js
Normal file
|
@ -0,0 +1,687 @@
|
||||||
|
import { format as formatDate } from "date-fns";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
import Mastodon from "mastodon";
|
||||||
|
import { v4 } from "uuid";
|
||||||
|
import axios from "axios";
|
||||||
|
import Pages from "./Pages";
|
||||||
|
import Export from "./Export";
|
||||||
|
|
||||||
|
import WantListModel from "../models/wantlist";
|
||||||
|
import JobsModel from "../models/jobs";
|
||||||
|
import UsersModel from "../models/users";
|
||||||
|
import ErrorEvent from "../libs/error";
|
||||||
|
|
||||||
|
import { getAlbumDetails, getAllDistincts } from "../helpers";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe permettant la gestion da la liste de souhaits d'un utilisateur
|
||||||
|
*/
|
||||||
|
class Wantlist extends Pages {
|
||||||
|
/**
|
||||||
|
* Méthode permettant d'ajouter un album dans une collection
|
||||||
|
* @param {Object} req
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
static async postAddOne(req) {
|
||||||
|
const { body, user } = req;
|
||||||
|
const { share, discogsId } = body;
|
||||||
|
|
||||||
|
let albumDetails = body.album;
|
||||||
|
if (discogsId) {
|
||||||
|
albumDetails = await getAlbumDetails(discogsId);
|
||||||
|
body.id = discogsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!albumDetails) {
|
||||||
|
throw new ErrorEvent(406, "Aucun album à ajouter");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
...albumDetails,
|
||||||
|
discogsId: albumDetails.id,
|
||||||
|
User: user._id,
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line no-nested-ternary
|
||||||
|
data.released = data.released
|
||||||
|
? typeof data.released === "string"
|
||||||
|
? new Date(data.released.replace("-00", "-01"))
|
||||||
|
: data.released
|
||||||
|
: null;
|
||||||
|
delete data.id;
|
||||||
|
|
||||||
|
const album = new WantListModel(data);
|
||||||
|
|
||||||
|
await album.save();
|
||||||
|
|
||||||
|
const jobData = {
|
||||||
|
model: "WantList",
|
||||||
|
id: album._id,
|
||||||
|
};
|
||||||
|
const job = new JobsModel(jobData);
|
||||||
|
|
||||||
|
job.save();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const User = await UsersModel.findOne({ _id: user._id });
|
||||||
|
|
||||||
|
const { mastodon: mastodonConfig } = User;
|
||||||
|
|
||||||
|
const { publish, token, url, wantlist } = mastodonConfig;
|
||||||
|
|
||||||
|
if (share && publish && url && token) {
|
||||||
|
const M = new Mastodon({
|
||||||
|
access_token: token,
|
||||||
|
api_url: url,
|
||||||
|
});
|
||||||
|
|
||||||
|
const video =
|
||||||
|
data.videos && data.videos.length > 0
|
||||||
|
? data.videos[0].uri
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const status = `${(
|
||||||
|
wantlist ||
|
||||||
|
"Je viens d'ajouter {artist} - {album} à ma liste de souhaits !"
|
||||||
|
)
|
||||||
|
.replaceAll("{artist}", data.artists[0].name)
|
||||||
|
.replaceAll("{format}", data.formats[0].name)
|
||||||
|
.replaceAll("{genres}", data.genres.join())
|
||||||
|
.replaceAll("{styles}", data.styles.join())
|
||||||
|
.replaceAll("{year}", data.year)
|
||||||
|
.replaceAll("{video}", video)
|
||||||
|
.replaceAll("{album}", data.title)}
|
||||||
|
|
||||||
|
Publié automatiquement via #musictopus`;
|
||||||
|
|
||||||
|
const media_ids = [];
|
||||||
|
|
||||||
|
if (data.images.length > 0) {
|
||||||
|
for (let i = 0; i < data.images.length; i += 1) {
|
||||||
|
if (media_ids.length === 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = `${v4()}.jpg`;
|
||||||
|
const file = `/tmp/${filename}`;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const { data: buff } = await axios.get(
|
||||||
|
data.images[i].uri,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"User-Agent":
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0",
|
||||||
|
},
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.writeFileSync(file, buff);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const { data: media } = await M.post("media", {
|
||||||
|
file: fs.createReadStream(file),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { id } = media;
|
||||||
|
|
||||||
|
media_ids.push(id);
|
||||||
|
|
||||||
|
fs.unlinkSync(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await M.post("statuses", { status, media_ids });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
500,
|
||||||
|
"Mastodon",
|
||||||
|
"Album ajouté à votre collection mais impossible de publier sur Mastodon"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return album;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(req, viewname) {
|
||||||
|
super(req, viewname);
|
||||||
|
|
||||||
|
this.colors = [
|
||||||
|
"#2e3440",
|
||||||
|
"#d8dee9",
|
||||||
|
"#8fbcbb",
|
||||||
|
"#5e81ac",
|
||||||
|
"#d08770",
|
||||||
|
"#bf616a",
|
||||||
|
"#ebcb8b",
|
||||||
|
"#a3be8c",
|
||||||
|
"#b48ead",
|
||||||
|
];
|
||||||
|
|
||||||
|
this.setPageContent("action", "wantlist");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de récupérer la liste des albums d'une collection
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
async getAll() {
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
exportFormat = "json",
|
||||||
|
sort = "artists_sort",
|
||||||
|
order = "asc",
|
||||||
|
artist,
|
||||||
|
format,
|
||||||
|
year,
|
||||||
|
genre,
|
||||||
|
style,
|
||||||
|
userId: collectionUserId,
|
||||||
|
discogsIds,
|
||||||
|
discogsId,
|
||||||
|
} = this.req.query;
|
||||||
|
|
||||||
|
const limit = this.req.user?.pagination || 16;
|
||||||
|
|
||||||
|
let userId = this.req.user?._id;
|
||||||
|
|
||||||
|
const where = {};
|
||||||
|
|
||||||
|
if (artist) {
|
||||||
|
where["artists.name"] = artist;
|
||||||
|
}
|
||||||
|
if (format) {
|
||||||
|
where["formats.name"] = format;
|
||||||
|
}
|
||||||
|
if (year) {
|
||||||
|
where.year = year;
|
||||||
|
}
|
||||||
|
if (genre) {
|
||||||
|
where.genres = genre;
|
||||||
|
}
|
||||||
|
if (style) {
|
||||||
|
where.styles = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.req.user && !collectionUserId) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
401,
|
||||||
|
"Collection",
|
||||||
|
"Cette collection n'est pas publique"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectionUserId) {
|
||||||
|
const userIsSharingCollection = await UsersModel.findById(
|
||||||
|
collectionUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!userIsSharingCollection ||
|
||||||
|
!userIsSharingCollection.isPublicCollection
|
||||||
|
) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
401,
|
||||||
|
"Collection",
|
||||||
|
"Cette collection n'est pas publique"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = userIsSharingCollection._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discogsIds) {
|
||||||
|
where.discogsId = { $in: discogsIds };
|
||||||
|
}
|
||||||
|
if (discogsId) {
|
||||||
|
where.discogsId = Number(discogsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const count = await WantListModel.count({
|
||||||
|
User: userId,
|
||||||
|
...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 WantListModel.find(
|
||||||
|
{
|
||||||
|
User: userId,
|
||||||
|
...where,
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (exportFormat) {
|
||||||
|
case "csv":
|
||||||
|
return Export.convertToCsv(rows);
|
||||||
|
case "xls":
|
||||||
|
return Export.convertToXls(rows);
|
||||||
|
case "xml":
|
||||||
|
return Export.convertToXml(rows);
|
||||||
|
case "musictopus":
|
||||||
|
return Export.convertToMusicTopus(rows);
|
||||||
|
case "json":
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
rows,
|
||||||
|
limit,
|
||||||
|
count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de récupérer le détails d'un album
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
async getOne() {
|
||||||
|
const { itemId: _id } = this.req.params;
|
||||||
|
const { _id: User } = this.req.user;
|
||||||
|
const album = await WantListModel.findOne({
|
||||||
|
_id,
|
||||||
|
User,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...album.toJSON(),
|
||||||
|
released: album.released
|
||||||
|
? formatDate(album.released, "MM/dd/yyyy")
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de mettre à jour un album
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
async patchOne() {
|
||||||
|
const { itemId: _id } = this.req.params;
|
||||||
|
const { _id: User } = this.req.user;
|
||||||
|
const query = {
|
||||||
|
_id,
|
||||||
|
User,
|
||||||
|
};
|
||||||
|
const album = await WantListModel.findOne(query);
|
||||||
|
|
||||||
|
if (!album) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
404,
|
||||||
|
"Mise à jour",
|
||||||
|
"Impossible de trouver cet album"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const values = await getAlbumDetails(album.discogsId);
|
||||||
|
|
||||||
|
await WantListModel.findOneAndUpdate(query, values, { new: true });
|
||||||
|
|
||||||
|
return this.getOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de supprimer un élément d'une collection
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
async deleteOne() {
|
||||||
|
const res = await WantListModel.findOneAndDelete({
|
||||||
|
User: this.req.user._id,
|
||||||
|
_id: this.req.params.itemId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ErrorEvent(
|
||||||
|
404,
|
||||||
|
"Suppression",
|
||||||
|
"Impossible de trouver cet album"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async shareOne() {
|
||||||
|
const { message: status } = this.req.body;
|
||||||
|
const { itemId: _id } = this.req.params;
|
||||||
|
const { _id: User } = this.req.user;
|
||||||
|
const query = {
|
||||||
|
_id,
|
||||||
|
User,
|
||||||
|
};
|
||||||
|
|
||||||
|
const album = await WantListModel.findOne(query);
|
||||||
|
|
||||||
|
if (!album) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
404,
|
||||||
|
"Mise à jour",
|
||||||
|
"Impossible de trouver cet album"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { mastodon: mastodonConfig } = this.req.user;
|
||||||
|
const { publish, token, url } = mastodonConfig;
|
||||||
|
|
||||||
|
if (publish && url && token) {
|
||||||
|
const M = new Mastodon({
|
||||||
|
access_token: token,
|
||||||
|
api_url: url,
|
||||||
|
});
|
||||||
|
|
||||||
|
const media_ids = [];
|
||||||
|
|
||||||
|
if (album.images.length > 0) {
|
||||||
|
for (let i = 0; i < album.images.length; i += 1) {
|
||||||
|
if (media_ids.length === 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = `${v4()}.jpg`;
|
||||||
|
const file = `/tmp/${filename}`;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const { data: buff } = await axios.get(
|
||||||
|
album.images[i].uri,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"User-Agent":
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0",
|
||||||
|
},
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.writeFileSync(file, buff);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const { data: media } = await M.post("media", {
|
||||||
|
file: fs.createReadStream(file),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { id } = media;
|
||||||
|
|
||||||
|
media_ids.push(id);
|
||||||
|
|
||||||
|
fs.unlinkSync(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await M.post("statuses", { status, media_ids });
|
||||||
|
} else {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
406,
|
||||||
|
`Vous n'avez pas configuré vos options de partage sur votre compte`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de créer la page "ma-collection"
|
||||||
|
*/
|
||||||
|
async loadMyCollection() {
|
||||||
|
const artists = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"artists.name",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
const formats = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"formats.name",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
const years = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"year",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
const genres = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"genres",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
const styles = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"styles",
|
||||||
|
this.req.user._id
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setPageContent("artists", artists);
|
||||||
|
this.setPageContent("formats", formats);
|
||||||
|
this.setPageContent("years", years);
|
||||||
|
this.setPageContent("genres", genres);
|
||||||
|
this.setPageContent("styles", styles);
|
||||||
|
this.setPageTitle("Ma collection");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant d'afficher le détails d'un album
|
||||||
|
*/
|
||||||
|
async loadItem() {
|
||||||
|
const item = await this.getOne();
|
||||||
|
|
||||||
|
this.setPageContent("item", item);
|
||||||
|
this.setPageTitle(
|
||||||
|
`Détails de l'album ${item.title} de ${item.artists_sort}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de choisir un album de manière aléatoire dans la collection d'un utilisateur
|
||||||
|
*/
|
||||||
|
async onAir() {
|
||||||
|
const { _id: User } = this.req.user;
|
||||||
|
const count = await WantListModel.count({
|
||||||
|
User,
|
||||||
|
});
|
||||||
|
|
||||||
|
const items = await WantListModel.find(
|
||||||
|
{
|
||||||
|
User,
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
skip: Math.floor(Math.random() * (count + 1)),
|
||||||
|
limit: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.req.params.itemId = items[0]._id;
|
||||||
|
|
||||||
|
await this.loadItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant d'afficher des statistiques au sujet de ma collection
|
||||||
|
*/
|
||||||
|
async statistics() {
|
||||||
|
const { _id: User } = this.req.user;
|
||||||
|
const top = {};
|
||||||
|
const byGenres = {};
|
||||||
|
const byStyles = {};
|
||||||
|
const byFormats = {};
|
||||||
|
const top10 = [];
|
||||||
|
let byStyles10 = [];
|
||||||
|
const max = this.colors.length - 1;
|
||||||
|
|
||||||
|
const colorsCount = this.colors.length;
|
||||||
|
|
||||||
|
const albums = await WantListModel.find({
|
||||||
|
User,
|
||||||
|
artists: { $exists: true, $not: { $size: 0 } },
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < albums.length; i += 1) {
|
||||||
|
const currentFormats = [];
|
||||||
|
const { artists, genres, styles, formats } = albums[i];
|
||||||
|
|
||||||
|
// INFO: On regroupe les artistes par nom pour en faire le top10
|
||||||
|
for (let j = 0; j < artists.length; j += 1) {
|
||||||
|
const { name } = artists[j];
|
||||||
|
if (!top[name]) {
|
||||||
|
top[name] = {
|
||||||
|
name,
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
top[name].count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: On regroupe les genres
|
||||||
|
for (let j = 0; j < genres.length; j += 1) {
|
||||||
|
const name = genres[j];
|
||||||
|
if (!byGenres[name]) {
|
||||||
|
byGenres[name] = {
|
||||||
|
name,
|
||||||
|
count: 0,
|
||||||
|
color: this.colors[
|
||||||
|
Object.keys(byGenres).length % colorsCount
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
byGenres[name].count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: On regroupe les styles
|
||||||
|
for (let j = 0; j < styles.length; j += 1) {
|
||||||
|
const name = styles[j];
|
||||||
|
if (!byStyles[name]) {
|
||||||
|
byStyles[name] = {
|
||||||
|
name,
|
||||||
|
count: 0,
|
||||||
|
color: this.colors[
|
||||||
|
Object.keys(byStyles).length % colorsCount
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
byStyles[name].count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: On regroupe les formats
|
||||||
|
for (let j = 0; j < formats.length; j += 1) {
|
||||||
|
const { name } = formats[j];
|
||||||
|
// INFO: On évite qu'un album avec 2 vinyles soit compté 2x
|
||||||
|
if (!currentFormats.includes(name)) {
|
||||||
|
if (!byFormats[name]) {
|
||||||
|
byFormats[name] = {
|
||||||
|
name,
|
||||||
|
count: 0,
|
||||||
|
color: this.colors[
|
||||||
|
Object.keys(byFormats).length % colorsCount
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
byFormats[name].count += 1;
|
||||||
|
currentFormats.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: On convertit le top en tableau
|
||||||
|
Object.keys(top).forEach((index) => {
|
||||||
|
top10.push(top[index]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// INFO: On convertit les styles en tableau
|
||||||
|
Object.keys(byStyles).forEach((index) => {
|
||||||
|
byStyles10.push(byStyles[index]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// INFO: On ordonne les artistes par quantité d'albums
|
||||||
|
top10.sort((a, b) => (a.count > b.count ? -1 : 1));
|
||||||
|
|
||||||
|
// INFO: On ordonne les styles par quantité
|
||||||
|
byStyles10.sort((a, b) => (a.count > b.count ? -1 : 1));
|
||||||
|
const tmp = [];
|
||||||
|
|
||||||
|
// INFO: On recupère le top N des styles et on mets le reste dans le label "autre"
|
||||||
|
for (let i = 0; i < byStyles10.length; i += 1) {
|
||||||
|
if (i < max) {
|
||||||
|
tmp.push({
|
||||||
|
...byStyles10[i],
|
||||||
|
color: this.colors[max - i],
|
||||||
|
});
|
||||||
|
} else if (i === max) {
|
||||||
|
tmp.push({
|
||||||
|
name: "Autre",
|
||||||
|
count: 0,
|
||||||
|
color: this.colors[0],
|
||||||
|
});
|
||||||
|
tmp[max].count += byStyles10[i].count;
|
||||||
|
} else {
|
||||||
|
tmp[max].count += byStyles10[i].count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byStyles10 = tmp;
|
||||||
|
|
||||||
|
this.setPageTitle("Mes statistiques");
|
||||||
|
this.setPageContent("top10", top10.splice(0, 10));
|
||||||
|
this.setPageContent("byGenres", byGenres);
|
||||||
|
this.setPageContent("byStyles", byStyles10);
|
||||||
|
this.setPageContent("byFormats", byFormats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode permettant de créer la page "collection/:userId"
|
||||||
|
*/
|
||||||
|
async loadPublicCollection() {
|
||||||
|
const { userId } = this.req.params;
|
||||||
|
|
||||||
|
const user = await UsersModel.findById(userId);
|
||||||
|
|
||||||
|
if (!user || !user.isPublicCollection) {
|
||||||
|
throw new ErrorEvent(
|
||||||
|
401,
|
||||||
|
"Collection non partagée",
|
||||||
|
"Cet utilisateur ne souhaite pas partager sa collection"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const artists = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"artists.name",
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
const formats = await getAllDistincts(
|
||||||
|
WantListModel,
|
||||||
|
"formats.name",
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
const years = await getAllDistincts(WantListModel, "year", userId);
|
||||||
|
const genres = await getAllDistincts(WantListModel, "genres", userId);
|
||||||
|
const styles = await getAllDistincts(WantListModel, "styles", userId);
|
||||||
|
|
||||||
|
this.setPageTitle(`Collection publique de ${user.username}`);
|
||||||
|
this.setPageContent("username", user.username);
|
||||||
|
this.setPageContent("artists", artists);
|
||||||
|
this.setPageContent("formats", formats);
|
||||||
|
this.setPageContent("years", years);
|
||||||
|
this.setPageContent("genres", genres);
|
||||||
|
this.setPageContent("styles", styles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wantlist;
|
|
@ -38,6 +38,7 @@ const UserSchema = new mongoose.Schema(
|
||||||
token: String,
|
token: String,
|
||||||
url: String,
|
url: String,
|
||||||
message: String,
|
message: String,
|
||||||
|
wantlist: String,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
37
src/models/wantlist.js
Normal file
37
src/models/wantlist.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
|
const WantListSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Users",
|
||||||
|
},
|
||||||
|
discogsId: Number,
|
||||||
|
year: Number,
|
||||||
|
released: Date,
|
||||||
|
uri: String,
|
||||||
|
artists: Array,
|
||||||
|
artists_sort: String,
|
||||||
|
labels: Array,
|
||||||
|
series: Array,
|
||||||
|
companies: Array,
|
||||||
|
formats: Array,
|
||||||
|
title: String,
|
||||||
|
country: String,
|
||||||
|
notes: String,
|
||||||
|
identifiers: Array,
|
||||||
|
videos: Array,
|
||||||
|
genres: Array,
|
||||||
|
styles: Array,
|
||||||
|
tracklist: Array,
|
||||||
|
extraartists: Array,
|
||||||
|
images: Array,
|
||||||
|
thumb: String,
|
||||||
|
thumbType: String,
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
export default mongoose.model("WantList", WantListSchema);
|
84
src/routes/api/v1/wantlist.js
Normal file
84
src/routes/api/v1/wantlist.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import express from "express";
|
||||||
|
import { ensureLoggedIn } from "connect-ensure-login";
|
||||||
|
|
||||||
|
import { sendResponse } from "../../../libs/format";
|
||||||
|
import Albums from "../../../middleware/Wantlist";
|
||||||
|
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/")
|
||||||
|
.get(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const albums = new Albums(req, null);
|
||||||
|
const data = await albums.getAll();
|
||||||
|
const { exportFormat = "json" } = req.query;
|
||||||
|
|
||||||
|
switch (exportFormat) {
|
||||||
|
case "csv":
|
||||||
|
case "musictopus":
|
||||||
|
res.header("Content-Type", "text/csv");
|
||||||
|
res.attachment("export-musictopus.csv");
|
||||||
|
return res.status(200).send(data);
|
||||||
|
case "xml":
|
||||||
|
res.header("Content-type", "text/xml");
|
||||||
|
res.attachment("export-musictopus.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) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.post(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const data = await Albums.postAddOne(req);
|
||||||
|
|
||||||
|
sendResponse(req, res, data);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/:itemId")
|
||||||
|
.patch(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const albums = new Albums(req, null);
|
||||||
|
const data = await albums.patchOne();
|
||||||
|
|
||||||
|
sendResponse(req, res, data);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.delete(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const albums = new Albums(req, null);
|
||||||
|
const data = await albums.deleteOne();
|
||||||
|
|
||||||
|
sendResponse(req, res, data);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/:itemId/share")
|
||||||
|
.post(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const albums = new Albums(req, null);
|
||||||
|
const data = await albums.shareOne();
|
||||||
|
|
||||||
|
sendResponse(req, res, data);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
|
@ -104,8 +104,23 @@ router
|
||||||
try {
|
try {
|
||||||
const page = new Pages(req, "ajouter-un-album");
|
const page = new Pages(req, "ajouter-un-album");
|
||||||
|
|
||||||
|
page.setPageContent("action", "albums");
|
||||||
page.setPageTitle("Ajouter un album");
|
page.setPageTitle("Ajouter un album");
|
||||||
|
|
||||||
|
render(res, page);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
router
|
||||||
|
.route("/ajouter-a-ma-liste-de-souhaits")
|
||||||
|
.get(ensureLoggedIn("/connexion"), (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const page = new Pages(req, "ajouter-un-album");
|
||||||
|
|
||||||
|
page.setPageContent("action", "wantlist");
|
||||||
|
page.setPageTitle("Ajouter un album à ma liste de souhaits");
|
||||||
|
|
||||||
render(res, page);
|
render(res, page);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next(err);
|
next(err);
|
||||||
|
|
99
src/routes/wantlist.js
Normal file
99
src/routes/wantlist.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import express from "express";
|
||||||
|
import { ensureLoggedIn } from "connect-ensure-login";
|
||||||
|
|
||||||
|
import Albums from "../middleware/Wantlist";
|
||||||
|
|
||||||
|
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, "collection");
|
||||||
|
|
||||||
|
await page.loadMyCollection();
|
||||||
|
|
||||||
|
if (page.getPageContent("artists").length > 0) {
|
||||||
|
render(res, page);
|
||||||
|
} else {
|
||||||
|
res.redirect("/ajouter-a-ma-liste-de-souhaits");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/on-air")
|
||||||
|
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const page = new Albums(req, "mon-compte/ma-collection/details");
|
||||||
|
|
||||||
|
await page.onAir();
|
||||||
|
|
||||||
|
render(res, page);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/statistiques")
|
||||||
|
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const page = new Albums(
|
||||||
|
req,
|
||||||
|
"mon-compte/ma-collection/statistiques"
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.statistics();
|
||||||
|
|
||||||
|
render(res, page);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router
|
||||||
|
.route("/exporter")
|
||||||
|
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const page = new Albums(req, "mon-compte/ma-collection/exporter");
|
||||||
|
|
||||||
|
page.setPageTitle("Exporter ma collection");
|
||||||
|
|
||||||
|
render(res, page);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
router
|
||||||
|
.route("/importer")
|
||||||
|
.get(ensureLoggedIn("/connexion"), async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const page = new Albums(req, "mon-compte/ma-collection/importer");
|
||||||
|
|
||||||
|
page.setPageTitle("Importer une collection");
|
||||||
|
|
||||||
|
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;
|
|
@ -58,12 +58,18 @@
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a class="button is-primary" href="/ajouter-un-album">
|
<a class="button is-primary" href="``">
|
||||||
<i class="icon-plus"></i>
|
<i class="icon-plus"></i>
|
||||||
<span>
|
<span>
|
||||||
Ajouter un album
|
Ajouter un album
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="button is-secondary" href="/ajouter-a-ma-liste-de-souhaits" aria-label="Ajouter un album à ma liste de souhaits">
|
||||||
|
<i class="icon-plus"></i>
|
||||||
|
<span>
|
||||||
|
Liste de souhaits
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -121,12 +127,16 @@
|
||||||
<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-liste-de-souhaits">
|
||||||
|
Ma liste de souhaits
|
||||||
|
</a>
|
||||||
<a class="navbar-item" href="/ma-collection/on-air">
|
<a class="navbar-item" href="/ma-collection/on-air">
|
||||||
On air
|
On air
|
||||||
</a>
|
</a>
|
||||||
<a class="navbar-item" href="/ma-collection/statistiques">
|
<a class="navbar-item" href="/ma-collection/statistiques">
|
||||||
Statistiques
|
Statistiques
|
||||||
</a>
|
</a>
|
||||||
|
<hr />
|
||||||
<a class="navbar-item" href="/ma-collection/exporter">
|
<a class="navbar-item" href="/ma-collection/exporter">
|
||||||
Exporter ma collection
|
Exporter ma collection
|
||||||
</a>
|
</a>
|
||||||
|
@ -134,6 +144,13 @@
|
||||||
Importer une collection
|
Importer une collection
|
||||||
</a>
|
</a>
|
||||||
<hr />
|
<hr />
|
||||||
|
<a class="navbar-item" href="/ma-liste-de-souhaits/exporter">
|
||||||
|
Exporter ma liste de souhaits
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="/ma-liste-de-souhaits/importer">
|
||||||
|
Importer une liste de souhaits
|
||||||
|
</a>
|
||||||
|
<hr />
|
||||||
<a class="navbar-item is-danger" href="/se-deconnecter">
|
<a class="navbar-item is-danger" href="/se-deconnecter">
|
||||||
Déconnexion
|
Déconnexion
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -200,4 +200,5 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const canPublish = <%- (user.mastodon && user.mastodon.publish) || false %>;
|
const canPublish = <%- (user.mastodon && user.mastodon.publish) || false %>;
|
||||||
|
const action = "<%- page.action %>";
|
||||||
</script>
|
</script>
|
|
@ -3,6 +3,7 @@
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<main class="layout-maxed collection" id="collection">
|
<main class="layout-maxed collection" id="collection">
|
||||||
|
<% if (page.action === 'albums') { %>
|
||||||
<h1>
|
<h1>
|
||||||
<% if ( pageType === 'private' ) {
|
<% if ( pageType === 'private' ) {
|
||||||
__append('Ma collection <i class="icon-share" @click="toggleModalShare" aria-label="Partager ma collection" title="Votre collection sera visible en lecture aux personnes ayant le lien de partage"></i>');
|
__append('Ma collection <i class="icon-share" @click="toggleModalShare" aria-label="Partager ma collection" title="Votre collection sera visible en lecture aux personnes ayant le lien de partage"></i>');
|
||||||
|
@ -17,6 +18,9 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<% } else { %>
|
||||||
|
<h1>Ma liste de souhaits</h1>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<%- include('../components/filters/index') %>
|
<%- include('../components/filters/index') %>
|
||||||
|
|
||||||
|
@ -30,7 +34,7 @@
|
||||||
<div class="item" v-if="!loading" v-for="item in items">
|
<div class="item" v-if="!loading" v-for="item in items">
|
||||||
<span class="title">
|
<span class="title">
|
||||||
<% if ( pageType === 'private' ) { %>
|
<% if ( pageType === 'private' ) { %>
|
||||||
<a :href="'/ma-collection/' + item._id">{{ renderAlbumTitle(item) }}</a>
|
<a :href="'/<%= page.action === 'albums' ? 'ma-collection' : 'ma-liste-de-souhaits' %>/' + item._id">{{ renderAlbumTitle(item) }}</a>
|
||||||
<i class="icon-trash" @click="showConfirmDelete(item._id)"></i>
|
<i class="icon-trash" @click="showConfirmDelete(item._id)"></i>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
{{ item.artists_sort}} - {{ item.title }}
|
{{ item.artists_sort}} - {{ item.title }}
|
||||||
|
@ -39,7 +43,7 @@
|
||||||
<div class="grid grid-cols-2 md:grid-cols-4">
|
<div class="grid grid-cols-2 md:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
<% if ( pageType === 'private' ) { %>
|
<% if ( pageType === 'private' ) { %>
|
||||||
<a :href="'/ma-collection/' + item._id"><img :src="item.thumb" :alt="item.title" /></a>
|
<a :href="'/<%= page.action === 'albums' ? 'ma-collection' : 'ma-liste-de-souhaits' %>/' + item._id"><img :src="item.thumb" :alt="item.title" /></a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<img :src="item.thumb" :alt="item.title" />
|
<img :src="item.thumb" :alt="item.title" />
|
||||||
<% } %>
|
<% } %>
|
||||||
|
@ -147,6 +151,7 @@
|
||||||
<script>
|
<script>
|
||||||
const vueType = "<%= pageType %>";
|
const vueType = "<%= pageType %>";
|
||||||
const query = <%- JSON.stringify(query) %>;
|
const query = <%- JSON.stringify(query) %>;
|
||||||
|
const action = "<%- page.action %>";
|
||||||
<% if ( pageType === 'private' ) { %>
|
<% if ( pageType === 'private' ) { %>
|
||||||
const isPublicCollection = <%= user.isPublicCollection ? 'true' : 'false' %>;
|
const isPublicCollection = <%= user.isPublicCollection ? 'true' : 'false' %>;
|
||||||
const userId = "<%= user._id %>";
|
const userId = "<%= user._id %>";
|
||||||
|
|
|
@ -110,6 +110,12 @@
|
||||||
id="mastodon.message"
|
id="mastodon.message"
|
||||||
v-model="formData.mastodon.message"
|
v-model="formData.mastodon.message"
|
||||||
></textarea>
|
></textarea>
|
||||||
|
<label for="mastodon.wantlist">Message pour la liste de souhaits</label>
|
||||||
|
<textarea
|
||||||
|
name="mastodon.wantlist"
|
||||||
|
id="mastodon.wantlist"
|
||||||
|
v-model="formData.mastodon.wantlist"
|
||||||
|
></textarea>
|
||||||
<small>
|
<small>
|
||||||
Variables possibles :
|
Variables possibles :
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<h1>
|
<h1>
|
||||||
<template v-for="artist in item.artists">
|
<template v-for="artist in item.artists">
|
||||||
<a :href="`/ma-collection?page=1&limit=16&sort=year&order=asc&artist=${artist.name}`">{{artist.name}}</a>
|
<a :href="`/<%= page.action === 'album' ? 'ma-collection' : 'ma-liste-de-souhaits' %>?page=1&limit=16&sort=year&order=asc&artist=${artist.name}`">{{artist.name}}</a>
|
||||||
<template v-if="artist.join"> {{artist.join}} </template>
|
<template v-if="artist.join"> {{artist.join}} </template>
|
||||||
</template>
|
</template>
|
||||||
- {{item.title}}
|
- {{item.title}}
|
||||||
|
@ -96,5 +96,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const item = <%- JSON.stringify(page.item) %>;
|
const item = <%- JSON.stringify(page.item) %>;
|
||||||
|
const action = "<%- page.action %>";
|
||||||
const canShareItem = <%= user.mastodon?.publish || false %>;
|
const canShareItem = <%= user.mastodon?.publish || false %>;
|
||||||
</script>
|
</script>
|
|
@ -1,5 +1,9 @@
|
||||||
<main class="layout-maxed" id="exporter">
|
<main class="layout-maxed" id="exporter">
|
||||||
|
<% if (page.action === 'albums') { %>
|
||||||
<h1>Exporter ma collection</h1>
|
<h1>Exporter ma collection</h1>
|
||||||
|
<% } else { %>
|
||||||
|
<h1>Exporter ma liste de souhaits</h1>
|
||||||
|
<% } %>
|
||||||
<p>
|
<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 :
|
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>
|
</p>
|
||||||
|
@ -45,3 +49,7 @@
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const action = "<%- page.action %>";
|
||||||
|
</script>
|
|
@ -1,7 +1,11 @@
|
||||||
<main class="layout-maxed" id="importer">
|
<main class="layout-maxed" id="importer">
|
||||||
|
<% if (page.action === 'albums') { %>
|
||||||
<h1>Importer une collection</h1>
|
<h1>Importer une collection</h1>
|
||||||
|
<% } else { %>
|
||||||
|
<h1>Importer une liste de souhaits</h1>
|
||||||
|
<% } %>
|
||||||
<p>
|
<p>
|
||||||
Il est actuellement possible d'importer une collection provenant de discogs.
|
Il est actuellement possible d'importer <%= page.action === 'albums' ? "une collection" : "une liste de souhaits" %> provenant de discogs.
|
||||||
<br />
|
<br />
|
||||||
Vous devez dans un premier temps vous rendre sur la page <a href="https://www.discogs.com/fr/users/export" target="_blank" rel="noopener noreferrer">Exporter</a> de discogs.
|
Vous devez dans un premier temps vous rendre sur la page <a href="https://www.discogs.com/fr/users/export" target="_blank" rel="noopener noreferrer">Exporter</a> de discogs.
|
||||||
<br />
|
<br />
|
||||||
|
@ -41,3 +45,7 @@
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const action = "<%- page.action %>";
|
||||||
|
</script>
|
Loading…
Reference in a new issue