@ -10,7 +10,7 @@ module.exports = (connection) => connection.model('series', new Schema({
user : String , //uid
user : String , //uid
timestamp : String , //Date.getTime(),
timestamp : String , //Date.getTime(),
action : String
action : String
} ] , default : ( ) => ( [ ] ) } ,
} ] , default : [ ] } ,
completed : { type : Boolean , default : false } , //SUBMISSION completed
completed : { type : Boolean , default : false } , //SUBMISSION completed
viewable : { type : Boolean , default : false } , // exists solely as completion override. WILL NOT make a completed series invisible if false
viewable : { type : Boolean , default : false } , // exists solely as completion override. WILL NOT make a completed series invisible if false
approved : { type : Schema . Types . Mixed , default : false } , //boolean or {approved: Boolean, by: <uid>}
approved : { type : Schema . Types . Mixed , default : false } , //boolean or {approved: Boolean, by: <uid>}
@ -19,13 +19,13 @@ module.exports = (connection) => connection.model('series', new Schema({
reviewFlags : { type : [ {
reviewFlags : { type : [ {
by : String ,
by : String ,
reason : String ,
reason : String ,
} ] , default : ( ) => ( [ ] ) } // notes left by an admin or curator about work that needs to be done on a series for it to be approved
} ] , default : [ ] } // notes left by an admin or curator about work that needs to be done on a series for it to be approved
} , //!REQ
} , //!REQ
name : { type : String , required : true , maxLength : 150 } , //!REQ
name : { type : String , required : true , maxLength : 150 } , //!REQ
romaji : { type : String , required : true , maxLength : 150 } , //!REQ
romaji : { type : String , required : true , maxLength : 150 } , //!REQ
kanji : { type : String , maxLength : 150 , default : null } ,
kanji : { type : String , maxLength : 150 , default : null } ,
altNames : { type : [ { type : String , maxLength : 150 } ] , default : ( ) => ( [ ] ) } ,
altNames : { type : [ { type : String , maxLength : 150 } ] , default : [ ] } ,
synopsis : { type : {
synopsis : { type : {
synopsis : { type : String , required : true , maxLength : 1000 } ,
synopsis : { type : String , required : true , maxLength : 1000 } ,
@ -33,40 +33,33 @@ 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
completed : { type : Boolean , default : false } , //SERIES completed
completed : { type : Boolean , default : false } , //SERIES completed
streamAt : { type : [ { type : String , maxLength : 25 } ] , default : ( ) => ( [ ] ) } ,
streamAt : { type : [ { type : String , maxLength : 25 } ] , default : [ ] } ,
publishers : { type : [ { type : String , maxLength : 50 } ] , default : ( ) => ( [ ] ) } ,
publishers : { type : [ { type : String , maxLength : 50 } ] , default : [ ] } ,
studios : { type : [ { type : String , maxLength : 50 } ] , default : ( ) => ( [ ] ) } ,
studios : { type : [ { type : String , maxLength : 50 } ] , default : [ ] } ,
air : {
air : {
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 : {
externalLinks : {
type : [ {
type : [ {
name : { type : String , maxLength : 100 } ,
url : { type : String , maxLength : 300 }
} ] , default : { }
} ] , default : ( ) => ( [ ] )
} , //streaming services, other databases, etc. //TODO externalLinks
} , //streaming services, other databases, etc. //TODO externalLinks
officialSite : { type : String , default : null } ,
officialSite : { type : String , default : null } ,
videos : {
videos : { type : Object , default : { } } , //OPs, EDs, trailers, etc.
type : [ {
title : { type : String , maxLength : 100 } , // Colors - Flow
subtitle : { type : String , maxLength : 100 } , // Code Geass OP 1 (Season 1),
url : { type : String , maxLength : 500 } // https://youtube.com/watch?v=...
} ] , default : ( ) => ( [ ] )
} , //OPs, EDs, trailers, etc.
art : {
art : {
cover : { type : [ String ] , default : ( ) => ( [ ] ) } , //first item of any list is default item
cover : { type : [ String ] , default : [ ] } , //first item of any list is default item
icon : { type : [ String ] , default : ( ) => ( [ ] ) } , //small 128x128 icon
icon : { type : [ String ] , default : [ ] } , //small 128x128 icon
banner : { type : [ String ] , default : ( ) => ( [ ] ) } ,
banner : { type : [ String ] , default : [ ] } ,
poster : { type : [ String ] , default : ( ) => ( [ ] ) } , //used for BGs, portrait
poster : { type : [ String ] , default : [ ] } , //used for BGs, portrait
widePoster : { type : [ String ] , default : ( ) => ( [ ] ) } , //used for desktop, client should format banners or displays at its discretion if unavailable
widePoster : { type : [ String ] , default : [ ] } , //used for desktop, client should format banners or displays at its discretion if unavailable
display : { type : [ String ] , default : ( ) => ( [ ] ) } , //used for some content BGs, landscape standard desktop res.
display : { type : [ String ] , default : [ ] } , //used for some content BGs, landscape standard desktop res.
} ,
} ,
ratings : { type : [ {
ratings : { type : [ {
@ -74,18 +67,18 @@ module.exports = (connection) => connection.model('series', new Schema({
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 : { type : Number , min : 1 , max : 5 , required : true } ,
plot : Number ,
characters : { type : Number , min : 1 , max : 5 , required : true } ,
characters : Number ,
soundtrack : { type : Number , min : 1 , max : 5 , required : true } ,
soundtrack : Number ,
animation : { type : Number , min : 1 , max : 5 , required : true }
animation : Number
} ,
} ,
comments : { type : String , maxLength : 2000 }
comments : { type : String , maxLength : 2000 }
} ] , default : ( ) => ( [ ] )
} ] , default : [ ]
} ,
} ,
/ * *
/ * *
@ -95,7 +88,7 @@ module.exports = (connection) => connection.model('series', new Schema({
* Stores only IDs and barebones data , requires clients to fetch their contents
* Stores only IDs and barebones data , requires clients to fetch their contents
* /
* /
seasons : { type : [ String ] , default : ( ) => ( [ ] ) } ,
seasons : { type : [ String ] , default : [ ] } ,
characters : { type : [ String ] , default : ( ) => ( [ ] ) } ,
characters : { type : [ String ] , default : [ ] } ,
related : { type : [ String ] , default : ( ) => ( [ ] ) } //TODO this shit even necessary?
related : { type : [ String ] , default : [ ] } //TODO this shit even necessary?
} ) ) ;
} ) ) ;