mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-12 12:17:26 +08:00
[+] Export maimai userdata
This commit is contained in:
@@ -21,26 +21,24 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<div class="fields">
|
||||||
<div class="fields">
|
{#each gameFields as field}
|
||||||
{#each gameFields as field}
|
<div class="field">
|
||||||
<div class="field">
|
{#if field.type === "Boolean"}
|
||||||
{#if field.type === "Boolean"}
|
<div class="bool">
|
||||||
<div class="bool">
|
<input id={field.key} type="checkbox" bind:checked={field.value}
|
||||||
<input id={field.key} type="checkbox" bind:checked={field.value}
|
on:change={() => submitGameOption(field.key, field.value)}/>
|
||||||
on:change={() => submitGameOption(field.key, field.value)}/>
|
<label for={field.key}>
|
||||||
<label for={field.key}>
|
<span class="name">{ts(`settings.fields.${field.key}.name`)}</span>
|
||||||
<span class="name">{ts(`settings.fields.${field.key}.name`)}</span>
|
<span class="desc">{ts(`settings.fields.${field.key}.desc`)}</span>
|
||||||
<span class="desc">{ts(`settings.fields.${field.key}.desc`)}</span>
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
{/each}
|
||||||
{/each}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<StatusOverlays {error} loading={!gameFields.length && !!submitting}/>
|
<StatusOverlays {error} loading={!gameFields.length && !!submitting}/>
|
||||||
</main>
|
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
.fields
|
.fields
|
||||||
|
|||||||
@@ -34,34 +34,53 @@
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportData() {
|
||||||
|
submitting = "export"
|
||||||
|
GAME.export('mai2')
|
||||||
|
.then(data => download(JSON.stringify(data), `AquaDX_maimai2_export_${values[0]}.json`))
|
||||||
|
.catch(e => error = e.message)
|
||||||
|
.finally(() => submitting = "")
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(data: string, filename: string) {
|
||||||
|
const blob = new Blob([data]);
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<div class="fields" out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||||
<div class="fields" out:fade={FADE_OUT} in:fade={FADE_IN}>
|
{#each profileFields as [field, name], i (field)}
|
||||||
{#each profileFields as [field, name], i (field)}
|
<div class="field">
|
||||||
<div class="field">
|
<label for={field}>{name}</label>
|
||||||
<label for={field}>{name}</label>
|
<div>
|
||||||
<div>
|
<input id={field} type="text"
|
||||||
<input id={field} type="text"
|
bind:value={values[i]} on:input={() => changed = [...changed, field]}
|
||||||
bind:value={values[i]} on:input={() => changed = [...changed, field]}
|
placeholder={field === 'password' ? t('settings.profile.unchanged') : t('settings.profile.unset')}/>
|
||||||
placeholder={field === 'password' ? t('settings.profile.unchanged') : t('settings.profile.unset')}/>
|
{#if changed.includes(field) && values[i]}
|
||||||
{#if changed.includes(field) && values[i]}
|
<button transition:slide={{axis: 'x'}} on:click={() => submit(field, values[i])}>
|
||||||
<button transition:slide={{axis: 'x'}} on:click={() => submit(field, values[i])}>
|
{#if submitting === field}
|
||||||
{#if submitting === field}
|
<Icon icon="line-md:loading-twotone-loop"/>
|
||||||
<Icon icon="line-md:loading-twotone-loop"/>
|
{:else}
|
||||||
{:else}
|
{t('settings.profile.save')}
|
||||||
{t('settings.profile.save')}
|
{/if}
|
||||||
{/if}
|
</button>
|
||||||
</button>
|
{/if}
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
</div>
|
||||||
<GameSettingFields game="mai2"/>
|
{/each}
|
||||||
</div>
|
<GameSettingFields game="mai2"/>
|
||||||
|
<button class="exportButton" on:click={exportData}>
|
||||||
|
<Icon icon="bxs:file-export"/>
|
||||||
|
{t('settings.export')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<StatusOverlays {error} loading={!values[0] || !!submitting}/>
|
<StatusOverlays {error} loading={!values[0] || !!submitting}/>
|
||||||
</main>
|
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
.fields
|
.fields
|
||||||
@@ -84,4 +103,10 @@
|
|||||||
|
|
||||||
> input
|
> input
|
||||||
flex: 1
|
flex: 1
|
||||||
|
|
||||||
|
.exportButton
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
gap: 5px
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
import GameSettingFields from "./GameSettingFields.svelte";
|
import GameSettingFields from "./GameSettingFields.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||||
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
<GameSettingFields game="wacca"/>
|
||||||
<GameSettingFields game="wacca"/>
|
</div>
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ export const EN_REF_SETTINGS = {
|
|||||||
'settings.profile.bio': 'Bio',
|
'settings.profile.bio': 'Bio',
|
||||||
'settings.profile.unset': 'Unset',
|
'settings.profile.unset': 'Unset',
|
||||||
'settings.profile.unchanged': 'Unchanged',
|
'settings.profile.unchanged': 'Unchanged',
|
||||||
|
'settings.export': 'Export Player Data',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EN_REF_USERBOX = {
|
export const EN_REF_USERBOX = {
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ const zhSettings: typeof EN_REF_SETTINGS = {
|
|||||||
'settings.profile.bio': '简介',
|
'settings.profile.bio': '简介',
|
||||||
'settings.profile.unset': '未设置',
|
'settings.profile.unset': '未设置',
|
||||||
'settings.profile.unchanged': '未更改',
|
'settings.profile.unchanged': '未更改',
|
||||||
|
'settings.export': '导出玩家数据',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ZH = { ...zhUser, ...zhWelcome, ...zhGeneral,
|
export const ZH = { ...zhUser, ...zhWelcome, ...zhGeneral,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function fetchWithParams(input: URL | RequestInfo, init?: RequestInitWith
|
|||||||
|
|
||||||
const cache: { [index: string]: any } = {}
|
const cache: { [index: string]: any } = {}
|
||||||
|
|
||||||
export async function post(endpoint: string, params: any, init?: RequestInitWithParams): Promise<any> {
|
export async function post(endpoint: string, params: Record<string, any> = {}, init?: RequestInitWithParams): Promise<any> {
|
||||||
// Add token if exists
|
// Add token if exists
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
if (token && !('token' in params)) params = { ...(params ?? {}), token }
|
if (token && !('token' in params)) params = { ...(params ?? {}), token }
|
||||||
@@ -301,6 +301,8 @@ export const GAME = {
|
|||||||
post(`/api/v2/game/${game}/ranking`, { }),
|
post(`/api/v2/game/${game}/ranking`, { }),
|
||||||
changeName: (game: GameName, newName: string): Promise<{ newName: string }> =>
|
changeName: (game: GameName, newName: string): Promise<{ newName: string }> =>
|
||||||
post(`/api/v2/game/${game}/change-name`, { newName }),
|
post(`/api/v2/game/${game}/change-name`, { newName }),
|
||||||
|
export: (game: GameName): Promise<Record<string, any>> =>
|
||||||
|
post(`/api/v2/game/${game}/export`),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DATA = {
|
export const DATA = {
|
||||||
|
|||||||
@@ -108,11 +108,11 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
|||||||
// Check existing data
|
// Check existing data
|
||||||
userDataRepo.findByCard(u.ghostCard)?.also { gu ->
|
userDataRepo.findByCard(u.ghostCard)?.also { gu ->
|
||||||
// Store a backup of the old data
|
// Store a backup of the old data
|
||||||
val fl = "mai2-backup-${u.auId}-${LocalDateTime.now().urlSafeStr()}.json"
|
val fl = "${game}-backup-${u.auId}-${LocalDateTime.now().urlSafeStr()}.json"
|
||||||
(Path(netProps.importBackupPath) / fl).writeText(export(u).toJson())
|
(Path(netProps.importBackupPath) / fl).writeText(export(u).toJson())
|
||||||
|
|
||||||
// Delete the old data (After migration v1000.7, all user-linked entities have ON DELETE CASCADE)
|
// Delete the old data (After migration v1000.7, all user-linked entities have ON DELETE CASCADE)
|
||||||
log.info("Mai2 Import: Deleting old data for user ${u.auId}")
|
log.info("$game Import: Deleting old data for user ${u.auId}")
|
||||||
userDataRepo.delete(gu)
|
userDataRepo.delete(gu)
|
||||||
userDataRepo.flush()
|
userDataRepo.flush()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user