hmn/src/templates/src/user_settings.html

206 lines
8.5 KiB
HTML
Raw Normal View History

{{ template "base.html" . }}
{{ define "extrahead" }}
<script src="{{ static "js/tabs.js" }}"></script>
2021-12-29 14:38:23 +00:00
<script src="{{ static "js/image_selector.js" }}"></script>
{{ end }}
{{ define "content" }}
<form class="tabbed edit-form" action="{{ .SubmitUrl }}" method="post" enctype="multipart/form-data">
{{ csrftoken .Session }}
<div class="tab" data-name="Account" data-slug="account">
<div class="edit-form-row">
<div>Username:</div>
<div>
<div>{{ .User.Username }}</div>
<div class="c--dim f7">If you would like to change your username, please <a href="{{ .ContactUrl }}">contact us</a>.</div>
</div>
</div>
<div class="edit-form-row">
<div class="pt-input-ns">Real name:</div>
<div>
<input type="text" name="realname" maxlength="255" class="textbox realname" value="{{ .User.Name }}">
<div class="c--dim f7">(optional)</div>
</div>
</div>
<div class="edit-form-row">
<div class="pt-input-ns">Email:</div>
<div>
<input type="email" name="email" maxlength="254" class="textbox email" value="{{ .Email }}" />
<div class="mt1">
<input type="checkbox" name="showemail" id="email" {{ if .ShowEmail }}checked{{ end }} />
<label for="email">Show on your profile</label>
</div>
</div>
</div>
<div class="edit-form-row">
<div>Theme:</div>
<div>
<input type="checkbox" name="darktheme" id="darktheme" {{ if .User.DarkTheme }}checked{{ end }} />
<label for="darktheme">Use dark theme</label>
</div>
</div>
<div class="edit-form-row">
<div>Avatar:</div>
2021-12-29 14:38:23 +00:00
<div class="user_avatar">
{{ template "image_selector.html" imageselectordata "avatar" .User.AvatarUrl false }}
<div class="c--dim f7">(Allowed image types: PNG, JPEG and GIF. Avatars may weigh up to 1MB and will be resized if larger than 400x400 pixels)</div>
</div>
2021-12-29 14:38:23 +00:00
<script>
let avatarMaxFileSize = {{ .AvatarMaxFileSize }};
let avatarSelector = new ImageSelector(
document.querySelector("#user_form"),
avatarMaxFileSize,
document.querySelector(".user_avatar"),
{{ .DefaultAvatarUrl }}
);
</script>
</div>
<div class="edit-form-row">
<div class="pt-input-ns">Short bio:</div>
<div>
<textarea class="shortbio" maxlength="140" data-max-chars="140" name="shortbio">
{{- .User.Blurb -}}
</textarea>
</div>
</div>
<div class="edit-form-row">
<div class="pt-input-ns">Forum signature:</div>
<div>
<textarea class="signature" maxlength="255" data-max-chars="255" name="signature">
{{- .User.Signature -}}
</textarea>
</div>
</div>
<div class="edit-form-row">
<div></div>
<div>
<input type="submit" value="Save profile" />
</div>
</div>
</div>
<div class="tab" data-name="Password" data-slug="password">
Add Discord login (#106) This leverages our existing Discord OAuth implementation. Any users with a linked Discord account will be able to log in immediately. When logging in, we request the `email` scope in addition to `identity`, so existing users will be prompted one time to accept the new permissions. On subsequent logins, Discord will skip the prompt. When linking your Discord account to an existing HMN account, we continue to only request the `identity` scope, so we do not receive the user's Discord email. Both login and linking go through the same Discord OAuth callback. All flows through the callback try to achieve the same end goal: a logged-in HMN user with a linked Discord account. Linking works the same as it ever has. Login, however, is different because we do not have a session ID to use as the OAuth state. To account for this, I have added a `pending_login` table that stores a secure unique ID and the eventual destination URL. These pending logins expire after 10 minutes. When we receive the OAuth callback, we look up the pending login by the OAuth `state` and immediately delete it. The destination URL will be used to redirect the user to the right place. If we have a `discord_user` entry for the OAuth'd Discord user, we immediately log the user into the associated HMN account. This is the typical login case. If we do not have a `discord_user`, but there is exactly one HMN user with the same email address as the Discord user, we will link the two accounts and log into the HMN account. (It is possible for multiple HMN accounts to have the same email, because we don't have a uniqueness constraint there. We fail the login in this case rather than link to the wrong account.) Finally, if no associated HMN user exists, a new one will be created. It will use the Discord user's username, email, and avatar. This user will have no password, but they can set or reset a password through the usual flows. Co-authored-by: Ben Visness <bvisness@gmail.com> Reviewed-on: https://git.handmade.network/hmn/hmn/pulls/106
2023-05-06 19:38:50 +00:00
{{ if .HasPassword }}
<div class="edit-form-row">
<div class="pt-input-ns">Old password:</div>
<div>
<input id="id_old_password" name="old_password" type="password" />
</div>
</div>
Add Discord login (#106) This leverages our existing Discord OAuth implementation. Any users with a linked Discord account will be able to log in immediately. When logging in, we request the `email` scope in addition to `identity`, so existing users will be prompted one time to accept the new permissions. On subsequent logins, Discord will skip the prompt. When linking your Discord account to an existing HMN account, we continue to only request the `identity` scope, so we do not receive the user's Discord email. Both login and linking go through the same Discord OAuth callback. All flows through the callback try to achieve the same end goal: a logged-in HMN user with a linked Discord account. Linking works the same as it ever has. Login, however, is different because we do not have a session ID to use as the OAuth state. To account for this, I have added a `pending_login` table that stores a secure unique ID and the eventual destination URL. These pending logins expire after 10 minutes. When we receive the OAuth callback, we look up the pending login by the OAuth `state` and immediately delete it. The destination URL will be used to redirect the user to the right place. If we have a `discord_user` entry for the OAuth'd Discord user, we immediately log the user into the associated HMN account. This is the typical login case. If we do not have a `discord_user`, but there is exactly one HMN user with the same email address as the Discord user, we will link the two accounts and log into the HMN account. (It is possible for multiple HMN accounts to have the same email, because we don't have a uniqueness constraint there. We fail the login in this case rather than link to the wrong account.) Finally, if no associated HMN user exists, a new one will be created. It will use the Discord user's username, email, and avatar. This user will have no password, but they can set or reset a password through the usual flows. Co-authored-by: Ben Visness <bvisness@gmail.com> Reviewed-on: https://git.handmade.network/hmn/hmn/pulls/106
2023-05-06 19:38:50 +00:00
{{ end }}
<div class="edit-form-row">
<div class="pt-input-ns">New password:</div>
<div>
2022-08-13 19:15:00 +00:00
<input name="new_password" type="password" />
<div class="c--dim f7 mw6">
Add Discord login (#106) This leverages our existing Discord OAuth implementation. Any users with a linked Discord account will be able to log in immediately. When logging in, we request the `email` scope in addition to `identity`, so existing users will be prompted one time to accept the new permissions. On subsequent logins, Discord will skip the prompt. When linking your Discord account to an existing HMN account, we continue to only request the `identity` scope, so we do not receive the user's Discord email. Both login and linking go through the same Discord OAuth callback. All flows through the callback try to achieve the same end goal: a logged-in HMN user with a linked Discord account. Linking works the same as it ever has. Login, however, is different because we do not have a session ID to use as the OAuth state. To account for this, I have added a `pending_login` table that stores a secure unique ID and the eventual destination URL. These pending logins expire after 10 minutes. When we receive the OAuth callback, we look up the pending login by the OAuth `state` and immediately delete it. The destination URL will be used to redirect the user to the right place. If we have a `discord_user` entry for the OAuth'd Discord user, we immediately log the user into the associated HMN account. This is the typical login case. If we do not have a `discord_user`, but there is exactly one HMN user with the same email address as the Discord user, we will link the two accounts and log into the HMN account. (It is possible for multiple HMN accounts to have the same email, because we don't have a uniqueness constraint there. We fail the login in this case rather than link to the wrong account.) Finally, if no associated HMN user exists, a new one will be created. It will use the Discord user's username, email, and avatar. This user will have no password, but they can set or reset a password through the usual flows. Co-authored-by: Ben Visness <bvisness@gmail.com> Reviewed-on: https://git.handmade.network/hmn/hmn/pulls/106
2023-05-06 19:38:50 +00:00
Your password must be 8 or more characters, and must differ from your username{{ if .HasPassword }} and current password{{ end }}.
Other than that, <a href="http://krebsonsecurity.com/password-dos-and-donts/" class="external" target="_blank">please follow best practices</a>.
</div>
</div>
</div>
<div class="edit-form-row">
<div></div>
<div>
<input type="submit" value="Update password" />
</div>
</div>
</div>
<div class="tab" data-name="Profile Page Options" data-slug="profile">
<div class="edit-form-row">
<div class="pt-input-ns">Links:</div>
<div>
<textarea class="links" name="links" id="links" maxlength="2048" data-max-chars="2048">
{{- .LinksText -}}
</textarea>
<div class="c--dim f7">
<div>Relevant links to put on your profile.</div>
<div>Format: url [Title] (e.g. <code>http://example.com/ Example Site</code>)</div>
<div>(1 per line, 10 max)</div>
</div>
</div>
</div>
<div class="edit-form-row">
<div class="pt-input-ns">Description:</div>
<div>
<textarea class="longbio" name="longbio" maxlength="1018" data-max-chars="1018">
{{- .User.Bio -}}
</textarea>
<div class="c--dim f7">
<div>Include some information about yourself, such as your background, interests, occupation, etc.</div>
</div>
</div>
</div>
<div class="edit-form-row">
<div></div>
<div>
<input type="submit" value="Save profile" />
</div>
</div>
</div>
<div class="tab" data-name="Discord" data-slug="discord">
<div>
{{ if .DiscordUser }}
Linked account:
<span class="b ph2">{{ .DiscordUser.Username }}#{{ .DiscordUser.Discriminator }}</span>
<a href="javascript:void(0)" onclick="unlinkDiscord()">
Unlink account
</a>
{{ else }}
You haven't linked your Discord account.
<a href="{{ .DiscordAuthorizeUrl }}">Link account</a>
{{ end }}
</div>
<div class="mv3">
<input type="checkbox" name="discord-showcase-auto" id="discord-showcase-auto" {{ if .User.DiscordSaveShowcase }}checked{{ end }} {{ if not .DiscordUser }}disabled{{ end }} />
<label for="discord-showcase-auto">Automatically capture everything I post in <span class="b nowrap">#project-showcase</span></label>
<div class="f7 c--dimmer">Snippets will only be created while this setting is on.</div>
</div>
<div class="mv3">
<input type="checkbox" name="discord-snippet-keep" id="discord-snippet-keep" {{ if not .User.DiscordDeleteSnippetOnMessageDelete }}checked{{ end }} {{ if not .DiscordUser }}disabled{{ end }} />
<label for="discord-snippet-keep">Keep captured snippets even if I delete them in Discord</label>
</div>
{{ if .DiscordUser }}
<div class="mv3 mw6">
<a href="javascript:void(0)" onclick="discordShowcaseBacklog()">
Create snippets from all of my <span class="b nowrap">#project-showcase</span> posts
</a>
<div class="f7 c--dimmer">
Use this if you have a backlog of content in <span class="b nowrap">#project-showcase</span> that you want on your profile.
</div>
{{ if gt .DiscordNumUnsavedMessages 0 }}
<div class="f7 c--dimmer">
<span class="b">WARNING:</span> {{ .DiscordNumUnsavedMessages }} of your messages are currently waiting to be processed. If you run this command now, some snippets may still be missing.
</div>
{{ end }}
</div>
{{ end }}
<input type="submit" value="Save profile" />
</div>
</form>
<form id="discord-unlink-form" class="dn" action="{{ .DiscordUnlinkUrl }}" method="POST">
{{ csrftoken .Session }}
<script>
function unlinkDiscord() {
document.querySelector('#discord-unlink-form').submit();
}
</script>
</form>
<form id="discord-showcase-backlog" class="dn" action="{{ .DiscordShowcaseBacklogUrl }}" method="POST">
{{ csrftoken .Session }}
<script>
function discordShowcaseBacklog() {
document.querySelector('#discord-showcase-backlog').submit();
}
</script>
</form>
2021-12-29 14:38:23 +00:00
{{ end }}