const { app , db } = require ( "../app.js" ) ;
const { ScoreIsSanitary } = require ( "./utils/submit.js" ) ;
const { Prediction } = require ( "./utils/prediction" ) ;
const moment = require ( "moment" ) ;
const Promise = require ( "bluebird" ) ;
var lastscores = {
jp : { } ,
en : { }
}
// hi
var tableValues = { } ;
var en _tableValues = { } ;
var lastCachedDate = moment ( ) . add ( - 1 , "hour" ) ;
var en _lastCachedDate = moment ( ) . add ( - 1 , "hour" ) ;
var tiers = [
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
50 , 100 , 500 , 1000 , 2000 , 5000 , 10000 , 20000 , 30000 , 50000 ,
] ;
const models = {
jp : new Prediction ( ) ,
en : new Prediction ( )
}
var cachedEvent = {
jp : undefined ,
en : undefined
}
const getEventData = async ( db , server = "jp" ) => {
if ( cachedEvent [ server ] && moment ( ) . isBefore ( cachedEvent [ server ] . EVENTEND ) ) {
return cachedEvent [ server ] ;
}
const eventData = await db . query (
` select eventid, startdate, enddate, rank_end from ${ server === "en" ? "en_" : "" } event order by id desc limit 1 `
) . then ( ( data ) => data . rows [ 0 ] ) ;
if ( ! eventData ) return { } ;
const EVENTID = eventData . eventid ;
const EVENTSTART = moment ( eventData . startdate ) ;
const EVENTEND = moment ( eventData . enddate ) ;
if ( moment ( ) . isAfter ( EVENTEND ) ) {
cachedEvent [ server ] = undefined ;
return { EVENTID : EVENTID + 1 }
}
const data = {
EVENTID ,
EVENTSTART ,
EVENTEND ,
RANK _END : eventData . rank _end
}
cachedEvent [ server ] = data ;
return data
}
app . post ( "/create-event" , async ( req , res ) => {
try {
const test = await db . query ( ` select eventid from ${ req . query . en ? "en_" : "" } event where eventid= $ 1 ` , [ req . body . eventid ] )
if ( test . rows . length > 0 ) return res . status ( 400 ) . send ( "Sorry bro event exists" ) ;
console . log ( req . body ) ;
await db . query (
` insert into ${ req . query . en ? "en_" : "" } event (eventid, name, startdate, enddate, rank_end, type) values ( $ 1, $ 2, $ 3, $ 4, $ 5, $ 6) returning *; `
, [
req . body . eventid ,
req . body . name ,
moment ( req . body . startdate ) . format ( "YYYY-MM-DD HH:mm:ssZ" ) ,
moment ( req . body . enddate ) . format ( "YYYY-MM-DD HH:mm:ssZ" ) ,
moment ( req . body . rank _end ) . format ( "YYYY-MM-DD HH:mm:ssZ" ) ,
req . body . type
] )
const initialData = tiers . map ( t => ( { eventid : req . body . eventid , rank : t , date : moment ( req . body . startdate ) , name : "Towa" , description : "TowaTowa" , points : 0 , playerid : null } ) )
const promises = initialData . map ( data => db . query (
"insert into " +
( req . query . en ? "en_" : "" ) +
"eventdata(eventid,rank,date,name,description,points,playerId) values ($1,$2,$3,$4,$5,$6,$7) returning *;" ,
[ data . eventid , data . rank , data . date , data . name , data . description , data . points , data . playerid ]
) )
model [ req . query . en ? "en" : "jp" ] = new Prediction ( )
await Promise . all ( promises ) ;
return res . status ( 200 ) . send ( "Thanks bro" ) ;
} catch ( err ) {
return res . status ( 500 ) . send ( "Something went wrong" ) ;
}
} ) ;
app . post ( "/eventsubmit" , async function ( req , res ) {
const { EVENTID , EVENTSTART , EVENTEND } = await getEventData ( db , req . query . en ? "en" : "jp" )
if ( ! EVENTID || ! EVENTSTART ) return res . status ( 404 ) . send ( "event_not_found" ) ;
async function submit ( data ) {
lastscores [ req . query . en ? "en" : "jp" ] = Number ( req . body . points ) ;
const getInsertData = ( obj ) => {
return {
eventid : obj . eventid ,
rank : obj . rank ,
date : obj . date ? obj . date
: obj . fin
? moment ( EVENTEND ) . add ( 5 , "minutes" ) . format ( "YYYY-MM-DD HH:mm:ssZ" )
: new Date ( ) ,
name : obj . name ,
description : obj . description ,
points : obj . points ,
playerid : obj . playerid
}
}
try {
const toInsert = Array . isArray ( data ) ? data . map ( getInsertData ) : getInsertData ( data ) ;
const promises = ( Array . isArray ( toInsert ) ? toInsert : [ toInsert ] ) . map ( data => db . query (
"insert into " +
( req . query . en ? "en_" : "" ) +
"eventdata(eventid,rank,date,name,description,points,playerId) values ($1,$2,$3,$4,$5,$6,$7) returning *;" ,
[ data . eventid , data . rank , data . date , data . name , data . description , data . points , data . playerid ]
) )
const resData = await Promise . all ( promises ) ;
if ( resData . every ( d => d . rows . length > 0 ) ) {
res . status ( 200 ) . send ( "Submitted." ) ;
} else {
res . status ( 500 ) . send ( "Failed to submit." ) ;
}
} catch ( err ) {
res . status ( 500 ) . send ( ` ${ err . stack } ` ) ;
}
}
const oldData = await db . query (
"select distinct on (rank) rank,eventid,date,name,description,points,difference,playerid from (select lead(points) over (partition by rank order by rank,date desc)-points difference,* from " +
( req . query . en ? "en_" : "" ) +
"eventdata where eventid=" +
EVENTID +
" order by rank,date desc)t order by rank,date desc"
) ;
const data = req . body . batch ? req . body . batch : [ req . body ] ;
const dataToUpdate = data . filter ( d => {
return ! lastscores [ req . query . en ? "en" : "jp" ] [ d . rank ] ||
/*FurtherTierIsOkay(req.body.rank,lastscores,req.body.points)&&*/ ( lastscores [
d . rank
] < d . points &&
( d . fin ||
ScoreIsSanitary (
d . rank ,
d . name ,
d . description ,
d . points
) ) ) /*||(lastscores[req.body.rank]<req.body.points &&(FurtherTierIsOkay(req.body.rank,lastscores,req.body.points))*/
} )
if ( dataToUpdate && dataToUpdate . length > 0 ) {
submit ( dataToUpdate ) ;
} else {
res . status ( 200 ) . send ( "No update required." ) ;
}
if ( oldData . rows && oldData . rows . length > 0 ) {
oldData . rows . map ( ( row ) => {
lastscores [ req . query . en ? "en" : "jp" ] [ row . rank ] = row . points ;
} ) ;
}
} ) ;
app . get ( "/eventdata" , function ( req , res ) {
var eventinfo = [ ] ;
db . query (
"select * from " +
( req . query . en ? "en_" : "" ) +
"event order by id desc limit 1"
)
. then ( ( data ) => {
eventinfo = data . rows ;
if ( ! req . query . event ) {
return db . query (
"select distinct on (rank) rank,eventid,date,name,description,points,difference,playerid from (select lead(points) over (partition by rank order by rank,date desc)-points difference,* from " +
( req . query . en ? "en_" : "" ) +
"eventdata where eventid=$1 order by rank,date desc)t order by rank,date desc;" ,
[
moment ( eventinfo [ 0 ] . startdate ) . isBefore ( moment ( ) )
? eventinfo [ 0 ] . eventid
: eventinfo [ 0 ] . eventid - 1 ,
]
) ;
} else {
}
} )
. then ( ( data ) => {
var finaldata = data . rows ;
for ( t of tiers ) {
//console.log(t)
//if (finaldata[String(t)]===undefined) {finaldata[String(t)]={"rank":t,"eventid":eventinfo[0].eventid,"name":"","description":"","date":eventinfo[0].startdate,"points":0}}
const found = finaldata . some ( data => data . rank === t ) ;
if ( ! found ) {
finaldata = [
... finaldata ,
{
rank : t ,
eventid : eventinfo [ 0 ] . eventid ,
name : "" ,
description : "" ,
date : eventinfo [ 0 ] . startdate ,
points : 0 ,
} ,
] ;
}
}
res . status ( 200 ) . json ( finaldata ) ;
} )
. catch ( ( err ) => {
res . status ( 500 ) . send ( err . message ) ;
} ) ;
} ) ;
app . get ( "/eventdata/t50" , async function ( req , res ) {
try {
const { EVENTID , RANK _END } = await getEventData ( db , req . query . en ? "en" : "jp" )
const data = await db . query (
"select distinct on (rank) rank,eventid,date,name,description,points,difference,playerid from (select lead(points) over (partition by rank order by rank,date desc)-points difference,* from " +
( req . query . en ? "en_" : "" ) +
"eventdata where rank>20 and eventid=$1 order by rank,date desc)t order by rank,date desc;" ,
[
moment ( RANK _END ) . isBefore ( moment ( ) )
? EVENTID
: EVENTID - 1 ,
]
) ;
res . status ( 200 ) . json ( data . rows ) ;
} catch ( err ) {
res . status ( 500 ) . send ( err . message ) ;
}
} ) ;
app . get ( "/eventdata/t20" , async function ( req , res ) {
const { EVENTID , RANK _END , EVENTSTART , EVENTEND } = await getEventData ( db , req . query . en ? "en" : "jp" )
try {
if ( req . query . date && req . query . rank ) {
const data = await db . query (
"select * from " +
( req . query . en ? "en_" : "" ) +
"eventdata where date<=$1 and rank=$2 and eventid=$3 order by date desc limit 1;" ,
[ req . query . date , req . query . rank , req . query . eventid ]
)
res . status ( 200 ) . json ( data . rows ) ;
} else if ( req . query . all && req . query . event ) {
const data = await db . query (
"select * from (select lag(points) over (partition by rank order by date asc)-points difference,rank,eventid,date,name,points,playerid from " +
( req . query . en ? "en_" : "" ) +
"eventdata where eventid=$1 order by date asc)t" ,
[ req . query . event ]
)
res . status ( 200 ) . json ( data . rows ) ;
} else if ( req . query . tier && req . query . event ) {
const data = await db . query (
"select * from (select lag(points) over (partition by rank order by date asc)-points difference,rank,eventid,date,name,points,playerid from " +
( req . query . en ? "en_" : "" ) +
"eventdata where eventid=$1 and rank=$2 order by date desc)t" ,
[ req . query . event , req . query . tier ]
)
res . status ( 200 ) . json ( data . rows ) ;
} else if ( req . query . chart ) {
function RandomQuestion ( ) {
var value = Math . random ( ) ;
if ( value <= 0.7 ) {
return "???" ;
} else if ( value <= 0.9 ) {
return "Miyu" ;
} else if ( value <= 0.95 ) {
return "Muni" ;
} else {
return "MuniMuni" ;
}
}
const model = models [ req . query . en ? "en" : "jp" ]
const cachedTime = req . query . en ? en _lastCachedDate : lastCachedDate
if (
req . query . event ||
moment ( ) . diff ( cachedTime , "minutes" ) >= 1 ||
( req . query . force && moment ( ) . diff ( cachedTime , "seconds" ) >= 10 )
) {
data = await db . query (
"select * from (select lag(points) over (partition by rank order by date asc)-points difference,rank,eventid,date,name,points,playerid from " +
( req . query . en ? "en_" : "" ) +
"eventdata where eventid=$1 order by date asc)t" ,
[
req . query . event
? req . query . event
: moment ( RANK _END ) . isBefore ( moment ( ) )
? EVENTID
: EVENTID - 1 ,
]
) ;
if ( data && data . rows && data . rows . length > 0 ) {
const newData = { }
model . SetupPredictionModel ( EVENTSTART ) ;
data . rows . forEach ( ( obj ) => {
if ( ! newData [ obj . rank ] ) {
newData [ obj . rank ] = [ ] ;
}
newData [ obj . rank ] . push ( obj )
} ) ;
Object . entries ( newData ) . forEach ( ( [ rank , values ] ) => {
model . chartData [ rank ] = values ;
} )
var tiers = [
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
50 , 100 , 500 , 1000 , 2000 , 5000 , 10000 , 20000 , 30000 , 50000 ,
] ;
for ( t of tiers ) {
model . CreatePrediction ( 1 , t , EVENTSTART , EVENTEND ) ;
var est = model . GetEstimate ( t , req . query . en ) ;
var temprate = 0 ;
const chartData = model . chartData ;
const predictionChartData = model . predictionChartData ;
if ( chartData [ t ] ) {
temprate =
t <= 20
? chartData [ t ]
? Math . ceil ( model . GetRate ( t ) )
: undefined
: Math . ceil (
model . GetRank ( t ) /
( moment (
chartData [ t ] [ chartData [ t ] . length - 1 ] . date
) . diff ( EVENTSTART , "minutes" ) /
60 )
) ;
}
const { tempname , tempdesc } = model . GetNameData ( t )
if ( req . query . en ) {
en _tableValues [ t ] = {
points : model . GetRank ( t ) ,
lastUpdate : model . GetTime ( t ) ,
lastUpdateColor : model . GetUpdateColor ( t ) ,
rate : temprate ? temprate : 0 ,
count : model . GetPointCount ( t ) ,
name : tempname ,
description : tempdesc ,
estimate : Number . isInteger ( est ) ? Math . ceil ( est ) : est ,
prediction :
predictionChartData [ t ] && moment ( ) . isBefore ( EVENTEND )
? predictionChartData [ t ] [
predictionChartData [ t ] . length - 1
] . y
: RandomQuestion ( ) ,
} ;
en _lastCachedDate = moment ( ) ;
} else {
tableValues [ t ] = {
points : model . GetRank ( t ) ,
lastUpdate : model . GetTime ( t ) ,
lastUpdateColor : model . GetUpdateColor ( t ) ,
rate : temprate ? temprate : 0 ,
count : model . GetPointCount ( t ) ,
name : tempname ,
description : tempdesc ,
estimate : Number . isInteger ( est ) ? Math . ceil ( est ) : est ,
prediction :
predictionChartData [ t ] && moment ( ) . isBefore ( EVENTEND )
? predictionChartData [ t ] [
predictionChartData [ t ] . length - 1
] . y
: RandomQuestion ( ) ,
} ;
lastCachedDate = moment ( ) ;
}
}
}
}
res . status ( 200 ) . send ( {
predictionData : model . predictionChartData ,
statistics : req . query . en ? en _tableValues : tableValues ,
} ) ;
} else {
let finaldata = ( await db . query (
"select distinct on (rank) rank,eventid,date,name,description,points,difference,playerid from (select lead(points) over (partition by rank order by rank,date desc)-points difference,* from " +
( req . query . en ? "en_" : "" ) +
"eventdata where rank<=20 and eventid=$1 order by rank,date desc)t order by rank,date desc;" ,
[
moment ( RANK _END ) . isBefore ( moment ( ) )
? EVENTID
: EVENTID - 1 ,
]
) ) . rows
var tiers = [
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
] ;
const model = models [ req . query . en ? "en" : "jp" ]
const chartData = model . chartData
for ( t of tiers ) {
//console.log(t)
//if (finaldata[String(t)]===undefined) {finaldata[String(t)]={"rank":t,"eventid":eventinfo[0].eventid,"name":"","description":"","date":eventinfo[0].startdate,"points":0}}
var found = false ;
for ( i in finaldata ) {
if ( finaldata [ i ] . rank === t ) {
found = true ;
var temprate = chartData [ t ] ? Math . ceil ( model . GetRate ( t ) ) : undefined ;
if ( ! temprate ) finaldata [ i ] . rate = "???" ;
else finaldata [ i ] . rate = temprate ;
break ;
}
}
if ( ! found ) {
finaldata = [
... finaldata ,
{
rate : 0 ,
rank : t ,
eventid : EVENTID ,
name : "" ,
description : "" ,
date : EVENTSTART ,
points : 0 ,
} ,
] ;
}
}
if ( req . query . maxspeed ) {
res . status ( 200 ) . json ( [ ... finaldata , { maxspeed : model . maxSpeed } ] ) ;
} else {
res . status ( 200 ) . json ( finaldata ) ;
}
}
} catch ( err ) {
res . status ( 500 ) . send ( err . stack ) ;
}
} ) ;
app . get ( "/ev" , function ( req , res ) {
if ( req . query . all ) {
db . query (
"select * from " + ( req . query . en ? "en_" : "" ) + "event order by id desc;"
)
. then ( ( data ) => {
res . status ( 200 ) . send ( data . rows ) ;
} )
. catch ( ( err ) => {
res . status ( 500 ) . send ( err . message ) ;
} ) ;
} else {
db . query (
"select * from " +
( req . query . en ? "en_" : "" ) +
"event order by id desc limit 1;"
)
. then ( ( data ) => {
res . status ( 200 ) . send ( data . rows [ 0 ] ) ;
} )
. catch ( ( err ) => {
res . status ( 500 ) . send ( err . message ) ;
} ) ;
}
} ) ;
app . get ( "/event/leaderboard" , async function ( req , res ) {
let eventId = req . query . eventId
if ( ! eventId ) {
const { EVENTID } = await getEventData ( db , req . query . en ? "en" : "jp" ) ;
eventId = EVENTID ;
}
if ( req . query . overview ) {
const r = await db . query ( ` select distinct eventid, leaderboardtype,leaderboardid from ${ req . query . en ? "en" : "" } event_leaderboards WHERE eventid= $ 1 ORDER BY eventid, leaderboardtype, leaderboardid ` , [ eventId ] )
return res . status ( 200 ) . send ( r . rows ) ;
}
const QUERY = ` select * from ${ req . query . en ? "en" : "" } event_leaderboards WHERE eventid= $ 1 ${ req . query . leaderboardType ? "AND leaderboardtype=$2" : "" } ${ req . query . leaderboardType && req . query . leaderboardId ? "AND leaderboardid=$3" : "" } `
try {
const data = await db . query ( QUERY , [ eventId , req . query . leaderboardType , req . query . leaderboardId ] . filter ( e => ! ! e ) ) ;
res . status ( 200 ) . send ( data . rows ) ;
} catch ( e ) {
console . log ( e )
res . status ( 500 ) . send ( "Oopsie" ) ;
}
} )
app . post ( "/event/leaderboard" , async function ( req , res ) {
const { EVENTID } = await getEventData ( db , req . query . en ? "en" : "jp" ) ;
if ( ! EVENTID ) return res . status ( 400 ) . send ( "Event Not Found" )
const dataPoints = req . body . batch ;
if ( ! dataPoints || dataPoints . length === 0 ) return res . status ( 401 ) . send ( "No Data Point" )
const QUERY = ` insert into ${ req . query . en ? "en" : "" } event_leaderboards (eventid, leaderboardtype, leaderboardid, rank, name, description, points, playerid, date)
VALUES ( $1 , $2 , $3 , $4 , $5 , $6 , $7 , $8 , $9 )
ON CONFLICT ( eventid , leaderboardtype , leaderboardid , rank ) DO UPDATE
SET name = excluded . name ,
description = excluded . description ,
points = excluded . points ,
playerId = excluded . playerId ,
date = excluded . date ; `
const promises = dataPoints . forEach ( data => {
const { eventId , leaderboardType , leaderboardId , rank , name , description , points , playerId , date } = data ;
return db . query ( QUERY , [
eventId ,
leaderboardType ,
leaderboardId ,
rank ,
name ,
description ,
points ,
playerId ,
date || new Date ( )
] )
} )
try {
await Promise . all ( promises )
} catch ( e ) {
}
return res . status ( 200 ) . send ( "updated" )
} ) ;
var rankings = {
1 : "Maho" ,
2 : "Shinobu" ,
3 : "Muni" ,
4 : "Rei" ,
5 : "Yuka" ,
6 : "Kyoko" ,
7 : "Esoran" ,
8 : "Rinku" ,
9 : "Ibuki" ,
10 : "Esora" ,
11 : "Noa" ,
12 : "Saki" ,
13 : "Towa" ,
14 : "Rika" ,
15 : "Aoi" ,
16 : "Kurumi" ,
17 : "Saori" ,
18 : "Hiiro" ,
19 : "Michiru" ,
20 : "Tsubaki" ,
} ;
var lastRankingUpdate = moment ( ) ;
var notPlaying = [
"Dalia" ,
"Marika" ,
"Nyochio" ,
"Nagisa" ,
"Miyu" ,
"Haruna" ,
"Miiko" ,
"Airi" ,
"Mana" ,
"Shano" ,
"Touka" ,
] ;
function RunRankingUpdate ( ) {
if ( moment ( ) . diff ( lastRankingUpdate , "minutes" ) >= 1 ) {
for ( var i = 0 ; i < 20 ; i ++ ) {
//Possibility to switch two positions.
var swap = false ;
if ( i == 0 ) {
if ( Math . random ( ) <= 0.01 ) {
swap = true ;
}
} else if ( Math . random ( ) <= 0.05 ) {
swap = true ;
}
if ( swap ) {
if ( i < 19 ) {
var previousName = rankings [ i + 1 ] ;
var newName = rankings [ i + 2 ] ;
rankings [ i + 1 ] = newName ;
rankings [ i + 2 ] = previousName ;
} else {
//Bring in a new name, swap out the old.
var previousName = rankings [ i + 1 ] ;
var newRandomSlot = Math . floor ( Math . random ( ) * notPlaying . length ) ;
var newName = notPlaying [ newRandomSlot ] ;
rankings [ i + 1 ] = newName ;
notPlaying [ newRandomSlot ] = previousName ;
}
}
}
lastRankingUpdate = moment ( ) ;
}
}