forked from Hay1tsme/artemis
Merge branch 'develop' into mai2_enhance_musicscoreapi
This commit is contained in:
@ -58,3 +58,62 @@ class Mai2BuddiesPlus(Mai2Buddies):
|
||||
"friendBonusFlag": False
|
||||
}
|
||||
}
|
||||
|
||||
async def handle_get_user_friend_check_api_request(self, data: Dict) -> Dict:
|
||||
user1rivalList = await self.data.profile.get_rivals(data["userId1"])
|
||||
user2rivalList = await self.data.profile.get_rivals(data["userId2"])
|
||||
|
||||
is_user2_in_user1_rivals = any(rival["rival"] == data["userId2"] for rival in user1rivalList)
|
||||
is_user1_in_user2_rivals = any(rival["rival"] == data["userId1"] for rival in user2rivalList)
|
||||
|
||||
if is_user2_in_user1_rivals and is_user1_in_user2_rivals:
|
||||
return {"returnCode": 0}
|
||||
else:
|
||||
return {"returnCode": 1}
|
||||
|
||||
async def handle_user_friend_regist_api_request(self, data: Dict) -> Dict:
|
||||
user1rivalList = await self.data.profile.get_rivals(data["userId1"]) or []
|
||||
user2rivalList = await self.data.profile.get_rivals(data["userId2"]) or []
|
||||
|
||||
is_user2_in_user1_rivals = any(row.rival == data["userId2"] for row in user1rivalList)
|
||||
is_user1_in_user2_rivals = any(row.rival == data["userId1"] for row in user2rivalList)
|
||||
user1_show_count = sum(1 for row in user1rivalList if row.show is True)
|
||||
user2_show_count = sum(1 for row in user2rivalList if row.show is True)
|
||||
|
||||
# initialize returnCode
|
||||
returnCode1 = 2
|
||||
returnCode2 = 2
|
||||
|
||||
# Case1 no rival
|
||||
if not is_user2_in_user1_rivals and not is_user1_in_user2_rivals:
|
||||
if user1_show_count >= 3 and user2_show_count >= 3:
|
||||
returnCode1, returnCode2 = 1, 1
|
||||
elif user1_show_count >= 3:
|
||||
returnCode1, returnCode2 = 1, 2
|
||||
elif user2_show_count >= 3:
|
||||
returnCode1, returnCode2 = 2, 1
|
||||
|
||||
# Case2 has single rival
|
||||
elif is_user2_in_user1_rivals != is_user1_in_user2_rivals:
|
||||
if user1_show_count >= 3 and user2_show_count >= 3:
|
||||
returnCode1, returnCode2 = 1, 1
|
||||
elif user1_show_count >= 3:
|
||||
returnCode1, returnCode2 = 1, 2
|
||||
elif user2_show_count >= 3:
|
||||
returnCode1, returnCode2 = 2, 1
|
||||
|
||||
# execute add_rival and show_rival
|
||||
if not is_user2_in_user1_rivals:
|
||||
await self.data.profile.add_rival(data["userId1"], data["userId2"])
|
||||
if returnCode1 == 2 and user1_show_count < 3:
|
||||
await self.data.profile.set_rival_shown(data["userId1"], data["userId2"], True)
|
||||
|
||||
if not is_user1_in_user2_rivals:
|
||||
await self.data.profile.add_rival(data["userId2"], data["userId1"])
|
||||
if returnCode2 == 2 and user2_show_count < 3:
|
||||
await self.data.profile.set_rival_shown(data["userId2"], data["userId1"], True)
|
||||
|
||||
return {
|
||||
"returnCode1": returnCode1,
|
||||
"returnCode2": returnCode2
|
||||
}
|
@ -258,9 +258,9 @@ class Mai2DX(Mai2Base):
|
||||
if kind_id is not None:
|
||||
await self.data.item.put_favorite(user_id, kind_id, fav["itemIdList"])
|
||||
|
||||
if "userFavoritemusicList" in upsert and len(upsert["userFavoritemusicList"]) > 0:
|
||||
for fav in upsert["userFavoritemusicList"]:
|
||||
await self.data.item.add_fav_music(user_id, fav["id"], fav["orderId"])
|
||||
# added in BUDDiES+
|
||||
if "isNewFavoritemusicList" in upsert and upsert["isNewFavoritemusicList"] != "" and "userFavoritemusicList" in upsert:
|
||||
await self.data.item.put_fav_music(user_id, ((fav["id"], fav["orderId"]) for fav in upsert["userFavoritemusicList"]))
|
||||
|
||||
if (
|
||||
"userFriendSeasonRankingList" in upsert
|
||||
|
@ -46,6 +46,9 @@ class Mai2Frontend(FE_Base):
|
||||
Route("/update.name", self.update_name, methods=['POST']),
|
||||
Route("/version.change", self.version_change, methods=['POST']),
|
||||
Route("/photo/{photo_id}", self.get_photo, methods=['GET']),
|
||||
Route("/rival.add", self.rival_POST, methods=['POST']),
|
||||
Route("/rival.delete", self.rival_POST, methods=['POST']),
|
||||
Route("/rival.show", self.rival_POST, methods=['POST']),
|
||||
]
|
||||
|
||||
async def render_GET(self, request: Request) -> bytes:
|
||||
@ -61,11 +64,22 @@ class Mai2Frontend(FE_Base):
|
||||
if usr_sesh.user_id > 0:
|
||||
versions = await self.data.profile.get_all_profile_versions(usr_sesh.user_id)
|
||||
profile = []
|
||||
new_rival_list = []
|
||||
if versions:
|
||||
# maimai_version is -1 means it is not initialized yet, select a default version from existing.
|
||||
if incoming_ver < 0:
|
||||
usr_sesh.maimai_version = versions[0]['version']
|
||||
profile = await self.data.profile.get_profile_detail(usr_sesh.user_id, usr_sesh.maimai_version)
|
||||
rival_list = await self.data.profile.get_rivals(usr_sesh.user_id)
|
||||
|
||||
for rival in rival_list:
|
||||
rivalid = rival["rival"]
|
||||
rivalShow = rival["show"]
|
||||
rivalprofile = await self.data.profile.get_profile_detail(rivalid, usr_sesh.maimai_version)
|
||||
rivalName = rivalprofile["userName"] if rivalprofile else "UnknownName"
|
||||
rivalRating = rivalprofile["playerRating"] if rivalprofile else 0
|
||||
new_rival = (rivalName, rivalRating, rivalid, rivalShow)
|
||||
new_rival_list.append(new_rival)
|
||||
versions = [x['version'] for x in versions]
|
||||
|
||||
resp = Response(template.render(
|
||||
@ -76,7 +90,8 @@ class Mai2Frontend(FE_Base):
|
||||
profile=profile,
|
||||
version_list=Mai2Constants.VERSION_STRING,
|
||||
versions=versions,
|
||||
cur_version=usr_sesh.maimai_version
|
||||
cur_version=usr_sesh.maimai_version,
|
||||
rival_list=new_rival_list
|
||||
), media_type="text/html; charset=utf-8")
|
||||
|
||||
if incoming_ver < 0:
|
||||
@ -420,3 +435,28 @@ class Mai2Frontend(FE_Base):
|
||||
return FileResponse(f"{out_folder}.jpeg")
|
||||
|
||||
return Response(status_code=404)
|
||||
async def rival_POST(self, request: Request):
|
||||
uri = request.url.path
|
||||
frm = await request.form()
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
usr_sesh = UserSession()
|
||||
|
||||
if usr_sesh.user_id > 0:
|
||||
if uri == "/game/mai2/rival.add":
|
||||
rival_id = frm.get("rivalUserId")
|
||||
await self.data.profile.add_rival(usr_sesh.user_id, rival_id)
|
||||
# self.logger.info(f"{usr_sesh.user_id} added a rival")
|
||||
return RedirectResponse("/game/mai2/", 303)
|
||||
|
||||
elif uri == "/game/mai2/rival.delete":
|
||||
rival_id = frm.get("rivalUserId")
|
||||
await self.data.profile.remove_rival(usr_sesh.user_id, rival_id)
|
||||
# self.logger.info(f"{response}")
|
||||
return RedirectResponse("/game/mai2/", 303)
|
||||
|
||||
elif uri == "/game/mai2/rival.show":
|
||||
rival_id = frm.get("rivalUserId")
|
||||
show = frm.get("showRival", "false") == "true"
|
||||
await self.data.profile.set_rival_shown(usr_sesh.user_id, rival_id, show)
|
||||
return RedirectResponse("/game/mai2/", 303)
|
@ -1,7 +1,8 @@
|
||||
from collections.abc import Iterable
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from sqlalchemy import Column, Table, UniqueConstraint, and_, or_
|
||||
from sqlalchemy import Column, Table, UniqueConstraint, and_, or_, not_
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
from sqlalchemy.engine import Row
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
@ -550,25 +551,36 @@ class Mai2ItemData(BaseData):
|
||||
if result:
|
||||
return result.fetchall()
|
||||
|
||||
async def add_fav_music(self, user_id: int, music_id: int, order_id: Optional[int] = None) -> Optional[int]:
|
||||
sql = insert(fav_music).values(
|
||||
user = user_id,
|
||||
musicId = music_id,
|
||||
orderId = order_id
|
||||
)
|
||||
async def put_fav_music(self, user_id: int, fav_list: Iterable[tuple[int, Optional[int]]]) -> Optional[int]:
|
||||
row_count = 0
|
||||
processed_music_ids = []
|
||||
|
||||
for music_id, order_id in fav_list:
|
||||
sql = insert(fav_music).values(
|
||||
user = user_id,
|
||||
musicId = music_id,
|
||||
orderId = order_id
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(orderId = order_id)
|
||||
result = await self.execute(conflict)
|
||||
|
||||
processed_music_ids.append(music_id)
|
||||
|
||||
if not result:
|
||||
self.logger.error(f"Failed to add music {music_id} as favorite for user {user_id}!")
|
||||
continue
|
||||
|
||||
row_count += result.rowcount
|
||||
|
||||
clear_stale_entries_stmt = fav_music.delete(and_(fav_music.c.user == user_id, not_(fav_music.c.musicId.in_(processed_music_ids))))
|
||||
result = await self.execute(clear_stale_entries_stmt)
|
||||
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to clear stale favorite music entries for user {user_id}!")
|
||||
return None
|
||||
|
||||
conflict = sql.on_duplicate_key_update(orderId = order_id)
|
||||
|
||||
result = await self.execute(conflict)
|
||||
if result:
|
||||
return result.lastrowid
|
||||
|
||||
self.logger.error(f"Failed to add music {music_id} as favorite for user {user_id}!")
|
||||
|
||||
async def remove_fav_music(self, user_id: int, music_id: int) -> None:
|
||||
result = await self.execute(fav_music.delete(and_(fav_music.c.user == user_id, fav_music.c.musicId == music_id)))
|
||||
if not result:
|
||||
self.logger.error(f"Failed to remove music {music_id} as favorite for user {user_id}!")
|
||||
return row_count + result.rowcount
|
||||
|
||||
async def put_card(
|
||||
self,
|
||||
|
@ -254,7 +254,7 @@ class Mai2StaticData(BaseData):
|
||||
|
||||
async def put_card(self, version: int, card_id: int, card_name: str, opt_id: int = None, **card_data) -> int:
|
||||
sql = insert(cards).values(
|
||||
version=version, cardId=card_id, cardName=card_name, opt=coalesce(cards.c.opt, opt_id) **card_data
|
||||
version=version, cardId=card_id, cardName=card_name, opt=coalesce(cards.c.opt, opt_id), **card_data
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(opt=coalesce(cards.c.opt, opt_id), **card_data)
|
||||
|
@ -17,6 +17,10 @@
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#name_change">Edit</button>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ID:</th>
|
||||
<th>{{ profile.user }}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>version:</td>
|
||||
<td>
|
||||
@ -86,6 +90,40 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-8 m-auto mt-3">
|
||||
<div class="card bg-card rounded">
|
||||
<table class="table-large table-rowdistinct">
|
||||
<caption align="top">
|
||||
RIVALS
|
||||
<button type="button" class="btn btn-primary btn-sm" style="position: absolute; right: 15px;" data-bs-toggle="modal" data-bs-target="#rival_add">Add</button>
|
||||
</caption>
|
||||
<tr>
|
||||
<th scope="col">Id</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Rating</th>
|
||||
<th scope="col">Show</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
{% for rival in rival_list %}
|
||||
<tr>
|
||||
<td>{{ rival.2 }}</td>
|
||||
<td>{{ rival.0 }}</td>
|
||||
<td>{{ rival.1 }}</td>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
id="rivalSwitch_{{ rival.2 }}"
|
||||
{% if rival.3 %}checked{% endif %}
|
||||
onchange="submitShow('{{ rival.2 }}', this.checked)">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#rival_delete_{{ rival.2 }}">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if error is defined %}
|
||||
@ -120,6 +158,75 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="rival_add" tabindex="-1" aria-labelledby="card_add_label" data-bs-theme="dark" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add rival</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="rival" action="/game/mai2/rival.add" method="post" style="outline: 0;">
|
||||
<label class="form-label" for="rivalUserId">Rival ID</label>
|
||||
<input class="form-control" aria-describedby="rivalIdHelphelp" form="rival" id="rivalUserId" name="rivalUserId" maxlength="8" type="number" required>
|
||||
<div id="rivalIdHelphelp" class="form-text">Please use the ID show next to your name in the profile page.</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type=submit class="btn btn-primary" type="button" form="rival" value="Add">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% for rival in rival_list %}
|
||||
<div class="modal fade" id="rival_delete_{{ rival.2 }}" tabindex="-1" aria-labelledby="rival_delete_label" data-bs-theme="dark" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Delete rival</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="rival_delete_{{ rival.2 }}_form" action="/game/mai2/rival.delete" method="post" style="outline: 0;">
|
||||
<p>Are you sure you want to delete rival {{ rival.0 }}?</p>
|
||||
<input type="hidden" name="rivalUserId" value="{{ rival.2 }}">
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="submit" class="btn btn-danger" form="rival_delete_{{ rival.2 }}_form" value="Delete">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for rival in rival_list %}
|
||||
<div class="modal fade" id="rival_show_{{ rival.2 }}" tabindex="-1" aria-labelledby="rival_show_label" data-bs-theme="dark" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% if rival.3 %}Hide{% else %}Show{% endif %} rival</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="rival_show_{{ rival.2 }}_form" action="/game/mai2/rival.show" method="post" style="outline: 0;">
|
||||
<p>Are you sure you want to {% if rival.3 %}hide{% else %}show{% endif %} rival {{ rival.0 }}?</p>
|
||||
<input type="hidden" name="rivalUserId" value="{{ rival.2 }}">
|
||||
<input type="hidden" name="showRival" value="{{ "false" if rival.3 else "true" }}">
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="submit" class="btn btn-primary" form="rival_show_{{ rival.2 }}_form" value="Confirm">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for rival in rival_list %}
|
||||
<form action="/game/mai2/rival.show" method="post" id="rival_show_{{ rival.2 }}_form" style="display: none;">
|
||||
<input type="hidden" name="rivalUserId" value="{{ rival.2 }}">
|
||||
<input type="hidden" name="showRival" id="showRival_{{ rival.2 }}" value="false">
|
||||
</form>
|
||||
{% endfor %}
|
||||
<script>
|
||||
function changeVersion(sel) {
|
||||
$.post("/game/mai2/version.change", { version: sel.value })
|
||||
@ -130,5 +237,17 @@
|
||||
alert("Failed to update version.");
|
||||
});
|
||||
}
|
||||
function submitShow(rivalId, checked) {
|
||||
if (checked) {
|
||||
let shownCount = document.querySelectorAll('.form-check-input:checked').length;
|
||||
if (shownCount > 3) {
|
||||
document.getElementById('rivalSwitch_' + rivalId).checked = false;
|
||||
alert('Show rival limit reached (max 3). Please unselect another rival first.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
document.getElementById('showRival_' + rivalId).value = checked;
|
||||
document.getElementById('rival_show_' + rivalId + '_form').submit();
|
||||
}
|
||||
</script>
|
||||
{% endblock content %}
|
Reference in New Issue
Block a user