mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-05 02:57:59 +08:00
Compare commits
23 Commits
drop-the-c
...
v1-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6776353556 | ||
|
|
3b19257ab1 | ||
|
|
a0cd7456ee | ||
|
|
aeafa6a396 | ||
|
|
448426a96d | ||
|
|
dfa6176689 | ||
|
|
d996fba291 | ||
|
|
0cb2a95ff3 | ||
|
|
be5220fd51 | ||
|
|
f23c0d6fe1 | ||
|
|
5aca650602 | ||
|
|
7c72348016 | ||
|
|
5eee6505f9 | ||
|
|
43b7ea65a5 | ||
|
|
85149dcd03 | ||
|
|
a767c8949c | ||
|
|
bbeb476a62 | ||
|
|
c444350cef | ||
|
|
13a318d519 | ||
|
|
e744d96c96 | ||
|
|
491044d37a | ||
|
|
9d30cf1e7d | ||
|
|
d2608472d8 |
25
.gitlab-ci.yml
Normal file
25
.gitlab-ci.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
image: gradle:alpine
|
||||
|
||||
before_script:
|
||||
- GRADLE_USER_HOME="$(pwd)/.gradle"
|
||||
- export GRADLE_USER_HOME
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script: gradle --build-cache assemble
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_NAME"
|
||||
policy: push
|
||||
paths:
|
||||
- build
|
||||
- .gradle
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script: gradle check
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_NAME"
|
||||
policy: pull
|
||||
paths:
|
||||
- build
|
||||
- .gradle
|
||||
@@ -1,32 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let username: string;
|
||||
export let email: string;
|
||||
|
||||
let shouldShow = navigator.language.startsWith('zh');
|
||||
|
||||
// 会导致瞬间出现,但是不知道为什么 svelte 的 transition 动画不工作
|
||||
// if (!shouldShow) {
|
||||
// fetch('https://47.122.72.135/ip/isChina')
|
||||
// .then(it => it.json())
|
||||
// .then(it => shouldShow = it)
|
||||
// .catch(() => shouldShow = false);
|
||||
// }
|
||||
|
||||
const jump = () => {
|
||||
const params = new URLSearchParams();
|
||||
if (username) params.set('username', username);
|
||||
if (email) params.set('email', email);
|
||||
location.href = `https://portal.mumur.net/register?${params.toString()}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if shouldShow}
|
||||
<div class="cursor-pointer" on:click={jump}>
|
||||
<h2>MuNET 了解一下!</h2>
|
||||
<div>
|
||||
<p>MuNET 是 AquaDX 的继任者,提供更适合中国用户的服务器和更好的游戏体验。</p>
|
||||
<p>如果你还没有游戏数据,建议在 MuNET 上创建账号并开始游戏。点击立即前往</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
60
AquaNet/src/components/Pagination.svelte
Normal file
60
AquaNet/src/components/Pagination.svelte
Normal file
@@ -0,0 +1,60 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let page: number
|
||||
export let totalPages: number
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let editing = false
|
||||
let inputPage: number
|
||||
|
||||
function updatePage(newPage: number) {
|
||||
if (newPage > 0 && newPage <= totalPages) dispatch('updatePage', newPage)
|
||||
}
|
||||
|
||||
function startEditing() {
|
||||
inputPage = page
|
||||
editing = true
|
||||
}
|
||||
|
||||
function finishEditing() {
|
||||
editing = false
|
||||
if (inputPage !== page) updatePage(inputPage)
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') finishEditing()
|
||||
else if (event.key === 'Escape') editing = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="pagination">
|
||||
<button on:click={() => updatePage(page - 1)} disabled={page <= 1}>Previous</button>
|
||||
|
||||
{#if editing}
|
||||
<input bind:value={inputPage} on:blur={finishEditing} on:keydown={handleKeydown} min="1" max={totalPages} autofocus/>
|
||||
{:else}
|
||||
<span on:click={startEditing} role="button" tabindex="0" on:keydown={(e) => e.key === 'Enter' && startEditing()}>
|
||||
Page {page} of {totalPages}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<button on:click={() => updatePage(page + 1)} disabled={page >= totalPages}>Next</button>
|
||||
</div>
|
||||
|
||||
<style lang="sass">
|
||||
.pagination
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
margin: 1rem 0
|
||||
gap: 1rem
|
||||
|
||||
input
|
||||
width: 100px
|
||||
text-align: center
|
||||
|
||||
span[role="button"]
|
||||
cursor: pointer
|
||||
</style>
|
||||
@@ -1,7 +1,6 @@
|
||||
<script>
|
||||
import { fade } from "svelte/transition";
|
||||
import { FADE_IN, FADE_OUT } from "../../libs/config";
|
||||
import GameSettingFields from "./GameSettingFields.svelte";
|
||||
import { t, ts } from "../../libs/i18n";
|
||||
import useLocalStorage from "../../libs/hooks/useLocalStorage.svelte";
|
||||
import RegionSelector from "./RegionSelector.svelte";
|
||||
@@ -11,9 +10,8 @@
|
||||
|
||||
<div out:fade={FADE_OUT} in:fade={FADE_IN} class="fields">
|
||||
<blockquote>
|
||||
{ts("settings.gameNotice")}
|
||||
{ts("settings.siteNotice")}
|
||||
</blockquote>
|
||||
<GameSettingFields game="general"/>
|
||||
<div class="field">
|
||||
<div class="bool">
|
||||
<input id="rounding" type="checkbox" bind:checked={rounding.value}/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { slide, fade } from "svelte/transition";
|
||||
import { FADE_IN, FADE_OUT } from "../../libs/config";
|
||||
import { FADE_IN, FADE_OUT, DATA_HOST } from "../../libs/config";
|
||||
import { t } from "../../libs/i18n.js";
|
||||
import Icon from "@iconify/svelte";
|
||||
import StatusOverlays from "../StatusOverlays.svelte";
|
||||
@@ -35,6 +35,169 @@
|
||||
break
|
||||
}
|
||||
}
|
||||
async function exportBatchManual() {
|
||||
submitting = "batchExport"
|
||||
const DIFFICULTY_MAP: Record<number, string> = {
|
||||
0: "Basic",
|
||||
1: "Advanced",
|
||||
2: "Expert",
|
||||
3: "Master",
|
||||
4: "Re:Master"
|
||||
}
|
||||
|
||||
const DAN_MAP: Record<number, string> = {
|
||||
1: "DAN_1",
|
||||
2: "DAN_2",
|
||||
3: "DAN_3",
|
||||
4: "DAN_4",
|
||||
5: "DAN_5",
|
||||
6: "DAN_6",
|
||||
7: "DAN_7",
|
||||
8: "DAN_8",
|
||||
9: "DAN_9",
|
||||
10: "DAN_10",
|
||||
11: "SHINDAN_1",
|
||||
12: "SHINDAN_2",
|
||||
13: "SHINDAN_3",
|
||||
14: "SHINDAN_4",
|
||||
15: "SHINDAN_5",
|
||||
16: "SHINDAN_6",
|
||||
17: "SHINDAN_7",
|
||||
18: "SHINDAN_8",
|
||||
19: "SHINDAN_9",
|
||||
20: "SHINDAN_10",
|
||||
21: "SHINKAIDEN",
|
||||
22: "URAKAIDEN"
|
||||
}
|
||||
|
||||
const CLASS_MAP: Record<number, string> = {
|
||||
0: "B5",
|
||||
1: "B4",
|
||||
2: "B3",
|
||||
3: "B2",
|
||||
4: "B1",
|
||||
5: "A5",
|
||||
6: "A4",
|
||||
7: "A3",
|
||||
8: "A2",
|
||||
9: "A1",
|
||||
10: "S5",
|
||||
11: "S4",
|
||||
12: "S3",
|
||||
13: "S2",
|
||||
14: "S1",
|
||||
15: "SS5",
|
||||
16: "SS4",
|
||||
17: "SS3",
|
||||
18: "SS2",
|
||||
19: "SS1",
|
||||
20: "SSS5",
|
||||
21: "SSS4",
|
||||
22: "SSS3",
|
||||
23: "SSS2",
|
||||
24: "SSS1",
|
||||
25: "LEGEND"
|
||||
}
|
||||
|
||||
let data: any
|
||||
let musicData: any
|
||||
let output: any = {
|
||||
"meta": {
|
||||
"game": "maimaidx",
|
||||
"playtype": "Single",
|
||||
"service": "AquaDX-Manual"
|
||||
},
|
||||
"scores": [],
|
||||
"classes": {}
|
||||
}
|
||||
try {
|
||||
musicData = await fetch(`${DATA_HOST}/d/mai2/00/all-music.json`).then(res => res.json())
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
submitting = ""
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data = await GAME.export('mai2');
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
submitting = ""
|
||||
return;
|
||||
}
|
||||
if (data && "userPlaylogList" in data) {
|
||||
for (let score of data.userPlaylogList) {
|
||||
if(score.musicId > 100000){
|
||||
continue; // UTAGE charts are not supported
|
||||
}
|
||||
const musicItem = musicData[score.musicId as string];
|
||||
if (!musicItem) continue;
|
||||
let difficulty = null;
|
||||
|
||||
if (!(score.level in DIFFICULTY_MAP))
|
||||
continue;
|
||||
|
||||
const isDX = score.musicId >= 10000;
|
||||
difficulty = isDX ? `DX ${DIFFICULTY_MAP[score.level]}` : DIFFICULTY_MAP[score.level];
|
||||
|
||||
const percent = score.achievement/10000;
|
||||
|
||||
const pcrit = score.tapCriticalPerfect + score.holdCriticalPerfect + score.slideCriticalPerfect + score.touchCriticalPerfect + score.breakCriticalPerfect;
|
||||
const perfect = score.tapPerfect + score.holdPerfect + score.slidePerfect + score.touchPerfect + score.breakPerfect;
|
||||
const great = score.tapGreat + score.holdGreat + score.slideGreat + score.touchGreat + score.breakGreat;
|
||||
const good = score.tapGood + score.holdGood + score.slideGood + score.touchGood + score.breakGood;
|
||||
const miss = score.tapMiss + score.holdMiss + score.slideMiss + score.touchMiss + score.breakMiss;
|
||||
const judgements = {
|
||||
"pcrit": pcrit,
|
||||
"perfect": perfect,
|
||||
"great": great,
|
||||
"good": good,
|
||||
"miss": miss
|
||||
}
|
||||
let lamp = null;
|
||||
if (score.isAllPerfect) {
|
||||
lamp = "ALL PERFECT";
|
||||
if (score.percent == 101.0) {
|
||||
lamp = "ALL PERFECT+";
|
||||
}
|
||||
} else if (score.isFullCombo) {
|
||||
lamp = "FULL COMBO";
|
||||
if (good == 0 && great == 0) {
|
||||
lamp = "FULL COMBO+";
|
||||
}
|
||||
} else if (score.isClear) {
|
||||
lamp = "CLEAR";
|
||||
} else {
|
||||
lamp = "FAILED";
|
||||
}
|
||||
|
||||
const optional = {
|
||||
"fast": score.fastCount,
|
||||
"slow": score.lateCount,
|
||||
"maxCombo": score.maxCombo
|
||||
}
|
||||
|
||||
output.scores.push({
|
||||
"percent": percent,
|
||||
"lamp": lamp,
|
||||
"matchType": "inGameID",
|
||||
"identifier": score.musicId.toString(),
|
||||
"difficulty": difficulty,
|
||||
"timeAchieved": new Date(score.userPlayDate).getTime(),
|
||||
"judgements": judgements,
|
||||
"optional": optional
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if(data.userData.courseRank in DAN_MAP){
|
||||
output.classes["dan"] = DAN_MAP[data.userData.courseRank]
|
||||
}
|
||||
if(data.userData.classRank in CLASS_MAP){
|
||||
output.classes["matchingClass"] = CLASS_MAP[data.userData.classRank]
|
||||
}
|
||||
download(JSON.stringify(output), `AquaDX_maimai2_BatchManualExport_${values[0]}.json`)
|
||||
submitting = ""
|
||||
}
|
||||
|
||||
function exportData() {
|
||||
submitting = "export"
|
||||
@@ -70,6 +233,10 @@
|
||||
<Icon icon="bxs:file-export"/>
|
||||
{t('settings.export')}
|
||||
</button>
|
||||
<button class="exportBatchManualButton" on:click={exportBatchManual}>
|
||||
<Icon icon="bxs:file-export"/>
|
||||
{t('settings.batchManualExport')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<StatusOverlays {error} loading={!values[0] || !!submitting}/>
|
||||
|
||||
@@ -144,23 +144,35 @@ export const EN_REF_HOME = {
|
||||
export const EN_REF_SETTINGS = {
|
||||
'settings.title': 'Settings',
|
||||
'settings.tabs.profile': 'Profile',
|
||||
'settings.tabs.game': 'Game',
|
||||
'settings.tabs.global': 'Global',
|
||||
'settings.tabs.chu3': 'Chuni',
|
||||
'settings.tabs.mai2': 'Mai',
|
||||
'settings.tabs.ongeki': 'Ongeki',
|
||||
'settings.tabs.wacca': 'Wacca',
|
||||
'settings.fields.unlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.unlockMusic.desc': 'Unlock all music and master difficulty in game.',
|
||||
'settings.fields.unlockChara.name': 'Unlock All Characters',
|
||||
'settings.fields.unlockChara.desc': 'Unlock all characters, voices, and partners in game.',
|
||||
'settings.fields.unlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.unlockCollectables.desc': 'Unlock all collectables (nameplate, title, icon, frame) in game.',
|
||||
'settings.fields.unlockTickets.name': 'Unlock All Tickets',
|
||||
'settings.fields.unlockTickets.desc': 'Infinite map/ex tickets (Note: maimai still limits which tickets can be used).',
|
||||
'settings.fields.waccaInfiniteWp.name': 'Wacca: Infinite WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': 'Set WP to 999999',
|
||||
'settings.fields.waccaAlwaysVip.name': 'Wacca: Always VIP',
|
||||
'settings.fields.waccaAlwaysVip.desc': 'Set VIP expiration date to 2077-01-01',
|
||||
'settings.fields.mai2UnlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.mai2UnlockMusic.desc': 'Unlock all music and master difficulty.',
|
||||
'settings.fields.mai2UnlockChara.name': 'Unlock All Characters',
|
||||
'settings.fields.mai2UnlockChara.desc': 'Unlock all characters (new characters start at level 1).',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.name': 'Max Character Level',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.desc': 'Set all characters to max level.',
|
||||
'settings.fields.mai2UnlockPartners.name': 'Unlock All Partners',
|
||||
'settings.fields.mai2UnlockPartners.desc': 'Unlock all partners.',
|
||||
'settings.fields.mai2UnlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.mai2UnlockCollectables.desc': 'Unlock all collectables (nameplate, title, icon, frame).',
|
||||
'settings.fields.mai2UnlockTickets.name': 'Unlock All Tickets',
|
||||
'settings.fields.mai2UnlockTickets.desc': 'Infinite tickets (Note: client still limits which tickets can be used).',
|
||||
'settings.fields.waccaUnlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.waccaUnlockMusic.desc': 'Unlock all music.',
|
||||
'settings.fields.waccaUnlockPlates.name': 'Unlock All Plates',
|
||||
'settings.fields.waccaUnlockPlates.desc': 'Unlock all plates.',
|
||||
'settings.fields.waccaUnlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.waccaUnlockCollectables.desc': 'Unlock all collectables (icon, trophy).',
|
||||
'settings.fields.waccaUnlockTickets.name': 'Infinite Tickets',
|
||||
'settings.fields.waccaUnlockTickets.desc': 'Infinite tickets.',
|
||||
'settings.fields.waccaInfiniteWp.name': 'Infinite WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': 'Set WP to 999999.',
|
||||
'settings.fields.waccaAlwaysVip.name': 'Always VIP',
|
||||
'settings.fields.waccaAlwaysVip.desc': 'Set VIP expiration date to 2077-01-01.',
|
||||
'settings.fields.chusanTeamName.name': 'Team Name',
|
||||
'settings.fields.chusanTeamName.desc': 'Customize the text displayed on the top of your profile.',
|
||||
'settings.fields.chusanInfinitePenguins.name': 'Infinite Penguins',
|
||||
@@ -196,10 +208,10 @@ export const EN_REF_SETTINGS = {
|
||||
'settings.export': 'Export Player Data',
|
||||
'settings.batchManualExport': "Export in Batch Manual (for Tachi)",
|
||||
'settings.cabNotice': "Note: These settings will only affect your own cab/setup. If you're playing on someone else's setup, please contact them to change these settings.",
|
||||
'settings.gameNotice': "These only apply to Mai and Wacca.",
|
||||
'settings.regionNotice': "These only apply to Mai, Ongeki and Chuni.",
|
||||
'settings.siteNotice': "These settings only apply to the website.",
|
||||
'settings.regionNotice': "These settings are shared amongst Mai, Ongeki and Chuni.",
|
||||
'settings.regionSelector.title': "Prefecture Selector",
|
||||
'settings.regionSelector.desc': "Select the region where you want the game to think you are playing",
|
||||
'settings.regionSelector.desc': "Select the region where you want the game to identify you",
|
||||
'settings.regionSelector.select': "Select Prefecture",
|
||||
}
|
||||
|
||||
|
||||
@@ -156,23 +156,35 @@ const zhHome: typeof EN_REF_HOME = {
|
||||
const zhSettings: typeof EN_REF_SETTINGS = {
|
||||
'settings.title': '用户设置',
|
||||
'settings.tabs.profile': '个人资料',
|
||||
'settings.tabs.game': '游戏设置',
|
||||
'settings.tabs.global': '全局',
|
||||
'settings.tabs.chu3': '中二',
|
||||
'settings.tabs.mai2': '舞萌',
|
||||
'settings.tabs.ongeki': '音击',
|
||||
'settings.tabs.wacca': '华卡',
|
||||
'settings.fields.unlockMusic.name': '解锁谱面',
|
||||
'settings.fields.unlockMusic.desc': '在游戏中解锁所有曲目和大师难度谱面。',
|
||||
'settings.fields.unlockChara.name': '解锁角色',
|
||||
'settings.fields.unlockChara.desc': '在游戏中解锁所有角色、语音和伙伴。',
|
||||
'settings.fields.unlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.unlockCollectables.desc': '在游戏中解锁所有收藏品(名牌、称号、图标、背景图)。',
|
||||
'settings.fields.unlockTickets.name': '解锁游戏券',
|
||||
'settings.fields.unlockTickets.desc': '无限跑图券/解锁券(注:maimai 客户端仍限制一些券不能使用)。',
|
||||
'settings.fields.waccaInfiniteWp.name': '华卡:无限 WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': '将 WP 设置为 999999',
|
||||
'settings.fields.waccaAlwaysVip.name': '华卡:永久会员',
|
||||
'settings.fields.waccaAlwaysVip.desc': '将 VIP 到期时间设置为 2077-01-01',
|
||||
'settings.fields.mai2UnlockMusic.name': '解锁谱面',
|
||||
'settings.fields.mai2UnlockMusic.desc': '解锁所有曲目和大师难度谱面。',
|
||||
'settings.fields.mai2UnlockChara.name': '解锁角色',
|
||||
'settings.fields.mai2UnlockChara.desc': '解锁所有角色(新角色从 1 级开始)。',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.name': '角色满级',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.desc': '将所有角色设置为满级。',
|
||||
'settings.fields.mai2UnlockPartners.name': '解锁搭档',
|
||||
'settings.fields.mai2UnlockPartners.desc': '解锁所有搭档。',
|
||||
'settings.fields.mai2UnlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.mai2UnlockCollectables.desc': '解锁所有收藏品(姓名框、称号、头像、背景)。',
|
||||
'settings.fields.mai2UnlockTickets.name': '解锁功能票',
|
||||
'settings.fields.mai2UnlockTickets.desc': '无限功能票(注:客户端仍限制一些功能票不能使用)。',
|
||||
'settings.fields.waccaUnlockMusic.name': '解锁谱面',
|
||||
'settings.fields.waccaUnlockMusic.desc': '解锁所有曲目。',
|
||||
'settings.fields.waccaUnlockPlates.name': '解锁铭牌',
|
||||
'settings.fields.waccaUnlockPlates.desc': '解锁所有铭牌。',
|
||||
'settings.fields.waccaUnlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.waccaUnlockCollectables.desc': '解锁所有收藏品。',
|
||||
'settings.fields.waccaUnlockTickets.name': '无限解锁券',
|
||||
'settings.fields.waccaUnlockTickets.desc': '无限解锁券。',
|
||||
'settings.fields.waccaInfiniteWp.name': '无限 WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': '将 WP 设置为 999999。',
|
||||
'settings.fields.waccaAlwaysVip.name': '永久会员',
|
||||
'settings.fields.waccaAlwaysVip.desc': '将 VIP 到期时间设置为 2077-01-01。',
|
||||
'settings.fields.chusanTeamName.name': '队伍名称',
|
||||
'settings.fields.chusanTeamName.desc': '自定义显示在个人资料顶部的文本。',
|
||||
'settings.fields.chusanInfinitePenguins.name': '我是桐谷遥',
|
||||
@@ -208,9 +220,10 @@ const zhSettings: typeof EN_REF_SETTINGS = {
|
||||
'settings.export': '导出玩家数据',
|
||||
'settings.batchManualExport': "导出 Batch Manual 格式(用于 Tachi)",
|
||||
'settings.cabNotice': '注意:下面这些设置只会影响你自己的机器,如果你是在其他人的机器上玩的话,请联系机主来改设置',
|
||||
'settings.gameNotice': "这些设置仅对舞萌和华卡生效。",
|
||||
// AI
|
||||
'settings.regionNotice': "这些设置仅适用于舞萌、音击和中二。",
|
||||
'settings.siteNotice': "这些设置仅适用于网站。",
|
||||
// AI
|
||||
'settings.regionNotice': "这些设置在舞萌、音击和中二节奏之间共享。",
|
||||
// AI
|
||||
'settings.regionSelector.title': "地区选择器",
|
||||
// AI
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
import { t } from "../libs/i18n";
|
||||
import ImportDataAction from "./Home/ImportDataAction.svelte";
|
||||
import Communities from "./Home/Communities.svelte";
|
||||
import MigrateAction from "./Home/MigrateAction.svelte";
|
||||
|
||||
USER.ensureLoggedIn();
|
||||
|
||||
@@ -59,9 +58,6 @@
|
||||
</ActionCard>
|
||||
|
||||
<ImportDataAction/>
|
||||
{#if me}
|
||||
<MigrateAction username={me.username}/>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if tab === 1}
|
||||
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { fade } from "svelte/transition"
|
||||
import { t } from "../../libs/i18n";
|
||||
import ActionCard from "../../components/ActionCard.svelte";
|
||||
import { CARD, GAME, USER } from "../../libs/sdk";
|
||||
|
||||
export let username: string;
|
||||
let shouldShow = navigator.language.startsWith('zh');
|
||||
let showWarning = false;
|
||||
let isCardBindIssue = false;
|
||||
|
||||
if (!shouldShow) {
|
||||
fetch('https://47.122.72.135/ip/isChina')
|
||||
.then(it => it.json())
|
||||
.then(it => shouldShow = it)
|
||||
.catch(() => shouldShow = false);
|
||||
}
|
||||
|
||||
CARD.userGames(username).then(games => {
|
||||
if (!Object.values(games).some(it => it)) {
|
||||
isCardBindIssue = true;
|
||||
}
|
||||
})
|
||||
|
||||
const handleClick = () => {
|
||||
if (isCardBindIssue) {
|
||||
showWarning = true;
|
||||
return
|
||||
}
|
||||
jump()
|
||||
}
|
||||
|
||||
const jump = () => {
|
||||
const token = localStorage.getItem('token')
|
||||
location.href = `https://portal.mumur.net/migrateFromAquaDx/${token}`
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if shouldShow}
|
||||
<ActionCard color="190, 149, 255" icon="system-uicons:jump-up" on:click={handleClick}>
|
||||
<h3>迁移到 MuNET</h3>
|
||||
<span>更适合中国宝宝体质的服务器,AquaDX 的继任者。点击查看详情</span>
|
||||
</ActionCard>
|
||||
{/if}
|
||||
|
||||
{#if showWarning}
|
||||
<div class="overlay" transition:fade>
|
||||
<div>
|
||||
<h2>提示</h2>
|
||||
<p>看起来你在 AquaDX 还没有游戏数据,也许是因为没有绑卡或者绑定的卡不是在游戏中点击“查看卡号”获取的…</p>
|
||||
<p>现在迁移的话,大概会导致你的游戏数据无法被正确的迁移。建议你先去检查一下吧</p>
|
||||
<div class="buttons">
|
||||
<button on:click={() => showWarning = false}>{t('action.cancel')}</button>
|
||||
<button on:click={jump}>继续</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="sass">
|
||||
h3
|
||||
font-size: 1.3rem
|
||||
margin: 0
|
||||
|
||||
.buttons
|
||||
display: grid
|
||||
grid-template-columns: 1fr 1fr
|
||||
gap: 1rem
|
||||
</style>
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { title } from "../libs/ui";
|
||||
import { GAME } from "../libs/sdk";
|
||||
import type { GenericRanking } from "../libs/generalTypes";
|
||||
@@ -8,6 +9,7 @@
|
||||
import { t } from "../libs/i18n";
|
||||
import UserCard from "../components/UserCard.svelte";
|
||||
import Tooltip from "../components/Tooltip.svelte";
|
||||
import Pagination from "../components/Pagination.svelte";
|
||||
|
||||
export let game: GameName = 'mai2';
|
||||
|
||||
@@ -15,15 +17,45 @@
|
||||
|
||||
let d: { users: GenericRanking[] };
|
||||
let error: string | null;
|
||||
|
||||
let page = 1
|
||||
const perPage = 50
|
||||
let totalPages = 1
|
||||
|
||||
function handleUpdatePage(event: CustomEvent<number>) {
|
||||
page = event.detail;
|
||||
const url = new URL(window.location.toString())
|
||||
url.searchParams.set('page', page.toString())
|
||||
history.pushState({}, '', url.toString())
|
||||
window.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const url = new URL(window.location.toString())
|
||||
const pageParam = url.searchParams.get('page')
|
||||
if (pageParam) {
|
||||
page = parseInt(pageParam, 10) || 1
|
||||
}
|
||||
|
||||
window.addEventListener('popstate', () => {
|
||||
const url = new URL(window.location.toString())
|
||||
const pageParam = url.searchParams.get('page')
|
||||
page = parseInt(pageParam, 10) || 1
|
||||
window.scrollTo(0, 0)
|
||||
})
|
||||
})
|
||||
|
||||
Promise.all([GAME.ranking(game)])
|
||||
.then(([users]) => {
|
||||
console.log(users)
|
||||
d = { users };
|
||||
d = { users }
|
||||
totalPages = Math.ceil(users.length / perPage)
|
||||
})
|
||||
.catch((e) => error = e.message);
|
||||
|
||||
let hoveringUser = "";
|
||||
let hoverLoading = false;
|
||||
|
||||
$: paginatedUsers = d ? d.users.slice((page - 1) * perPage, page * perPage) : []
|
||||
</script>
|
||||
|
||||
<main class="content leaderboard">
|
||||
@@ -37,8 +69,12 @@
|
||||
</div>
|
||||
|
||||
{#if d}
|
||||
{#if page > 1}
|
||||
<Pagination {page} {totalPages} on:updatePage={handleUpdatePage} />
|
||||
{/if}
|
||||
|
||||
<div class="leaderboard-container">
|
||||
<div class="lb-user" on:mouseenter={() => hoveringUser = d.users[0].username} role="heading" aria-level="2">
|
||||
<div class="lb-user" on:mouseenter={() => hoveringUser = paginatedUsers[0]?.username} role="heading" aria-level="2">
|
||||
<span class="rank">{t("Leaderboard.Rank")}</span>
|
||||
<span class="name"></span>
|
||||
<span class="rating">{t("Leaderboard.Rating")}</span>
|
||||
@@ -46,7 +82,7 @@
|
||||
<span class="fc">{t("Leaderboard.FC")}</span>
|
||||
<span class="ap">{t("Leaderboard.AP")}</span>
|
||||
</div>
|
||||
{#each d.users as user, i (user.rank)}
|
||||
{#each paginatedUsers as user, i (user.rank)}
|
||||
<div class="lb-user" class:alternate={i % 2 === 1} role="listitem"
|
||||
on:mouseover={() => hoveringUser = user.username} on:focus={() => {}}>
|
||||
|
||||
@@ -70,6 +106,8 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<Pagination {page} {totalPages} on:updatePage={handleUpdatePage} />
|
||||
|
||||
<Tooltip triggeredBy=".name" loading={hoverLoading}>
|
||||
<UserCard username={hoveringUser} {game} setLoading={l => hoverLoading = l} />
|
||||
</Tooltip>
|
||||
@@ -132,5 +170,4 @@
|
||||
&.alternate
|
||||
background-color: vars.$ov-light
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
let error: string;
|
||||
let submitting = ""
|
||||
let tab = 0
|
||||
let tabs = [ 'profile', 'game' ]
|
||||
let tabs = ['profile']
|
||||
|
||||
const profileFields = [
|
||||
[ 'displayName', t('settings.profile.name') ],
|
||||
@@ -45,18 +45,11 @@
|
||||
me = m
|
||||
|
||||
CARD.userGames(m.username).then(games => {
|
||||
if (games.chu3 && !tabs.includes('chu3')) {
|
||||
tabs = [...tabs, 'chu3']
|
||||
}
|
||||
if (games.mai2 && !tabs.includes('mai2')) {
|
||||
tabs = [...tabs, 'mai2']
|
||||
}
|
||||
if (games.wacca && !tabs.includes('wacca')) {
|
||||
tabs = [...tabs, 'wacca']
|
||||
}
|
||||
if (games.ongeki && !tabs.includes('ongeki')) {
|
||||
tabs = [...tabs, 'ongeki']
|
||||
}
|
||||
tabs = [
|
||||
...tabs,
|
||||
...['chu3', 'mai2','wacca', 'ongeki'].filter(v => games[v as keyof typeof games]), // :xdx:
|
||||
'global'
|
||||
]
|
||||
})
|
||||
}).catch(e => error = e.message)
|
||||
getMe()
|
||||
@@ -217,7 +210,7 @@
|
||||
<WaccaSettings />
|
||||
{:else if tabs[tab] === 'ongeki'}
|
||||
<OngekiSettings />
|
||||
{:else if tabs[tab] === 'game'}
|
||||
{:else if tabs[tab] === 'global'}
|
||||
<GeneralGameSettings />
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import Icon from "@iconify/svelte";
|
||||
import { USER } from "../libs/sdk";
|
||||
import { t } from "../libs/i18n"
|
||||
import MunetRegisterBanner from "../components/MunetRegisterBanner.svelte";
|
||||
|
||||
let params = new URLSearchParams(window.location.search)
|
||||
|
||||
@@ -100,9 +99,6 @@
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-2")
|
||||
}
|
||||
else if (e.message === 'Login not allowed: Card has been migrated to Minato.') {
|
||||
location.href = `https://portal.mumur.net/login?username=${encodeURIComponent(email)}`
|
||||
}
|
||||
else {
|
||||
error = e.message
|
||||
submitting = false // unnecessary? see line 113, same for both reset functions
|
||||
@@ -162,7 +158,7 @@
|
||||
return submitting = false
|
||||
}
|
||||
|
||||
// Send request to server
|
||||
// Send request to server
|
||||
await USER.changePassword({ token, password })
|
||||
.then(() => {
|
||||
state = 'verify'
|
||||
@@ -221,9 +217,6 @@
|
||||
on:turnstile-expired={_ => window.location.reload()}
|
||||
on:turnstile-timeout={_ => console.log(error = t('welcome.turnstile-timeout'))} />
|
||||
{/if}
|
||||
{#if isSignup}
|
||||
<MunetRegisterBanner username={username} email={email}/>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if state === "submitreset"}
|
||||
<div class="login-form" transition:slide>
|
||||
@@ -264,7 +257,7 @@
|
||||
{#if error}
|
||||
<span class="error">{error}</span>
|
||||
{/if}
|
||||
<div class="login-form" transition:slide>
|
||||
<div class="login-form" transition:slide>
|
||||
<input type="password" placeholder={t('new-password')} bind:value={password}>
|
||||
<button on:click={changePassword}>
|
||||
{#if submitting}
|
||||
|
||||
@@ -7,12 +7,14 @@ plugins {
|
||||
val ktVer = "2.1.10"
|
||||
|
||||
java
|
||||
kotlin("plugin.lombok") version ktVer
|
||||
kotlin("jvm") version ktVer
|
||||
kotlin("plugin.spring") version ktVer
|
||||
kotlin("plugin.jpa") version ktVer
|
||||
kotlin("plugin.serialization") version ktVer
|
||||
kotlin("plugin.allopen") version ktVer
|
||||
kotlin("kapt") version ktVer
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
id("org.springframework.boot") version "3.2.3"
|
||||
id("com.github.ben-manes.versions") version "0.51.0"
|
||||
id("org.hibernate.orm") version "6.4.4.Final"
|
||||
|
||||
@@ -15,6 +15,7 @@ import kotlinx.coroutines.withContext
|
||||
import org.apache.tika.Tika
|
||||
import org.apache.tika.mime.MimeTypes
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity.BodyBuilder
|
||||
@@ -34,8 +35,10 @@ import java.util.concurrent.locks.Lock
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
|
||||
typealias RP = RequestParam
|
||||
@@ -80,7 +83,9 @@ annotation class SettingField(
|
||||
|
||||
// Reflection
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> KClass<T>.vars() = memberProperties.mapNotNull { it as? Var<T, Any> }
|
||||
fun <T : Any> KClass<T>.ownVars() = declaredMemberProperties.sortedBy { it.javaField?.declaringClass?.declaredFields?.indexOf(it.javaField) ?: Int.MAX_VALUE }.mapNotNull { it as? Var<T, Any> }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> KClass<T>.vars(): List<Var<T, Any>> = supertypes.mapNotNull { it.classifier as? KClass<*> }.filter { !it.java.isInterface }.flatMap{ it.vars() as List<Var<T, Any>> } + ownVars()
|
||||
fun <T : Any> KClass<T>.varsMap() = vars().associateBy { it.name }
|
||||
fun <T : Any> KClass<T>.getters() = java.methods.filter { it.name.startsWith("get") }
|
||||
fun <T : Any> KClass<T>.gettersMap() = getters().associateBy { it.name.removePrefix("get").firstCharLower() }
|
||||
@@ -212,8 +217,6 @@ val <K, V> Map<K, V>.mut get() = toMutableMap()
|
||||
val <T> Set<T>.mut get() = toMutableSet()
|
||||
|
||||
fun <T> List<T>.unique(fn: (T) -> Any) = distinctBy(fn).ifEmpty { null }
|
||||
val <T> Collection<T>.csv get() = joinToString(",")
|
||||
val IntArray.csv get() = joinToString(",")
|
||||
|
||||
// Optionals
|
||||
operator fun <T> Optional<T>.invoke(): T? = orElse(null)
|
||||
@@ -230,7 +233,6 @@ fun Str.fromChusanUsername() = String(this.toByteArray(StandardCharsets.ISO_8859
|
||||
fun Str.truncate(len: Int) = if (this.length > len) this.take(len) + "..." else this
|
||||
val Str.some get() = ifBlank { null }
|
||||
val ByteArray.hexStr get() = toHexString()
|
||||
operator fun StringBuilder.plusAssign(other: String) { this.append(other) }
|
||||
|
||||
// Coroutine
|
||||
suspend fun <T> async(block: suspend kotlinx.coroutines.CoroutineScope.() -> T): T = withContext(Dispatchers.IO) { block() }
|
||||
@@ -259,7 +261,6 @@ operator fun <E> List<E>.component13(): E = get(12)
|
||||
|
||||
inline operator fun <reified E> List<Any?>.invoke(i: Int) = get(i) as E
|
||||
val empty = emptyList<Any>()
|
||||
val emptyMap = emptyMap<Any, Any>()
|
||||
|
||||
val <F> Pair<F, *>.l get() = component1()
|
||||
val <S> Pair<*, S>.r get() = component2()
|
||||
@@ -268,3 +269,6 @@ val <S> Pair<*, S>.r get() = component2()
|
||||
val Query.exec get() = resultList.map { (it as Array<*>).toList() }
|
||||
fun List<List<Any?>>.numCsv(vararg head: Str) = head.joinToString(",") + "\n" +
|
||||
joinToString("\n") { it.joinToString(",") }
|
||||
|
||||
// DI
|
||||
inline fun <reified T> ApplicationContext.lazy() = lazy { getBean(T::class.java) }
|
||||
|
||||
@@ -21,15 +21,15 @@ val JSON_FUZZY_BOOLEAN = SimpleModule().addDeserializer(Boolean::class.java, obj
|
||||
else -> 400 - "Invalid boolean value ${parser.text}"
|
||||
}
|
||||
})
|
||||
val JSON_DATETIME = SimpleModule().addDeserializer(java.time.LocalDateTime::class.java, object : JsonDeserializer<java.time.LocalDateTime>() {
|
||||
val JSON_DATETIME = SimpleModule().addDeserializer(java.time.LocalDateTime::class.java, object : JsonDeserializer<LocalDateTime>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext) =
|
||||
// First try standard formats via asDateTime() method
|
||||
parser.text.asDateTime() ?: try {
|
||||
parser.text.takeIf { it.isNotEmpty() }?.run { asDateTime() ?: try {
|
||||
// Try maimai2 format (yyyy-MM-dd HH:mm:ss.0)
|
||||
LocalDateTime.parse(parser.text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0"))
|
||||
} catch (e: Exception) {
|
||||
400 - "Invalid date time value ${parser.text}"
|
||||
}
|
||||
} }
|
||||
})
|
||||
val JACKSON = jacksonObjectMapper().apply {
|
||||
setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
|
||||
@@ -4,7 +4,6 @@ import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.model.sensitiveInfo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
@@ -53,7 +52,7 @@ class BotController(
|
||||
secret.checkSecret()
|
||||
|
||||
// 1. Find user card
|
||||
val oc = (us.cardRepo.findByLuid(card) ?: (404 - "Card not found")).maybeGhost()
|
||||
val oc = (us.cardRepo.findByLuid(card)() ?: (404 - "Card not found")).maybeGhost()
|
||||
|
||||
// 2. Change the status to migrated
|
||||
us.cardRepo.save(oc.apply {
|
||||
@@ -67,7 +66,7 @@ class BotController(
|
||||
fun clearMigrateFlag(@RP secret: Str, @RP card: Str): Any {
|
||||
secret.checkSecret()
|
||||
|
||||
val oc = (us.cardRepo.findByLuid(card) ?: (404 - "Card not found")).maybeGhost()
|
||||
val oc = (us.cardRepo.findByLuid(card)() ?: (404 - "Card not found")).maybeGhost()
|
||||
|
||||
us.cardRepo.save(oc.apply {
|
||||
status = CardStatus.NORMAL
|
||||
@@ -83,14 +82,14 @@ class BotController(
|
||||
secret.checkSecret()
|
||||
|
||||
// 1. Check if the card exist
|
||||
var cards: MutableList<Card> = listOfNotNull(
|
||||
us.cardRepo.findByLuid(cardId),
|
||||
var cards = listOfNotNull(
|
||||
us.cardRepo.findByLuid(cardId)(),
|
||||
).mut
|
||||
|
||||
cardId.toLongOrNull()?.let {
|
||||
cards += listOfNotNull(
|
||||
us.cardRepo.findById(it)(),
|
||||
us.cardRepo.findByExtId(it),
|
||||
us.cardRepo.findByExtId(it)(),
|
||||
)
|
||||
|
||||
cards += listOfNotNull(
|
||||
@@ -111,8 +110,8 @@ class BotController(
|
||||
|
||||
return cards.map { card ->
|
||||
// Find all games played by this card
|
||||
val chu3 = chu3Db.userData.findByCard_ExtId(card.extId)
|
||||
val mai2 = mai2Db.userData.findByCard_ExtId(card.extId)
|
||||
val chu3 = chu3Db.userData.findByCard_ExtId(card.extId)()
|
||||
val mai2 = mai2Db.userData.findByCard_ExtId(card.extId)()
|
||||
val gamesDict = listOfNotNull(chu3, mai2).map {
|
||||
// Find the keychip owner
|
||||
val keychip = it.lastClientId
|
||||
|
||||
@@ -8,7 +8,6 @@ import icu.samnyan.aqua.net.games.IUserData
|
||||
import icu.samnyan.aqua.net.utils.AquaNetProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserDataRepo
|
||||
import icu.samnyan.aqua.sega.diva.PlayerProfileRepository
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
@@ -20,6 +19,7 @@ import org.springframework.scheduling.annotation.Scheduled
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.random.Random
|
||||
|
||||
@RestController
|
||||
@@ -101,8 +101,7 @@ class CardController(
|
||||
val games = migrate.split(',')
|
||||
cardGameService.migrate(card, games)
|
||||
|
||||
fedy.onCardLinked(card.luid, oldExtId = card.extId, ghostExtId = u.ghostCard.extId,
|
||||
games.map { Fedy.getGameName(it) }.filterNotNull())
|
||||
fedy.onCardLinked(card.luid, oldExtId = card.extId, ghostExtId = u.ghostCard.extId, games)
|
||||
|
||||
log.info("Net /card/link : Linked card ${card.id} to user ${u.username} and migrated data to ${games.joinToString()}")
|
||||
|
||||
@@ -204,10 +203,11 @@ class CardGameService(
|
||||
val chusan: Chu3UserDataRepo,
|
||||
val wacca: WcUserRepo,
|
||||
val ongeki: OgkUserDataRepo,
|
||||
val diva: PlayerProfileRepository,
|
||||
val diva: icu.samnyan.aqua.sega.diva.dao.userdata.PlayerProfileRepository,
|
||||
val safety: AquaNetSafetyService,
|
||||
val cardRepo: CardRepository,
|
||||
val em: EntityManager
|
||||
val em: EntityManager,
|
||||
val cardService: CardService
|
||||
) {
|
||||
companion object {
|
||||
val log = logger()
|
||||
@@ -225,7 +225,9 @@ class CardGameService(
|
||||
val remainingGames = dataRepos.keys.toMutableSet()
|
||||
games.forEach { game ->
|
||||
val dataRepo = dataRepos[game] ?: return@forEach
|
||||
migrateCard(game, dataRepo, cardRepo, crd)
|
||||
if (migrateCard(game, dataRepo, cardRepo, crd))
|
||||
// Update timestamp for the ghost card (data migrated in)
|
||||
cardService.updateCardTimestamp(crd.aquaUser!!.ghostCard, game, resetCreatedAt = true)
|
||||
remainingGames.remove(game)
|
||||
}
|
||||
// For remaining games, orphan the data by assigning them to a dummy card
|
||||
@@ -238,7 +240,7 @@ class CardGameService(
|
||||
"chu3" to getSummaryFor(chusan, card),
|
||||
"ongeki" to getSummaryFor(ongeki, card),
|
||||
"wacca" to getSummaryFor(wacca, card),
|
||||
"diva" to diva.findByPdId(card.extId)()?.let {
|
||||
"diva" to diva.findByPdId(card.extId).getOrNull()?.let {
|
||||
mapOf(
|
||||
"name" to it.playerName,
|
||||
"rating" to it.level,
|
||||
|
||||
@@ -2,36 +2,39 @@ package icu.samnyan.aqua.net
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.components.EmailProperties
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.security.MessageDigest
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.net.components.JWT
|
||||
import icu.samnyan.aqua.net.db.AquaGameOptions
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.mai2.Mai2Import
|
||||
import icu.samnyan.aqua.net.games.ExportOptions
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UploadUserPlaylogHandler as Mai2UploadUserPlaylogHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UpsertUserAllHandler as Mai2UpsertUserAllHandler
|
||||
import icu.samnyan.aqua.net.utils.ApiException
|
||||
import org.springframework.transaction.PlatformTransactionManager
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserDataRepo
|
||||
import icu.samnyan.aqua.net.games.GenericUserDataRepo
|
||||
import icu.samnyan.aqua.net.games.IUserData
|
||||
import icu.samnyan.aqua.net.games.mai2.Mai2Import
|
||||
import icu.samnyan.aqua.net.utils.ApiException
|
||||
import icu.samnyan.aqua.net.utils.PathProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserDataRepo
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserDataRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserDataRepo
|
||||
import icu.samnyan.aqua.sega.wacca.model.db.WcUserRepo
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.transaction.PlatformTransactionManager
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.security.MessageDigest
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.io.path.getLastModifiedTime
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.writeBytes
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UploadUserPlaylogHandler as Mai2UploadUserPlaylogHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UpsertUserAllHandler as Mai2UpsertUserAllHandler
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "aqua-net.fedy")
|
||||
@@ -41,11 +44,11 @@ class FedyProps {
|
||||
var remote: String = ""
|
||||
}
|
||||
|
||||
data class UserProfilePicture(val url: Str, val lastUpdatedMs: Long)
|
||||
data class UserProfilePicture(val url: Str, val updatedAtMs: Long)
|
||||
data class UserBasicInfo(
|
||||
val auId: Long, val ghostExtId: Long, val registrationTimeMs: Long,
|
||||
val username: Str, val displayName: Str, val email: Str, val passwordHash: Str, val profileBio: Str,
|
||||
val profilePicture: UserProfilePicture?,
|
||||
val profilePicture: UserProfilePicture?, val gameOptions: Map<Str, Any?>?,
|
||||
)
|
||||
|
||||
private data class UserUpdatedEvent(val user: UserBasicInfo, val isNewlyCreated: Bool)
|
||||
@@ -66,21 +69,23 @@ private data class FedyEvent(
|
||||
@API("/api/v2/fedy", consumes = ["multipart/form-data"])
|
||||
class Fedy(
|
||||
val jwt: JWT,
|
||||
val us: AquaUserServices,
|
||||
val emailProps: EmailProperties,
|
||||
val cardRepo: CardRepository,
|
||||
val cardService: CardService,
|
||||
val mai2Import: Mai2Import,
|
||||
val mai2UserDataRepo: Mai2UserDataRepo,
|
||||
val mai2UploadUserPlaylog: Mai2UploadUserPlaylogHandler,
|
||||
val mai2UpsertUserAll: Mai2UpsertUserAllHandler,
|
||||
val chu3UserDataRepo: Chu3UserDataRepo,
|
||||
val ongekiUserDataRepo: OgkUserDataRepo,
|
||||
val waccaUserDataRepo: WcUserRepo,
|
||||
val props: FedyProps,
|
||||
val paths: PathProps,
|
||||
val transactionManager: PlatformTransactionManager
|
||||
val transactionManager: PlatformTransactionManager,
|
||||
ctx: ApplicationContext
|
||||
) {
|
||||
val us by ctx.lazy<AquaUserServices>()
|
||||
val cardService by ctx.lazy<CardService>()
|
||||
val mai2Import by ctx.lazy<Mai2Import>()
|
||||
val mai2UploadUserPlaylog by ctx.lazy<Mai2UploadUserPlaylogHandler>()
|
||||
val mai2UpsertUserAll by ctx.lazy<Mai2UpsertUserAllHandler>()
|
||||
|
||||
val transaction by lazy { TransactionTemplate(transactionManager) }
|
||||
|
||||
private fun Str.checkKey() {
|
||||
@@ -127,7 +132,7 @@ class Fedy(
|
||||
} caught { UserRegisterRes(error = it) }
|
||||
}
|
||||
|
||||
data class UserUpdateReq(val auId: Long, val fields: Map<Str, Str?>?)
|
||||
data class UserUpdateReq(val auId: Long, val fields: Map<Str, Str?>?, val gameOptions: Map<Str, Any?>?)
|
||||
data class UserUpdateRes(val error: FedyErr? = null, val user: UserBasicInfo? = null)
|
||||
@API("/user/update")
|
||||
fun handleUserUpdate(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: UserUpdateReq, @RT(PFP_PART) pfpFile: MultipartFile?): UserUpdateRes = handleFedy(key) {
|
||||
@@ -138,12 +143,16 @@ class Fedy(
|
||||
if (k == "email") { ru.email = us.validateEmail(v) }
|
||||
else us.update(ru, k, v)
|
||||
}
|
||||
pfpFile?.run {
|
||||
pfpFile?.apply {
|
||||
val mime = TIKA.detect(pfpFile.bytes).takeIf { it.startsWith("image/") } ?: (400 - "Invalid file type")
|
||||
val name = "${ru.auId}${MIMES.forName(mime)?.extension ?: ".jpg"}"
|
||||
(paths.aquaNetPortrait.path() / name).writeBytes(bytes)
|
||||
ru.profilePicture = name
|
||||
}
|
||||
req.gameOptions?.apply {
|
||||
val options = ru.gameOptions ?: AquaGameOptions().also { ru.gameOptions = it }
|
||||
forEach { (k, v) -> v?.let { GAME_OPTIONS_FIELDS[k]?.set(options, it) } }
|
||||
}
|
||||
us.userRepo.save(ru)
|
||||
if (fields.containsKey("pwHash") ?: false) { us.clearAllSessions(ru) }
|
||||
UserUpdateRes(user = ru.fedyBasicInfo())
|
||||
@@ -157,36 +166,44 @@ class Fedy(
|
||||
?.let { paths.aquaNetPortrait.path() / it }?.takeIf { it.isRegularFile() }
|
||||
?.let { UserProfilePicture(
|
||||
url = "/uploads/net/portrait/${profilePicture}",
|
||||
lastUpdatedMs = it.getLastModifiedTime().toMillis()
|
||||
) }
|
||||
updatedAtMs = it.getLastModifiedTime().toMillis()
|
||||
) },
|
||||
gameOptions?.let { o -> GAME_OPTIONS_FIELDS.mapValues { it.value.get(o) } }
|
||||
)
|
||||
|
||||
data class DataPullReq(val extId: Long, val game: Str, val exportOptions: ExportOptions)
|
||||
data class DataPullRes(val error: FedyErr? = null, val result: Any? = null)
|
||||
data class DataPullReq(val extId: Long, val game: Str, val createdAtMs: Long, val updatedAtMs: Long, val exportOptions: ExportOptions)
|
||||
data class DataPullResult(val data: Any?, val createdAtMs: Long, val updatedAtMs: Long, val isRebased: Bool)
|
||||
data class DataPullRes(val error: FedyErr? = null, val result: DataPullResult? = null)
|
||||
@API("/data/pull")
|
||||
fun handleDataPull(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: DataPullReq): DataPullRes = handleFedy(key) {
|
||||
val card = cardRepo.findByExtId(req.extId)
|
||||
val card = cardRepo.findByExtId(req.extId).orElse(null)
|
||||
?: (404 - "Card with extId ${req.extId} not found")
|
||||
val cardTimestamp = cardService.getCardTimestamp(card, req.game)
|
||||
if (cardTimestamp.updatedAt.toEpochMilli() == req.updatedAtMs) return@handleFedy DataPullRes(error = null, result = null) // No changes
|
||||
val isRebased = req.createdAtMs > 0 && cardTimestamp.createdAt.toEpochMilli() > req.createdAtMs
|
||||
val exportOptions = if (!isRebased) { req.exportOptions } else { req.exportOptions.copy(playlogAfter = null) }
|
||||
{
|
||||
DataPullRes(result = when (req.game) {
|
||||
"mai2" -> mai2Import.export(card, req.exportOptions)
|
||||
DataPullRes(result = DataPullResult(data = when (req.game) {
|
||||
"mai2" -> mai2Import.export(card, exportOptions)
|
||||
else -> 406 - "Unsupported game"
|
||||
})
|
||||
}, createdAtMs = cardTimestamp.createdAt.toEpochMilli(), updatedAtMs = cardTimestamp.updatedAt.toEpochMilli(), isRebased = isRebased))
|
||||
} caught { DataPullRes(error = it) }
|
||||
}
|
||||
|
||||
data class DataPushReq(val extId: Long, val game: Str, val data: JDict, val removeOldData: Bool)
|
||||
data class DataPushReq(val extId: Long, val game: Str, val data: JDict, val removeOldData: Bool, val updatedAtMs: Long)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@API("/data/push")
|
||||
fun handleDataPush(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: DataPushReq): Any = handleFedy(key) {
|
||||
val extId = req.extId
|
||||
fun<UserData : IUserData, UserRepo : GenericUserDataRepo<UserData>> removeOldData(repo: UserRepo) {
|
||||
repo.findByCard_ExtId(extId)?.let { oldData ->
|
||||
val oldData = repo.findByCard_ExtId(extId)
|
||||
if (oldData.isPresent) {
|
||||
log.info("Fedy: Deleting old data for $extId (${req.game})")
|
||||
repo.delete(oldData);
|
||||
repo.delete(oldData.get());
|
||||
repo.flush()
|
||||
}
|
||||
}
|
||||
val card = cardRepo.findByExtId(extId).orElse(null) ?: (404 - "Card not found")
|
||||
transaction.execute { when (req.game) {
|
||||
"mai2" -> {
|
||||
if (req.removeOldData) { removeOldData(mai2UserDataRepo) }
|
||||
@@ -197,7 +214,7 @@ class Fedy(
|
||||
}
|
||||
else -> 406 - "Unsupported game"
|
||||
} }
|
||||
|
||||
cardService.updateCardTimestamp(card, req.game, now = Instant.ofEpochMilli(req.updatedAtMs), resetCreatedAt = req.removeOldData)
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -220,9 +237,9 @@ class Fedy(
|
||||
var pairedCard = cardService.tryLookup(req.pairedLuid)?.maybeGhost()
|
||||
if (pairedCard?.extId != card?.extId) {
|
||||
var isGhost = pairedCard?.isGhost == true
|
||||
var isFresh = pairedCard != null && isCardFresh(pairedCard)
|
||||
if (isGhost && isFresh) isPairedLuidDiverged = true
|
||||
else if (!isGhost && card?.isGhost == true) {
|
||||
var isNonFresh = pairedCard != null && !isCardFresh(pairedCard)
|
||||
if (isGhost || isNonFresh) isPairedLuidDiverged = true
|
||||
else if (card?.isGhost == true) {
|
||||
// Ensure paired card is linked, if the main card is linked
|
||||
// If the main card is not linked, there's nothing Fedy can do. It's Fedy's best effort.
|
||||
if (pairedCard == null) { pairedCard = cardService.registerByAccessCode(req.pairedLuid, card.aquaUser) }
|
||||
@@ -275,17 +292,16 @@ class Fedy(
|
||||
log.info("Fedy /card/unlink : Unlinked card ${card.id} (${card.luid}) from user ${cu.auId} (${cu.username})")
|
||||
}
|
||||
|
||||
fun onUserUpdated(u: AquaNetUser, isNew: Bool = false) = maybeNotifyAsync(FedyEvent(userUpdated = UserUpdatedEvent(u.fedyBasicInfo(), isNew)))
|
||||
fun onCardCreated(luid: Str, extId: Long) = maybeNotifyAsync(FedyEvent(cardCreated = CardCreatedEvent(luid, extId)))
|
||||
fun onCardLinked(luid: Str, oldExtId: Long?, ghostExtId: Long, migratedGames: List<Str>) = maybeNotifyAsync(FedyEvent(cardLinked = CardLinkedEvent(luid, oldExtId, ghostExtId, migratedGames)))
|
||||
fun onCardUnlinked(luid: Str) = maybeNotifyAsync(FedyEvent(cardUnlinked = CardUnlinkedEvent(luid)))
|
||||
fun onDataUpdated(extId: Long, game: Str, removeOldData: Bool) = maybeNotifyAsync({
|
||||
val card = cardRepo.findByExtId(extId) ?: return@maybeNotifyAsync null // Card not found, nothing to do
|
||||
fun onUserUpdated(u: AquaNetUser, isNew: Bool = false) = maybeNotifyAsync { FedyEvent(userUpdated = UserUpdatedEvent(u.fedyBasicInfo(), isNew)) }
|
||||
fun onCardCreated(luid: Str, extId: Long) = maybeNotifyAsync { FedyEvent(cardCreated = CardCreatedEvent(luid, extId)) }
|
||||
fun onCardLinked(luid: Str, oldExtId: Long?, ghostExtId: Long, migratedGames: List<Str>) = maybeNotifyAsync { FedyEvent(cardLinked = CardLinkedEvent(luid, oldExtId, ghostExtId, migratedGames)) }
|
||||
fun onCardUnlinked(luid: Str) = maybeNotifyAsync { FedyEvent(cardUnlinked = CardUnlinkedEvent(luid)) }
|
||||
fun onDataUpdated(extId: Long, game: Str, removeOldData: Bool) = maybeNotifyAsync {
|
||||
val card = cardRepo.findByExtId(extId).orElse(null) ?: return@maybeNotifyAsync null // Card not found, nothing to do
|
||||
FedyEvent(dataUpdated = DataUpdatedEvent(extId, card.isGhost, game, removeOldData))
|
||||
})
|
||||
}
|
||||
|
||||
private fun maybeNotifyAsync(event: FedyEvent) = maybeNotifyAsync({ event })
|
||||
private fun maybeNotifyAsync(getEvent: () -> FedyEvent?) = if (!props.enabled && !suppressEvents.get()) {} else CompletableFuture.runAsync {
|
||||
private fun maybeNotifyAsync(getEvent: () -> FedyEvent?) = if (!props.enabled || suppressEvents.get()) {} else CompletableFuture.runAsync {
|
||||
var event: FedyEvent? = null
|
||||
try {
|
||||
event = getEvent()
|
||||
@@ -325,7 +341,7 @@ class Fedy(
|
||||
|
||||
// Apparently existing cards could possibly be fresh and never used in any game. Treat them as new cards.
|
||||
private fun isCardFresh(c: Card): Bool {
|
||||
fun <T : IUserData> checkForGame(repo: GenericUserDataRepo<T>, card: Card): Bool = repo.findByCard(card) == null
|
||||
fun <T : IUserData> checkForGame(repo: GenericUserDataRepo<T>, card: Card): Bool = repo.findByCard(card) != null
|
||||
return when {
|
||||
checkForGame(mai2UserDataRepo, c) -> false
|
||||
checkForGame(chu3UserDataRepo, c) -> false
|
||||
@@ -344,18 +360,12 @@ class Fedy(
|
||||
const val KEY_HEADER = "X-Fedy-Key"
|
||||
const val REQ_PART = "request"
|
||||
const val PFP_PART = "profilePicture"
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val GAME_OPTIONS_FIELDS = listOf(
|
||||
O::mai2UnlockMusic, O::mai2UnlockChara, O::mai2UnlockCharaMaxLevel, O::mai2UnlockPartners, O::mai2UnlockCollectables, O::mai2UnlockTickets
|
||||
).map { it as Var<O, Any?> }.associateBy { it.name }
|
||||
val log = logger()
|
||||
|
||||
fun getGameName(gameId: Str) = when (gameId) {
|
||||
"mai2" -> "mai2"
|
||||
"SDEZ" -> "mai2"
|
||||
"chu3" -> "chu3"
|
||||
"SDHD" -> "chu3"
|
||||
"ongeki" -> "mu3"
|
||||
"SDDT" -> "mu3"
|
||||
"wacca" -> "wacca"
|
||||
"SDFE" -> "wacca"
|
||||
else -> null // Not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias O = AquaGameOptions
|
||||
|
||||
@@ -33,7 +33,7 @@ class Frontier(
|
||||
|
||||
if (accessCode.length != 20) 400 - "Invalid access code"
|
||||
// if (!accessCode.startsWith("9900")) 400 - "Frontier access code must start with 9900"
|
||||
if (async { cardService.cardRepo.findByLuid(accessCode) } != null) 400 - "Card already registered"
|
||||
if (async { cardService.cardRepo.findByLuid(accessCode) }.isPresent) 400 - "Card already registered"
|
||||
|
||||
val card = async { cardService.registerByAccessCode(accessCode) }
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package icu.samnyan.aqua.net
|
||||
|
||||
import ext.JACKSON
|
||||
import ext.invoke
|
||||
import ext.logger
|
||||
import ext.parse
|
||||
import icu.samnyan.aqua.net.db.AquaNetUserRepo
|
||||
@@ -23,7 +24,7 @@ class Migrations(
|
||||
|
||||
@PostConstruct
|
||||
fun migrate() {
|
||||
val db = props.findByPropertyKey("migrations") ?: PropertyEntry("migrations", "[]")
|
||||
val db = props.findByPropertyKey("migrations")() ?: PropertyEntry("migrations", "[]")
|
||||
val p = JACKSON.parse<ArrayList<String>>(db.propertyValue)
|
||||
val old = p.size
|
||||
|
||||
@@ -46,7 +47,7 @@ class Migrations(
|
||||
if (c.extId > max) {
|
||||
var new = c.extId and max
|
||||
log.info("Removing signed bit: {${c.extId} -> $new} for ${c.luid}")
|
||||
while (cardRepo.findByExtId(new) != null) {
|
||||
while (cardRepo.findByExtId(new).isPresent) {
|
||||
log.error("> Conflicting card found for ${c.luid}: $new")
|
||||
new++
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import kotlin.reflect.jvm.jvmErasure
|
||||
class SettingsApi(
|
||||
val us: AquaUserServices,
|
||||
val userRepo: AquaNetUserRepo,
|
||||
val goRepo: AquaGameOptionsRepo
|
||||
val goRepo: AquaGameOptionsRepo,
|
||||
val fedy: Fedy
|
||||
) {
|
||||
// Get all params with SettingField annotation
|
||||
val fields = AquaGameOptions::class.vars()
|
||||
@@ -41,6 +42,6 @@ class SettingsApi(
|
||||
}
|
||||
// Check field type
|
||||
field.setCast(options, value)
|
||||
goRepo.save(options)
|
||||
goRepo.save(options).also { fedy.onUserUpdated(u) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,12 @@ package icu.samnyan.aqua.net
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.components.*
|
||||
import icu.samnyan.aqua.net.db.AquaNetUserRepo
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.db.EmailConfirmationRepo
|
||||
import icu.samnyan.aqua.net.db.ResetPasswordRepo
|
||||
import icu.samnyan.aqua.net.db.*
|
||||
import icu.samnyan.aqua.net.utils.PathProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Lazy
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
@@ -27,6 +21,7 @@ class UserRegistrar(
|
||||
val hasher: PasswordEncoder,
|
||||
val turnstileService: TurnstileService,
|
||||
val emailService: EmailService,
|
||||
val fedy: Fedy,
|
||||
val geoIP: GeoIP,
|
||||
val jwt: JWT,
|
||||
val confirmationRepo: EmailConfirmationRepo,
|
||||
@@ -36,7 +31,6 @@ class UserRegistrar(
|
||||
val emailProps: EmailProperties,
|
||||
final val paths: PathProps
|
||||
) {
|
||||
@Autowired @Lazy lateinit var fedy: Fedy
|
||||
val portraitPath = paths.aquaNetPortrait.path()
|
||||
|
||||
companion object {
|
||||
@@ -92,8 +86,6 @@ class UserRegistrar(
|
||||
?: (400 - "User not found")
|
||||
if (!hasher.matches(password, user.pwHash)) 400 - "Invalid password"
|
||||
|
||||
if (user.ghostCard.status == CardStatus.MIGRATED_TO_MINATO) 400 - "Login not allowed: Card has been migrated to Minato."
|
||||
|
||||
// Check if email is verified
|
||||
if (!user.emailConfirmed && emailProps.enable) {
|
||||
// Check if last confirmation email was sent within a minute
|
||||
|
||||
@@ -3,7 +3,11 @@ package icu.samnyan.aqua.net.components
|
||||
import ext.Bool
|
||||
import ext.Str
|
||||
import ext.logger
|
||||
import icu.samnyan.aqua.net.db.*
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.net.db.EmailConfirmation
|
||||
import icu.samnyan.aqua.net.db.EmailConfirmationRepo
|
||||
import icu.samnyan.aqua.net.db.ResetPassword
|
||||
import icu.samnyan.aqua.net.db.ResetPasswordRepo
|
||||
import org.simplejavamail.api.mailer.Mailer
|
||||
import org.simplejavamail.email.EmailBuilder
|
||||
import org.simplejavamail.springsupport.SimpleJavaMailSpringSupport
|
||||
|
||||
@@ -2,7 +2,11 @@ package icu.samnyan.aqua.net.components
|
||||
|
||||
import ext.Str
|
||||
import ext.minus
|
||||
import icu.samnyan.aqua.net.db.*
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.net.db.AquaNetUserRepo
|
||||
import icu.samnyan.aqua.net.db.SessionToken
|
||||
import icu.samnyan.aqua.net.db.SessionTokenRepo
|
||||
import icu.samnyan.aqua.net.db.getTokenExpiry
|
||||
import io.jsonwebtoken.JwtParser
|
||||
import io.jsonwebtoken.Jwts
|
||||
import io.jsonwebtoken.security.Keys
|
||||
|
||||
@@ -2,10 +2,7 @@ package icu.samnyan.aqua.net.db
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import ext.SettingField
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.GeneratedValue
|
||||
import jakarta.persistence.GenerationType
|
||||
import jakarta.persistence.Id
|
||||
import jakarta.persistence.*
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
@Entity
|
||||
@@ -14,21 +11,29 @@ class AquaGameOptions(
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long = 0,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockMusic: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockChara: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockCollectables: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockTickets: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_music")
|
||||
var mai2UnlockMusic: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_chara")
|
||||
var mai2UnlockChara: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_chara_max_level")
|
||||
var mai2UnlockCharaMaxLevel: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_partners")
|
||||
var mai2UnlockPartners: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_collectables")
|
||||
var mai2UnlockCollectables: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_tickets")
|
||||
var mai2UnlockTickets: Boolean = false,
|
||||
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockMusic: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockPlates: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockCollectables: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockTickets: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaInfiniteWp: Boolean = false,
|
||||
|
||||
@SettingField("wacca")
|
||||
var waccaAlwaysVip: Boolean = false,
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.io.Serializable
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
fun getTokenExpiry() = Instant.now().plusSeconds(7 * 86400)
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ class AquaUserServices(
|
||||
|
||||
suspend fun cardByName(username: Str) =
|
||||
if (username.startsWith("user")) username.substring(4).toLongOrNull()
|
||||
?.let { cardRepo.findById(it)() } ?: (404 - "Card not found")
|
||||
?.let { cardRepo.findById(it).getOrNull() } ?: (404 - "Card not found")
|
||||
else byName(username) { it.ghostCard }
|
||||
|
||||
suspend fun <T> cardByName(username: Str, callback: suspend (Card) -> T) = callback(cardByName(username))
|
||||
|
||||
@@ -5,7 +5,7 @@ import icu.samnyan.aqua.net.BotProps
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import jakarta.annotation.PostConstruct
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -27,9 +27,12 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
abstract val playlogRepo: GenericPlaylogRepo<*>
|
||||
abstract val userMusicRepo: GenericUserMusicRepo<*>
|
||||
abstract val shownRanks: List<Pair<Int, String>>
|
||||
|
||||
abstract val settableFields: Map<String, (T, String) -> Unit>
|
||||
open val gettableFields: Set<String> = setOf()
|
||||
|
||||
@Autowired lateinit var cardService: CardService
|
||||
|
||||
@API("trend")
|
||||
abstract suspend fun trend(@RP username: String): List<TrendOut>
|
||||
@API("user-summary")
|
||||
@@ -56,7 +59,7 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
|
||||
val reqUser = token?.let { us.jwt.auth(it) }?.let { u ->
|
||||
// Optimization: If the user is not banned, we don't need to process user information
|
||||
if (!u.ghostCard.rankingBanned && !u.cards.any { it.rankingBanned } && u.ghostCard.status == CardStatus.NORMAL) null
|
||||
if (!u.ghostCard.rankingBanned && !u.cards.any { it.rankingBanned } && u.ghostCard.status.isNormal) null
|
||||
else u
|
||||
}
|
||||
|
||||
@@ -118,19 +121,17 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
}
|
||||
|
||||
@API("playlog")
|
||||
fun playlog(@RP id: Long): IGenericGamePlaylog = playlogRepo.findById(id)() ?: (404 - "Playlog not found")
|
||||
fun playlog(@RP id: Long): IGenericGamePlaylog = playlogRepo.findById(id).getOrNull() ?: (404 - "Playlog not found")
|
||||
|
||||
val userDetailFields by lazy { userDataClass.gettersMap().let { vm ->
|
||||
(settableFields.keys.toSet() + gettableFields)
|
||||
.associateWith { k -> (vm[k] ?: error("Field $k not found")) }
|
||||
} }
|
||||
|
||||
@API("user-detail")
|
||||
suspend fun userDetail(@RP username: String) = us.cardByName(username) { card ->
|
||||
val u = userDataRepo.findByCard(card) ?: (404 - "User not found")
|
||||
userDetailFields.toList().associate { (k, f) -> k to f.invoke(u) }
|
||||
}
|
||||
|
||||
@API("user-detail-set")
|
||||
suspend fun userDetailSet(@RP token: String, @RP field: String, @RP value: String): Any {
|
||||
val prop = settableFields[field] ?: (400 - "Invalid field $field")
|
||||
@@ -139,10 +140,16 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
val user = async { userDataRepo.findByCard(u.ghostCard) } ?: (404 - "User not found")
|
||||
prop(user, value)
|
||||
async { userDataRepo.save(user) }
|
||||
cardService.updateCardTimestamp(u.ghostCard, name)
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@API("user-option")
|
||||
open suspend fun userOption(@RP token: String): Any? = 400 - "Unsupported by this game"
|
||||
@API("user-option-set")
|
||||
open suspend fun userOptionSet(@RP token: String, @RP field: String, @RP value: Int): Any = 400 - "Unsupported by this game"
|
||||
|
||||
@API("user-music-from-list")
|
||||
suspend fun userMusicFromList(@RP username: Str, @RB musicList: List<Int>) = us.cardByName(username) { card ->
|
||||
userMusicRepo.findByUser_Card_ExtIdAndMusicIdIn(card.extId, musicList)
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package icu.samnyan.aqua.net.games
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.Fedy
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.Fedy
|
||||
import icu.samnyan.aqua.net.utils.AquaNetProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Lazy
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.repository.NoRepositoryBean
|
||||
import org.springframework.transaction.PlatformTransactionManager
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.reflect.KClass
|
||||
@@ -42,13 +43,14 @@ interface IExportClass<UserModel: IUserData> {
|
||||
@NoRepositoryBean
|
||||
interface IUserRepo<UserModel, ThisModel>: JpaRepository<ThisModel, Long> {
|
||||
fun findByUser(user: UserModel): List<ThisModel>
|
||||
fun findSingleByUser(user: UserModel): ThisModel?
|
||||
fun findSingleByUser(user: UserModel): Optional<ThisModel>
|
||||
}
|
||||
|
||||
/**
|
||||
* Import controller for a game
|
||||
*
|
||||
* @param game: 4-letter Game ID
|
||||
* @param gameName: mai2/chu3/ongeki
|
||||
* @param exportFields: Mapping of type names to variables in the export model
|
||||
* (e.g. "Mai2UserCharacter" -> Mai2DataExport::userCharacterList)
|
||||
* @param exportRepos: Mapping of variables to repositories that can be used to find the data
|
||||
@@ -56,6 +58,7 @@ interface IUserRepo<UserModel, ThisModel>: JpaRepository<ThisModel, Long> {
|
||||
*/
|
||||
abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel: IUserData>(
|
||||
val game: String,
|
||||
val gameName: String,
|
||||
val exportClass: KClass<ExportModel>,
|
||||
val exportFields: Map<String, Var<ExportModel, Any>>,
|
||||
val exportRepos: Map<Var<ExportModel, Any>, IUserRepo<UserModel, *>>,
|
||||
@@ -70,7 +73,7 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
||||
@Autowired lateinit var netProps: AquaNetProps
|
||||
@Autowired lateinit var transManager: PlatformTransactionManager
|
||||
val trans by lazy { TransactionTemplate(transManager) }
|
||||
@Autowired @Lazy lateinit var fedy: Fedy
|
||||
@Autowired lateinit var cardService: CardService
|
||||
|
||||
init {
|
||||
artemisRenames.values.forEach {
|
||||
@@ -88,7 +91,7 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
||||
userData = userDataRepo.findByCard(c) ?: (404 - "User not found")
|
||||
exportRepos.forEach { (f, u) ->
|
||||
if (f returns List::class) f.set(this, u.findByUser(userData))
|
||||
else u.findSingleByUser(userData)?.let { f.set(this, it) }
|
||||
else u.findSingleByUser(userData)()?.let { f.set(this, it) }
|
||||
}
|
||||
customExporters.forEach { (f, exporter) ->
|
||||
exporter(userData, options)?.let { f.set(this, it) }
|
||||
@@ -147,7 +150,7 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
||||
}
|
||||
}
|
||||
|
||||
Fedy.getGameName(game)?.let { fedy.onDataUpdated(u.ghostCard.extId, it, true) }
|
||||
cardService.updateCardTimestamp(u.ghostCard, gameName, resetCreatedAt = true)
|
||||
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ open class BaseEntity(
|
||||
@NoRepositoryBean
|
||||
interface GenericUserDataRepo<T : IUserData> : JpaRepository<T, Long> {
|
||||
fun findByCard(card: Card): T?
|
||||
fun findByCard_ExtId(extId: Long): T?
|
||||
fun findByCard_ExtId(extId: Long): Optional<T>
|
||||
|
||||
@Query("select e from #{#entityName} e where e.card.rankingBanned = false")
|
||||
fun findAllNonBanned(): List<T>
|
||||
|
||||
@@ -17,7 +17,7 @@ import kotlin.reflect.full.declaredMembers
|
||||
class Chu3Import(
|
||||
val repos: Chu3Repos,
|
||||
) : ImportController<Chu3DataExport, Chu3UserData>(
|
||||
"SDHD", Chu3DataExport::class,
|
||||
"SDHD", "chu3", Chu3DataExport::class,
|
||||
exportFields = Chu3DataExport::class.vars().associateBy {
|
||||
it.name.replace("List", "").lowercase()
|
||||
},
|
||||
|
||||
@@ -3,13 +3,15 @@ package icu.samnyan.aqua.net.games.chu3
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.*
|
||||
import icu.samnyan.aqua.net.utils.chu3Scores
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserDataRepo
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserMusicDetailRepo
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserPlaylogRepo
|
||||
import icu.samnyan.aqua.net.utils.*
|
||||
import icu.samnyan.aqua.sega.chusan.model.*
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserGameOption
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@RestController
|
||||
@API("api/v2/game/chu3")
|
||||
@@ -36,6 +38,7 @@ class Chusan(
|
||||
"trophyIdSub2" to { u, v -> u.trophyIdSub2 = v.int },
|
||||
"mapIconId" to { u, v -> u.mapIconId = v.int },
|
||||
"voiceId" to { u, v -> u.voiceId = v.int },
|
||||
"characterId" to { u, v -> u.characterId = v.int },
|
||||
"avatarWear" to { u, v -> u.avatarWear = v.int },
|
||||
"avatarHead" to { u, v -> u.avatarHead = v.int },
|
||||
"avatarFace" to { u, v -> u.avatarFace = v.int },
|
||||
@@ -47,7 +50,7 @@ class Chusan(
|
||||
"lastRomVersion" to { u, v -> u.lastRomVersion = v },
|
||||
"lastDataVersion" to { u, v -> u.lastDataVersion = v },
|
||||
) }
|
||||
override val gettableFields: Set<String> = setOf("level", "playerRating", "characterId")
|
||||
override val gettableFields: Set<String> = setOf("level", "playerRating")
|
||||
|
||||
override suspend fun userSummary(@RP username: Str, @RP token: String?) = us.cardByName(username) { card ->
|
||||
// Summary values: total plays, player rating, server-wide ranking
|
||||
@@ -97,6 +100,23 @@ class Chusan(
|
||||
)
|
||||
}
|
||||
|
||||
@API("user-option")
|
||||
override suspend fun userOption(@RP token: String): Any? = us.jwt.auth(token) { u ->
|
||||
rp.userGameOption.findByUser_Card_ExtId(u.ghostCard.extId).getOrNull(0)
|
||||
}
|
||||
@API("user-option-set")
|
||||
override suspend fun userOptionSet(@RP token: String, @RP field: String, @RP value: Int): Any = us.jwt.auth(token) { u ->
|
||||
val gameOptions = rp.userGameOption.findSingleByUser_Card_ExtId(u.ghostCard.extId).getOrNull()
|
||||
val property = UserGameOption::class.memberProperties.filterIsInstance<KMutableProperty1<Any, Any?>>().find{ it.name == field }
|
||||
|
||||
if (property != null && gameOptions != null) {
|
||||
property.setter.call(gameOptions, value)
|
||||
rp.userGameOption.save(gameOptions)
|
||||
200 - "Success"
|
||||
} else
|
||||
400 - "Invalid parameters"
|
||||
}
|
||||
|
||||
// UserBox related APIs
|
||||
@API("user-box")
|
||||
fun userBox(@RP token: String) = us.jwt.auth(token) {
|
||||
|
||||
@@ -14,13 +14,12 @@ import icu.samnyan.aqua.sega.maimai2.model.userdata.*
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import kotlin.reflect.full.declaredMembers
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@RestController
|
||||
@API("api/v2/game/mai2")
|
||||
class Mai2Import(
|
||||
val repos: Mai2Repos,
|
||||
) : ImportController<Maimai2DataExport, Mai2UserDetail>(
|
||||
"SDEZ", Maimai2DataExport::class,
|
||||
"SDEZ", "mai2", Maimai2DataExport::class,
|
||||
exportFields = Maimai2DataExport::class.vars().associateBy {
|
||||
it.name.replace("List", "").lowercase()
|
||||
},
|
||||
@@ -62,7 +61,7 @@ class Mai2Import(
|
||||
}
|
||||
},
|
||||
Maimai2DataExport::userFavoriteMusicList to { user: Mai2UserDetail, _: ExportOptions ->
|
||||
repos.userGeneralData.findByUserAndPropertyKey(user, "favorite_music")
|
||||
repos.userGeneralData.findByUserAndPropertyKey(user, "favorite_music").orElse(null)
|
||||
?.propertyValue
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.split(",")
|
||||
@@ -79,7 +78,7 @@ class Mai2Import(
|
||||
if (favoriteMusicList.isNotEmpty()) {
|
||||
val key = "favorite_music"
|
||||
// This field always imports as incremental, since the userGeneralData field (for backwards compatibility) is processed before this
|
||||
val data = repos.userGeneralData.findByUserAndPropertyKey(user, key)
|
||||
val data = repos.userGeneralData.findByUserAndPropertyKey(user, key).orElse(null)
|
||||
?: Mai2UserGeneralData().apply { this.user = user; propertyKey = key }
|
||||
repos.userGeneralData.save(data.apply {
|
||||
propertyValue = favoriteMusicList.sortedBy { it.orderId }.map { it.id }.joinToString(",")
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package icu.samnyan.aqua.net.games.mai2
|
||||
|
||||
import ext.API
|
||||
import ext.RB
|
||||
import ext.RP
|
||||
import ext.minus
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserMusicDetail
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
@@ -16,26 +14,34 @@ import org.springframework.web.bind.annotation.RestController
|
||||
class Mai2MusicDetailImport(
|
||||
val us: AquaUserServices,
|
||||
val repos: Mai2Repos,
|
||||
val cardService: CardService,
|
||||
) {
|
||||
@PostMapping("import-music-detail")
|
||||
suspend fun importMusicDetail(@RP token: String, @RB data: List<Mai2UserMusicDetail>) = us.jwt.auth(token) { u ->
|
||||
us.cardByName(u.username) { card ->
|
||||
val user = repos.userData.findByCardExtId(card.extId) ?: (404 - "User not found")
|
||||
val user = repos.userData.findByCardExtId(card.extId).orElse(null) ?: (404 - "User not found")
|
||||
data.forEach { newMusic ->
|
||||
newMusic.user = user
|
||||
repos.userMusicDetail.findByUserAndMusicIdAndLevel(user, newMusic.musicId, newMusic.level)?.let { m ->
|
||||
val musicRec = repos.userMusicDetail.findByUserAndMusicIdAndLevel(user, newMusic.musicId, newMusic.level)
|
||||
if (musicRec.isPresent) {
|
||||
val music = musicRec.get()
|
||||
newMusic.apply {
|
||||
id = m.id
|
||||
achievement = achievement.coerceAtLeast(m.achievement)
|
||||
scoreRank = scoreRank.coerceAtLeast(m.scoreRank)
|
||||
comboStatus = comboStatus.coerceAtLeast(m.comboStatus)
|
||||
syncStatus = syncStatus.coerceAtLeast(m.syncStatus)
|
||||
deluxscoreMax = deluxscoreMax.coerceAtLeast(m.deluxscoreMax)
|
||||
playCount = playCount.coerceAtLeast(m.playCount)
|
||||
id = music.id
|
||||
this.user = user
|
||||
achievement = achievement.coerceAtLeast(music.achievement)
|
||||
scoreRank = scoreRank.coerceAtLeast(music.scoreRank)
|
||||
comboStatus = comboStatus.coerceAtLeast(music.comboStatus)
|
||||
syncStatus = syncStatus.coerceAtLeast(music.syncStatus)
|
||||
deluxscoreMax = deluxscoreMax.coerceAtLeast(music.deluxscoreMax)
|
||||
playCount = playCount.coerceAtLeast(music.playCount)
|
||||
}
|
||||
} else {
|
||||
newMusic.apply {
|
||||
this.user = user
|
||||
}
|
||||
}
|
||||
}
|
||||
repos.userMusicDetail.saveAll(data)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,17 @@ package icu.samnyan.aqua.net.games.mai2
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.*
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.net.utils.mai2Scores
|
||||
import icu.samnyan.aqua.net.utils.*
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UploadUserPhotoHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserDataRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserMusicDetailRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserPlaylogRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserDetail
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserGeneralData
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserLoginBonus
|
||||
import icu.samnyan.aqua.sega.maimai2.model.*
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.*
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.util.*
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@RestController
|
||||
@API("api/v2/game/mai2")
|
||||
@@ -63,9 +61,9 @@ class Maimai2(
|
||||
us.jwt.auth(t) { u ->
|
||||
if (u.username == username) return@auth null
|
||||
us.cardByName(u.username) { myCard ->
|
||||
val user = repos.userData.findByCardExtId(card.extId) ?: (404 - "User not found")
|
||||
val myRival = (repos.userGeneralData.findByUser_Card_ExtIdAndPropertyKey(myCard.extId, "favorite_rival")?.propertyValue?.split(',') ?: emptyList())
|
||||
.filter { it.isNotEmpty() }.map { it.long() }
|
||||
val user = repos.userData.findByCardExtId(card.extId).orElse(null) ?: (404 - "User not found")
|
||||
val myRival = repos.userGeneralData.findByUser_Card_ExtIdAndPropertyKey(myCard.extId, "favorite_rival")
|
||||
.map { it.propertyValue.split(',') }.orElse(emptyList()).filter { it.isNotEmpty() }.map { it.long() }
|
||||
myRival.contains(user.id)
|
||||
}
|
||||
}
|
||||
@@ -115,6 +113,7 @@ class Maimai2(
|
||||
val user = userDataRepo.findByCard(card) ?: (404 - "User not found")
|
||||
user.userName = newNameFull
|
||||
userDataRepo.save(user)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
}
|
||||
mapOf("newName" to newNameFull)
|
||||
}
|
||||
@@ -137,17 +136,36 @@ class Maimai2(
|
||||
if (loginBonus.none { it.bonusId == bonusId }) {
|
||||
// create one
|
||||
val newBonus = Mai2UserLoginBonus().apply {
|
||||
user = repos.userData.findByCardExtId(card.extId) ?: (404 - "User not found")
|
||||
user = repos.userData.findByCardExtId(card.extId).orElse(null) ?: (404 - "User not found")
|
||||
this.bonusId = bonusId
|
||||
isCurrent = true
|
||||
}
|
||||
loginBonus.add(newBonus)
|
||||
}
|
||||
repos.userLoginBonus.saveAll(loginBonus)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
}
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@API("user-option")
|
||||
override suspend fun userOption(@RP token: String) = us.jwt.auth(token) { u ->
|
||||
repos.userOption.findByUser_Card_ExtId(u.ghostCard.extId).getOrNull(0)
|
||||
}
|
||||
@API("user-option-set")
|
||||
override suspend fun userOptionSet(@RP token: String, @RP field: String, @RP value: Int): Any = us.jwt.auth(token) { u ->
|
||||
val gameOptions = repos.userOption.findSingleByUser_Card_ExtId(u.ghostCard.extId).getOrNull()
|
||||
val property = Mai2UserOption::class.memberProperties.filterIsInstance<KMutableProperty1<Any, Any?>>().find{ it.name == field }
|
||||
|
||||
if (property != null && gameOptions != null) {
|
||||
property.setter.call(gameOptions, value)
|
||||
repos.userOption.save(gameOptions)
|
||||
200 - "Success"
|
||||
} else
|
||||
400 - "Invalid parameters"
|
||||
|
||||
}
|
||||
|
||||
@API("owned-items")
|
||||
suspend fun ownedItems(@RP token: String) = us.jwt.auth(token) { u ->
|
||||
us.cardByName(u.username) { card ->
|
||||
@@ -159,10 +177,10 @@ class Maimai2(
|
||||
suspend fun setRival(@RP token: String, @RP rivalUserName: String, @RP isAdd: Boolean) = us.jwt.auth(token) { u ->
|
||||
us.cardByName(u.username) { myCard ->
|
||||
val rivalCard = us.cardByName(rivalUserName) { it }
|
||||
val rivalUser = repos.userData.findByCardExtId(rivalCard.extId) ?: (404 - "User not found")
|
||||
val myRival = repos.userGeneralData.findByUser_Card_ExtIdAndPropertyKey(myCard.extId, "favorite_rival")
|
||||
val rivalUser = repos.userData.findByCardExtId(rivalCard.extId).orElse(null) ?: (404 - "User not found")
|
||||
val myRival = repos.userGeneralData.findByUser_Card_ExtIdAndPropertyKey(myCard.extId, "favorite_rival").orElse(null)
|
||||
?: Mai2UserGeneralData().apply {
|
||||
user = repos.userData.findByCardExtId(myCard.extId) ?: (404 - "User not found")
|
||||
user = repos.userData.findByCardExtId(myCard.extId).orElse(null) ?: (404 - "User not found")
|
||||
propertyKey = "favorite_rival"
|
||||
}
|
||||
val myRivalList = myRival.propertyValue.split(',').filter { it.isNotEmpty() }.mut
|
||||
@@ -177,6 +195,7 @@ class Maimai2(
|
||||
|
||||
myRival.propertyValue = myRivalList.joinToString(",")
|
||||
repos.userGeneralData.save(myRival)
|
||||
cardService.updateCardTimestamp(myCard, "mai2")
|
||||
}
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
package icu.samnyan.aqua.net.games.ongeki
|
||||
|
||||
import ext.API
|
||||
import ext.RP
|
||||
import ext.minus
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.*
|
||||
import icu.samnyan.aqua.net.utils.ongekiScores
|
||||
import icu.samnyan.aqua.net.utils.*
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserDataRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserGeneralDataRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserMusicDetailRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserOptionRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserPlaylogRepo
|
||||
import icu.samnyan.aqua.sega.ongeki.model.UserData
|
||||
import icu.samnyan.aqua.sega.ongeki.model.UserOption
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
@RestController
|
||||
@API("api/v2/game/ongeki")
|
||||
@@ -18,7 +26,8 @@ class Ongeki(
|
||||
override val playlogRepo: OgkUserPlaylogRepo,
|
||||
override val userDataRepo: OgkUserDataRepo,
|
||||
override val userMusicRepo: OgkUserMusicDetailRepo,
|
||||
val userGeneralDataRepository: OgkUserGeneralDataRepo
|
||||
val userGeneralDataRepository: OgkUserGeneralDataRepo,
|
||||
val userOptionRepo: OgkUserOptionRepo
|
||||
): GameApiController<UserData>("ongeki", UserData::class) {
|
||||
override suspend fun trend(username: String) = us.cardByName(username) { card ->
|
||||
findTrend(playlogRepo.findByUser_Card_ExtId(card.extId)
|
||||
@@ -45,4 +54,21 @@ class Ongeki(
|
||||
|
||||
genericUserSummary(card, ratingComposition)
|
||||
}
|
||||
|
||||
@API("user-option")
|
||||
override suspend fun userOption(@RP token: String) = us.jwt.auth(token) { u ->
|
||||
userOptionRepo.findByUser_Card_ExtId(u.ghostCard.extId).getOrNull(0)
|
||||
}
|
||||
@API("user-option-set")
|
||||
override suspend fun userOptionSet(@RP token: String, @RP field: String, @RP value: Int): Any = us.jwt.auth(token) { u ->
|
||||
val gameOptions = userOptionRepo.findSingleByUser_Card_ExtId(u.ghostCard.extId).getOrNull()
|
||||
val property = UserOption::class.memberProperties.filterIsInstance<KMutableProperty1<Any, Any?>>().find{ it.name == field }
|
||||
|
||||
if (property != null && gameOptions != null) {
|
||||
property.setter.call(gameOptions, value)
|
||||
userOptionRepo.save(gameOptions)
|
||||
200 - "Success"
|
||||
} else
|
||||
400 - "Invalid parameters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package icu.samnyan.aqua.net.games.wacca
|
||||
|
||||
import ext.API
|
||||
import ext.RP
|
||||
import ext.isoDate
|
||||
import ext.utc
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.*
|
||||
import icu.samnyan.aqua.net.utils.waccaScores
|
||||
@@ -37,7 +34,7 @@ class Wacca(
|
||||
|
||||
val data = userDataRepo.findByCard_ExtId(card.extId)
|
||||
|
||||
genericUserSummary(card, mapOf(), null, data?.favoriteSongs)
|
||||
genericUserSummary(card, mapOf(), null, if (data.isPresent) data.get().favoriteSongs else null)
|
||||
}
|
||||
|
||||
override val shownRanks: List<Pair<Int, String>> = waccaScores.filter { it.first > 85 * 10000 }
|
||||
|
||||
@@ -3,10 +3,10 @@ package icu.samnyan.aqua.net.transfer
|
||||
import ext.header
|
||||
import ext.post
|
||||
import ext.request
|
||||
import java.net.URI
|
||||
import icu.samnyan.aqua.sega.aimedb.AimeDbClient
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetBillingDecoder
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetBillingDecoder.decodeAllNetResp
|
||||
import java.net.URI
|
||||
|
||||
val keychipPattern = Regex("([A-Z\\d]{4}-[A-Z\\d]{11}|[A-Z\\d]{11})")
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserItem
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserMusicDetail
|
||||
import icu.samnyan.aqua.sega.ongeki.model.OngekiUpsertUserAll
|
||||
import icu.samnyan.aqua.sega.ongeki.model.UserItem
|
||||
import icu.samnyan.aqua.sega.util.BasicMapper
|
||||
import icu.samnyan.aqua.sega.util.IMapper
|
||||
import icu.samnyan.aqua.sega.util.StringMapper
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import icu.samnyan.aqua.sega.util.jackson.IMapper
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper
|
||||
|
||||
|
||||
abstract class DataBroker(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package icu.samnyan.aqua.sega.aimedb
|
||||
|
||||
import ext.logger
|
||||
import ext.toHex
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.Fedy
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetProps
|
||||
@@ -126,7 +125,7 @@ class AimeDB(
|
||||
}
|
||||
}
|
||||
|
||||
fun getCard(accessCode: String) = us.cardRepo.findByLuid(accessCode)?.maybeGhost()?.let { card ->
|
||||
fun getCard(accessCode: String) = us.cardRepo.findByLuid(accessCode)()?.maybeGhost()?.let { card ->
|
||||
// Update card access time and return the extId
|
||||
us.cardRepo.save(card.apply { accessTime = LocalDateTime.now() }).extId
|
||||
} ?: -1
|
||||
@@ -197,7 +196,7 @@ class AimeDB(
|
||||
var status = 0
|
||||
var aimeId = 0L
|
||||
|
||||
if (us.cardRepo.findByLuid(luid) == null) {
|
||||
if (us.cardRepo.findByLuid(luid).isEmpty) {
|
||||
val card: Card = cardService.registerByAccessCode(luid)
|
||||
|
||||
status = 1
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
package icu.samnyan.aqua.sega.aimedb
|
||||
|
||||
import icu.samnyan.aqua.sega.util.ByteBufUtil
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled.copiedBuffer
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
fun ByteBuf.toBytes(): ByteArray {
|
||||
val readerPos = readerIndex()
|
||||
resetReaderIndex()
|
||||
val result = ByteArray(readableBytes())
|
||||
readBytes(result)
|
||||
readerIndex(readerPos)
|
||||
return result
|
||||
}
|
||||
|
||||
fun ByteBuf.toAllBytes(): ByteArray {
|
||||
val readerPos = readerIndex()
|
||||
resetReaderIndex()
|
||||
writerIndex(capacity())
|
||||
val result = ByteArray(capacity())
|
||||
readBytes(result)
|
||||
readerIndex(readerPos)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@@ -33,6 +15,7 @@ object AimeDbEncryption {
|
||||
val enc = Cipher.getInstance("AES/ECB/NoPadding").apply { init(Cipher.ENCRYPT_MODE, KEY) }
|
||||
val dec = Cipher.getInstance("AES/ECB/NoPadding").apply { init(Cipher.DECRYPT_MODE, KEY) }
|
||||
|
||||
fun decrypt(src: ByteBuf) = copiedBuffer(dec.doFinal(src.toBytes()))
|
||||
fun encrypt(src: ByteBuf) = copiedBuffer(enc.doFinal(src.toAllBytes()))
|
||||
fun decrypt(src: ByteBuf) = copiedBuffer(dec.doFinal(ByteBufUtil.toBytes(src)))
|
||||
|
||||
fun encrypt(src: ByteBuf) = copiedBuffer(enc.doFinal(ByteBufUtil.toAllBytes(src)))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||
import io.netty.handler.logging.LogLevel
|
||||
import io.netty.handler.logging.LoggingHandler
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@@ -3,6 +3,7 @@ package icu.samnyan.aqua.sega.allnet
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaNetUserRepo
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetBillingDecoder.decodeAllNet
|
||||
import icu.samnyan.aqua.sega.util.AquaConst
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
@@ -13,6 +14,7 @@ import java.io.InputStream
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "allnet.server")
|
||||
@@ -82,7 +84,7 @@ class AllNet(
|
||||
|
||||
logger.info("AllNet /DownloadOrder : $reqMap")
|
||||
|
||||
val serial = reqMap["serial"] ?: "A69E01A8888"
|
||||
val serial = reqMap["serial"] ?: AquaConst.DEFAULT_KEYCHIP_ID
|
||||
val resp = mapOf(
|
||||
"stat" to "1",
|
||||
"serial" to serial
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker
|
||||
|
||||
import ext.API
|
||||
import ext.logger
|
||||
import ext.long
|
||||
import ext.parsing
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.util.BasicMapper
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.web.bind.annotation.ModelAttribute
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/g/card")
|
||||
class CardMakerController(
|
||||
val mapper: BasicMapper,
|
||||
@param:Value("\${allnet.server.host:}") val ALLNET_HOST: String,
|
||||
@param:Value("\${allnet.server.port:}") val ALLNET_PORT: String,
|
||||
@param:Value("\${server.port:}") val SERVER_PORT: String
|
||||
) {
|
||||
val logger = logger()
|
||||
|
||||
@API("GetGameSettingApi")
|
||||
fun getGameSetting(@ModelAttribute request: MutableMap<String, Any>): Any? {
|
||||
val formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss")
|
||||
val rebootStartTime = LocalDateTime.now().minusHours(3)
|
||||
val rebootEndTime = LocalDateTime.now().minusHours(2)
|
||||
|
||||
val gameSetting = mapOf(
|
||||
"dataVersion" to "1.35.0",
|
||||
"ongekiCmVersion" to "1.32.0",
|
||||
"chuniCmVersion" to "1.30.0",
|
||||
"maimaiCmVersion" to "1.45.0",
|
||||
"isMaintenance" to false,
|
||||
"requestInterval" to 10,
|
||||
"rebootStartTime" to rebootStartTime.format(formatter),
|
||||
"rebootEndTime" to rebootEndTime.format(formatter),
|
||||
"isBackgroundDistribute" to false,
|
||||
"maxCountCharacter" to 100,
|
||||
"maxCountItem" to 100,
|
||||
"maxCountCard" to 100,
|
||||
"watermark" to false
|
||||
)
|
||||
|
||||
val json = mapper.write(mapOf(
|
||||
"gameSetting" to gameSetting,
|
||||
"isDumpUpload" to false,
|
||||
"isAou" to false
|
||||
))
|
||||
|
||||
logger.info("Response: {}", json)
|
||||
return json
|
||||
}
|
||||
|
||||
fun gameConnect(modelKind: Int, modelVersion: Int, url: String) =
|
||||
mapOf("modelKind" to modelKind, "modelVersion" to modelVersion, "url" to url)
|
||||
|
||||
@API("GetGameConnectApi")
|
||||
fun getGameConnect(@ModelAttribute request: MutableMap<String, Any>): Any? {
|
||||
val version = parsing { request["version"]!!.long } // Rom version
|
||||
val session = TokenChecker.Companion.getCurrentSession()
|
||||
|
||||
val addr = ALLNET_HOST.ifBlank { null } ?:
|
||||
try { InetAddress.getLocalHost().hostAddress }
|
||||
catch (_: UnknownHostException) { "localhost" }
|
||||
val port = ALLNET_PORT.ifBlank { null } ?: SERVER_PORT
|
||||
|
||||
val base = if (session == null) "/g" else "/gs/" + session.token
|
||||
val json = mapper.write(mapOf(
|
||||
"length" to 3,
|
||||
"gameConnectList" to listOf(
|
||||
gameConnect(0, 1, "http://$addr:$port$base/chu3/$version/"),
|
||||
gameConnect(1, 1, "http://$addr:$port$base/mai2/"),
|
||||
gameConnect(2, 1, "http://$addr:$port$base/ongeki/")
|
||||
)
|
||||
))
|
||||
|
||||
logger.info("Response: $json")
|
||||
return json
|
||||
}
|
||||
|
||||
@API("GetClientBookkeepingApi")
|
||||
fun getClientBookkeeping(@ModelAttribute request: MutableMap<String, Any>): Any? {
|
||||
val placeId = parsing { request["placeId"]!!.long }
|
||||
val json = mapper.write(mapOf(
|
||||
"placeId" to placeId,
|
||||
"length" to 0,
|
||||
"clientBookkeepingList" to mutableListOf<Any>()
|
||||
))
|
||||
|
||||
logger.info("Response: $json")
|
||||
return json
|
||||
}
|
||||
|
||||
@API("UpsertClientBookkeepingApi")
|
||||
fun upsertClientBookkeeping() = "{\"returnCode\":1,\"apiName\":\"UpsertClientBookkeepingApi\"}"
|
||||
|
||||
@API("UpsertClientSettingApi")
|
||||
fun upsertClientSetting() = "{\"returnCode\":1,\"apiName\":\"UpsertClientSettingApi\"}"
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import ext.logger
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.web.bind.annotation.ModelAttribute
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestControllerAdvice(basePackages = ["icu.samnyan.aqua.sega.cardmaker"])
|
||||
class CardMakerControllerAdvice {
|
||||
val logger = logger()
|
||||
val mapper = ObjectMapper()
|
||||
|
||||
/**
|
||||
* Get the map object from json string
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
*/
|
||||
@ModelAttribute
|
||||
fun preHandle(request: HttpServletRequest): MutableMap<String, Any> {
|
||||
val src = request.inputStream.readAllBytes()
|
||||
val outputString = String(src, StandardCharsets.UTF_8).trim { it <= ' ' }
|
||||
logger.info("Request ${request.requestURI}: $outputString")
|
||||
return mapper.readValue(outputString, object : TypeReference<MutableMap<String, Any>>() {})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.controller;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.cardmaker.handler.impl.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/g/card")
|
||||
public class CardMakerController {
|
||||
private final GetGameSettingHandler getGameSettingHandler;
|
||||
private final GetClientBookkeepingHandler getClientBookkeepingHandler;
|
||||
private final GetGameConnectHandler getGameConnectHandler;
|
||||
|
||||
@Autowired
|
||||
public CardMakerController(GetGameSettingHandler getGameSettingHandler, GetClientBookkeepingHandler getClientBookkeepingHandler, GetGameConnectHandler getGameConnectHandler) {
|
||||
this.getGameSettingHandler = getGameSettingHandler;
|
||||
this.getClientBookkeepingHandler = getClientBookkeepingHandler;
|
||||
this.getGameConnectHandler = getGameConnectHandler;
|
||||
}
|
||||
|
||||
@PostMapping("GetGameSettingApi")
|
||||
public String getGameSetting(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameSettingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameConnectApi")
|
||||
public String getGameConnect(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameConnectHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetClientBookkeepingApi")
|
||||
public String getClientBookkeeping(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getClientBookkeepingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientBookkeepingApi")
|
||||
public String upsertClientBookkeeping(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":1,\"apiName\":\"UpsertClientBookkeepingApi\"}";
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientSettingApi")
|
||||
public String upsertClientSetting(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":1,\"apiName\":\"UpsertClientSettingApi\"}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestControllerAdvice(basePackages = "icu.samnyan.aqua.sega.cardmaker")
|
||||
public class CardMakerControllerAdvice {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CardMakerControllerAdvice.class);
|
||||
|
||||
|
||||
/**
|
||||
* Get the map object from json string
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
*/
|
||||
@ModelAttribute
|
||||
public Map<String, Object> preHandle(HttpServletRequest request) throws IOException {
|
||||
byte[] src = request.getInputStream().readAllBytes();
|
||||
String outputString = new String(src, StandardCharsets.UTF_8).trim();
|
||||
logger.info("Request " + request.getRequestURI() + ": " + outputString);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
return mapper.readValue(outputString, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component("CardMakerGetClientBookkeepingHandler")
|
||||
public class GetClientBookkeepingHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetClientBookkeepingHandler.class);
|
||||
|
||||
private final BasicMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetClientBookkeepingHandler(BasicMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
long placeId = ((Number) request.get("placeId")).longValue();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("placeId", placeId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("clientBookkeepingList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.allnet.KeychipSession;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.cardmaker.model.response.data.GameConnect;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component("CardMakerGetGameConnectHandler")
|
||||
public class GetGameConnectHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameConnectHandler.class);
|
||||
|
||||
private final BasicMapper mapper;
|
||||
private final String ALLNET_HOST;
|
||||
private final String ALLNET_PORT;
|
||||
private final String SERVER_PORT;
|
||||
|
||||
@Autowired
|
||||
public GetGameConnectHandler(BasicMapper mapper, @Value("${allnet.server.host:}") String ALLNET_HOST,
|
||||
@Value("${allnet.server.port:}") String ALLNET_PORT, @Value("${server.port:}") String SERVER_PORT) {
|
||||
this.mapper = mapper;
|
||||
this.ALLNET_HOST = ALLNET_HOST;
|
||||
this.ALLNET_PORT = ALLNET_PORT;
|
||||
this.SERVER_PORT = SERVER_PORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
int type = ((Number) request.get("type")).intValue(); // Allnet enabled or not
|
||||
long version = ((Number) request.get("version")).longValue(); // Rom version
|
||||
KeychipSession session = TokenChecker.Companion.getCurrentSession();
|
||||
|
||||
// Unless ip and port is explicitly overridden, use the guessed ip and port as same as AllNet Controller does.
|
||||
String localAddr;
|
||||
try {
|
||||
localAddr = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
// If above didn't work then how did this run? I really don't know.
|
||||
localAddr = "localhost";
|
||||
}
|
||||
|
||||
String addr = ALLNET_HOST.equals("") ? localAddr : ALLNET_HOST;
|
||||
String port = ALLNET_PORT.equals("") ? SERVER_PORT : ALLNET_PORT;
|
||||
|
||||
String base = session == null ? "/g" : "/gs/" + session.getToken();
|
||||
List<GameConnect> gameConnectList = new ArrayList<>();
|
||||
GameConnect chuni = new GameConnect(0, 1, "http://" + addr + ":" + port + base + "/chu3/" + version + "/");
|
||||
GameConnect mai = new GameConnect(1, 1, "http://" + addr + ":" + port + base + "/mai2/");
|
||||
GameConnect ongeki = new GameConnect(2, 1, "http://" + addr + ":" + port + base + "/ongeki/");
|
||||
gameConnectList.add(chuni);
|
||||
gameConnectList.add(mai);
|
||||
gameConnectList.add(ongeki);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("length", gameConnectList.size());
|
||||
resultMap.put("gameConnectList", gameConnectList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.cardmaker.model.response.GetGameSettingResp;
|
||||
import icu.samnyan.aqua.sega.cardmaker.model.response.data.GameSetting;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component("CardMakerGetGameSettingHandler")
|
||||
public class GetGameSettingHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameSettingHandler.class);
|
||||
|
||||
private final BasicMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameSettingHandler(BasicMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String handle(@NotNull Map<String, ?> request) throws JsonProcessingException {
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
|
||||
LocalDateTime rebootStartTime = LocalDateTime.now().minusHours(3);
|
||||
LocalDateTime rebootEndTime = LocalDateTime.now().minusHours(2);
|
||||
|
||||
GameSetting gameSetting = new GameSetting(
|
||||
"1.35.0",
|
||||
"1.32.0",
|
||||
"1.30.0",
|
||||
"1.45.0",
|
||||
false,
|
||||
10,
|
||||
rebootStartTime.format(formatter),
|
||||
rebootEndTime.format(formatter),
|
||||
false,
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
false);
|
||||
|
||||
GetGameSettingResp resp = new GetGameSettingResp(
|
||||
gameSetting,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
String json = mapper.write(resp);
|
||||
|
||||
logger.info("Response: {}", json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.model.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class CodeResp {
|
||||
private int returnCode;
|
||||
private String apiName;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.model.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import icu.samnyan.aqua.sega.cardmaker.model.response.data.GameSetting;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GetGameSettingResp {
|
||||
private GameSetting gameSetting;
|
||||
@JsonProperty("isDumpUpload")
|
||||
private boolean isDumpUpload;
|
||||
@JsonProperty("isAou")
|
||||
private boolean isAou;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.model.response.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameConnect {
|
||||
private int modelKind; // 0: chunithm, 1: maimai, 2: ongeki
|
||||
private int type; // 0: LAN, 1: WAN
|
||||
private String titleUri;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package icu.samnyan.aqua.sega.cardmaker.model.response.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameSetting {
|
||||
private String dataVersion;
|
||||
private String ongekiCmVersion;
|
||||
private String chuniCmVersion;
|
||||
private String maimaiCmVersion;
|
||||
@JsonProperty("isMaintenance")
|
||||
private boolean isMaintenance;
|
||||
private int requestInterval;
|
||||
private String rebootStartTime;
|
||||
private String rebootEndTime;
|
||||
@JsonProperty("isBackgroundDistribute")
|
||||
private boolean isBackgroundDistribute;
|
||||
private int maxCountCharacter;
|
||||
private int maxCountItem;
|
||||
private int maxCountCard;
|
||||
private boolean watermark;
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.controller;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.chunithm.handler.impl.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/g/chu2/{ROM_VERSION}/{CLIENT_ID}/ChuniServlet")
|
||||
@AllArgsConstructor
|
||||
public class ChuniServletController {
|
||||
|
||||
private final GameLoginHandler gameLoginHandler;
|
||||
private final GameLogoutHandler gameLogoutHandler;
|
||||
private final GetGameChargeHandler getGameChargeHandler;
|
||||
private final GetGameEventHandler getGameEventHandler;
|
||||
private final GetGameIdlistHandler getGameIdlistHandler;
|
||||
private final GetGameMessageHandler getGameMessageHandler;
|
||||
private final GetGameRankingHandler getGameRankingHandler;
|
||||
private final GetGameSaleHandler getGameSaleHandler;
|
||||
private final GetGameSettingHandler getGameSettingHandler;
|
||||
private final GetTeamCourseRuleHandler getTeamCourseRuleHandler;
|
||||
private final GetTeamCourseSettingHandler getTeamCourseSettingHandler;
|
||||
private final GetUserActivityHandler getUserActivityHandler;
|
||||
private final GetUserCharacterHandler getUserCharacterHandler;
|
||||
private final GetUserChargeHandler getUserChargeHandler;
|
||||
private final GetUserCourseHandler getUserCourseHandler;
|
||||
private final GetUserDataExHandler getUserDataExHandler;
|
||||
private final GetUserDataHandler getUserDataHandler;
|
||||
private final GetUserDuelHandler getUserDuelHandler;
|
||||
private final GetUserFavoriteItemHandler getUserFavoriteItemHandler;
|
||||
private final GetUserFavoriteMusicHandler getUserFavoriteMusicHandler;
|
||||
private final GetUserItemHandler getUserItemHandler;
|
||||
private final GetUserLoginBonusHandler getUserLoginBonusHandler;
|
||||
private final GetUserMapHandler getUserMapHandler;
|
||||
private final GetUserMusicHandler getUserMusicHandler;
|
||||
private final GetUserOptionExHandler getUserOptionExHandler;
|
||||
private final GetUserOptionHandler getUserOptionHandler;
|
||||
private final GetUserPreviewHandler getUserPreviewHandler;
|
||||
private final GetUserRecentRatingHandler getUserRecentRatingHandler;
|
||||
private final GetUserRegionHandler getUserRegionHandler;
|
||||
private final GetUserRivalDataHandler getUserRivalDataHandler;
|
||||
private final GetUserRivalMusicHandler getUserRivalMusicHandler;
|
||||
private final GetUserTeamHandler getUserTeamHandler;
|
||||
private final UpsertClientSettingHandler upsertClientSettingHandler;
|
||||
private final UpsertUserAllHandler upsertUserAllHandler;
|
||||
private final UpsertUserChargelogHandler upsertUserChargelogHandler;
|
||||
|
||||
|
||||
@PostMapping("GameLoginApi")
|
||||
String gameLogin(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return gameLoginHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GameLogoutApi")
|
||||
String gameLogout(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return gameLogoutHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameChargeApi")
|
||||
String getGameCharge(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameChargeHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameEventApi")
|
||||
String getGameEvent(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameEventHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameIdlistApi")
|
||||
String getGameIdList(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameIdlistHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameMessageApi")
|
||||
String getGameMessage(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameMessageHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameRankingApi")
|
||||
String getGameRanking(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameRankingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetGameSaleApi")
|
||||
String getGameSale(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameSaleHandler.handle(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* The game start up request
|
||||
*
|
||||
* @return json of GameSetting object
|
||||
*/
|
||||
@PostMapping("GetGameSettingApi")
|
||||
String getGameSetting(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getGameSettingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetTeamCourseRuleApi")
|
||||
String getTeamCourseRule(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getTeamCourseRuleHandler.handle(request);
|
||||
}
|
||||
@PostMapping("GetTeamCourseSettingApi")
|
||||
String getTeamCourseSetting(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getTeamCourseSettingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserActivityApi")
|
||||
String getUserActivity(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserActivityHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserCharacterApi")
|
||||
String getUserCharacter(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserCharacterHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserChargeApi")
|
||||
String getUserCharge(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserChargeHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserCourseApi")
|
||||
String getUserCourse(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserCourseHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserDataApi")
|
||||
String getUserData(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserDataHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserDataExApi")
|
||||
String getUserDataEx(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserDataExHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserDuelApi")
|
||||
String getUserDuel(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserDuelHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserFavoriteItemApi")
|
||||
String getUserFavoriteItem(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserFavoriteItemHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserFavoriteMusicApi")
|
||||
public String getUserFavoriteMusic(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserFavoriteMusicHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserItemApi")
|
||||
String getUserItem(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserItemHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserLoginBonusApi")
|
||||
String getUserLoginBonus(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserLoginBonusHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserMapApi")
|
||||
String getUserMap(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserMapHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserMusicApi")
|
||||
String getUserMusic(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserMusicHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserOptionApi")
|
||||
String getUserOption(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserOptionHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserOptionExApi")
|
||||
String getUserOptionEx(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserOptionExHandler.handle(request);
|
||||
}
|
||||
|
||||
// Call when login. Return null if no profile exist
|
||||
@PostMapping("GetUserPreviewApi")
|
||||
String getUserPreview(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserPreviewHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserRecentRatingApi")
|
||||
String getUserRecentRating(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserRecentRatingHandler.handle(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* For older version chunithm
|
||||
*/
|
||||
@PostMapping("GetUserRecentPlayerApi")
|
||||
String getUserRecentPlayerApi(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserRecentRatingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserRegionApi")
|
||||
String getUserRegion(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserRegionHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserRivalDataApi")
|
||||
String getUserRivalData(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserRivalDataHandler.handle(request);
|
||||
}
|
||||
@PostMapping("GetUserRivalMusicApi")
|
||||
String getUserRivalMusic(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserRivalMusicHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("GetUserTeamApi")
|
||||
String getUserTeam(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return getUserTeamHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientBookkeepingApi")
|
||||
String upsertClientBookkeeping(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":\"1\"}";
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientDevelopApi")
|
||||
String upsertClientDevelop(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":\"1\"}";
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientErrorApi")
|
||||
String upsertClientError(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":\"1\"}";
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientSettingApi")
|
||||
String upsertClientSetting(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return upsertClientSettingHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("UpsertClientTestmodeApi")
|
||||
String upsertClientTestmode(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":\"1\"}";
|
||||
}
|
||||
|
||||
@PostMapping("UpsertUserAllApi")
|
||||
String upsertUserAll(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return upsertUserAllHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("UpsertUserChargelogApi")
|
||||
String upsertUserChargelog(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
|
||||
return upsertUserChargelogHandler.handle(request);
|
||||
}
|
||||
|
||||
@PostMapping("Ping")
|
||||
String ping(@ModelAttribute Map<String, Object> request) {
|
||||
return "{\"returnCode\":\"1\"}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import static icu.samnyan.aqua.sega.util.AquaConst.*;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestControllerAdvice(basePackages = "icu.samnyan.aqua.sega.chunithm")
|
||||
public class ChuniServletControllerAdvice {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ChuniServletControllerAdvice.class);
|
||||
|
||||
|
||||
/**
|
||||
* Get the map object from json string
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
*/
|
||||
@ModelAttribute
|
||||
public Map<String, Object> preHandle(HttpServletRequest request) throws IOException {
|
||||
var pathVar = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||
byte[] src = request.getInputStream().readAllBytes();
|
||||
String outputString = new String(src, StandardCharsets.UTF_8).trim();
|
||||
logger.info("Request " + request.getRequestURI() + ": " + outputString);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
Map<String, Object> result = mapper.readValue(outputString, new TypeReference<>() {
|
||||
});
|
||||
result.put(SERIAL_KEY, pathVar.getOrDefault(SERIAL_KEY, DEFAULT_KEYCHIP_ID));
|
||||
result.put(VERSION_KEY, pathVar.getOrDefault(VERSION_KEY, CHUNI_DEFAULT_VERSION));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.Character;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameCharacterRepository")
|
||||
public interface GameCharacterRepository extends JpaRepository<Character, Long> {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.CharacterSkill;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameCharacterSkillRepository")
|
||||
public interface GameCharacterSkillRepository extends JpaRepository<CharacterSkill, Long> {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameCharge;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameChargeRepository")
|
||||
public interface GameChargeRepository extends JpaRepository<GameCharge, Long> {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameEvent;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameEventRepository")
|
||||
public interface GameEventRepository extends JpaRepository<GameEvent, Integer> {
|
||||
|
||||
List<GameEvent> findByEnable(boolean enable);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameMessage;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameMessageRepository")
|
||||
public interface GameMessageRepository extends JpaRepository<GameMessage, Integer> {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.gamedata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.Music;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniGameMusicRepository")
|
||||
public interface GameMusicRepository extends JpaRepository<Music, Long> {
|
||||
|
||||
Optional<Music> findByMusicId(int musicId);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserActivity;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserActivityRepository extends JpaRepository<UserActivity, Long> {
|
||||
|
||||
Optional<UserActivity> findTopByUserAndActivityIdAndKindOrderByIdDesc(UserData user, int activityId, int kind);
|
||||
|
||||
List<UserActivity> findAllByUser_Card_ExtIdAndKindOrderBySortNumberDesc(Long extId, int kind);
|
||||
|
||||
List<UserActivity> findAllByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCharacter;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserCharacterRepository extends JpaRepository<UserCharacter, Long> {
|
||||
|
||||
Page<UserCharacter> findByUser_Card_ExtId(Long extId, Pageable pageable);
|
||||
|
||||
List<UserCharacter> findByUser_Card_ExtId(Long extId);
|
||||
|
||||
Optional<UserCharacter> findTopByUserAndCharacterIdOrderByIdDesc(UserData user, int characterId);
|
||||
|
||||
Optional<UserCharacter> findByUser_Card_ExtIdAndCharacterId(Long extId, int characterId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCharge;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserChargeRepository extends JpaRepository<UserCharge, Long> {
|
||||
List<UserCharge> findByUser_Card_ExtId(Long extId);
|
||||
|
||||
Optional<UserCharge> findByUserAndChargeId(UserData extId, int chargeId);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCourse;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserCourseRepository extends JpaRepository<UserCourse, Long> {
|
||||
Optional<UserCourse> findTopByUserAndCourseIdOrderByIdDesc(UserData user, int courseId);
|
||||
|
||||
Page<UserCourse> findByUser_Card_ExtId(Long extId, Pageable page);
|
||||
|
||||
List<UserCourse> findByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserDataEx;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserDataExRepository extends JpaRepository<UserDataEx, Long> {
|
||||
|
||||
Optional<UserDataEx> findByUser(UserData user);
|
||||
|
||||
Optional<UserDataEx> findByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.general.model.Card;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserDataRepository extends JpaRepository<UserData, Long> {
|
||||
|
||||
Optional<UserData> findByCard(Card card);
|
||||
|
||||
Optional<UserData> findByCard_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserDuel;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserDuelRepository extends JpaRepository<UserDuel, Long> {
|
||||
|
||||
Optional<UserDuel> findTopByUserAndDuelIdOrderByIdDesc(UserData user, int duelId);
|
||||
|
||||
List<UserDuel> findByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserGameOptionEx;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserGameOptionExRepository extends JpaRepository<UserGameOptionEx, Long> {
|
||||
Optional<UserGameOptionEx> findByUser(UserData user);
|
||||
|
||||
Optional<UserGameOptionEx> findByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserGameOption;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserGameOptionRepository extends JpaRepository<UserGameOption, Long> {
|
||||
|
||||
Optional<UserGameOption> findByUser(UserData user);
|
||||
|
||||
Optional<UserGameOption> findByUser_Card_ExtId(Long extId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserGeneralData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository("ChuniUserGeneralDataRepository")
|
||||
public interface UserGeneralDataRepository extends JpaRepository<UserGeneralData, Long> {
|
||||
|
||||
Optional<UserGeneralData> findByUserAndPropertyKey(UserData user, String key);
|
||||
|
||||
Optional<UserGeneralData> findByUser_Card_ExtIdAndPropertyKey(Long extId, String key);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserItem;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserItemRepository extends JpaRepository<UserItem, Long> {
|
||||
|
||||
Optional<UserItem> findTopByUserAndItemIdAndItemKindOrderByIdDesc(UserData user, int itemId, int itemKind);
|
||||
|
||||
Page<UserItem> findAllByUser_Card_ExtIdAndItemKind(Long extId, int itemKind, Pageable pageable);
|
||||
|
||||
List<UserItem> findAllByUser_Card_ExtId(Long extId);
|
||||
|
||||
Page<UserItem> findByUser_Card_ExtId(Long extId, Pageable pageable);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMap;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserMapRepository extends JpaRepository<UserMap, Long> {
|
||||
List<UserMap> findAllByUser(UserData user);
|
||||
|
||||
List<UserMap> findAllByUser_Card_ExtId(Long extId);
|
||||
|
||||
Optional<UserMap> findTopByUserAndMapIdOrderByIdDesc(UserData user, int mapId);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMusicDetail;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserMusicDetailRepository extends JpaRepository<UserMusicDetail, Long> {
|
||||
|
||||
Optional<UserMusicDetail> findTopByUserAndMusicIdAndLevelOrderByIdDesc(UserData user, int musicId, int level);
|
||||
|
||||
List<UserMusicDetail> findByUser_Card_ExtId(Long extId);
|
||||
|
||||
List<UserMusicDetail> findByUser_Card_ExtIdAndMusicId(Long extId, int musicId);
|
||||
|
||||
Page<UserMusicDetail> findByUser_Card_ExtId(Long extId, Pageable page);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.dao.userdata;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.GameRanking;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserPlaylog;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Repository
|
||||
public interface UserPlaylogRepository extends JpaRepository<UserPlaylog, Long> {
|
||||
List<UserPlaylog> findByUser_Card_ExtIdAndLevelNot(Long extId, int levelNot, Pageable page);
|
||||
|
||||
Page<UserPlaylog> findByUser_Card_ExtId(Long extId, Pageable page);
|
||||
|
||||
List<UserPlaylog> findByUser_Card_ExtIdAndMusicIdAndLevel(Long extId, int musicId, int level);
|
||||
|
||||
List<UserPlaylog> findByUser_Card_ExtId(Long extId);
|
||||
|
||||
@Query("SELECT NEW icu.samnyan.aqua.sega.chunithm.model.response.data.GameRanking(c.musicId, COUNT(c.musicId)) FROM ChuniUserPlaylog c WHERE NOT c.level = 4 GROUP BY c.musicId ORDER BY COUNT(c.musicId) DESC")
|
||||
Page<GameRanking> findGameRankingByPlaylog(Pageable page);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.CodeResp;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GameLoginHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GameLoginHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserDataService userDataService;
|
||||
|
||||
public GameLoginHandler(StringMapper mapper, UserDataService userDataService) {
|
||||
this.mapper = mapper;
|
||||
this.userDataService = userDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
Optional<UserData> userDataOptional = userDataService.getUserByExtId(userId);
|
||||
userDataOptional.ifPresent(userDataService::updateLoginTime);
|
||||
|
||||
String json = mapper.write(new CodeResp(1));
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.CodeResp;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GameLogoutHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GameLogoutHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
public GameLogoutHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
|
||||
String json = mapper.write(new CodeResp(1));
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.chunithm.dao.gamedata.GameChargeRepository;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameCharge;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameChargeHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameChargeHandler.class);
|
||||
private final GameChargeRepository gameChargeRepository;
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameChargeHandler(GameChargeRepository gameChargeRepository, StringMapper mapper) {
|
||||
this.gameChargeRepository = gameChargeRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
|
||||
List<GameCharge> gameChargeList = gameChargeRepository.findAll();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("length", gameChargeList.size());
|
||||
resultMap.put("gameChargeList", gameChargeList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.chunithm.dao.gamedata.GameEventRepository;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameEvent;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameEventHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameEventHandler.class);
|
||||
|
||||
private final GameEventRepository gameEventRepository;
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameEventHandler(GameEventRepository gameEventRepository, StringMapper mapper) {
|
||||
this.gameEventRepository = gameEventRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String type = (String) request.get("type");
|
||||
|
||||
List<GameEvent> gameEventList = gameEventRepository.findByEnable(true);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("type", type);
|
||||
resultMap.put("length", gameEventList.size());
|
||||
resultMap.put("gameEventList", gameEventList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameIdlistHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameIdlistHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameIdlistHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String type = (String) request.get("type");
|
||||
|
||||
List<Object> gameIdlistList = new ArrayList<>();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("type", type);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("gameIdlistList", gameIdlistList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.chunithm.dao.gamedata.GameMessageRepository;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.gamedata.GameMessage;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameMessageHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameMessageHandler.class);
|
||||
|
||||
private final GameMessageRepository gameMessageRepository;
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameMessageHandler(GameMessageRepository gameMessageRepository, StringMapper mapper) {
|
||||
this.gameMessageRepository = gameMessageRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String type = (String) request.get("type");
|
||||
|
||||
List<GameMessage> gameMessageList = gameMessageRepository.findAll();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("type", type);
|
||||
resultMap.put("length", gameMessageList.size());
|
||||
resultMap.put("gameMessageList", gameMessageList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import icu.samnyan.aqua.sega.chunithm.dao.userdata.UserPlaylogRepository;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.GameRanking;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameRankingHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameRankingHandler.class);
|
||||
|
||||
private final UserPlaylogRepository userPlaylogRepository;
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameRankingHandler(StringMapper mapper, UserPlaylogRepository userPlaylogRepository) {
|
||||
this.userPlaylogRepository = userPlaylogRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String type = (String) request.get("type");
|
||||
|
||||
Page<GameRanking> rankingPage = userPlaylogRepository.findGameRankingByPlaylog(PageRequest.of(0, 10));
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("type", type);
|
||||
resultMap.put("gameRankingList", rankingPage.getContent());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.GameSale;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameSaleHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameSaleHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameSaleHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String type = (String) request.get("type");
|
||||
|
||||
List<GameSale> gameSaleList = new ArrayList<>();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("type", type);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("gameSaleList", gameSaleList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.GetGameSettingResp;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.GameSetting;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetGameSettingHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetGameSettingHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetGameSettingHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
|
||||
// Fixed reboot time triggers chunithm maintenance lockout, so let's try minime method which sets it dynamically
|
||||
// Special thanks to skogaby
|
||||
|
||||
// Hardcode so that the reboot time always started 3 hours ago and ended 2 hours ago
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
|
||||
LocalDateTime rebootStartTime = LocalDateTime.now().minusHours(3);
|
||||
LocalDateTime rebootEndTime = LocalDateTime.now().minusHours(2);
|
||||
|
||||
GameSetting gameSetting = new GameSetting(
|
||||
1,
|
||||
false,
|
||||
10,
|
||||
rebootStartTime.format(formatter),
|
||||
rebootEndTime.format(formatter),
|
||||
false,
|
||||
300,
|
||||
300,
|
||||
300);
|
||||
|
||||
GetGameSettingResp resp = new GetGameSettingResp(
|
||||
gameSetting,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
String json = mapper.write(resp);
|
||||
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.CodeResp;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.GameSale;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
public class GetTeamCourseRuleHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetTeamCourseRuleHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
|
||||
public GetTeamCourseRuleHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("nextIndex", 0);
|
||||
resultMap.put("teamCourseRuleList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetTeamCourseSettingHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetTeamCourseSettingHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
|
||||
public GetTeamCourseSettingHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("nextIndex", 0);
|
||||
resultMap.put("teamCourseSettingList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserActivity;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserActivityService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserActivityHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserActivityHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserActivityService userActivityService;
|
||||
|
||||
@Autowired
|
||||
public GetUserActivityHandler(StringMapper mapper, UserActivityService userActivityService) {
|
||||
this.mapper = mapper;
|
||||
this.userActivityService = userActivityService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
String kind = (String) request.get("kind");
|
||||
|
||||
List<UserActivity> userActivityList = userActivityService.getAllByUserIdAndKind(userId, kind);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userActivityList.size());
|
||||
resultMap.put("kind", kind);
|
||||
resultMap.put("userActivityList", userActivityList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCharacter;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserCharacterService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle getUserCharacter request
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserCharacterHandler implements BaseHandler {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserCharacterHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserCharacterService userCharacterService;
|
||||
|
||||
|
||||
@Autowired
|
||||
public GetUserCharacterHandler(StringMapper mapper, UserCharacterService userCharacterService) {
|
||||
this.mapper = mapper;
|
||||
this.userCharacterService = userCharacterService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
int nextIndex = Integer.parseInt((String) request.get("nextIndex"));
|
||||
int maxCount = Integer.parseInt((String) request.get("maxCount"));
|
||||
|
||||
int pageNum = nextIndex / maxCount;
|
||||
|
||||
Page<UserCharacter> dbPage = userCharacterService.getByUserId(userId, pageNum, maxCount);
|
||||
|
||||
long currentIndex = maxCount * pageNum + dbPage.getNumberOfElements();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", dbPage.getNumberOfElements());
|
||||
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : currentIndex);
|
||||
resultMap.put("userCharacterList", dbPage.getContent());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCharge;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserChargeService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserChargeHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserChargeHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserChargeService userChargeService;
|
||||
|
||||
@Autowired
|
||||
public GetUserChargeHandler(StringMapper mapper, UserChargeService userChargeService) {
|
||||
this.mapper = mapper;
|
||||
this.userChargeService = userChargeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
List<UserCharge> userChargeList = userChargeService.getByUserId(userId);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userChargeList.size());
|
||||
resultMap.put("userChargeList", userChargeList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCourse;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserCourseService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle GetUserCourse request
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserCourseHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserCourseHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserCourseService userCourseService;
|
||||
|
||||
@Autowired
|
||||
public GetUserCourseHandler(StringMapper mapper, UserCourseService userCourseService) {
|
||||
this.mapper = mapper;
|
||||
this.userCourseService = userCourseService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
|
||||
if(request.containsKey("nextIndex")) {
|
||||
int nextIndex = Integer.parseInt((String) request.get("nextIndex"));
|
||||
int maxCount = Integer.parseInt((String) request.get("maxCount"));
|
||||
|
||||
int pageNum = nextIndex / maxCount;
|
||||
|
||||
Page<UserCourse> dbPage = userCourseService.getByUserId(userId, pageNum, maxCount);
|
||||
|
||||
long currentIndex = maxCount * pageNum + dbPage.getNumberOfElements();
|
||||
|
||||
resultMap.put("length", dbPage.getNumberOfElements());
|
||||
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : currentIndex);
|
||||
resultMap.put("userCourseList", dbPage.getContent());
|
||||
} else {
|
||||
List<UserCourse> courseList = userCourseService.getByUserId(userId);
|
||||
resultMap.put("length", courseList.size());
|
||||
resultMap.put("userCourseList", courseList);
|
||||
}
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserDataEx;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDataExService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserDataExHandler implements BaseHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserDataExHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserDataExService userDataExService;
|
||||
|
||||
@Autowired
|
||||
public GetUserDataExHandler(StringMapper mapper, UserDataExService userDataExService) {
|
||||
this.mapper = mapper;
|
||||
this.userDataExService = userDataExService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
Optional<UserDataEx> userDataExOptional = userDataExService.getByExtId(userId);
|
||||
|
||||
if (userDataExOptional.isPresent()) {
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("userDataEx", userDataExOptional.get());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
|
||||
import icu.samnyan.aqua.sega.general.service.ClientSettingService;
|
||||
import icu.samnyan.aqua.sega.util.VersionUtil;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static icu.samnyan.aqua.sega.util.AquaConst.SERIAL_KEY;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserDataHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserDataHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final ClientSettingService clientSettingService;
|
||||
|
||||
private final UserDataService userDataService;
|
||||
|
||||
@Autowired
|
||||
public GetUserDataHandler(StringMapper mapper,
|
||||
ClientSettingService clientSettingService, UserDataService userDataService
|
||||
) {
|
||||
this.mapper = mapper;
|
||||
this.clientSettingService = clientSettingService;
|
||||
this.userDataService = userDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
Optional<UserData> userDataOptional = userDataService.getUserByExtId(userId);
|
||||
|
||||
if (userDataOptional.isPresent()) {
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
UserData user = userDataOptional.get();
|
||||
|
||||
var vo = clientSettingService.getSetting((String) request.get(SERIAL_KEY));
|
||||
if (vo.isPresent()) {
|
||||
var version = vo.get();
|
||||
user.setLastRomVersion(VersionUtil.getTargetVersion(user.getLastRomVersion(), version.getRomVersion()));
|
||||
user.setLastDataVersion(VersionUtil.getTargetVersion(user.getLastDataVersion(), version.getDataVersion()));
|
||||
}
|
||||
|
||||
resultMap.put("userData", user);
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserDuel;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDuelService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle GetUserDuel request
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserDuelHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserDuelHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserDuelService userDuelService;
|
||||
|
||||
@Autowired
|
||||
public GetUserDuelHandler(StringMapper mapper, UserDuelService userDuelService) {
|
||||
this.mapper = mapper;
|
||||
this.userDuelService = userDuelService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
String duelId = (String) request.get("duelId");
|
||||
String isAllDuel = (String) request.get("isAllDuel");
|
||||
|
||||
// TODO:
|
||||
|
||||
List<UserDuel> userDuelList = userDuelService.getByUserId(userId);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userDuelList.size());
|
||||
resultMap.put("userDuelList", userDuelList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle GetUserFavoriteItem request
|
||||
* @author yueou (yueou.xu@gmail.com)
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class GetUserFavoriteItemHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserFavoriteItemHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetUserFavoriteItemHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
String kind = (String) request.get("kind");
|
||||
|
||||
// TODO:
|
||||
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("kind", kind);
|
||||
resultMap.put("nextIndex", -1);
|
||||
resultMap.put("userFavoriteItemList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserDuel;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserDuelService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle GetUserDuel request
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserFavoriteMusicHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserFavoriteMusicHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetUserFavoriteMusicHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
// TODO:
|
||||
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("userFavoriteMusicList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserItem;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserItemService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handler for getting user item.
|
||||
* This get call before profile create.
|
||||
*
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserItemHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserItemHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserItemService userItemService;
|
||||
|
||||
public GetUserItemHandler(StringMapper mapper, UserItemService userItemService) {
|
||||
this.mapper = mapper;
|
||||
this.userItemService = userItemService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
Long nextIndexVal = Long.parseLong((String) request.get("nextIndex"));
|
||||
int maxCount = Integer.parseInt((String) request.get("maxCount"));
|
||||
|
||||
Long mul = 10000000000L;
|
||||
|
||||
int kind = (int) (nextIndexVal / mul);
|
||||
int nextIndex = (int) (nextIndexVal % mul);
|
||||
int pageNum = nextIndex / maxCount;
|
||||
|
||||
Page<UserItem> userItemPage = userItemService.getByUserAndItemKind(userId, kind, pageNum, maxCount);
|
||||
|
||||
List<UserItem> userItemList = userItemPage.getContent();
|
||||
|
||||
long currentIndex = kind * mul + maxCount * pageNum + userItemPage.getNumberOfElements();
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userItemPage.getNumberOfElements());
|
||||
resultMap.put("nextIndex", userItemPage.getNumberOfElements() < maxCount ? -1 : currentIndex);
|
||||
resultMap.put("itemKind", kind);
|
||||
resultMap.put("userItemList", userItemList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetUserLoginBonusHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserLoginBonusHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public GetUserLoginBonusHandler(StringMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
// TODO:
|
||||
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", 0);
|
||||
resultMap.put("userLoginBonusList", List.of());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMap;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserMapService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handle GetUserMap request
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserMapHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserItemHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserMapService userMapService;
|
||||
|
||||
@Autowired
|
||||
public GetUserMapHandler(StringMapper mapper, UserMapService userMapService) {
|
||||
this.mapper = mapper;
|
||||
this.userMapService = userMapService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
|
||||
List<UserMap> userMapList = userMapService.getByUserId(userId);
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userMapList.size());
|
||||
resultMap.put("userMapList", userMapList);
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package icu.samnyan.aqua.sega.chunithm.handler.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.response.data.UserMusicListItem;
|
||||
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMusicDetail;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.GameMusicService;
|
||||
import icu.samnyan.aqua.sega.chunithm.service.UserMusicDetailService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
|
||||
import icu.samnyan.aqua.spring.data.OffsetPageRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Response:
|
||||
*
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component
|
||||
public class GetUserMusicHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GetUserMusicHandler.class);
|
||||
|
||||
private final StringMapper mapper;
|
||||
|
||||
private final UserMusicDetailService userMusicDetailService;
|
||||
|
||||
private final GameMusicService gameMusicService;
|
||||
|
||||
@Autowired
|
||||
public GetUserMusicHandler(StringMapper mapper, UserMusicDetailService userMusicDetailService, GameMusicService gameMusicService) {
|
||||
this.mapper = mapper;
|
||||
this.userMusicDetailService = userMusicDetailService;
|
||||
this.gameMusicService = gameMusicService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = (String) request.get("userId");
|
||||
int currentIndex = Integer.parseInt((String) request.get("nextIndex"));
|
||||
int maxCount = Integer.parseInt((String) request.get("maxCount"));
|
||||
if(currentIndex < 0) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
Page<UserMusicDetail> dbPage = userMusicDetailService
|
||||
.getByUserId(userId, OffsetPageRequest.of(currentIndex, maxCount, Sort.by("musicId")));
|
||||
|
||||
|
||||
// Convert to result format
|
||||
// Result Map
|
||||
Map<Integer, UserMusicListItem> userMusicMap = new LinkedHashMap<>();
|
||||
|
||||
dbPage.getContent().forEach(userMusicDetail -> {
|
||||
UserMusicListItem list;
|
||||
if (userMusicMap.containsKey(userMusicDetail.getMusicId())) {
|
||||
list = userMusicMap.get(userMusicDetail.getMusicId());
|
||||
} else {
|
||||
list = new UserMusicListItem(0, new ArrayList<>());
|
||||
userMusicMap.put(userMusicDetail.getMusicId(), list);
|
||||
}
|
||||
list.getUserMusicDetailList().add(userMusicDetail);
|
||||
list.setLength(list.getUserMusicDetailList().size());
|
||||
});
|
||||
|
||||
// Remove the last music id if the result length is the same as maxCount,
|
||||
// to prevent a music id split across multiple page, which will cause some
|
||||
// problem with the game.
|
||||
int lastListSize = 0;
|
||||
if(dbPage.getNumberOfElements() >= maxCount) {
|
||||
// Get last key
|
||||
int lastMusicId = userMusicMap.keySet().stream().reduce((a, b) -> b).orElseThrow();
|
||||
List<UserMusicDetail> lastList = userMusicMap.get(lastMusicId).getUserMusicDetailList();
|
||||
lastListSize = lastList.size();
|
||||
// Remove last one from map
|
||||
userMusicMap.remove(lastMusicId);
|
||||
}
|
||||
|
||||
long nextIndex = currentIndex + dbPage.getNumberOfElements() - lastListSize;
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("userId", userId);
|
||||
resultMap.put("length", userMusicMap.size());
|
||||
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : nextIndex);
|
||||
resultMap.put("userMusicList", userMusicMap.values());
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user