You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
584 lines
23 KiB
584 lines
23 KiB
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();
|
|
}
|
|
}
|
|
|