core: support oauth bind/unbind account (#971)

Co-authored-by: panda <panda_dtdyy@outlook.com>
This commit is contained in:
undefinedandpanda authored and GitHub committed 2025-04-01 10:55:21 +01:00
1 parent 1a8232899c
commit 536c697f4b
16 files changed
+393 -141

No files matched your search

@@ -20,7 +20,7 @@
line-height: rem($form-control-height)
color: green
.autherlist
.autherlist, .platform-list
font-size: rem($font-size-secondary)
.autherlist__icon
@@ -33,13 +33,34 @@
padding: rem(10px 0)
&:not(:last-child)
border-bottom: 1px solid #DDD
border-bottom: 1px solid #DDD
input
margin: 0
.platform-list__item
margin: rem(6px 0)
padding: rem(6px 0)
&:not(:first-child)
border-top: 1px solid #DDD
.button
margin: 0
.media__left
width: rem(48px)
text-align: center
svg
width: rem(30px)
height: rem(30px)
color: #888
fill: #888
margin: rem(0 20px)
+mobile()
.sessionlist__item
.sessionlist__item, .platform-list__item
.media__left
display: none
@@ -11,6 +11,59 @@ import {
const t = (s) => escape(i18n(s));
async function changeMail() {
const changeMailDialog = new ActionDialog({
$body: tpl`
<div class="typo">
<p>${i18n('Please enter your current password and new email address:')}</p>
<label>${i18n('Current Password')}
<div class="textbox-container">
<input class="textbox" type="password" name="password" data-autofocus required></input>
</div>
</label>
<label>${i18n('Current Email')}
<div class="textbox-container">
<input class="textbox" type="text" name="currentEmail" value="${UserContext.mail}" disabled></input>
</div>
</label>
<label>${i18n('New Email')}
<div class="textbox-container">
<input class="textbox" type="text" name="mail" required></input>
</div>
</label>
</div>
`,
onDispatch(action) {
if (action === 'ok') {
const $password = $('[name="password"]');
const $mail = $('[name="mail"]');
if (!$password.val() || !$mail.val()) {
if (!$password.val()) $password.focus();
else $mail.focus();
return false;
}
}
return true;
},
}).open();
const action = await changeMailDialog;
if (action !== 'ok') return;
try {
await request.post('', {
operation: 'change_mail',
password: $('[name="password"]').val(),
mail: $('[name="mail"]').val(),
});
} catch (err) {
Notification.error(err.message);
console.error(err);
return;
}
Notification.success(i18n('Successfully changed.'));
await delay(2000);
window.location.reload();
}
async function enableTfa() {
const enableTFA = new ActionDialog({
$body: tpl`
@@ -143,4 +196,9 @@ export default new NamedPage('home_security', () => {
if (action === 'tfa') enableTfa();
else enableAuthn(action);
});
$(document).on('click', '[data-operation="change_mail"]', async (ev) => {
ev.preventDefault();
await changeMail();
});
});
@@ -11,43 +11,6 @@
</div>
</div>
{% endif %}
<div class="medium-6 columns">
<div class="section">
<div class="section__header">
<h1 class="section__title" id="email" data-heading>{{ _('Change Email') }}</h1>
</div>
<div class="section__body">
<form method="post">
{{ form.form_text({
type:'password',
label:"SuperUser's Password" if sudoUid else 'Current Password',
columns:10,
name:'password',
required:true
}) }}
{{ form.form_text({
type:'text',
label:'Current Email',
columns:10,
name:'currentEmail',
value:handler.user.mail,
disabled:true
}) }}
{{ form.form_text({
type:'text',
label:'New Email',
columns:10,
name:'mail',
required:true
}) }}
<div class="row"><div class="columns">
<input type="hidden" name="operation" value="change_mail">
<input type="submit" class="rounded primary button" value="{{ _('Change Email') }}">
</div></div>
</form>
</div>
</div>
</div>
<div class="medium-6 columns">
<div class="section">
<div class="section__header">
@@ -84,6 +47,70 @@
</div>
</div>
</div>
<div class="medium-6 columns">
<div class="section">
<div class="section__header">
<h1 class="section__title" id="linked-accounts" data-heading>{{ _('Linked Accounts') }}</h1>
</div>
<div class="section__body">
<ul class="platform-list">
<li class="platform-list__item">
<div class="media">
<div class="media__left medium">
<span class="autherlist__icon icon icon-mail"></span>
</div>
<div class="media__body medium typo">
<p>{{ _('Email Account') }}: {{ handler.user.mail }}</p>
</div>
<div class="media__right medium">
<button type="button" class="rounded button" data-operation="change_mail">{{ _('Change') }}</button>
</div>
</div>
</li>
<form method="post">
<input type="hidden" name="operation" value="unlink_account">
{%- for relation in relations -%}{% if relation.platform != 'mail' %}
{% set platform = handler.loginMethods.find(eval("r => r.id === '" + relation.platform + "'")) %}
<li class="platform-list__item">
<div class="media">
{% if platform.icon %}
<div class="media__left medium">{{ platform.icon|safe }}</div>
{% endif %}
<div class="media__body medium typo">
<p>{{ platform.name }}: {{ relation.id }}</p>
</div>
<div class="media__right medium">
<button type="submit" name="platform" value="{{ relation.platform }}" class="rounded button">{{ _('Unlink') }}</button>
</div>
</div>
</li>
{%- endif -%}{%- endfor -%}
</form>
<form method="post">
<input type="hidden" name="operation" value="link_account">
{%- for method in handler.loginMethods -%}
{%- if not relations.some(eval("r => r.platform === '" + method.id + "'")) -%}
<li class="platform-list__item">
<div class="media">
{% if method.icon %}
<div class="media__left medium">{{ method.icon|safe }}</div>
{% endif %}
<div class="media__body">
<p>{{ method.name }}</p>
</div>
<div class="media__right">
<button type="submit" name="platform" value="{{ method.id }}" class="rounded button">{{ _('Link') }}</button>
</div>
</div>
</li>
{%- endif -%}
{%- endfor -%}
</form>
</ul>
</ul>
</div>
</div>
</div>
</div>
<div class="row nojs--hide">
<div class="columns">