8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-23 07:23:46 +00:00
This commit is contained in:
Hugo Levy-Falk 2020-04-23 22:32:01 +02:00 committed by Gabriel Detraz
parent e7795a775c
commit f6b2225eb8
13 changed files with 380 additions and 36 deletions

View file

@ -48,6 +48,7 @@ from .models import (
LdapServiceUser, LdapServiceUser,
LdapServiceUserGroup, LdapServiceUserGroup,
LdapUserGroup, LdapUserGroup,
SSHKey,
) )
from .forms import ( from .forms import (
UserChangeForm, UserChangeForm,
@ -130,6 +131,12 @@ class WhitelistAdmin(VersionAdmin):
pass pass
class SSHKeyAdmin(VersionAdmin):
"""SSHKey model for admin."""
pass
class UserAdmin(VersionAdmin, BaseUserAdmin): class UserAdmin(VersionAdmin, BaseUserAdmin):
"""Gestion d'un user : modification des champs perso, mot de passe, etc""" """Gestion d'un user : modification des champs perso, mot de passe, etc"""
@ -224,6 +231,7 @@ admin.site.register(Ban, BanAdmin)
admin.site.register(EMailAddress, EMailAddressAdmin) admin.site.register(EMailAddress, EMailAddressAdmin)
admin.site.register(Whitelist, WhitelistAdmin) admin.site.register(Whitelist, WhitelistAdmin)
admin.site.register(Request, RequestAdmin) admin.site.register(Request, RequestAdmin)
admin.site.register(SSHKey, SSHKeyAdmin)
# Now register the new UserAdmin... # Now register the new UserAdmin...
admin.site.unregister(User) admin.site.unregister(User)
admin.site.unregister(ServiceUser) admin.site.unregister(ServiceUser)

View file

@ -24,6 +24,7 @@ from rest_framework import serializers
import users.models as users import users.models as users
from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer
class UserSerializer(NamespacedHMSerializer): class UserSerializer(NamespacedHMSerializer):
"""Serialize `users.models.User` objects. """Serialize `users.models.User` objects.
""" """
@ -210,7 +211,7 @@ class EMailAddressSerializer(NamespacedHMSerializer):
class Meta: class Meta:
model = users.EMailAddress model = users.EMailAddress
fields = ("user", "local_part", "complete_email_address", "api_url") fields = ("user", "local_part", "complete_email_address", "api_url")
class LocalEmailUsersSerializer(NamespacedHMSerializer): class LocalEmailUsersSerializer(NamespacedHMSerializer):
email_address = EMailAddressSerializer(read_only=True, many=True) email_address = EMailAddressSerializer(read_only=True, many=True)
@ -241,4 +242,12 @@ class MailingSerializer(ClubSerializer):
admins = MailingMemberSerializer(source="administrators", many=True) admins = MailingMemberSerializer(source="administrators", many=True)
class Meta(ClubSerializer.Meta): class Meta(ClubSerializer.Meta):
fields = ("name", "members", "admins") fields = ("name", "members", "admins")
class SSHKeySerializer(NamespacedHMSerializer):
"""Serialize an SSHKey."""
class Meta:
model = users.SSHKey
fields = "__all__"

View file

@ -34,16 +34,16 @@ urls_viewset = [
(r"users/shell", views.ShellViewSet, "shell"), (r"users/shell", views.ShellViewSet, "shell"),
(r"users/ban", views.BanViewSet, None), (r"users/ban", views.BanViewSet, None),
(r"users/whitelist", views.WhitelistViewSet, None), (r"users/whitelist", views.WhitelistViewSet, None),
(r"users/emailaddress", views.EMailAddressViewSet, None) (r"users/emailaddress", views.EMailAddressViewSet, None),
(r"users/sshkey", views.SSHKeyViewSet, None),
] ]
urls_view = [ urls_view = [
(r"users/localemail", views.LocalEmailUsersView), (r"users/localemail", views.LocalEmailUsersView),
(r"users/mailing-standard", views.StandardMailingView), (r"users/mailing-standard", views.StandardMailingView),
(r"users/mailing-club", views.ClubMailingView), (r"users/mailing-club", views.ClubMailingView),
# Deprecated # Deprecated
(r"localemail/users", views.LocalEmailUsersView), (r"localemail/users", views.LocalEmailUsersView),
(r"mailing/standard", views.StandardMailingView), (r"mailing/standard", views.StandardMailingView),
(r"mailing/club", views.ClubMailingView), (r"mailing/club", views.ClubMailingView),
] ]

View file

@ -169,7 +169,7 @@ class StandardMailingView(views.APIView):
adherents_data = serializers.MailingMemberSerializer( adherents_data = serializers.MailingMemberSerializer(
all_has_access(), many=True all_has_access(), many=True
).data ).data
data = [{"name": "adherents", "members": adherents_data}] data = [{"name": "adherents", "members": adherents_data}]
groups = Group.objects.all() groups = Group.objects.all()
for group in groups: for group in groups:
@ -189,4 +189,12 @@ class ClubMailingView(generics.ListAPIView):
""" """
queryset = users.Club.objects.all() queryset = users.Club.objects.all()
serializer_class = serializers.MailingSerializer serializer_class = serializers.MailingSerializer
class SSHKeyViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.SSHKey` objects.
"""
queryset = users.SSHKey.objects.all()
serializer_class = serializers.SSHKeySerializer

View file

@ -38,7 +38,10 @@ from __future__ import unicode_literals
from django import forms from django import forms
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.password_validation import validate_password, password_validators_help_text_html from django.contrib.auth.password_validation import (
validate_password,
password_validators_help_text_html,
)
from django.core.validators import MinLengthValidator from django.core.validators import MinLengthValidator
from django.utils import timezone from django.utils import timezone
from django.utils.functional import lazy from django.utils.functional import lazy
@ -69,6 +72,7 @@ from .models import (
Ban, Ban,
Adherent, Adherent,
Club, Club,
SSHKey,
) )
@ -84,7 +88,7 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
label=_("New password"), label=_("New password"),
max_length=255, max_length=255,
widget=forms.PasswordInput, widget=forms.PasswordInput,
help_text=password_validators_help_text_html() help_text=password_validators_help_text_html(),
) )
passwd2 = forms.CharField( passwd2 = forms.CharField(
label=_("New password confirmation"), label=_("New password confirmation"),
@ -133,12 +137,10 @@ class UserCreationForm(FormRevMixin, forms.ModelForm):
label=_("Password"), label=_("Password"),
widget=forms.PasswordInput, widget=forms.PasswordInput,
max_length=255, max_length=255,
help_text=password_validators_help_text_html() help_text=password_validators_help_text_html(),
) )
password2 = forms.CharField( password2 = forms.CharField(
label=_("Password confirmation"), label=_("Password confirmation"), widget=forms.PasswordInput, max_length=255,
widget=forms.PasswordInput,
max_length=255,
) )
is_admin = forms.BooleanField(label=_("Is admin")) is_admin = forms.BooleanField(label=_("Is admin"))
@ -287,9 +289,7 @@ class MassArchiveForm(forms.Form):
date = forms.DateTimeField(help_text="%d/%m/%y") date = forms.DateTimeField(help_text="%d/%m/%y")
full_archive = forms.BooleanField( full_archive = forms.BooleanField(
label=_( label=_("Fully archive users? WARNING: CRITICAL OPERATION IF TRUE"),
"Fully archive users? WARNING: CRITICAL OPERATION IF TRUE"
),
initial=False, initial=False,
required=False, required=False,
) )
@ -380,6 +380,7 @@ class AdherentCreationForm(AdherentForm):
AdherentForm auquel on ajoute une checkbox afin d'éviter les AdherentForm auquel on ajoute une checkbox afin d'éviter les
doublons d'utilisateurs et, optionnellement, doublons d'utilisateurs et, optionnellement,
un champ mot de passe""" un champ mot de passe"""
# Champ pour choisir si un lien est envoyé par mail pour le mot de passe # Champ pour choisir si un lien est envoyé par mail pour le mot de passe
init_password_by_mail_info = _( init_password_by_mail_info = _(
"If this options is set, you will receive a link to set" "If this options is set, you will receive a link to set"
@ -392,9 +393,7 @@ class AdherentCreationForm(AdherentForm):
) )
init_password_by_mail = forms.BooleanField( init_password_by_mail = forms.BooleanField(
help_text=init_password_by_mail_info, help_text=init_password_by_mail_info, required=False, initial=True
required=False,
initial=True
) )
init_password_by_mail.label = _("Send password reset link by email.") init_password_by_mail.label = _("Send password reset link by email.")
@ -405,7 +404,7 @@ class AdherentCreationForm(AdherentForm):
label=_("Password"), label=_("Password"),
widget=forms.PasswordInput, widget=forms.PasswordInput,
max_length=255, max_length=255,
help_text=password_validators_help_text_html() help_text=password_validators_help_text_html(),
) )
password2 = forms.CharField( password2 = forms.CharField(
required=False, required=False,
@ -482,8 +481,12 @@ class AdherentCreationForm(AdherentForm):
# Save the provided password in hashed format # Save the provided password in hashed format
user = super(AdherentForm, self).save(commit=False) user = super(AdherentForm, self).save(commit=False)
is_set_password_allowed = OptionalUser.get_cached_value("allow_set_password_during_user_creation") is_set_password_allowed = OptionalUser.get_cached_value(
set_passwd = is_set_password_allowed and not self.cleaned_data.get("init_password_by_mail") "allow_set_password_during_user_creation"
)
set_passwd = is_set_password_allowed and not self.cleaned_data.get(
"init_password_by_mail"
)
if set_passwd: if set_passwd:
user.set_password(self.cleaned_data["password1"]) user.set_password(self.cleaned_data["password1"])
@ -886,3 +889,15 @@ class InitialRegisterForm(forms.Form):
if self.cleaned_data["register_machine"]: if self.cleaned_data["register_machine"]:
if self.mac_address and self.nas_type: if self.mac_address and self.nas_type:
self.user.autoregister_machine(self.mac_address, self.nas_type) self.user.autoregister_machine(self.mac_address, self.nas_type)
class SSHKeyForm(FormRevMixin, ModelForm):
"""Create or edit an SSHKey"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(SSHKeyForm, self).__init__(*args, prefix=prefix, **kwargs)
class Meta:
model = SSHKey
exclude = ["user"]

View file

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-23 16:04
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import ldapdb.models.fields
import re2o.mixins
class Migration(migrations.Migration):
dependencies = [
("users", "0091_auto_20200423_1256"),
]
operations = [
migrations.CreateModel(
name="SSHKey",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("key", models.TextField(blank=True, verbose_name="Public ssh key")),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "SSH key",
"verbose_name_plural": "SSH keys",
"permissions": (("view_sshkey", "Can view an SSHKey object"),),
},
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model),
),
migrations.AddField(
model_name="ldapuser",
name="ssh_keys",
field=ldapdb.models.fields.ListField(
blank=True, db_column="sshkeys", null=True
),
),
]

View file

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-23 18:28
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("users", "0092_auto_20200423_1804"),
]
operations = [
migrations.RenameField(
model_name="ldapuser", old_name="ssh_keys", new_name="sshkeys",
),
]

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-23 18:30
from __future__ import unicode_literals
from django.db import migrations
import ldapdb.models.fields
class Migration(migrations.Migration):
dependencies = [
("users", "0093_auto_20200423_2028"),
]
operations = [
migrations.AlterField(
model_name="ldapuser",
name="sshkeys",
field=ldapdb.models.fields.ListField(
blank=True, db_column="sshkeys", max_length=200, null=True
),
),
]

View file

@ -105,7 +105,7 @@ def linux_user_validator(login):
pas les contraintes unix (maj, min, chiffres ou tiret)""" pas les contraintes unix (maj, min, chiffres ou tiret)"""
if not linux_user_check(login): if not linux_user_check(login):
raise forms.ValidationError( raise forms.ValidationError(
_("The username \"%(label)s\" contains forbidden characters."), _('The username "%(label)s" contains forbidden characters.'),
params={"label": login}, params={"label": login},
) )
@ -405,7 +405,10 @@ class User(
@cached_property @cached_property
def get_shadow_expire(self): def get_shadow_expire(self):
"""Return the shadow_expire value for the user""" """Return the shadow_expire value for the user"""
if self.state == self.STATE_DISABLED or self.email_state == self.EMAIL_STATE_UNVERIFIED: if (
self.state == self.STATE_DISABLED
or self.email_state == self.EMAIL_STATE_UNVERIFIED
):
return str(0) return str(0)
else: else:
return None return None
@ -670,7 +673,12 @@ class User(
self.full_archive() self.full_archive()
def ldap_sync( def ldap_sync(
self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False self,
base=True,
access_refresh=True,
mac_refresh=True,
group_refresh=False,
sshkeys_refresh=False,
): ):
""" Synchronisation du ldap. Synchronise dans le ldap les attributs de """ Synchronisation du ldap. Synchronise dans le ldap les attributs de
self self
@ -734,6 +742,10 @@ class User(
for group in Group.objects.all(): for group in Group.objects.all():
if hasattr(group, "listright"): if hasattr(group, "listright"):
group.listright.ldap_sync() group.listright.ldap_sync()
if sshkeys_refresh:
user_ldap.sshkeys = [
str(key.key) for key in SSHKey.objects.filter(user=self)
]
user_ldap.save() user_ldap.save()
def ldap_del(self): def ldap_del(self):
@ -1051,7 +1063,7 @@ class User(
False, False,
_( _(
"Impossible to edit the organisation's" "Impossible to edit the organisation's"
" user without the \"change_all_users\" right." ' user without the "change_all_users" right.'
), ),
("users.change_all_users",), ("users.change_all_users",),
) )
@ -1120,7 +1132,8 @@ class User(
if not ( if not (
( (
self.pk == user_request.pk self.pk == user_request.pk
and OptionalUser.get_cached_value("self_room_policy") != OptionalUser.DISABLED and OptionalUser.get_cached_value("self_room_policy")
!= OptionalUser.DISABLED
) )
or user_request.has_perm("users.change_user") or user_request.has_perm("users.change_user")
): ):
@ -1263,7 +1276,7 @@ class User(
can = user_request.is_superuser can = user_request.is_superuser
return ( return (
can, can,
_("\"superuser\" right required to edit the superuser flag.") _('"superuser" right required to edit the superuser flag.')
if not can if not can
else None, else None,
[], [],
@ -1357,9 +1370,7 @@ class User(
# Allow empty emails only if the user had an empty email before # Allow empty emails only if the user had an empty email before
is_created = not self.pk is_created = not self.pk
if not self.email and (self.__original_email or is_created): if not self.email and (self.__original_email or is_created):
raise forms.ValidationError( raise forms.ValidationError(_("Email field cannot be empty."))
_("Email field cannot be empty.")
)
self.email = self.email.lower() self.email = self.email.lower()
@ -1432,14 +1443,12 @@ class Adherent(User):
a user or if the `options.all_can_create` is set. a user or if the `options.all_can_create` is set.
""" """
if not user_request.is_authenticated: if not user_request.is_authenticated:
if not OptionalUser.get_cached_value( if not OptionalUser.get_cached_value("self_adhesion"):
"self_adhesion"
):
return False, _("Self registration is disabled."), None return False, _("Self registration is disabled."), None
else: else:
return True, None, None return True, None, None
else: else:
if OptionalUser.get_cached_value("all_can_create_adherent"): if OptionalUser.get_cached_value("all_can_create_adherent"):
return True, None, None return True, None, None
else: else:
can = user_request.has_perm("users.add_user") can = user_request.has_perm("users.add_user")
@ -2000,6 +2009,9 @@ class LdapUser(ldapdb.models.Model):
shadowexpire = ldapdb.models.fields.CharField( shadowexpire = ldapdb.models.fields.CharField(
db_column="shadowExpire", blank=True, null=True db_column="shadowExpire", blank=True, null=True
) )
sshkeys = ldapdb.models.fields.ListField(
db_column="sshkeys", max_length=200, blank=True, null=True
)
def __str__(self): def __str__(self):
return self.name return self.name
@ -2248,3 +2260,53 @@ class EMailAddress(RevMixin, AclMixin, models.Model):
if result: if result:
raise ValidationError(reason) raise ValidationError(reason)
super(EMailAddress, self).clean(*args, **kwargs) super(EMailAddress, self).clean(*args, **kwargs)
class SSHKey(RevMixin, AclMixin, models.Model):
"""Represents an SSH public key belonging to a user."""
key = models.TextField(blank=True, verbose_name=_("Public ssh key"))
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
permissions = (("view_sshkey", _("Can view an SSHKey object")),)
verbose_name = _("SSH key")
verbose_name_plural = _("SSH keys")
def can_edit(self, user_request, *_args, **_kwargs):
"""Check if a user can edit the SSH key
Args:
user_request: The user who wants to edit the object.
Returns:
a message and a boolean which is True if the user can edit
the local email account.
"""
if self.user == user_request or user_request.has_perm("users.edit_sshkey"):
return True, None, None
return (
False,
_("You don't have the right to edit another user's SSHKey."),
("users.edit_sshkey",),
)
@receiver(post_save, sender=SSHKey)
def sshkey_post_save(**kwargs):
"""Sync LDAP record for user when SSHKey is saved."""
key = kwargs["instance"]
is_created = kwargs["created"]
user = key.user
user.ldap_sync(
base=False, access_refresh=False, mac_refresh=False, sshkeys_refresh=True
)
@receiver(post_delete, sender=SSHKey)
def sshkey_post_delete(**kwargs):
"""Sync LDAP record for user when SSHKey is deleted"""
user = kwargs["instance"].user
user.ldap_sync(
base=False, access_refresh=False, mac_refresh=False, sshkeys_refresh=True
)

View file

@ -0,0 +1,60 @@
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Lara Kermarec
Copyright © 2017 Augustin Lemesle
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load i18n %}
{% load acl %}
{% load logs_extra %}
{% if sshkeys.paginator %}
{% include 'pagination.html' with list=sshkeys %}
{% endif %}
<table class="table table-striped">
<thead>
<tr>
<th>{% trans "SSH key" %}</th>
<th></th>
</tr>
</thead>
{% for sshkey in sshkeys %}
<td>{{ sshkey.key }}</td>
<td class="text-right">
{% can_delete sshkey %}
{% include 'buttons/suppr.html' with href='users:del-sshkey' id=sshkey.id %}
{% acl_end %}
{% history_button sshkey %}
{% can_edit sshkey %}
{% include 'buttons/edit.html' with href='users:edit-sshkey' id=sshkey.id %}
{% acl_end %}
</td>
</tr>
{% endfor %}
</table>
{% if sshkey.paginator %}
{% include 'pagination.html' with list=sshkey %}
{% endif %}

View file

@ -562,6 +562,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div> </div>
</div> </div>
<div class="panel panel-default">
<div class="panel-heading clearfix profil" data-parent="#accordion" data-toggle="collapse" data-target="#sshkeys">
<h3 class="panel-title pull-left">
<i class="fa fa-key"></i>
{% trans "SSH keys" %}
</h3>
</div>
<div id="sshkeys" class="panel-collapse collapse">
<div class="panel-body">
{% can_edit users %}
{% can_create SSHKey %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-sshkey' users.id %}">
<i class="fa fa-key"></i>
{% trans "Add an SSH key" %}
</a>
{% acl_end %}
{% acl_end %}
</div>
<div class="panel-body">
{% if sshkeys %}
{% include 'users/aff_sshkeys.html' with sshkeys=sshkeys %}
{% else %}
<p>{% trans "No SSH key" %}</p>
{% endif %}
</div>
</div>
</div>
{% for template in optionnal_templates_list %} {% for template in optionnal_templates_list %}
{{ template }} {{ template }}
{% endfor %} {% endfor %}

View file

@ -44,7 +44,11 @@ urlpatterns = [
url(r"^state/(?P<userid>[0-9]+)$", views.state, name="state"), url(r"^state/(?P<userid>[0-9]+)$", views.state, name="state"),
url(r"^groups/(?P<userid>[0-9]+)$", views.groups, name="groups"), url(r"^groups/(?P<userid>[0-9]+)$", views.groups, name="groups"),
url(r"^password/(?P<userid>[0-9]+)$", views.password, name="password"), url(r"^password/(?P<userid>[0-9]+)$", views.password, name="password"),
url(r"^confirm_email/(?P<userid>[0-9]+)$", views.resend_confirmation_email, name="resend-confirmation-email"), url(
r"^confirm_email/(?P<userid>[0-9]+)$",
views.resend_confirmation_email,
name="resend-confirmation-email",
),
url( url(
r"^del_group/(?P<userid>[0-9]+)/(?P<listrightid>[0-9]+)$", r"^del_group/(?P<userid>[0-9]+)/(?P<listrightid>[0-9]+)$",
views.del_group, views.del_group,
@ -127,4 +131,7 @@ urlpatterns = [
url(r"^$", views.index, name="index"), url(r"^$", views.index, name="index"),
url(r"^index_clubs/$", views.index_clubs, name="index-clubs"), url(r"^index_clubs/$", views.index_clubs, name="index-clubs"),
url(r"^initial_register/$", views.initial_register, name="initial-register"), url(r"^initial_register/$", views.initial_register, name="initial-register"),
url(r"^add_sshkey/(?P<userid>[0-9]+)$", views.add_sshkey, name="add-sshkey",),
url(r"^edit_sshkey/(?P<sshkeyid>[0-9]+)$", views.edit_sshkey, name="edit-sshkey",),
url(r"^del_sshkey/(?P<sshkeyid>[0-9]+)$", views.del_sshkey, name="del-sshkey",),
] ]

View file

@ -86,6 +86,7 @@ from .models import (
Club, Club,
ListShell, ListShell,
EMailAddress, EMailAddress,
SSHKey,
) )
from .forms import ( from .forms import (
BanForm, BanForm,
@ -110,6 +111,7 @@ from .forms import (
ClubAdminandMembersForm, ClubAdminandMembersForm,
GroupForm, GroupForm,
InitialRegisterForm, InitialRegisterForm,
SSHKeyForm,
) )
@ -932,6 +934,7 @@ def profil(request, users, **_kwargs):
request.GET.get("order"), request.GET.get("order"),
SortTable.USERS_INDEX_WHITE, SortTable.USERS_INDEX_WHITE,
) )
sshkeys = users.sshkey_set.all()
try: try:
balance = find_payment_method(Paiement.objects.get(is_balance=True)) balance = find_payment_method(Paiement.objects.get(is_balance=True))
except Paiement.DoesNotExist: except Paiement.DoesNotExist:
@ -956,6 +959,7 @@ def profil(request, users, **_kwargs):
"local_email_accounts_enabled": ( "local_email_accounts_enabled": (
OptionalUser.objects.first().local_email_accounts_enabled OptionalUser.objects.first().local_email_accounts_enabled
), ),
"sshkeys": sshkeys,
}, },
) )
@ -1101,3 +1105,51 @@ def initial_register(request):
request, request,
) )
@login_required
@can_create(SSHKey)
@can_edit(User)
def add_sshkey(request, user, userid):
"""Create an SSHKey for the given user."""
sshkey_instance = SSHKey(user=user)
sshkey = SSHKeyForm(request.POST or None, instance=sshkey_instance)
if sshkey.is_valid():
sshkey.save()
messages.success(request, _("The SSH key was added."))
return redirect(reverse("users:profil", kwargs={"userid": str(userid)}))
return form(
{"userform": sshkey, "action_name": _("Add")}, "users/user.html", request
)
@login_required
@can_edit(SSHKey)
def edit_sshkey(request, sshkey_instance, **_kwargs):
"""Edit an SSHKey for the given user."""
sshkey = SSHKeyForm(request.POST or None, instance=sshkey_instance)
sshkey.request = request
if sshkey.is_valid():
if sshkey.changed_data:
sshkey.save()
messages.success(request, _("The SSH Key was edited."))
return redirect(reverse("users:profil", kwargs={"userid": str(userid)}))
return form(
{"userform": sshkey, "action_name": _("Edit")}, "users/user.html", request
)
@login_required
@can_delete(SSHKey)
def del_sshkey(request, sshkey, **_kwargs):
"""Delete SSH key."""
if request.method == "POST":
sshkey.delete()
messages.success(request, _("The SSH key was deleted."))
return redirect(reverse("users:profil", kwargs={"userid": str(sshkey.user.id)}))
return form(
{"objet": sshkey, "objet_name": _("SSH key")}, "users/delete.html", request
)