it's just that shrimple

master
Kit Kasune 1 year ago
parent 6414e64ca5
commit a468f94493
  1. 24
      api/ani/v1/routes/series/edits.js
  2. 2
      api/ani/v1/routes/user.js
  3. 22
      api/util/editstring.js
  4. 2
      api/util/startup/cache/series.js
  5. 31
      db/ani/series.js

@ -55,33 +55,11 @@ module.exports = (app, router) => {
].forEach(field => edits.stringWrap(...field)); ].forEach(field => edits.stringWrap(...field));
const editStringList = async (name, bodyName, match) => {
const camelName = app.util.bodyCase(name);
router.use(`/:id/${name}`, app.auth.tokenPass, app.auth.permsPass('series-approve'), async (req, res, next) => {
if (!req.params.id) {return await res.status(400).send("Missing ID!");}
const series = await Anime.findOne({id: req.params.id.toLowerCase()});
if (!editCheck(series, req, res)) {return;}
req.series = series;
req.listData = series[camelName];
next();
}, app.util.list(router, `/:id/${name}`, true, bodyName, async (req, res, list, item) => {
if (item && !match(item)) {res.status(400).send(`The ${camelName} you provided is invalid.`); return 0;}
if (item) {list[list.length - 1] = item;}
req.series[camelName] = list;
req.series.markModified(camelName);
await req.series.save();
}, (req, res, next) => {
if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");}
if (req.unauthorized) {return res.status(401).send("You are not authorized to edit that!");}
return next();
}));
};
[ //?STRING LIST FIELDS [ //?STRING LIST FIELDS
['tags', 'tag', x => x.match(/^[a-z-]+$/) && x.length < 25], //TODO set list length limits ['tags', 'tag', x => x.match(/^[a-z-]+$/) && x.length < 25], //TODO set list length limits
['genres', 'genre', x => x.match(/^[a-zA-Z- ]+$/) && x.length < 25], ['genres', 'genre', x => x.match(/^[a-zA-Z- ]+$/) && x.length < 25],
['stream-at', 'location', x => x.match(/^[\w- ]+$/) && x.length < 40] //TODO doc cheeky field ['stream-at', 'location', x => x.match(/^[\w- ]+$/) && x.length < 40] //TODO doc cheeky field
].forEach(x => editStringList(...x)); ].forEach(x => edits.list(...x)); //it's just that shrimple

@ -94,5 +94,5 @@ module.exports = (app, router) => {
if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");} if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");}
if (req.unauthorized) {return res.status(401).send("You are not authorized to edit users!");} if (req.unauthorized) {return res.status(401).send("You are not authorized to edit users!");}
return next(); return next();
})); })); //TODO convert to util usage
}; };

@ -24,6 +24,28 @@ module.exports = {
await this.string(req, res, name, match).catch(() => res.status(500).send(`There was an error trying to update your ${name}. Please try again.`)); await this.string(req, res, name, match).catch(() => res.status(500).send(`There was an error trying to update your ${name}. Please try again.`));
}); });
return route return route
},
list: function (name, bodyName, match, forcePermission, deepRoute) {
const camelName = app.util.bodyCase(name);
router.use(`${routePrefix}/${name}`, app.auth.tokenPass, app.auth.permsPass(forcePermission || permission), async (req, res, next) => {
if (!req.params.id) {return await res.status(400).send("Missing ID!");}
const document = await model.findOne({id: req.params.id.toLowerCase()});
if (!editCheck(document, req, res)) {return;}
req.document = document;
req.listData = document[camelName];
next();
}, app.util.list(router, `${routePrefix}/${name}`, true, bodyName, async (req, res, list, item) => {
if (item && !match(item)) {res.status(400).send(`The ${camelName} you provided is invalid.`); return 0;}
if (item) {list[list.length - 1] = item;}
req.document[camelName] = list;
req.document.markModified(camelName);
await req.document.save();
}, (req, res, next) => {
if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");}
if (req.unauthorized) {return res.status(401).send("You are not authorized to edit that!");}
return next();
}));
} }
} }
} }

@ -7,12 +7,12 @@ module.exports = async (app, spinner) => {
const st = new Date().getTime(); const st = new Date().getTime();
let amount = 1; let amount = 1;
app.cache.seriesQueue = [];
for await (const series of Series.find()) { for await (const series of Series.find()) {
let {id, name, romaji, kanji, altNames, genres, tags} = series; let {id, name, romaji, kanji, altNames, genres, tags} = series;
app.cache.series[series.id] = {id, name, romaji, kanji, altNames, genres, tags}; //keep an in-memory index of series' searchable items app.cache.series[series.id] = {id, name, romaji, kanji, altNames, genres, tags}; //keep an in-memory index of series' searchable items
app.cache.series[series.id].synopsis = series.synopsis.synopsis; app.cache.series[series.id].synopsis = series.synopsis.synopsis;
app.cache.seriesQueue = [];
if (series.meta.submitted) {app.cache.seriesQueue.push({id: series.id, submitter: series.meta.submitted});} if (series.meta.submitted) {app.cache.seriesQueue.push({id: series.id, submitter: series.meta.submitted});}
spinner.update({text: `${chalk.gray('[PROC]')} >> ${chalk.blueBright(`Cached`)} ${chalk.white(`${amount}`)} ${chalk.blueBright(`ani DB series.`)}`}); spinner.update({text: `${chalk.gray('[PROC]')} >> ${chalk.blueBright(`Cached`)} ${chalk.white(`${amount}`)} ${chalk.blueBright(`ani DB series.`)}`});
app.cache.seriesCount++; app.cache.seriesCount++;

@ -1,7 +1,7 @@
const {Schema} = require("mongoose"); const {Schema} = require("mongoose");
module.exports = (connection) => connection.model('series', new Schema({ module.exports = (connection) => connection.model('series', new Schema({
id: {type: String, unique: true, required: true, maxLength: 25}, //!REQ id: {type: String, unique: true, required: true, maxLength: 25, lowercase: true}, //!REQ
numericalId: {type: Number, unique: true, required: true, min: 1}, //!REQ numericalId: {type: Number, unique: true, required: true, min: 1}, //!REQ
meta: { meta: {
locked: {type: Boolean, default: false}, locked: {type: Boolean, default: false},
@ -33,7 +33,7 @@ module.exports = (connection) => connection.model('series', new Schema({
}, required: true}, //if not present, use "Synopsis not available yet" //!REQ }, required: true}, //if not present, use "Synopsis not available yet" //!REQ
genres: {type: [{type: String, maxLength: 25}], required: true}, //!REQ genres: {type: [{type: String, maxLength: 25}], required: true}, //!REQ
//TODO database for genres or cache //TODO database for genres or cache
tags: {default: [], type: [{type: String, maxLength: 25}]}, tags: {default: [], type: [{type: String, maxLength: 25}], lowercase: true},
nsfw: {type: Boolean, default: false}, nsfw: {type: Boolean, default: false},
nsfwReason: {type: String, default: null}, //gore, language, nudity, strong themes nsfwReason: {type: String, default: null}, //gore, language, nudity, strong themes
@ -45,7 +45,11 @@ module.exports = (connection) => connection.model('series', new Schema({
from: {type: String, default: null}, //absence of start date means anime is confirmed but not released //TODO special handling for unstarted series from: {type: String, default: null}, //absence of start date means anime is confirmed but not released //TODO special handling for unstarted series
to: {type: String, default: null} //null indicates still airing; completed: true + non-null "to" value means series is waiting on another season to: {type: String, default: null} //null indicates still airing; completed: true + non-null "to" value means series is waiting on another season
}, },
externalLinks: {type: Object, default: {}}, //streaming services, other databases, etc. //TODO externalLinks externalLinks: {
type: [{
}], default: {}
}, //streaming services, other databases, etc. //TODO externalLinks
officialSite: {type: String, default: null}, officialSite: {type: String, default: null},
videos: {type: Object, default: {}}, //OPs, EDs, trailers, etc. videos: {type: Object, default: {}}, //OPs, EDs, trailers, etc.
@ -61,20 +65,21 @@ module.exports = (connection) => connection.model('series', new Schema({
ratings: {type: [{ ratings: {type: [{
user: String, user: String,
rating: Number rating: Number
}], default: []}, //all ratings mapped by user }], default: () => ([])}, //all ratings mapped by user
rating: {type: Number, default: 0}, //automatic collection of user ratings for avg. rating: {type: Number, default: 0}, //automatic collection of user ratings for avg.
watchers: {type: [String], default: []}, //people with this anime on their watching and/or watchlists watchers: {type: [String], default: []}, //people with this anime on their watching and/or watchlists
likes: {type: Number, default: 0}, //no need to map by user here likes: {type: Number, default: 0}, //no need to map by user here
reviews: {type: [{ //full review vs rating reviews: {type: [{ //full review vs rating
user: String, user: String,
ratings: { ratings: {
plot: Number, plot: Number,
characters: Number, characters: Number,
soundtrack: Number, soundtrack: Number,
animation: Number animation: Number
}, },
comments: {type: String, maxLength: 2000} comments: {type: String, maxLength: 2000}
}], default: []}, }], default: []
},
/** /**
* !API-DEPENDENT FIELDS * !API-DEPENDENT FIELDS

Loading…
Cancel
Save