feat: Add trust bridge and user activation
This commit is contained in:
parent
74afc805dc
commit
0f1cd98a80
8 changed files with 78 additions and 52 deletions
|
@ -43,12 +43,14 @@ export class User {
|
||||||
email: string | undefined;
|
email: string | undefined;
|
||||||
password: string | undefined;
|
password: string | undefined;
|
||||||
username: string | null = null;
|
username: string | null = null;
|
||||||
confidantEmail: string | null = null;
|
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
|
isTrusted = false;
|
||||||
private token = "";
|
private token = "";
|
||||||
|
|
||||||
static async confirm(uid: string, token: string): Promise<void> {
|
async activate(): Promise<void> {
|
||||||
await api_request("POST", "users/activation", 204, { uid, token });
|
await api_request("POST", "users/activate", 204, {
|
||||||
|
password: this.password,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(): Promise<void> {
|
async login(): Promise<void> {
|
||||||
|
@ -84,7 +86,6 @@ export class User {
|
||||||
200,
|
200,
|
||||||
{
|
{
|
||||||
username: this.username,
|
username: this.username,
|
||||||
confidant_email: this.confidantEmail,
|
|
||||||
},
|
},
|
||||||
this.token
|
this.token
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,20 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-notification
|
<b-notification type="is-info" aria-close-label="Close notification">
|
||||||
v-if="!user.username"
|
Dein Konto ist noch nicht aktiv.
|
||||||
type="is-warning"
|
<a @click="activate()">Jetzt aktivieren</a>
|
||||||
aria-close-label="Close notification"
|
|
||||||
>
|
|
||||||
Um dein Konto zu aktivieren, musst du einen
|
|
||||||
<strong>Benutzernamen</strong> festlegen.
|
|
||||||
</b-notification>
|
|
||||||
<b-notification
|
|
||||||
v-if="!user.confidant_email"
|
|
||||||
type="is-warning"
|
|
||||||
aria-close-label="Close notification"
|
|
||||||
>
|
|
||||||
Um dein Konto zu aktivieren, musst du eine
|
|
||||||
<strong>Vertrauensperson</strong> angeben.
|
|
||||||
</b-notification>
|
</b-notification>
|
||||||
<table class="table is-fullwidth">
|
<table class="table is-fullwidth">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -34,10 +22,6 @@
|
||||||
<inline-editor v-model="user.confidantEmail" @input="user.save()" />
|
<inline-editor v-model="user.confidantEmail" @input="user.save()" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>E-Mail-Adresse</td>
|
|
||||||
<td>{{ user.email }} (bestätigt)</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,5 +37,9 @@ import InlineEditor from "@/components/InlineEditor.vue";
|
||||||
})
|
})
|
||||||
export default class UserTable extends Vue {
|
export default class UserTable extends Vue {
|
||||||
@Prop() private user!: User;
|
@Prop() private user!: User;
|
||||||
|
|
||||||
|
async activate(): Promise<void> {
|
||||||
|
await this.user.activate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from userausfall.models import User
|
from userausfall.models import User, TrustBridge
|
||||||
|
|
||||||
|
admin.site.register(TrustBridge)
|
||||||
admin.site.register(User)
|
admin.site.register(User)
|
||||||
|
|
29
userausfall/migrations/0010_auto_20210802_1131.py
Normal file
29
userausfall/migrations/0010_auto_20210802_1131.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 2.2.20 on 2021-08-02 11:31
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('userausfall', '0009_auto_20210802_0745'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='confidant',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='confidant_unconfirmed',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='email',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='email_unconfirmed',
|
||||||
|
),
|
||||||
|
]
|
23
userausfall/migrations/0011_trustbridge.py
Normal file
23
userausfall/migrations/0011_trustbridge.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.20 on 2021-08-02 11:41
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('userausfall', '0010_auto_20210802_1131'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrustBridge',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('is_trusted', models.BooleanField(default=False)),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='trust_bridge', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -66,28 +66,16 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||||
unique=True,
|
unique=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
email = models.EmailField(_("email address"), blank=True)
|
|
||||||
email_unconfirmed = models.EmailField(_("email address"), blank=True)
|
|
||||||
is_staff = models.BooleanField(
|
is_staff = models.BooleanField(
|
||||||
_("staff status"),
|
_("staff status"),
|
||||||
default=False,
|
default=False,
|
||||||
help_text=_("Designates whether the user can log into this admin site."),
|
help_text=_("Designates whether the user can log into this admin site."),
|
||||||
)
|
)
|
||||||
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
||||||
confidant = models.ForeignKey(
|
|
||||||
"User", on_delete=models.SET_NULL, null=True, blank=True, related_name="confidants"
|
|
||||||
)
|
|
||||||
confidant_unconfirmed = models.ForeignKey(
|
|
||||||
"User",
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name="unconfirmed_confidants",
|
|
||||||
)
|
|
||||||
|
|
||||||
objects = UserManager()
|
objects = UserManager()
|
||||||
|
|
||||||
EMAIL_FIELD = "email"
|
# EMAIL_FIELD = "email"
|
||||||
USERNAME_FIELD = "username"
|
USERNAME_FIELD = "username"
|
||||||
REQUIRED_FIELDS = []
|
REQUIRED_FIELDS = []
|
||||||
|
|
||||||
|
@ -95,13 +83,6 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||||
verbose_name = _("user")
|
verbose_name = _("user")
|
||||||
verbose_name_plural = _("users")
|
verbose_name_plural = _("users")
|
||||||
|
|
||||||
@property
|
|
||||||
def confidant_email(self):
|
|
||||||
if self.confidant is not None:
|
|
||||||
return self.confidant.email
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
self.email = self.__class__.objects.normalize_email(self.email)
|
self.email = self.__class__.objects.normalize_email(self.email)
|
||||||
|
@ -114,10 +95,13 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||||
"""Create the LDAP account which corresponds to this user."""
|
"""Create the LDAP account which corresponds to this user."""
|
||||||
if not self.username:
|
if not self.username:
|
||||||
raise MissingUserAttribute("User is missing a username.")
|
raise MissingUserAttribute("User is missing a username.")
|
||||||
if not self.confidant:
|
|
||||||
raise MissingUserAttribute("User is missing a confirmed confidant.")
|
|
||||||
if not self.check_password(raw_password):
|
if not self.check_password(raw_password):
|
||||||
raise PasswordMismatch(
|
raise PasswordMismatch(
|
||||||
"The given password does not match the user's password."
|
"The given password does not match the user's password."
|
||||||
)
|
)
|
||||||
return ldap.create_account(self.username, raw_password)
|
return ldap.create_account(self.username, raw_password)
|
||||||
|
|
||||||
|
|
||||||
|
class TrustBridge(models.Model):
|
||||||
|
user = models.OneToOneField("User", on_delete=models.CASCADE, related_name="trust_bridge")
|
||||||
|
is_trusted = models.BooleanField(default=False)
|
||||||
|
|
|
@ -14,13 +14,13 @@ class ConfidantConfirmationView(ConfirmationView):
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = [UserPermission]
|
# permission_classes = [UserPermission]
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
|
|
||||||
@action(detail=True, methods=["post"])
|
@action(detail=False, methods=["post"])
|
||||||
def activate(self, request, pk=None):
|
def activate(self, request, pk=None):
|
||||||
"""Create the corresponding LDAP account."""
|
"""Create the corresponding LDAP account."""
|
||||||
user: User = self.get_object()
|
user: User = request.user # self.get_object()
|
||||||
serializer = UserActivationSerializer(data=request.data)
|
serializer = UserActivationSerializer(data=request.data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -2,10 +2,10 @@ from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from userausfall.models import User
|
from userausfall.models import User
|
||||||
from userausfall.confirmations import ConfidantConfirmation
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
@receiver(post_save, sender=User)
|
||||||
def user_saved(sender, instance: User, **kwargs):
|
def user_saved(sender, instance: User, **kwargs):
|
||||||
if instance.confidant_unconfirmed is not None:
|
# if instance.confidant_unconfirmed is not None:
|
||||||
ConfidantConfirmation(instance.confidant_unconfirmed, instance).send_request()
|
# ConfidantConfirmation(instance.confidant_unconfirmed, instance).send_request()
|
||||||
|
pass
|
||||||
|
|
Reference in a new issue