Customization!
Add ability to control page title and color scheme. Also, partially implements manual triggering of cronjobs. Fixes #18master
parent
1c34b3f013
commit
6495e1c8ef
109
public/main.js
109
public/main.js
|
@ -1,4 +1,5 @@
|
||||||
var requestsDiv = document.getElementById("requests");
|
var requestsDiv = document.getElementById("requests");
|
||||||
|
var cronJobs = ['processBans']
|
||||||
|
|
||||||
function getRequests(count,allRequests) {
|
function getRequests(count,allRequests) {
|
||||||
var reqUrl;
|
var reqUrl;
|
||||||
|
@ -65,6 +66,22 @@ function applyUrlTransforms(url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getColorObject() {
|
||||||
|
return {
|
||||||
|
bg: {
|
||||||
|
primary: document.getElementById('color-bg-primary').value,
|
||||||
|
table: document.getElementById('color-bg-table').value,
|
||||||
|
navbar: document.getElementById('color-bg-navbar').value,
|
||||||
|
error: document.getElementById('color-bg-error').value,
|
||||||
|
},
|
||||||
|
fg: {
|
||||||
|
primary: document.getElementById('color-fg-primary').value,
|
||||||
|
ahover: document.getElementById('color-fg-ahover').value,
|
||||||
|
title: document.getElementById('color-fg-title').value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addRequestErr(msg) {
|
function addRequestErr(msg) {
|
||||||
document.getElementById('addRequestError').style.display = "inline-block";
|
document.getElementById('addRequestError').style.display = "inline-block";
|
||||||
document.getElementById('addRequestError').innerText = msg;
|
document.getElementById('addRequestError').innerText = msg;
|
||||||
|
@ -85,33 +102,45 @@ function updateRequestErrReset() {
|
||||||
document.getElementById('updateRequestError').innerText = "";
|
document.getElementById('updateRequestError').innerText = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMessage(msg) {
|
function streamerSettingsErr(msg) {
|
||||||
document.getElementById("messageModalText").innerText = msg;
|
document.getElementById('streamerSettingsError').style.display = "inline-block";
|
||||||
|
document.getElementById('streamerSettingsError').innerText = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamerSettingsErrReset() {
|
||||||
|
document.getElementById('streamerSettingsError').style.display = "none";
|
||||||
|
document.getElementById('streamerSettingsError').innerText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hides all modals in preparation to show a one or to close out of
|
||||||
|
// all modals and return to the page. Does NOT hide modalBackground.
|
||||||
|
function hideModals() {
|
||||||
|
document.getElementById("messageModal").style.display = "none";
|
||||||
document.getElementById("addRequestModal").style.display = "none";
|
document.getElementById("addRequestModal").style.display = "none";
|
||||||
document.getElementById("updateRequestModal").style.display = "none";
|
document.getElementById("updateRequestModal").style.display = "none";
|
||||||
document.getElementById("deleteRequestModal").style.display = "none";
|
document.getElementById("deleteRequestModal").style.display = "none";
|
||||||
|
document.getElementById("streamerSettingsModal").style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAllModals() {
|
||||||
|
hideModals();
|
||||||
|
document.getElementById("modalBackground").style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage(msg) {
|
||||||
|
hideModals();
|
||||||
|
document.getElementById("messageModalText").innerText = msg;
|
||||||
document.getElementById("modalBackground").style.display = "flex";
|
document.getElementById("modalBackground").style.display = "flex";
|
||||||
document.getElementById("messageModal").style.display = "block";
|
document.getElementById("messageModal").style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeMessageModal() {
|
|
||||||
document.getElementById("modalBackground").style.display = "none";
|
|
||||||
document.getElementById("messageModal").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
function openAddRequestModal() {
|
function openAddRequestModal() {
|
||||||
|
hideModals();
|
||||||
document.getElementById("modalBackground").style.display = "flex";
|
document.getElementById("modalBackground").style.display = "flex";
|
||||||
document.getElementById("updateRequestModal").style.display = "none";
|
|
||||||
document.getElementById("messageModal").style.display = "none";
|
|
||||||
document.getElementById("addRequestModal").style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeAddRequestModal() {
|
|
||||||
document.getElementById("modalBackground").style.display = "none";
|
|
||||||
document.getElementById("addRequestModal").style.display = "none";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openUpdateRequestModal(tr) {
|
function openUpdateRequestModal(tr) {
|
||||||
|
hideModals();
|
||||||
var url = tr.getElementsByClassName('request-link')[0].firstChild.href;
|
var url = tr.getElementsByClassName('request-link')[0].firstChild.href;
|
||||||
var score = tr.getElementsByClassName('request-score')[0].innerText;
|
var score = tr.getElementsByClassName('request-score')[0].innerText;
|
||||||
var state = tr.getElementsByClassName('request-state')[0].innerText;
|
var state = tr.getElementsByClassName('request-state')[0].innerText;
|
||||||
|
@ -120,18 +149,12 @@ function openUpdateRequestModal(tr) {
|
||||||
document.getElementById("updateRequestModalCurrentScore").innerText = score;
|
document.getElementById("updateRequestModalCurrentScore").innerText = score;
|
||||||
document.querySelector(`#updateRequestStateSelect [value="${state}"]`).selected = true;
|
document.querySelector(`#updateRequestStateSelect [value="${state}"]`).selected = true;
|
||||||
document.getElementById("scoreModifierInput").value = 0;
|
document.getElementById("scoreModifierInput").value = 0;
|
||||||
document.getElementById("messageModal").style.display = "none";
|
|
||||||
document.getElementById("addRequestModal").style.display = "none";
|
|
||||||
document.getElementById("modalBackground").style.display = "flex";
|
document.getElementById("modalBackground").style.display = "flex";
|
||||||
document.getElementById("updateRequestModal").style.display = "block";
|
document.getElementById("updateRequestModal").style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeUpdateRequestModal() {
|
|
||||||
document.getElementById("modalBackground").style.display = "none";
|
|
||||||
document.getElementById("updateRequestModal").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
function openDeleteRequestModal(url) {
|
function openDeleteRequestModal(url) {
|
||||||
|
hideModals();
|
||||||
document.getElementById("updateRequestUrl").href = url;
|
document.getElementById("updateRequestUrl").href = url;
|
||||||
document.getElementById("updateRequestUrl").innerText = url;
|
document.getElementById("updateRequestUrl").innerText = url;
|
||||||
document.getElementById("messageModal").style.display = "none";
|
document.getElementById("messageModal").style.display = "none";
|
||||||
|
@ -141,17 +164,21 @@ function openDeleteRequestModal(url) {
|
||||||
document.getElementById("deleteRequestModal").style.display = "block";
|
document.getElementById("deleteRequestModal").style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns to update request modal
|
||||||
function closeDeleteRequestModal() {
|
function closeDeleteRequestModal() {
|
||||||
|
hideModals();
|
||||||
document.getElementById("deleteRequestModal").style.display = "none";
|
document.getElementById("deleteRequestModal").style.display = "none";
|
||||||
document.getElementById("updateRequestModal").style.display = "block";
|
document.getElementById("updateRequestModal").style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAllModals() {
|
function openStreamerSettingsModal() {
|
||||||
document.getElementById("messageModal").style.display = "none";
|
hideModals();
|
||||||
document.getElementById("addRequestModal").style.display = "none";
|
document.getElementById("modalBackground").style.display = "flex";
|
||||||
document.getElementById("updateRequestModal").style.display = "none";
|
document.getElementById("streamerSettingsModal").style.display = "block";
|
||||||
document.getElementById("deleteRequestModal").style.display = "none";
|
}
|
||||||
document.getElementById("modalBackground").style.display = "none";
|
|
||||||
|
function cronRequest(job) {
|
||||||
|
if (!cronJobs.includes(job)) throw new Error("Request for invalid job");
|
||||||
}
|
}
|
||||||
|
|
||||||
const validUrlRegexes = [
|
const validUrlRegexes = [
|
||||||
|
@ -262,7 +289,33 @@ function deleteRequest(url) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePageTitle(pageTitle) {
|
||||||
|
streamerSettingsErrReset();
|
||||||
|
fetch("/api/updatePageTitle", { method: 'POST', body: new URLSearchParams({
|
||||||
|
pageTitle: pageTitle
|
||||||
|
})})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
response.text().then(streamerSettingsErr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColors(colors) {
|
||||||
|
streamerSettingsErrReset();
|
||||||
|
fetch("/api/updateColors", { method: 'POST', headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}, body: JSON.stringify(colors)})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
response.text().then(streamerSettingsErr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
updateTable();
|
updateTable();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,12 @@ button, input, select {
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="color"] {
|
||||||
|
border: none;
|
||||||
|
padding: 0px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
}
|
}
|
||||||
|
|
137
src/app.ts
137
src/app.ts
|
@ -30,6 +30,7 @@ const app = express();
|
||||||
app.use(version.checkVersionMiddleware);
|
app.use(version.checkVersionMiddleware);
|
||||||
app.use(express.static('public'));
|
app.use(express.static('public'));
|
||||||
app.use(express.urlencoded({extended: false}));
|
app.use(express.urlencoded({extended: false}));
|
||||||
|
app.use(express.json());
|
||||||
app.use(session({
|
app.use(session({
|
||||||
secret: config.sessionSecret,
|
secret: config.sessionSecret,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
|
@ -189,6 +190,101 @@ app.post("/api/updateRequestScoreModifier", async (request, response) => {
|
||||||
.catch((e: any) => errorHandler(request,response,e));
|
.catch((e: any) => errorHandler(request,response,e));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/api/updatePageTitle", async (request, response) => {
|
||||||
|
if (request.session) await validateApiToken(request.session);
|
||||||
|
if (!request.session || !request.session.user) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("Session expired; please log in again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var streamerid = await db.query(queries.getStreamerId).then((result: pg.QueryResult) => result.rows[0]['userid']);
|
||||||
|
if (request.session.user.id != streamerid) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("You are not the streamer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!request.body.pageTitle) {
|
||||||
|
response.status(400);
|
||||||
|
response.send("Missing pageTitle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pageTitle = request.body.pageTitle as string;
|
||||||
|
response.type('text/plain');
|
||||||
|
pageTitle = pageTitle.replace(/[&<>"']/g, function(m) {
|
||||||
|
switch (m) {
|
||||||
|
case '&':
|
||||||
|
return '&';
|
||||||
|
case '<':
|
||||||
|
return '<';
|
||||||
|
case '>':
|
||||||
|
return '>';
|
||||||
|
case '"':
|
||||||
|
return '"';
|
||||||
|
case "'":
|
||||||
|
return ''';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await db.query(Object.assign(queries.updatePageTitle,{ values: [pageTitle] }))
|
||||||
|
.catch((e: any) => errorHandler(request,response,e));
|
||||||
|
response.status(200);
|
||||||
|
response.send('Successfully updated page title');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/api/updateColors", async (request, response) => {
|
||||||
|
if (request.session) await validateApiToken(request.session);
|
||||||
|
if (!request.session || !request.session.user) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("Session expired; please log in again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var streamerid = await db.query(queries.getStreamerId).then((result: pg.QueryResult) => result.rows[0]['userid']);
|
||||||
|
if (request.session.user.id != streamerid) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("You are not the streamer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!request.body.bg) {
|
||||||
|
response.status(400);
|
||||||
|
response.send("Missing bg");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!request.body.fg) {
|
||||||
|
response.status(400);
|
||||||
|
response.send("Missing fg");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
type Colors = { [key: string]: { [key: string]: string} }
|
||||||
|
var colors: Colors = { bg: {}, fg: {} };
|
||||||
|
console.log(JSON.stringify(request.body,null,2));
|
||||||
|
for (var color of ['primary','table','navbar','error']) {
|
||||||
|
var setcolor = request.body.bg[color];
|
||||||
|
if (/^#[0-9a-fA-F]{6}$/.test(setcolor)) {
|
||||||
|
colors.bg[color] = setcolor
|
||||||
|
} else {
|
||||||
|
response.status(400);
|
||||||
|
response.send(`Color 'bg.${color}' missing or invalid`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var color of ['primary','ahover','title']) {
|
||||||
|
var setcolor = request.body.fg[color];
|
||||||
|
if (/^#[0-9a-fA-F]{6}$/.test(setcolor)) {
|
||||||
|
colors.fg[color] = setcolor
|
||||||
|
} else {
|
||||||
|
response.status(400);
|
||||||
|
response.send(`Color 'fg.${color}' missing or invalid`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.type('text/plain');
|
||||||
|
await db.query(Object.assign(queries.updateColors,{ values: [JSON.stringify(colors)] }))
|
||||||
|
.catch((e: any) => errorHandler(request,response,e));
|
||||||
|
response.status(200);
|
||||||
|
response.send('Successfully updated colors');
|
||||||
|
});
|
||||||
|
|
||||||
app.post("/api/deleteRequest", async (request, response) => {
|
app.post("/api/deleteRequest", async (request, response) => {
|
||||||
if (request.session) await validateApiToken(request.session);
|
if (request.session) await validateApiToken(request.session);
|
||||||
if (!request.session || !request.session.user) {
|
if (!request.session || !request.session.user) {
|
||||||
|
@ -266,6 +362,37 @@ app.post("/api/deleteVote", async (request,response) => {
|
||||||
.catch((e: any) => errorHandler(request,response,e));
|
.catch((e: any) => errorHandler(request,response,e));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get("/api/cronRequest", async (request, response) => {
|
||||||
|
if (request.session) await validateApiToken(request.session);
|
||||||
|
if (!request.session || !request.session.user) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("Session expired; please log in again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var streamerid = await db.query(queries.getStreamerId).then((result: pg.QueryResult) => result.rows[0]['userid']);
|
||||||
|
if (request.session.user.id != streamerid) {
|
||||||
|
response.status(401);
|
||||||
|
response.send("You are not the streamer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!request.query.job) {
|
||||||
|
response.status(400);
|
||||||
|
response.send("Missing job");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var job = request.body.job as string;
|
||||||
|
try {
|
||||||
|
cron.validateJob(job)
|
||||||
|
} catch (e) {
|
||||||
|
response.status(400);
|
||||||
|
response.send("Invalid job")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.type('text/plain');
|
||||||
|
cron.request(job).catch((e: any) => errorHandler(request,response,e));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Twitch callback
|
// Twitch callback
|
||||||
app.get("/callback", async (request, response) => {
|
app.get("/callback", async (request, response) => {
|
||||||
if (request.query.error) {
|
if (request.query.error) {
|
||||||
|
@ -302,7 +429,7 @@ app.get("/callback", async (request, response) => {
|
||||||
app.get("/", async (request, response) => {
|
app.get("/", async (request, response) => {
|
||||||
if (request.session) await validateApiToken(request.session);
|
if (request.session) await validateApiToken(request.session);
|
||||||
var streamerInfo = await db.query(queries.getStreamerInfo).then((result: pg.QueryResult) => result.rows[0]);
|
var streamerInfo = await db.query(queries.getStreamerInfo).then((result: pg.QueryResult) => result.rows[0]);
|
||||||
var config = await db.query(queries.getConfig).then((result: pg.QueryResult) => result.rows[0]);
|
var streamerConfig = await db.query(queries.getConfig).then((result: pg.QueryResult) => result.rows[0]);
|
||||||
if (typeof streamerInfo == 'undefined') {
|
if (typeof streamerInfo == 'undefined') {
|
||||||
response.redirect(307, `https://id.twitch.tv/oauth2/authorize?client_id=${config.twitchClientId}&redirect_uri=${config.urlPrefix}/callback&response_type=code&scope=channel:read:subscriptions moderation:read`);
|
response.redirect(307, `https://id.twitch.tv/oauth2/authorize?client_id=${config.twitchClientId}&redirect_uri=${config.urlPrefix}/callback&response_type=code&scope=channel:read:subscriptions moderation:read`);
|
||||||
return;
|
return;
|
||||||
|
@ -312,7 +439,7 @@ app.get("/", async (request, response) => {
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
clientId: config.twitchClientId,
|
clientId: config.twitchClientId,
|
||||||
urlPrefix: config.urlPrefix,
|
urlPrefix: config.urlPrefix,
|
||||||
pageTitle: config.title,
|
pageTitle: streamerConfig.title,
|
||||||
streamerName: streamerInfo['displayname'],
|
streamerName: streamerInfo['displayname'],
|
||||||
streamerProfilePicture: streamerInfo['imageurl']
|
streamerProfilePicture: streamerInfo['imageurl']
|
||||||
});
|
});
|
||||||
|
@ -324,9 +451,10 @@ app.get("/", async (request, response) => {
|
||||||
userProfilePicture: request.session.user.profile_image_url,
|
userProfilePicture: request.session.user.profile_image_url,
|
||||||
validStates: validStates,
|
validStates: validStates,
|
||||||
isStreamer: streamerInfo['userid'] == request.session.user.id,
|
isStreamer: streamerInfo['userid'] == request.session.user.id,
|
||||||
pageTitle: config.title,
|
pageTitle: streamerConfig.title,
|
||||||
streamerName: streamerInfo['displayname'],
|
streamerName: streamerInfo['displayname'],
|
||||||
streamerProfilePicture: streamerInfo['imageurl']
|
streamerProfilePicture: streamerInfo['imageurl'],
|
||||||
|
colors: streamerConfig.colors
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -334,7 +462,6 @@ app.get("/", async (request, response) => {
|
||||||
app.get("/colors.css", async (_request, response) => {
|
app.get("/colors.css", async (_request, response) => {
|
||||||
var streamerInfo = await db.query(queries.getStreamerInfo).then((result: pg.QueryResult) => result.rows[0]);
|
var streamerInfo = await db.query(queries.getStreamerInfo).then((result: pg.QueryResult) => result.rows[0]);
|
||||||
var colors = await db.query(queries.getConfig).then((result: pg.QueryResult) => result.rows[0]['colors']);
|
var colors = await db.query(queries.getConfig).then((result: pg.QueryResult) => result.rows[0]['colors']);
|
||||||
console.log(colors);
|
|
||||||
if (typeof streamerInfo == 'undefined') return;
|
if (typeof streamerInfo == 'undefined') return;
|
||||||
response.contentType("text/css");
|
response.contentType("text/css");
|
||||||
response.render('colors.eta', colors);
|
response.render('colors.eta', colors);
|
||||||
|
|
22
src/cron.ts
22
src/cron.ts
|
@ -9,6 +9,24 @@ interface CronJob {
|
||||||
(streamer: twitch.StreamerUserIdTokenPair): Promise<void>
|
(streamer: twitch.StreamerUserIdTokenPair): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateJob(job: string) {
|
||||||
|
if (!Object.keys(cronjobs).includes(job)) throw new Error("Invalid cronjob " + job);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runJob(job: string) {
|
||||||
|
validateJob(job);
|
||||||
|
var streamer = await db.query(queries.getStreamerIdToken).then(
|
||||||
|
(result: pg.QueryResult) => result.rows[0]);
|
||||||
|
return await (cronjobs as { [key: string]: CronJob })[job](streamer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a specific job on request of streamer
|
||||||
|
async function request(job: string) {
|
||||||
|
validateJob(job);
|
||||||
|
// TODO: Rate limiting
|
||||||
|
await runJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
// If instance is not yet set up, end processing at this point
|
// If instance is not yet set up, end processing at this point
|
||||||
var streamer = await db.query(queries.getStreamerIdToken).then(
|
var streamer = await db.query(queries.getStreamerIdToken).then(
|
||||||
|
@ -42,11 +60,11 @@ async function run() {
|
||||||
log(LogLevel.ERROR,`cron: Job ${job} exception message: ${e}`)
|
log(LogLevel.ERROR,`cron: Job ${job} exception message: ${e}`)
|
||||||
} finally {
|
} finally {
|
||||||
log(LogLevel.DEBUG,`cron: Job ${job} hit finally; releasing dbconn`);
|
log(LogLevel.DEBUG,`cron: Job ${job} hit finally; releasing dbconn`);
|
||||||
await dbconn.release();
|
dbconn.release();
|
||||||
}
|
}
|
||||||
log(LogLevel.INFO,"cron: Finished job " + job);
|
log(LogLevel.INFO,"cron: Finished job " + job);
|
||||||
}
|
}
|
||||||
log(LogLevel.INFO,"End cron run")
|
log(LogLevel.INFO,"End cron run")
|
||||||
}
|
}
|
||||||
|
|
||||||
export = {run}
|
export = {run,validateJob,request}
|
||||||
|
|
|
@ -37,6 +37,16 @@ export const updateStreamer = {
|
||||||
ON CONFLICT (userid) DO UPDATE SET tokenPair = $2"
|
ON CONFLICT (userid) DO UPDATE SET tokenPair = $2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const updatePageTitle = {
|
||||||
|
name: "updatePageTitle",
|
||||||
|
text: "UPDATE config SET title = $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateColors = {
|
||||||
|
name: "updateColors",
|
||||||
|
text: "UPDATE config SET colors = $1"
|
||||||
|
}
|
||||||
|
|
||||||
// Request-related queries
|
// Request-related queries
|
||||||
export const getRequests = {
|
export const getRequests = {
|
||||||
name: "getRequests",
|
name: "getRequests",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<link rel=stylesheet href=/style.css />
|
<link rel=stylesheet href=/style.css />
|
||||||
<link rel=stylesheet href=/colors.css />
|
<link rel=stylesheet href=/colors.css />
|
||||||
<title><%= it.pageTitle.replace('{username}',it.streamerName) %></title>
|
<title><%~ it.pageTitle.replace('{username}',it.streamerName) %></title>
|
||||||
<script>
|
<script>
|
||||||
window.loggedIn = <%= it.loggedIn %>;
|
window.loggedIn = <%= it.loggedIn %>;
|
||||||
window.validStates = <%~ it.validStates %>;
|
window.validStates = <%~ it.validStates %>;
|
||||||
|
@ -18,6 +18,9 @@
|
||||||
<div id="nav-requests"><a href="/">Requests</a></div>
|
<div id="nav-requests"><a href="/">Requests</a></div>
|
||||||
<%- if (it.loggedIn) { -%>
|
<%- if (it.loggedIn) { -%>
|
||||||
<div id="nav-addrequest"><a href="#" onclick="openAddRequestModal()">Add Request</a></div>
|
<div id="nav-addrequest"><a href="#" onclick="openAddRequestModal()">Add Request</a></div>
|
||||||
|
<%- if (it.isStreamer) { -%>
|
||||||
|
<div id="nav-streamersettings"><a href="#" onclick="openStreamerSettingsModal()">Streamer Settings</a></div>
|
||||||
|
<%- } %>
|
||||||
<div id="nav-userpic"><img src="<%= it.userProfilePicture %>" /></div>
|
<div id="nav-userpic"><img src="<%= it.userProfilePicture %>" /></div>
|
||||||
<div id="nav-username"><%= it.userName %></div>
|
<div id="nav-username"><%= it.userName %></div>
|
||||||
<div id="nav-logout"><a href="/logout">Logout</a></div>
|
<div id="nav-logout"><a href="/logout">Logout</a></div>
|
||||||
|
@ -39,11 +42,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="modalBackground">
|
<div id="modalBackground">
|
||||||
<div class="modal" id="messageModal">
|
<div class="modal" id="messageModal">
|
||||||
<div class="modalClose"><a href="#" onclick="closeMessageModal()">×</a></div>
|
<div class="modalClose"><a href="#" onclick="closeAllModals()">×</a></div>
|
||||||
<span id="messageModalText"></span>
|
<span id="messageModalText"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal" id="addRequestModal">
|
<div class="modal" id="addRequestModal">
|
||||||
<div class="modalClose"><a href="#" onclick="closeAddRequestModal()">×</a></div>
|
<div class="modalClose"><a href="#" onclick="closeAllModals()">×</a></div>
|
||||||
<h1>Add Request</h1>
|
<h1>Add Request</h1>
|
||||||
<div class="error" id="addRequestError"></div>
|
<div class="error" id="addRequestError"></div>
|
||||||
<span id="addRequestInputContainer">
|
<span id="addRequestInputContainer">
|
||||||
|
@ -53,7 +56,7 @@
|
||||||
Currently, only Youtube links are accepted.
|
Currently, only Youtube links are accepted.
|
||||||
</div>
|
</div>
|
||||||
<div class="modal" id="updateRequestModal">
|
<div class="modal" id="updateRequestModal">
|
||||||
<div class="modalClose"><a href="#" onclick="closeAddRequestModal()">×</a></div>
|
<div class="modalClose"><a href="#" onclick="closeAllModals()">×</a></div>
|
||||||
<h2>Update Request</h2>
|
<h2>Update Request</h2>
|
||||||
<div class="error" id="updateRequestError"></div>
|
<div class="error" id="updateRequestError"></div>
|
||||||
<br>
|
<br>
|
||||||
|
@ -84,7 +87,7 @@
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div>
|
<div>
|
||||||
<a id="updateMetadataLink" href="#" onclick="updateRequestMetadata(
|
<a href="#" onclick="updateRequestMetadata(
|
||||||
document.getElementById('updateRequestUrl').innerText
|
document.getElementById('updateRequestUrl').innerText
|
||||||
)">Update Request Metadata</a>
|
)">Update Request Metadata</a>
|
||||||
<br>
|
<br>
|
||||||
|
@ -112,6 +115,43 @@
|
||||||
<button onclick="closeDeleteRequestModal()">No</button>
|
<button onclick="closeDeleteRequestModal()">No</button>
|
||||||
<button onclick="deleteRequest(document.getElementById('updateRequestUrl').innerText)">Yes</button>
|
<button onclick="deleteRequest(document.getElementById('updateRequestUrl').innerText)">Yes</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal" id="streamerSettingsModal">
|
||||||
|
<div class="modalClose"><a href="#" onclick="closeAllModals()">×</a></div>
|
||||||
|
<h2>Streamer Settings</h2>
|
||||||
|
<div class="error" id="streamerSettingsError"></div>
|
||||||
|
<br>
|
||||||
|
<div>
|
||||||
|
<h3 style='margin-bottom: 0.5em'>Customization</h3>
|
||||||
|
<p>
|
||||||
|
Page Title:
|
||||||
|
<input type="text" id="pageTitle" style="width: 15em" value="<%~ it.pageTitle %>"></input>
|
||||||
|
<button onclick="updatePageTitle(document.getElementById('pageTitle').value)">Submit</button>
|
||||||
|
<button onclick="updatePageTitle('{username}\'s Learn Request Queue')">Reset</button>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<h3>Colors:</h3>
|
||||||
|
<p>Click a color to change it</p>
|
||||||
|
<b>Background:</b><br>
|
||||||
|
Primary: <input type="color" id="color-bg-primary" value="<%= it.colors.bg.primary %>"></input><br>
|
||||||
|
Table: <input type="color" id="color-bg-table" value="<%= it.colors.bg.table %>"></input><br>
|
||||||
|
Navbar: <input type="color" id="color-bg-navbar" value="<%= it.colors.bg.navbar %>"></input><br>
|
||||||
|
Error: <input type="color" id="color-bg-error" value="<%= it.colors.bg.error %>"></input><br>
|
||||||
|
<br>
|
||||||
|
<b>Foreground:</b><br>
|
||||||
|
Primary: <input type="color" id="color-fg-primary" value="<%= it.colors.fg.primary %>"></input><br>
|
||||||
|
Link Hover: <input type="color" id="color-fg-ahover" value="<%= it.colors.fg.ahover %>"></input><br>
|
||||||
|
Title: <input type="color" id="color-fg-title" value="<%= it.colors.fg.title %>"></input><br>
|
||||||
|
<br>
|
||||||
|
<button onclick="updateColors(getColorObject())">Submit</button>
|
||||||
|
<button onclick="updateColors({bg:{error: '#ff0000',table: '#282828',navbar: '#666666',primary: '#444444'},fg: { title: '#eeeeee', ahover: '#ffffff', primary: '#dddddd'}})">Reset</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<h3 style='margin-bottom: 0.5em'>Batch Jobs</h3>
|
||||||
|
<a href="#" onclick="cronRequest('processBans')">Force Refresh Banned Users (NYI)</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue