master
Kit Kasune 2 years ago
parent db5dcd953a
commit 685eec13b6
  1. 5
      .idea/.gitignore
  2. 7
      .idea/discord.xml
  3. 8
      .idea/modules.xml
  4. 12
      .idea/natsuki-api.iml
  5. 6
      .idea/vcs.xml
  6. 50
      api/ani/v1/routes/series/add.js
  7. 20
      db/ani/series.js
  8. 3
      package.json

5
.idea/.gitignore vendored

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/natsuki-api.iml" filepath="$PROJECT_DIR$/.idea/natsuki-api.iml" />
</modules>
</component>
</project>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -1,3 +1,5 @@
// how many hours have i spent banging my head at the wall now?
module.exports = (app, router) => {
const Anime = app.db.models.ani.series;
@ -50,6 +52,54 @@ module.exports = (app, router) => {
genres: req.body.genres && Array.isArray(req.body.genres) && req.body.genres.length ? req.body.genres : []
});
if (!req.body.synopsis || !req.body.genres || !Array.isArray(req.body.genres) || !req.body.genres.length) {series.meta.submitted = req.authenticatedUser.id;}
//VALIDATION
const badReq = msg => {res.status(400).send(msg); return null;};
const validateStringList = (maxLength, list, listName, regex) => {
let bad = false;
list.forEach(item => {bad = !bad && typeof item === 'string' && item.length < maxLength && (!regex || item.match(regex))});
if (bad) {return badReq();}
return list;
};
let options = req.body;
if (options.altNames && Array.isArray(options.altNames) && options.altNames.length <= 10) {
let bad = false;
options.altNames.forEach(name => bad = !bad && typeof name === 'string' && name.length < 150);
if (bad) {return badReq("Your altNames did not contain purely strings, or one of them was too long.");}
series.altNames = options.altNames;
}
if (options.tags && Array.isArray(options.tags) && options.tags.length <= 10) {
let bad = false;
options.tags.forEach(tag => bad = !bad && typeof tag === 'string' && tag.length < 25 && tag.match(/^[\w-]+$/gm));
if (bad) {return badReq("Your tags did not contain purely strings, or one of them was too long, or contained invalud characters");}
series.tags = options.tags.map(tag => tag.toLowerCase());
}
if (options.nsfw === true && !(options.nsfwReason || ['gore', 'language', 'nudity', 'themes'].includes(options.nsfwReason))) {return badReq("You marked this series as nsfw, but did not provide a reason.");}
else if (options.nsfw) {
series.nsfw = options.nsfw;
series.nsfwReason = options.nsfwReason;
}
if (options.genres && Array.isArray(options.genres) && options.genres.length <= 10) {
let bad = false;
options.genres.forEach(tag => bad = !bad && typeof tag === 'string' && tag.length < 25 && tag.match(/^[\w- ]+$/gm));
if (bad) {return badReq("Your genres did not contain purely strings, or one of them was too long.");}
series.genres = options.genres;
} //TODO genres as DB
if (options.streamAt && Array.isArray(options.streamAt) && options.streamAt.length <= 10) {
let bad = false;
options.streamAt.forEach(tag => bad = !bad && typeof tag === 'string' && tag.length < 25 && tag.match(/^[\w- ]+$/gm));
if (bad) {return badReq("Your streamAt locations did not contain purely strings, or one of them was too long.");}
series.streamAt = options.streamAt;
}
if (options.publishers && Array.isArray(options.publishers) && options.publishers.length <= 10) {
let bad = false;
options.publishers.forEach(tag => bad = !bad && typeof tag === 'string' && tag.length < 25 && tag.match(/^[\w- ]+$/gm));
if (bad) {return badReq("Your publishers did not contain purely strings, or one of them was too long.");}
series.publishers = options.publishers;
}
return series.save().then(async () => {
app.cache.series[series.id] = {
id: series.id,

@ -14,7 +14,7 @@ module.exports = (connection) => connection.model('series', new Schema({
completed: {type: Boolean, default: false}, //SUBMISSION completed
approved: {type: Schema.Types.Mixed, default: false}, //boolean or {approved: Boolean, by: <uid>}
submitted: Schema.Types.Mixed, //can be false or a string with the ID of the submitter, //!REQ
hidden: {type: Boolean, defualt: false},
hidden: {type: Boolean, default: false},
reviewFlags: {type: [{
by: String,
reason: String,
@ -24,28 +24,28 @@ module.exports = (connection) => connection.model('series', new Schema({
name: {type: String, required: true, maxLength: 150}, //!REQ
romaji: {type: String, required: true, maxLength: 150}, //!REQ
kanji: {type: String, maxLength: 150, default: null},
altNames: {type: [String], default: []},
altNames: {type: [{type: String, maxLength: 150}], default: []},
synopsis: {type: {
synopsis: {type: String, required: true, maxLength: 1000},
by: String //uid
}, required: true}, //if not present, use "Synopsis not available yet" //!REQ
genres: {type: [String], required: true}, //!REQ
genres: {type: [{type: String, maxLength: 25}], required: true}, //!REQ
//TODO database for genres or cache
tags: {default: [], type: [String]},
tags: {default: [], type: [{type: String, maxLength: 25}]},
nsfw: {type: Boolean, default: false},
nsfwReason: {type: String, default: null}, //gore, language, nudity, strong themes
completed: {type: Boolean, default: false}, //SERIES completed
streamAt: {type: [String], default: []},
publishers: {type: [String], default: []},
studios: {type: [String], default: []},
streamAt: {type: [{type: String, maxLength: 25}], default: []},
publishers: {type: [{type: String, maxLength: 50}], default: []},
studios: {type: [{type: String, maxLength: 50}], default: []},
air: {
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, defualt: 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
officialSite: {type: String, defualt: null},
officialSite: {type: String, default: null},
videos: {type: Object, default: {}}, //OPs, EDs, trailers, etc.
art: {
@ -72,7 +72,7 @@ module.exports = (connection) => connection.model('series', new Schema({
soundtrack: Number,
animation: Number
},
comments: String
comments: {type: String, maxLength: 2000}
}], default: []},
/**

@ -18,7 +18,8 @@
"mongoose": "^6.8.4"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start": "cd api && node index",
"test": "node test"
},
"keywords": [],
"author": "wubzygd",

Loading…
Cancel
Save