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));
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
['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],
['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.unauthorized) {return res.status(401).send("You are not authorized to edit users!");}
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.`));
});
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();
let amount = 1;
app.cache.seriesQueue = [];
for await (const series of Series.find()) {
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].synopsis = series.synopsis.synopsis;
app.cache.seriesQueue = [];
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.`)}`});
app.cache.seriesCount++;

@ -1,7 +1,7 @@
const {Schema} = require("mongoose");
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
meta: {
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
genres: {type: [{type: String, maxLength: 25}], required: true}, //!REQ
//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},
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
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},
videos: {type: Object, default: {}}, //OPs, EDs, trailers, etc.
@ -61,20 +65,21 @@ module.exports = (connection) => connection.model('series', new Schema({
ratings: {type: [{
user: String,
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.
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
reviews: {type: [{ //full review vs rating
user: String,
ratings: {
plot: Number,
characters: Number,
soundtrack: Number,
animation: Number
},
comments: {type: String, maxLength: 2000}
}], default: []},
user: String,
ratings: {
plot: Number,
characters: Number,
soundtrack: Number,
animation: Number
},
comments: {type: String, maxLength: 2000}
}], default: []
},
/**
* !API-DEPENDENT FIELDS

Loading…
Cancel
Save