mirror of https://github.com/hykilpikonna/AquaDX
[+] mai2: support adding rival
parent
94ba1f0b09
commit
473f4a4295
|
@ -99,6 +99,7 @@ export interface GenericGameSummary {
|
|||
lastVersion: string
|
||||
ratingComposition: { [key: string]: any }
|
||||
recent: GenericGamePlaylog[]
|
||||
rival?: boolean
|
||||
}
|
||||
|
||||
export interface MusicMeta {
|
||||
|
|
|
@ -24,6 +24,8 @@ export const EN_REF_USER = {
|
|||
'UserHome.RankDetail.Title': 'Achievement Details',
|
||||
'UserHome.RankDetail.Level': 'Level',
|
||||
'UserHome.B50': 'B50',
|
||||
'UserHome.AddRival': "Add to Rival",
|
||||
'UserHome.RemoveRival': "Remove from Rival",
|
||||
}
|
||||
|
||||
export const EN_REF_Welcome = {
|
||||
|
|
|
@ -33,6 +33,8 @@ const zhUser: typeof EN_REF_USER = {
|
|||
'UserHome.RankDetail.Title': '评分详细',
|
||||
'UserHome.RankDetail.Level': "等级",
|
||||
'UserHome.B50': "B50",
|
||||
'UserHome.AddRival': "添加劲敌",
|
||||
'UserHome.RemoveRival': "移除劲敌",
|
||||
}
|
||||
|
||||
const zhWelcome: typeof EN_REF_Welcome = {
|
||||
|
|
|
@ -305,6 +305,8 @@ export const GAME = {
|
|||
post(`/api/v2/game/${game}/export`),
|
||||
import: (game: GameName, data: any): Promise<Record<string, any>> =>
|
||||
post(`/api/v2/game/${game}/import`, {}, { body: JSON.stringify(data) }),
|
||||
setRival: (game: GameName, rivalUserName: string, isAdd: boolean) =>
|
||||
post(`/api/v2/game/${game}/set-rival`, { rivalUserName, isAdd }),
|
||||
}
|
||||
|
||||
export const DATA = {
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
let allMusics: AllMusic
|
||||
let showDetailRank = false
|
||||
let isLoading = false
|
||||
USER.isLoggedIn() && USER.me().then(u => me = u)
|
||||
|
||||
|
||||
|
@ -90,6 +91,13 @@
|
|||
})
|
||||
}).catch((e) => error = e.message);
|
||||
}).catch((e) => { error = e.message; console.error(e) } );
|
||||
|
||||
const setRival = (isAdd: boolean) => {
|
||||
isLoading = true
|
||||
GAME.setRival(game, username, isAdd).then(() => {
|
||||
d!.user.rival = isAdd
|
||||
}).catch(e => error = e.message).finally(() => isLoading = false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<main id="user-home" class="content">
|
||||
|
@ -98,6 +106,11 @@
|
|||
<img use:pfp={d.user.aquaUser} alt="" class="pfp" on:error={pfpNotFound}>
|
||||
<div class="name-box">
|
||||
<h2>{d.user.name}</h2>
|
||||
{#if typeof d.user.rival === 'boolean' && game === 'mai2'}
|
||||
<a class="clickable" on:click={()=>setRival(!d.user.rival)}>
|
||||
{d.user.rival ? t("UserHome.RemoveRival") : t("UserHome.AddRival")}
|
||||
</a>
|
||||
{/if}
|
||||
{#if me && me.username === username}
|
||||
<a class="setting-icon clickable" use:tooltip={t("UserHome.Settings")} href="/settings">
|
||||
<Icon icon="eos-icons:rotating-gear"/>
|
||||
|
@ -267,7 +280,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<StatusOverlays {error} loading={!d} />
|
||||
<StatusOverlays {error} loading={!d || isLoading} />
|
||||
</main>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract class GameApiController<T : IUserData>(name: String, userDataClass: KCl
|
|||
@API("trend")
|
||||
abstract suspend fun trend(@RP username: String): List<TrendOut>
|
||||
@API("user-summary")
|
||||
abstract suspend fun userSummary(@RP username: String): GenericGameSummary
|
||||
abstract suspend fun userSummary(@RP username: String, @RP token: String?): GenericGameSummary
|
||||
|
||||
@API("recent")
|
||||
suspend fun recent(@RP username: String): List<IGenericGamePlaylog> = us.cardByName(username) { card ->
|
||||
|
@ -93,7 +93,7 @@ abstract class GameApiController<T : IUserData>(name: String, userDataClass: KCl
|
|||
}
|
||||
}
|
||||
|
||||
fun genericUserSummary(card: Card, ratingComp: Map<String, String>): GenericGameSummary {
|
||||
fun genericUserSummary(card: Card, ratingComp: Map<String, String>, rival: Boolean? = null): GenericGameSummary {
|
||||
// Summary values: total plays, player rating, server-wide ranking
|
||||
// number of each rank, max combo, number of full combo, number of all perfect
|
||||
val user = userDataRepo.findByCard(card) ?: (404 - "Game data not found")
|
||||
|
@ -138,7 +138,8 @@ abstract class GameApiController<T : IUserData>(name: String, userDataClass: KCl
|
|||
lastVersion = user.lastRomVersion,
|
||||
ratingComposition = ratingComp,
|
||||
recent = plays.sortedBy { it.userPlayDate.toString() }.takeLast(15).reversed(),
|
||||
lastPlayedHost = us.userRepo.findByKeychip(user.lastClientId)?.username
|
||||
lastPlayedHost = us.userRepo.findByKeychip(user.lastClientId)?.username,
|
||||
rival = rival
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,9 @@ data class GenericGameSummary(
|
|||
|
||||
val ratingComposition: Map<String, Any>,
|
||||
|
||||
val recent: List<IGenericGamePlaylog>
|
||||
val recent: List<IGenericGamePlaylog>,
|
||||
|
||||
val rival: Boolean?
|
||||
)
|
||||
|
||||
data class GenericRankingPlayer(
|
||||
|
|
|
@ -29,7 +29,7 @@ class Chusan(
|
|||
"userName" to usernameCheck(SEGA_USERNAME_CAHRS)
|
||||
) }
|
||||
|
||||
override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card ->
|
||||
override suspend fun userSummary(@RP username: Str, @RP token: String?) = us.cardByName(username) { card ->
|
||||
// Summary values: total plays, player rating, server-wide ranking
|
||||
// number of each rank, max combo, number of full combo, number of all perfect
|
||||
val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId)
|
||||
|
@ -41,4 +41,4 @@ class Chusan(
|
|||
|
||||
genericUserSummary(card, ratingComposition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class Maimai2(
|
|||
override val playlogRepo: Mai2UserPlaylogRepo,
|
||||
override val userDataRepo: Mai2UserDataRepo,
|
||||
val repos: Mai2Repos,
|
||||
): GameApiController<Mai2UserDetail>("mai2", Mai2UserDetail::class) {
|
||||
) : GameApiController<Mai2UserDetail>("mai2", Mai2UserDetail::class) {
|
||||
override suspend fun trend(@RP username: Str): List<TrendOut> = us.cardByName(username) { card ->
|
||||
findTrend(playlogRepo.findByUserCardExtId(card.extId)
|
||||
.map { TrendLog(it.playDate, it.afterRating) })
|
||||
|
@ -25,11 +25,13 @@ class Maimai2(
|
|||
|
||||
// Only show > S rank
|
||||
override val shownRanks = mai2Scores.filter { it.first >= 97 * 10000 }
|
||||
override val settableFields: Map<String, (Mai2UserDetail, String) -> Unit> by lazy { mapOf(
|
||||
"userName" to usernameCheck(SEGA_USERNAME_CAHRS),
|
||||
) }
|
||||
override val settableFields: Map<String, (Mai2UserDetail, String) -> Unit> by lazy {
|
||||
mapOf(
|
||||
"userName" to usernameCheck(SEGA_USERNAME_CAHRS),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun userSummary(@RP username: Str) = us.cardByName(username) { card ->
|
||||
override suspend fun userSummary(@RP username: Str, @RP token: String?) = us.cardByName(username) { card ->
|
||||
val extra = repos.userGeneralData.findByUser_Card_ExtId(card.extId)
|
||||
.associate { it.propertyKey to it.propertyValue }
|
||||
|
||||
|
@ -38,7 +40,20 @@ class Maimai2(
|
|||
"best15" to (extra["recent_rating_new"] ?: "")
|
||||
)
|
||||
|
||||
genericUserSummary(card, ratingComposition)
|
||||
// if isLogin than boolean or null
|
||||
// use the type to check user login in frontend
|
||||
val isMyRival = token?.let { t ->
|
||||
us.jwt.auth(t) { u ->
|
||||
if (u.username == username) return@auth null
|
||||
us.cardByName(u.username) { myCard ->
|
||||
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()).map { it.long() }
|
||||
myRival.contains(user.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
genericUserSummary(card, ratingComposition, isMyRival)
|
||||
}
|
||||
|
||||
@API("user-rating")
|
||||
|
@ -100,4 +115,30 @@ class Maimai2(
|
|||
}
|
||||
mapOf("newName" to newNameFull)
|
||||
}
|
||||
|
||||
@PostMapping("set-rival")
|
||||
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).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).orElse(null) ?: (404 - "User not found")
|
||||
propertyKey = "favorite_rival"
|
||||
}
|
||||
val myRivalList = myRival.propertyValue.split(',').toMutableSet()
|
||||
|
||||
if (isAdd && myRivalList.size >= 4) {
|
||||
(400 - "Rival list is full")
|
||||
} else if (isAdd) {
|
||||
myRivalList.add(rivalUser.id.toString())
|
||||
} else {
|
||||
myRivalList.remove(rivalUser.id.toString())
|
||||
}
|
||||
|
||||
myRival.propertyValue = myRivalList.joinToString(",")
|
||||
repos.userGeneralData.save(myRival)
|
||||
}
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class Ongeki(
|
|||
"userName" to usernameCheck(SEGA_USERNAME_CAHRS)
|
||||
) }
|
||||
|
||||
override suspend fun userSummary(username: String) = us.cardByName(username) { card ->
|
||||
override suspend fun userSummary(username: String, token: String?) = us.cardByName(username) { card ->
|
||||
val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId)
|
||||
.associate { it.propertyKey to it.propertyValue }
|
||||
|
||||
|
@ -40,4 +40,4 @@ class Ongeki(
|
|||
|
||||
genericUserSummary(card, ratingComposition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ class Wacca(
|
|||
.map { TrendLog(it.userPlayDate.utc().isoDate(), it.afterRating) })
|
||||
}
|
||||
|
||||
override suspend fun userSummary(@RP username: String) = us.cardByName(username) { card ->
|
||||
override suspend fun userSummary(@RP username: String, @RP token: String?) = us.cardByName(username) { card ->
|
||||
// TODO: Rating composition
|
||||
genericUserSummary(card, mapOf())
|
||||
}
|
||||
|
||||
override val shownRanks: List<Pair<Int, String>> = waccaScores.filter { it.first > 85 * 10000 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,11 +122,13 @@ class Maimai2ServletController(
|
|||
val getUserRivalData = UserReqHandler { req, userId ->
|
||||
val rivalId = parsing { (req["rivalId"] as Number).toLong() }
|
||||
|
||||
// rivalId should store and fetch with the id column of table rather than card_ext_id
|
||||
// or user will be able to get others' ext_id by setting them as rival
|
||||
mapOf(
|
||||
"userId" to userId,
|
||||
"userRivalData" to mapOf(
|
||||
"rivalId" to rivalId,
|
||||
"rivalName" to (repos.userData.findByCardExtId(rivalId)()?.userName ?: "")
|
||||
"rivalName" to (repos.userData.findById(rivalId)()?.userName ?: "")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class GetUserRivalMusicHandler implements BaseHandler {
|
|||
long userId = ((Number) request.get("userId")).longValue();
|
||||
long rivalId = ((Number) request.get("rivalId")).intValue();
|
||||
|
||||
List<Mai2UserMusicDetail> details = userMusicDetailRepository.findByUser_Card_ExtId(rivalId);
|
||||
List<Mai2UserMusicDetail> details = userMusicDetailRepository.findByUserId(rivalId);
|
||||
List<UserRivalMusic> userRivalMusicList = new LinkedList<>();
|
||||
Map<Integer, UserRivalMusic> userRivalMusicMap = new HashMap<>();
|
||||
for (Mai2UserMusicDetail detail : details) {
|
||||
|
|
|
@ -96,6 +96,8 @@ interface Mai2UserMusicDetailRepo : Mai2UserLinked<Mai2UserMusicDetail> {
|
|||
fun findByUserAndMusicIdAndLevel(user: Mai2UserDetail, musicId: Int, level: Int): Optional<Mai2UserMusicDetail>
|
||||
|
||||
fun findByUser_Card_ExtIdAndMusicIdIn(userId: Long, musicId: List<Int>): List<Mai2UserMusicDetail>
|
||||
|
||||
fun findByUserId(userId: Long): List<Mai2UserMusicDetail>
|
||||
}
|
||||
|
||||
interface Mai2UserOptionRepo : Mai2UserLinked<Mai2UserOption>
|
||||
|
|
Loading…
Reference in New Issue