feat: configure activation codes

This commit is contained in:
Vlad Stan
2026-02-05 12:21:08 +02:00
parent b702229cb1
commit eb84621f23
6 changed files with 103 additions and 4 deletions
+3
View File
@@ -48,6 +48,9 @@ class UsersSettings(LNbitsSettings):
lnbits_user_activation_by_payment: bool = Field(default=False) lnbits_user_activation_by_payment: bool = Field(default=False)
lnbits_user_activation_by_invitation_code: bool = Field(default=False) lnbits_user_activation_by_invitation_code: bool = Field(default=False)
lnbits_register_reusable_activation_code: str = Field(default="")
lnbits_register_one_time_activation_codes: list[str] = Field(default=[])
@property @property
def new_accounts_allowed(self) -> bool: def new_accounts_allowed(self) -> bool:
return self.lnbits_allow_new_accounts and len(self.lnbits_allowed_users) == 0 return self.lnbits_allow_new_accounts and len(self.lnbits_allowed_users) == 0
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+8
View File
@@ -711,6 +711,14 @@ window.localisation.en = {
require_user_activation: 'Require user activation', require_user_activation: 'Require user activation',
require_user_activation_desc: require_user_activation_desc:
'New users will be activated only after they pass one of the confirmation methods. Admins can activate users manually from the admin panel.', 'New users will be activated only after they pass one of the confirmation methods. Admins can activate users manually from the admin panel.',
reusable_activation_code: 'Reusable activation code',
reusable_activation_code_label: 'Reusable activation code',
reusable_activation_code_hint:
'This activation code can be used multiple times by different users.',
one_time_activation_code: 'One-time activation codes',
one_time_activation_code_label: 'Add activation code',
one_time_activation_code_hint:
'List of one-time activation codes. Each code can be used only once, then will be reomved from the list.',
new_user_not_allowed: 'Registration is disabled.', new_user_not_allowed: 'Registration is disabled.',
start_user_impersonation: 'Impersonate this user', start_user_impersonation: 'Impersonate this user',
stop_user_impersonation: 'Stop User Impersonation', stop_user_impersonation: 'Stop User Impersonation',
@@ -4,7 +4,9 @@ window.app.component('lnbits-admin-users', {
data() { data() {
return { return {
formAddUser: '', formAddUser: '',
formAddAdmin: '' formAddAdmin: '',
formAddActivationCode: '',
showReusableActivationCode: false
} }
}, },
methods: { methods: {
@@ -31,6 +33,24 @@ window.app.component('lnbits-admin-users', {
removeAdminUser(user) { removeAdminUser(user) {
let admin_users = this.formData.lnbits_admin_users let admin_users = this.formData.lnbits_admin_users
this.formData.lnbits_admin_users = admin_users.filter(u => u !== user) this.formData.lnbits_admin_users = admin_users.filter(u => u !== user)
},
addOneTimeActivationCode() {
const code = this.formAddActivationCode
const activationCodes =
this.formData.lnbits_register_one_time_activation_codes
if (code?.length && !activationCodes.includes(code)) {
this.formData.lnbits_register_one_time_activation_codes = [
...activationCodes,
code
]
this.formAddActivationCode = ''
}
},
removeOneTimeActivationCode(code) {
const codes = this.formData.lnbits_register_one_time_activation_codes
this.formData.lnbits_register_one_time_activation_codes = codes.filter(
u => u !== code
)
} }
} }
}) })
+69 -1
View File
@@ -141,6 +141,74 @@
</div> </div>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<div class="row">
<div class="col-12 col-md-6 q-pr-sm">
<p><span v-text="$t('reusable_activation_code')"></span></p>
<q-input
filled
v-model="formData.lnbits_register_reusable_activation_code"
:type="showReusableActivationCode ? 'text' : 'password'"
:label="$t('reusable_activation_code_label')"
:hint="$t('reusable_activation_code_hint')"
>
<q-btn
@click="
showReusableActivationCode = !showReusableActivationCode
"
dense
flat
:icon="
showReusableActivationCode
? 'visibility_off'
: 'visibility'
"
color="grey"
></q-btn>
<q-btn
@click="
utils.copyText(
formData.lnbits_register_reusable_activation_code
)
"
dense
flat
icon="content_copy"
color="grey"
></q-btn>
</q-input>
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('one_time_activation_code')"></span></p>
<q-input
filled
v-model="formAddActivationCode"
@keydown.enter="addOneTimeActivationCode"
type="text"
:label="$t('one_time_activation_code_label')"
:hint="$t('one_time_activation_code_hint')"
>
<q-btn
@click="addOneTimeActivationCode"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="code in formData.lnbits_register_one_time_activation_codes"
:key="code"
removable
@remove="removeOneTimeActivationCode(code)"
color="primary"
text-color="white"
:label="code"
class="ellipsis"
>
</q-chip>
</div>
</div>
</div>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
@@ -150,7 +218,7 @@
<template v-slot:header> <template v-slot:header>
<q-item-section avatar> <q-item-section avatar>
<q-avatar> <q-avatar>
<q-icon name="receipt" size="md"></q-icon> <q-icon name="bolt" size="md"></q-icon>
</q-avatar> </q-avatar>
</q-item-section> </q-item-section>