drasl/view/user.tmpl
2025-07-26 12:31:22 -04:00

625 lines
20 KiB
Cheetah

{{ template "layout" . }}
{{ define "title" }}{{ call .T "%s's Account" .TargetUser.Username }}{{ end }}
{{ define "content" }}
{{ template "header" . }}
<h1 style="text-align: center;">{{ .TargetUser.Username }}</h1>
<div style="display: none">
{{ range $player := .TargetUser.Players }}
<form
id="delete-{{ $player.UUID }}"
action="{{ $.App.FrontEndURL }}/web/delete-player"
method="post"
onsubmit="return confirm('{{ call $.T "Are you sure you want to delete the player “%s”? This action is irreversible." $player.Name }}');"
>
<input name="returnUrl" value="{{ $.URL }}" />
<input name="uuid" value="{{ $player.UUID }}" />
</form>
{{ end }}
</div>
<div style="display: none">
{{ range $providerName := .LinkedOIDCProviderNames }}
<form
id="unlink-{{ $providerName }}"
action="{{ $.App.FrontEndURL }}/web/oidc-unlink"
method="post"
onsubmit="return confirm('{{
call $.T "Are you sure you want to unlink your %s account? You will no longer be able to log in to your %s account using %s."
$providerName
$.App.Config.ApplicationName
$providerName
}}');"
>
<input name="returnUrl" value="{{ $.URL }}" />
<input name="userUuid" value="{{ $.TargetUser.UUID }}" />
<input name="providerName" value="{{ $providerName }}" />
</form>
{{ end }}
</div>
<h3>{{ if .AdminView }}{{ call .T
"%s's players" .TargetUser.Username
}}{{ else }}{{ call .T
"Your players"
}}{{ end }}</h3>
{{ if .TargetUser.Players }}
<table>
<thead>
<tr>
<td colspan="2">{{ call .T "Player" }}</td>
<td>{{ call .T "UUID" }}</td>
{{ if or .App.Config.AllowAddingDeletingPlayers .User.IsAdmin }}
<td>{{ call .T "Delete Player" }}</td>
{{ end }}
</tr>
</thead>
<tbody>
{{ range $player := .TargetUser.Players }}
<tr>
<td style="width: 30px">
<div
class="list-profile-picture"
{{ with $playerSkinURL := PlayerSkinURL $player }}
{{ if $playerSkinURL }}
style="background-image: url({{ $playerSkinURL }});"
{{ end }}
{{ end }}
></div>
</td>
<td>
<a href="{{ $.App.FrontEndURL }}/web/player/{{ $player.UUID }}" >{{ $player.Name }}</a>
</td>
<td>{{ $player.UUID }}</td>
{{ if or $.App.Config.AllowAddingDeletingPlayers $.User.IsAdmin }}
<td>
<input type="submit" form="delete-{{ $player.UUID }}" value="{{ call $.T "Delete" }}" />
</td>
{{ end }}
</tr>
{{ end }}
</tbody>
</table>
{{ else }}
{{ call .T "No players yet." }}
{{ end }}
<p>{{ if or (and (not .User.IsAdmin) (not .App.Config.AllowAddingDeletingPlayers)) (eq .MaxPlayerCount 0) }}
{{ if .AdminView }}
{{ call .T
"%s is not allowed to add new players. You can override this limit since you're an admin."
.TargetUser.Username
}}
{{ else }}
{{ call .T "You are not allowed to add new players." }}
{{ end }}
{{ else if (gt .MaxPlayerCount 0) }}
{{ if .AdminView }}
{{ call .TN
"%s is only allowed to have %d player. You can override this limit since you're an admin."
"%s is allowed to have up to %d players. You can override this limit since you're an admin."
.MaxPlayerCount
.TargetUser.Username
.MaxPlayerCount
}}
{{ else }}
{{ call .TN
"You are only allowed to have %d player."
"You are allowed to have up to %d players."
.MaxPlayerCount
.TargetUser.Username
.MaxPlayerCount
}}
{{ end }}
{{ else }}
{{ if .AdminView }}
{{ call .T "%s is allowed to have an unlimited number of players." }}
{{ else }}
{{ call .T "You are allowed to have an unlimited number of players." }}
{{ end }}
{{ end }}</p>
{{ if or (and .App.Config.AllowAddingDeletingPlayers (or (lt (len .TargetUser.Players) .MaxPlayerCount) (lt .MaxPlayerCount 0))) .User.IsAdmin }}
{{ if .App.Config.CreateNewPlayer.Allow }}
{{ if or .User.IsAdmin .App.Config.CreateNewPlayer.AllowChoosingUUID }}
<h4>{{ call .T "Create a new player" }}</h4>
{{ else }}
<p>{{ call .T "Create a new player with a random UUID:" }}</p>
{{ end }}
<form action="{{ .App.FrontEndURL }}/web/create-player" method="post">
<input hidden name="userUuid" value="{{ .TargetUser.UUID }}">
<input
type="text"
name="playerName"
placeholder="{{ call .T "Player name" }}"
maxlength="{{ .App.Constants.MaxPlayerNameLength }}"
required
/>
{{ if or .User.IsAdmin .App.Config.CreateNewPlayer.AllowChoosingUUID }}
<input
class="long"
type="text"
name="playerUuid"
placeholder="{{ call .T "Player UUID (leave blank for random)" }}"
pattern="^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$"
/>
{{ end }}
<input hidden name="returnUrl" value="{{ .URL }}" />
<input type="submit" value="{{ call .T "Create player" }}" />
</form>
{{ end }}
{{ if .App.Config.ImportExistingPlayer.Allow }}
<h4>{{ call .T "Import a player from %s" .App.Config.ImportExistingPlayer.Nickname }}</h4>
{{ if .App.Config.ImportExistingPlayer.RequireSkinVerification }}
<p>{{ call .T
"Create a new player with the UUID of an existing %s player. Requires verification that you own the account."
.App.Config.ImportExistingPlayer.Nickname
}}</p>
<form action="{{ .App.FrontEndURL }}/web/create-player-challenge" method="get">
<input
type="text"
name="playerName"
placeholder="{{ call .T "%s player name" .App.Config.ImportExistingPlayer.Nickname }}"
maxlength="{{ .App.Constants.MaxUsernameLength }}"
required
/>
<input hidden name="userUuid" value="{{ .TargetUser.UUID }}">
<input hidden name="returnUrl" value="{{ .URL }}" />
<input type="submit" value="{{ call .T "Continue" }}" />
</form>
{{ else }}
<p>{{ call .T
"Create a new player with the UUID of an existing %s player."
.App.Config.ImportExistingPlayer.Nickname
}}</p>
<form action="{{ .App.FrontEndURL }}/web/create-player" method="post">
<input
type="text"
name="playerName"
placeholder="{{ call .T "%s player name" .App.Config.ImportExistingPlayer.Nickname }}"
maxlength="{{ .App.Constants.MaxPlayerNameLength }}"
required
/>
<input hidden type="checkbox" name="existingPlayer" checked />
<input hidden name="userUuid" value="{{ .TargetUser.UUID }}">
<input hidden name="returnUrl" value="{{ .URL }}" />
<input type="submit" value="{{ call .T "Create player" }}" />
</form>
{{ end }}
{{ end }}
{{ end }}
{{ if gt (len .App.OIDCProvidersByName) 0 }}
<h3>{{ call .T "Linked accounts" }}</h3>
{{ if gt (len $.LinkedOIDCProviderNames) 0 }}
<p>{{ if .AdminView }} {{ call .T
"These external accounts are linked to %s's %s account:"
.TargetUser.Username
.App.Config.ApplicationName
}}{{ else }}{{ call .T
"These external accounts are linked to your %s account:"
.App.Config.ApplicationName
}}{{ end }}</p>
<table>
<tbody>
{{ range $providerName := $.LinkedOIDCProviderNames }}
<tr>
<td>{{ $providerName }}</td>
<td>
<input
type="submit"
form="unlink-{{ $providerName }}"
value="{{ call $.T "Remove" }}"
{{ if le (len $.LinkedOIDCProviderNames) 1 }}disabled title="{{ call $.T `Can't remove the last linked OIDC account.` }}"{{ end }}
/>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ else }}
<p>{{ if .AdminView }}{{ call .T
"No external accounts are linked to %s's account."
.TargetUser.Username
}}{{ else }}{{ call .T
"No external accounts are linked to your account."
}} <span class="warning-message">{{ call .T
"If you link an external account, you will no longer be able to log in using your %s password. You'll need to use your Minecraft Token to log into Minecraft Launchers"
.App.Config.ApplicationName
}}</span>{{ end }}</p>
{{ end }}
{{ if and (eq .User.UUID .TargetUser.UUID) (gt (len $.UnlinkedOIDCProviders) 0) }}
{{ range $provider := $.UnlinkedOIDCProviders }}
<p>
<a href="{{ $provider.AuthURL }}">{{ call $.T "Link with %s" $provider.Name }}</a></td>
</p>
{{ end }}
{{ end }}
{{ end }}
<h3>{{ call .T "Account settings" }}</h3>
<form
action="{{ .App.FrontEndURL }}/web/update-user"
method="post"
enctype="multipart/form-data"
>
{{ if and .User.IsAdmin (not .TargetUser.IsAdmin) }}
<p>
<label for="max-player-count">{{ call .T "Max number of players" }}</label><br>
<small>{{ call .T "Specify -1 to allow unlimited players or leave blank to reset to the configured default value." }}</small><br>
<input
name="maxPlayerCount"
type="number"
{{ if .TargetUser.IsAdmin }}disabled{{ end }}
value="{{ if or .TargetUser.IsAdmin (eq .TargetUser.MaxPlayerCount $.App.Constants.MaxPlayerCountUnlimited) }}-1{{ else if eq .TargetUser.MaxPlayerCount $.App.Constants.MaxPlayerCountUseDefault}}{{ else }}{{ .TargetUser.MaxPlayerCount }}{{ end }}"
placeholder="{{ .App.Config.DefaultMaxPlayerCount }}"
min="-1">
</input>
</p>
{{ end }}
{{ if and .App.Config.AllowPasswordLogin (eq (len $.LinkedOIDCProviderNames) 0) }}
<p>
<label for="password">{{ call .T "Password" }}</label><br />
<input
type="password"
name="password"
id="password"
placeholder="{{ call .T "Leave blank to keep" }}"
/>
</p>
{{ end }}
<p>
<label for="minecraftToken">{{ call .T "Minecraft Token" }}</label><br>
<small>{{ call .T "Can be used instead of a password to sign in to Minecraft launchers." }}</small><br>
<input
type="text"
name="minecraftToken"
id="minecraft-token"
class="long"
readonly
value="{{ .TargetUser.MinecraftToken }}"
/>
<br>
<input type="checkbox" name="resetMinecraftToken" id="reset-minecraft-token" />
<label for="reset-minecraft-token">{{ call .T "check the box to reset your Minecraft token" }}</label>
</p>
<p>
<label for="apiToken">{{ call .T "API Token" }}</label><br />
{{ if ne .App.Constants.SwaggerUIURL "" }}
<small>{{ render
(call .T `See <a href="{{ index . 0 }}">the %s API documentation</a>` .App.Config.ApplicationName)
(printf "%s/?url=%s/swagger.json" .App.Constants.SwaggerUIURL .App.APIURL)
}}</small><br />
{{ end }}
<input
type="text"
name="apiToken"
id="api-token"
class="long"
readonly
value="{{ .TargetUser.APIToken }}"
/>
<br />
<input type="checkbox" name="resetApiToken" id="reset-api-token" />
<label for="reset-api-token">{{ call .T "check the box to reset your API token" }}</label>
</p>
<p>
<label for="preferred-language">{{ call .T "Preferred Language (used by Minecraft)" }}</label><br />
<select
name="preferredLanguage"
id="preferred-language"
value="{{ .TargetUser.PreferredLanguage }}"
>
<option
value="sq"
{{ if eq .TargetUser.PreferredLanguage "sq" }}selected{{ end }}
>
Albanian
</option>
<option
value="ar"
{{ if eq .TargetUser.PreferredLanguage "ar" }}selected{{ end }}
>
Arabic
</option>
<option
value="be"
{{ if eq .TargetUser.PreferredLanguage "be" }}selected{{ end }}
>
Belarusian
</option>
<option
value="bg"
{{ if eq .TargetUser.PreferredLanguage "bg" }}selected{{ end }}
>
Bulgarian
</option>
<option
value="ca"
{{ if eq .TargetUser.PreferredLanguage "ca" }}selected{{ end }}
>
Catalan
</option>
<option
value="zh"
{{ if eq .TargetUser.PreferredLanguage "zh" }}selected{{ end }}
>
Chinese
</option>
<option
value="hr"
{{ if eq .TargetUser.PreferredLanguage "hr" }}selected{{ end }}
>
Croatian
</option>
<option
value="cs"
{{ if eq .TargetUser.PreferredLanguage "cs" }}selected{{ end }}
>
Czech
</option>
<option
value="da"
{{ if eq .TargetUser.PreferredLanguage "da" }}selected{{ end }}
>
Danish
</option>
<option
value="nl"
{{ if eq .TargetUser.PreferredLanguage "nl" }}selected{{ end }}
>
Dutch
</option>
<option
value="en"
{{ if eq .TargetUser.PreferredLanguage "en" }}selected{{ end }}
>
English
</option>
<option
value="et"
{{ if eq .TargetUser.PreferredLanguage "et" }}selected{{ end }}
>
Estonian
</option>
<option
value="fi"
{{ if eq .TargetUser.PreferredLanguage "fi" }}selected{{ end }}
>
Finnish
</option>
<option
value="fr"
{{ if eq .TargetUser.PreferredLanguage "fr" }}selected{{ end }}
>
French
</option>
<option
value="de"
{{ if eq .TargetUser.PreferredLanguage "de" }}selected{{ end }}
>
German
</option>
<option
value="el"
{{ if eq .TargetUser.PreferredLanguage "el" }}selected{{ end }}
>
Greek
</option>
<option
value="iw"
{{ if eq .TargetUser.PreferredLanguage "iw" }}selected{{ end }}
>
Hebrew
</option>
<option
value="hi"
{{ if eq .TargetUser.PreferredLanguage "hi" }}selected{{ end }}
>
Hindi
</option>
<option
value="hu"
{{ if eq .TargetUser.PreferredLanguage "hu" }}selected{{ end }}
>
Hungarian
</option>
<option
value="is"
{{ if eq .TargetUser.PreferredLanguage "is" }}selected{{ end }}
>
Icelandic
</option>
<option
value="in"
{{ if eq .TargetUser.PreferredLanguage "in" }}selected{{ end }}
>
Indonesian
</option>
<option
value="ga"
{{ if eq .TargetUser.PreferredLanguage "ga" }}selected{{ end }}
>
Irish
</option>
<option
value="it"
{{ if eq .TargetUser.PreferredLanguage "it" }}selected{{ end }}
>
Italian
</option>
<option
value="ja"
{{ if eq .TargetUser.PreferredLanguage "ja" }}selected{{ end }}
>
Japanese
</option>
<option
value="ko"
{{ if eq .TargetUser.PreferredLanguage "ko" }}selected{{ end }}
>
Korean
</option>
<option
value="lv"
{{ if eq .TargetUser.PreferredLanguage "lv" }}selected{{ end }}
>
Latvian
</option>
<option
value="lt"
{{ if eq .TargetUser.PreferredLanguage "lt" }}selected{{ end }}
>
Lithuanian
</option>
<option
value="mk"
{{ if eq .TargetUser.PreferredLanguage "mk" }}selected{{ end }}
>
Macedonian
</option>
<option
value="ms"
{{ if eq .TargetUser.PreferredLanguage "ms" }}selected{{ end }}
>
Malay
</option>
<option
value="mt"
{{ if eq .TargetUser.PreferredLanguage "mt" }}selected{{ end }}
>
Maltese
</option>
<option
value="no"
{{ if eq .TargetUser.PreferredLanguage "no" }}selected{{ end }}
>
Norwegian
</option>
<option
value="nb"
{{ if eq .TargetUser.PreferredLanguage "nb" }}selected{{ end }}
>
Norwegian Bokmål
</option>
<option
value="nn"
{{ if eq .TargetUser.PreferredLanguage "nn" }}selected{{ end }}
>
Norwegian Nynorsk
</option>
<option
value="pl"
{{ if eq .TargetUser.PreferredLanguage "pl" }}selected{{ end }}
>
Polish
</option>
<option
value="pt"
{{ if eq .TargetUser.PreferredLanguage "pt" }}selected{{ end }}
>
Portuguese
</option>
<option
value="ro"
{{ if eq .TargetUser.PreferredLanguage "ro" }}selected{{ end }}
>
Romanian
</option>
<option
value="ru"
{{ if eq .TargetUser.PreferredLanguage "ru" }}selected{{ end }}
>
Russian
</option>
<option
value="sr"
{{ if eq .TargetUser.PreferredLanguage "sr" }}selected{{ end }}
>
Serbian
</option>
<option
value="sk"
{{ if eq .TargetUser.PreferredLanguage "sk" }}selected{{ end }}
>
Slovak
</option>
<option
value="sl"
{{ if eq .TargetUser.PreferredLanguage "sl" }}selected{{ end }}
>
Slovenian
</option>
<option
value="es"
{{ if eq .TargetUser.PreferredLanguage "es" }}selected{{ end }}
>
Spanish
</option>
<option
value="sv"
{{ if eq .TargetUser.PreferredLanguage "sv" }}selected{{ end }}
>
Swedish
</option>
<option
value="th"
{{ if eq .TargetUser.PreferredLanguage "th" }}selected{{ end }}
>
Thai
</option>
<option
value="tr"
{{ if eq .TargetUser.PreferredLanguage "tr" }}selected{{ end }}
>
Turkish
</option>
<option
value="uk"
{{ if eq .TargetUser.PreferredLanguage "uk" }}selected{{ end }}
>
Ukrainian
</option>
<option
value="vi"
{{ if eq .TargetUser.PreferredLanguage "vi" }}selected{{ end }}
>
Vietnamese
</option>
</select>
</p>
<input hidden name="uuid" value="{{ .TargetUser.UUID }}" />
<input hidden name="returnUrl" value="{{ .URL }}" />
<p style="text-align: center;">
<input type="submit" value="{{ call .T "Save changes" }}" />
</p>
</form>
<p>
<details>
<summary>{{ call .T "Delete Account" }}</summary>
<form
action="{{ .App.FrontEndURL }}/web/delete-user"
method="post"
onsubmit="return confirm('{{ call .T "Are you sure? This action is irreversible." }}');"
>
<input hidden name="uuid" value="{{ .TargetUser.UUID }}" />
<input
hidden
name="returnUrl"
value="{{ if .AdminView }}
{{ .App.FrontEndURL }}/web/admin
{{ else }}
{{ .App.FrontEndURL }}
{{ end }}"
/>
<input type="submit" value="{{ call .T "Delete Account" }}" />
</form>
</details>
</p>
{{ template "footer" . }}
{{ end }}