A suite to track Project Diva score statistics and ratings / D4DJ event data.
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.
 
 
 
 
 
 
projectdivar/server/routes/d4dj-routes.js

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