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] 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(); } }