mai2: add event editing for sysops

This commit is contained in:
Hay1tsme 2024-07-01 18:26:39 -04:00
parent 44fb6037cf
commit 9b5283d389
6 changed files with 315 additions and 11 deletions

View File

@ -234,11 +234,11 @@ class ChuniFrontend(FE_Base):
if usr_sesh.user_id > 0: if usr_sesh.user_id > 0:
form_data = await request.form() form_data = await request.form()
chunithm_version = form_data.get("version") chunithm_version = form_data.get("version")
self.logger.info(f"version change to: {chunithm_version}") self.logger.debug(f"version change to: {chunithm_version}")
if(chunithm_version.isdigit()): if(chunithm_version.isdigit()):
usr_sesh.chunithm_version=int(chunithm_version) usr_sesh.chunithm_version=int(chunithm_version)
encoded_sesh = self.encode_session(usr_sesh) encoded_sesh = self.encode_session(usr_sesh)
self.logger.info(f"Created session with JWT {encoded_sesh}") self.logger.debug(f"Created session with JWT {encoded_sesh}")
resp = RedirectResponse("/game/chuni/", 303) resp = RedirectResponse("/game/chuni/", 303)
resp.set_cookie("ARTEMIS_SESH", encoded_sesh) resp.set_cookie("ARTEMIS_SESH", encoded_sesh)
return resp return resp

View File

@ -5,8 +5,9 @@ from starlette.responses import Response, RedirectResponse
from os import path from os import path
import yaml import yaml
import jinja2 import jinja2
from datetime import datetime
from core.frontend import FE_Base, UserSession from core.frontend import FE_Base, UserSession, PermissionOffset
from core.config import CoreConfig from core.config import CoreConfig
from .database import Mai2Data from .database import Mai2Data
from .config import Mai2Config from .config import Mai2Config
@ -32,6 +33,12 @@ class Mai2Frontend(FE_Base):
Route("/", self.render_GET_playlog, methods=['GET']), Route("/", self.render_GET_playlog, methods=['GET']),
Route("/{index}", self.render_GET_playlog, methods=['GET']), Route("/{index}", self.render_GET_playlog, methods=['GET']),
]), ]),
Mount("/events", routes=[
Route("/", self.render_events, methods=['GET']),
Route("/{event_id:int}", self.render_event_edit, methods=['GET']),
Route("/update", self.update_event, methods=['POST']),
Route("/version.change", self.version_change, methods=['POST']),
]),
Route("/update.name", self.update_name, methods=['POST']), Route("/update.name", self.update_name, methods=['POST']),
Route("/version.change", self.version_change, methods=['POST']), Route("/version.change", self.version_change, methods=['POST']),
] ]
@ -43,13 +50,15 @@ class Mai2Frontend(FE_Base):
usr_sesh = self.validate_session(request) usr_sesh = self.validate_session(request)
if not usr_sesh: if not usr_sesh:
usr_sesh = UserSession() usr_sesh = UserSession()
incoming_ver = usr_sesh.maimai_version
if usr_sesh.user_id > 0: if usr_sesh.user_id > 0:
versions = await self.data.profile.get_all_profile_versions(usr_sesh.user_id) versions = await self.data.profile.get_all_profile_versions(usr_sesh.user_id)
profile = [] profile = []
if versions: if versions:
# maimai_version is -1 means it is not initialized yet, select a default version from existing. # maimai_version is -1 means it is not initialized yet, select a default version from existing.
if usr_sesh.maimai_version < 0: if incoming_ver < 0:
usr_sesh.maimai_version = versions[0]['version'] usr_sesh.maimai_version = versions[0]['version']
profile = await self.data.profile.get_profile_detail(usr_sesh.user_id, usr_sesh.maimai_version) profile = await self.data.profile.get_profile_detail(usr_sesh.user_id, usr_sesh.maimai_version)
versions = [x['version'] for x in versions] versions = [x['version'] for x in versions]
@ -65,7 +74,7 @@ class Mai2Frontend(FE_Base):
cur_version=usr_sesh.maimai_version cur_version=usr_sesh.maimai_version
), media_type="text/html; charset=utf-8") ), media_type="text/html; charset=utf-8")
if usr_sesh.maimai_version >= 0: if incoming_ver < 0:
encoded_sesh = self.encode_session(usr_sesh) encoded_sesh = self.encode_session(usr_sesh)
resp.delete_cookie("ARTEMIS_SESH") resp.delete_cookie("ARTEMIS_SESH")
resp.set_cookie("ARTEMIS_SESH", encoded_sesh) resp.set_cookie("ARTEMIS_SESH", encoded_sesh)
@ -80,12 +89,10 @@ class Mai2Frontend(FE_Base):
) )
usr_sesh = self.validate_session(request) usr_sesh = self.validate_session(request)
if not usr_sesh: if not usr_sesh:
print("wtf")
usr_sesh = UserSession() usr_sesh = UserSession()
if usr_sesh.user_id > 0: if usr_sesh.user_id > 0:
if usr_sesh.maimai_version < 0: if usr_sesh.maimai_version < 0:
print(usr_sesh.maimai_version)
return RedirectResponse("/game/mai2/", 303) return RedirectResponse("/game/mai2/", 303)
path_index = request.path_params.get('index') path_index = request.path_params.get('index')
if not path_index or int(path_index) < 1: if not path_index or int(path_index) < 1:
@ -175,6 +182,11 @@ class Mai2Frontend(FE_Base):
if not usr_sesh: if not usr_sesh:
usr_sesh = UserSession() usr_sesh = UserSession()
if "/events/" in request.url.path:
resp = RedirectResponse("/game/mai2/events/", 303)
else:
resp = RedirectResponse("/game/mai2/", 303)
if usr_sesh.user_id > 0: if usr_sesh.user_id > 0:
form_data = await request.form() form_data = await request.form()
maimai_version = form_data.get("version") maimai_version = form_data.get("version")
@ -182,9 +194,108 @@ class Mai2Frontend(FE_Base):
if(maimai_version.isdigit()): if(maimai_version.isdigit()):
usr_sesh.maimai_version=int(maimai_version) usr_sesh.maimai_version=int(maimai_version)
encoded_sesh = self.encode_session(usr_sesh) encoded_sesh = self.encode_session(usr_sesh)
self.logger.info(f"Created session with JWT {encoded_sesh}") self.logger.debug(f"Created session with JWT {encoded_sesh}")
resp = RedirectResponse("/game/mai2/", 303)
resp.set_cookie("ARTEMIS_SESH", encoded_sesh) resp.set_cookie("ARTEMIS_SESH", encoded_sesh)
return resp return resp
else: else:
return RedirectResponse("/gate/", 303) return RedirectResponse("/gate/", 303)
async def render_events(self, request: Request) -> Response:
usr_sesh = self.validate_session(request)
if not usr_sesh:
return RedirectResponse("/gate/", 303)
if not self.test_perm(usr_sesh.permissions, PermissionOffset.SYSADMIN):
return RedirectResponse("/game/mai2/", 303)
template = self.environment.get_template(
"titles/mai2/templates/events/mai2_events.jinja"
)
incoming_ver = usr_sesh.maimai_version
evts = []
if incoming_ver < 0:
usr_sesh.maimai_version = Mai2Constants.VER_MAIMAI_DX
event_list = await self.data.static.get_game_events(usr_sesh.maimai_version)
self.logger.info(f"Get events for v{usr_sesh.maimai_version}")
for event in event_list:
evts.append({
"id": event['id'],
"version": event['version'],
"eventId": event['eventId'],
"eventType": event['type'],
"name": event['name'],
"startDate": event['startDate'].strftime("%x %X"),
"enabled": "true" if event['enabled'] else "false",
})
resp = Response(template.render(
title=f"{self.core_config.server.name} | {self.nav_name} Events",
game_list=self.environment.globals["game_list"],
sesh=vars(usr_sesh),
version_list=Mai2Constants.VERSION_STRING,
events=evts
), media_type="text/html; charset=utf-8")
if incoming_ver < 0:
encoded_sesh = self.encode_session(usr_sesh)
resp.delete_cookie("ARTEMIS_SESH")
resp.set_cookie("ARTEMIS_SESH", encoded_sesh)
return resp
async def render_event_edit(self, request: Request) -> Response:
usr_sesh = self.validate_session(request)
if not usr_sesh:
return RedirectResponse("/gate/", 303)
if not self.test_perm(usr_sesh.permissions, PermissionOffset.SYSADMIN):
return RedirectResponse("/game/mai2/", 303)
template = self.environment.get_template(
"titles/mai2/templates/events/mai2_event_edit.jinja"
)
evt_id = request.path_params.get("event_id")
event_id = await self.data.static.get_event_by_id(evt_id)
if not event_id:
return RedirectResponse("/game/mai2/events/", 303)
return Response(template.render(
title=f"{self.core_config.server.name} | {self.nav_name} Edit Event {evt_id}",
game_list=self.environment.globals["game_list"],
sesh=vars(usr_sesh),
user_id=usr_sesh.user_id,
version_list=Mai2Constants.VERSION_STRING,
cur_version=usr_sesh.maimai_version,
event=event_id._asdict()
), media_type="text/html; charset=utf-8")
async def update_event(self, request: Request) -> RedirectResponse:
usr_sesh = self.validate_session(request)
if not usr_sesh:
return RedirectResponse("/gate/", 303)
if not self.test_perm(usr_sesh.permissions, PermissionOffset.SYSADMIN):
return RedirectResponse("/game/mai2/", 303)
form_data = await request.form()
print(form_data)
event_id: int = form_data.get("evtId", None)
new_enabled: bool = bool(form_data.get("evtEnabled", False))
try:
new_start_date: datetime = datetime.strptime(form_data.get("evtStart", None), "%Y-%m-%dT%H:%M:%S")
except:
new_start_date = None
print(f"{event_id} {new_enabled} {new_start_date}")
if event_id is None or new_start_date is None:
return RedirectResponse("/game/mai2/events/?e=4", 303)
await self.data.static.update_event_by_id(int(event_id), new_enabled, new_start_date)
return RedirectResponse("/game/mai2/events/?s=1", 303)

View File

@ -7,6 +7,7 @@ from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select from sqlalchemy.sql import func, select
from sqlalchemy.engine import Row from sqlalchemy.engine import Row
from sqlalchemy.dialects.mysql import insert from sqlalchemy.dialects.mysql import insert
from datetime import datetime
event = Table( event = Table(
"mai2_static_event", "mai2_static_event",
@ -248,3 +249,18 @@ class Mai2StaticData(BaseData):
if result is None: if result is None:
return None return None
return result.fetchall() return result.fetchall()
async def get_event_by_id(self, table_id: int) -> Optional[Row]:
result = await self.execute(event.select(event.c.id == table_id))
if result:
return result.fetchone()
async def get_events_by_event_id(self, event_id: int) -> Optional[List[Row]]:
result = await self.execute(event.select(event.c.eventId == event_id))
if result:
return result.fetchall()
async def update_event_by_id(self, table_id: int, is_enable: bool, start_date: datetime) -> None:
result = await self.execute(event.update(event.c.id == table_id).values(enabled=is_enable, startDate = start_date))
if not result:
self.logger.error(f"Failed to update event {table_id} - {is_enable} {start_date}")

View File

@ -0,0 +1,16 @@
{% extends "core/templates/index.jinja" %}
{% block content %}
<!-- TODO: This can probably just be a modal on the main event page -->
<form id="frmEvent" method="post" action="/game/mai2/events/update">
<h3>Event {{ event.eventId }} for {{ version_list[event.version] }}: {{ event.name }}</h3>
<input type="hidden" readonly value="{{event.id}}" id="evtId" name="evtId">
<label for="evtEnabled" class="form-label">Enabled</label><br>
<input class="form-check-input" type="checkbox" {{ 'checked' if event.enabled else ''}} id="evtEnabled" name="evtEnabled"><br><br>
<label for="evtStart" class="form-label">Start Date</label><br>
<input class="form-input" type="datetime-local" id="evtStart" name="evtStart" value="{{ event.startDate }}"><br><br>
<button type="submit" class="btn btn-primary">Update</button>&nbsp;
<button type="cancel" class="btn btn-danger">Delete</button>
</form>
{% endblock content %}

View File

@ -0,0 +1,156 @@
{% extends "core/templates/index.jinja" %}
{% block content %}
<h1>Events</h1>
<form id="verForm" method="POST" action="/game/mai2/events/version.change">
<select id="version" name="version" onchange="updateVer()" form="verForm">
{% for ver in range(version_list|length) %}
<option value="{{ver}}">{{ version_list[ver] }}</option>
{% endfor %}
</select>
</form>
<table class="table table-dark table-striped-columns" id="tbl_events">
<caption>Viewing all events</caption>
<thead>
<tr>
<th>ID</th>
<th>Version</th>
<th>Event ID</th>
<th>Event Type</th>
<th>Name</th>
<th>Start Date</th>
<th>Enabled</th>
<th>Actions</th>
</tr>
</thead>
{% if events is not defined or events|length == 0 %}
<tr>
<td colspan="11" style="text-align:center"><i>No Events</i></td>
</tr>
{% endif %}
</table>
<div id="div_tbl_ctrl">
<select id="sel_per_page" onchange="update_tbl()">
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
&nbsp;
<button class="btn btn-primary" id="btn_prev" disabled onclick="chg_page(-1)"><<</button>
<button class="btn btn-primary" id="btn_next" onclick="chg_page(1)">>></button>
</div>
<script type="text/javascript">
{% if events is defined %}
const TBL_DATA = {{events}};
{% else %}
const TBL_DATA = [];
{% endif %}
document.getElementById("version").value = {{ sesh.maimai_version }};
var per_page = 0;
var page = 0;
function updateVer() {
var sel = document.getElementById("version");
var frm = document.getElementById("verForm");
if (sel.value == {{ sesh.maimai_version }}) {
return;
}
frm.submit();
}
function update_tbl() {
if (TBL_DATA.length == 0) { return; }
var tbl = document.getElementById("tbl_events");
for (var i = 0; i < per_page; i++) {
try{
tbl.deleteRow(1);
} catch {
break;
}
}
per_page = document.getElementById("sel_per_page").value;
if (per_page >= TBL_DATA.length) {
page = 0;
document.getElementById("btn_next").disabled = true;
document.getElementById("btn_prev").disabled = true;
}
for (var i = 0; i < per_page; i++) {
let off = (page * per_page) + i;
if (off >= TBL_DATA.length) {
if (page != 0) {
document.getElementById("btn_next").disabled = true;
document.getElementById("btn_prev").disabled = false;
}
break;
}
var data = TBL_DATA[off];
var row = tbl.insertRow(i + 1);
var cell_id = row.insertCell(0);
cell_id.innerHTML = data.id;
var cell_ver = row.insertCell(1);
cell_ver.innerHTML = data.version;
var cell_evtid = row.insertCell(2);
cell_evtid.innerHTML = data.eventId;
var cell_evttype = row.insertCell(3);
cell_evttype.innerHTML = data.eventType;
var cell_name = row.insertCell(4);
cell_name.innerHTML = data.name;
var cell_date = row.insertCell(5);
cell_date.innerHTML = data.startDate;
var call_enabled = row.insertCell(6);
if (data.enabled === "true")
call_enabled.innerHTML = "✔"
else
call_enabled.innerHTML = "✖"
var cell_action = row.insertCell(7);
cell_action.innerHTML = "<a href=/game/mai2/events/" + data.id +"><button class='btn btn-primary'>🖉</button></a>"
}
}
function chg_page(num) {
var max_page = TBL_DATA.length / per_page;
console.log(max_page);
page = page + num;
if (page > max_page && max_page >= 1) {
page = max_page;
document.getElementById("btn_next").disabled = true;
document.getElementById("btn_prev").disabled = false;
return;
} else if (page < 0) {
page = 0;
document.getElementById("btn_next").disabled = false;
document.getElementById("btn_prev").disabled = true;
return;
} else if (page == 0) {
document.getElementById("btn_next").disabled = false;
document.getElementById("btn_prev").disabled = true;
} else {
document.getElementById("btn_next").disabled = false;
document.getElementById("btn_prev").disabled = false;
}
update_tbl();
}
update_tbl();
</script>
{% endblock content %}

View File

@ -3,6 +3,9 @@
<ul class="mai2-navi"> <ul class="mai2-navi">
<li><a class="nav-link" href="/game/mai2/">PROFILE</a></li> <li><a class="nav-link" href="/game/mai2/">PROFILE</a></li>
<li><a class="nav-link" href="/game/mai2/playlog/">RECORD</a></li> <li><a class="nav-link" href="/game/mai2/playlog/">RECORD</a></li>
{% if sesh is defined and sesh is not none and "{:08b}".format(sesh.permissions)[4] == "1" %}
<li><a class="nav-link" href="/game/mai2/events/">EVENTS</a></li>
{% endif %}
</ul> </ul>
</div> </div>
<script> <script>
@ -12,6 +15,8 @@
$('.nav-link[href="/game/mai2/"]').addClass('active'); $('.nav-link[href="/game/mai2/"]').addClass('active');
} else if (currentPath.startsWith('/game/mai2/playlog/')) { } else if (currentPath.startsWith('/game/mai2/playlog/')) {
$('.nav-link[href="/game/mai2/playlog/"]').addClass('active'); $('.nav-link[href="/game/mai2/playlog/"]').addClass('active');
} } {% if sesh is defined and sesh is not none and "{:08b}".format(sesh.permissions)[4] == "1" %}else if (currentPath.startsWith('/game/mai2/events/')) {
$('.nav-link[href="/game/mai2/events/"]').addClass('active');
} {% endif %}
}); });
</script> </script>