diff --git a/templates/user_manager/list.html b/templates/user_manager/list.html
index 2bf04e3..532a5d3 100644
--- a/templates/user_manager/list.html
+++ b/templates/user_manager/list.html
@@ -6,6 +6,7 @@
{{ user_acl.user.username }} |
{{ user_acl.get_user_level_display }} |
+
+ {% if user_acl.peer_groups.all %}
+ {% for peer_group in user_acl.peer_groups.all %}
+ {{ peer_group.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ {% else %}
+ Any
+ {% endif %}
+ |
|
diff --git a/user_manager/forms.py b/user_manager/forms.py
index 449d0e9..145641d 100644
--- a/user_manager/forms.py
+++ b/user_manager/forms.py
@@ -8,20 +8,67 @@ from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Row, Column, Submit, HTML
-class UserAclForm(UserCreationForm):
+class UserAclForm(forms.Form):
+ username = forms.CharField(max_length=150)
+ password1 = forms.CharField(widget=forms.PasswordInput, required=False, label="Password")
+ password2 = forms.CharField(widget=forms.PasswordInput, required=False, label="Password confirmation")
user_level = forms.ChoiceField(choices=UserAcl.user_level.field.choices, required=True, label="User Level")
-
- class Meta(UserCreationForm.Meta):
- model = User
- fields = UserCreationForm.Meta.fields + ('user_level',)
+ peer_groups = forms.ModelMultipleChoiceField(
+ queryset=PeerGroup.objects.all(),
+ required=False,
+ )
def __init__(self, *args, **kwargs):
+ self.instance = kwargs.pop('instance', None)
self.user_id = kwargs.pop('user_id', None)
super().__init__(*args, **kwargs)
- if self.instance and self.instance.pk:
- self.fields['password1'].required = False
- self.fields['password2'].required = False
+
+ if self.instance:
+ self.fields['username'].initial = self.instance.username
self.fields['username'].widget.attrs['readonly'] = True
+ self.fields['peer_groups'].initial = self.instance.useracl.peer_groups.all()
+ else:
+ self.fields['password1'].required = True
+ self.fields['password2'].required = True
+
+ self.helper = FormHelper()
+ self.helper.form_method = 'post'
+
+ if self.instance:
+ delete_html = "Delete"
+ else:
+ delete_html = ''
+
+ self.helper.layout = Layout(
+ Row(
+ Column('username', css_class='form-group col-md-12 mb-0'),
+ css_class='form-row'
+ ),
+ Row(
+ Column('password1', css_class='form-group col-md-12 mb-0'),
+ css_class='form-row'
+ ),
+ Row(
+ Column('password2', css_class='form-group col-md-12 mb-0'),
+ css_class='form-row'
+ ),
+ Row(
+ Column('user_level', css_class='form-group col-md-12 mb-0'),
+ css_class='form-row'
+ ),
+ Row(
+ Column('peer_groups', css_class='form-group col-md-12 mb-0'),
+ css_class='form-row'
+ ),
+ Row(
+ Column(
+ Submit('submit', 'Save', css_class='btn btn-success'),
+ HTML(' Back '),
+ HTML(delete_html),
+ css_class='col-md-12'),
+ css_class='form-row'
+ )
+ )
def clean_username(self):
username = self.cleaned_data.get('username')
@@ -29,23 +76,51 @@ class UserAclForm(UserCreationForm):
raise ValidationError("A user with that username already exists.")
return username
- def save(self, commit=True):
- user = super().save(commit=False)
- new_password = self.cleaned_data.get("password1")
-
- if new_password:
- user.set_password(new_password)
- user.save()
- else:
- if not user.id:
- user.save()
+ def clean(self):
+ cleaned_data = super().clean()
+ password1 = cleaned_data.get('password1')
+ password2 = cleaned_data.get('password2')
- if commit:
- user_acl, created = UserAcl.objects.update_or_create(
- user=user,
- defaults={'user_level': self.cleaned_data.get('user_level')}
+ if not self.instance:
+ if not password1:
+ raise ValidationError("Password is required for new users.")
+ if not password2:
+ raise ValidationError("Password confirmation is required for new users.")
+
+ if password1 or password2:
+ if password1 != password2:
+ raise ValidationError("The two password fields didn't match.")
+ if len(password1) < 8:
+ raise ValidationError("Password must be at least 8 characters long.")
+
+ return cleaned_data
+
+ def save(self):
+ username = self.cleaned_data['username']
+ password = self.cleaned_data.get('password1')
+ user_level = self.cleaned_data['user_level']
+ peer_groups = self.cleaned_data.get('peer_groups', [])
+
+ if self.instance:
+ user = self.instance
+ if password:
+ user.set_password(password)
+ user.save()
+ else:
+ user = User.objects.create_user(
+ username=username,
+ password=password
)
+ user_acl, created = UserAcl.objects.update_or_create(
+ user=user,
+ defaults={
+ 'user_level': user_level
+ }
+ )
+
+ user_acl.peer_groups.set(peer_groups)
+
return user
diff --git a/user_manager/views.py b/user_manager/views.py
index 2fffd43..6550416 100644
--- a/user_manager/views.py
+++ b/user_manager/views.py
@@ -80,33 +80,43 @@ def view_user_list(request):
def view_manage_user(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
+
user_acl = None
user = None
+ initial_data = {}
+
if 'uuid' in request.GET:
user_acl = get_object_or_404(UserAcl, uuid=request.GET['uuid'])
user = user_acl.user
- form = UserAclForm(instance=user, initial={'user_level': user_acl.user_level}, user_id=user.id)
+ initial_data = {
+ 'username': user.username,
+ 'user_level': user_acl.user_level,
+ 'peer_groups': user_acl.peer_groups.all()
+ }
+ form = UserAclForm(initial=initial_data, instance=user, user_id=user.id)
page_title = 'Edit User '+ user.username
+
if request.GET.get('action') == 'delete':
username = user.username
if request.GET.get('confirmation') == username:
user.delete()
messages.success(request, 'User deleted|The user '+ username +' has been deleted.')
return redirect('/user/list/')
-
+ else:
+ messages.warning(request, 'User not deleted|Invalid confirmation.')
return redirect('/user/list/')
else:
form = UserAclForm()
page_title = 'Add User'
if request.method == 'POST':
- if user_acl:
+ if user:
form = UserAclForm(request.POST, instance=user, user_id=user.id)
else:
form = UserAclForm(request.POST)
if form.is_valid():
- form.save()
+ saved_user = form.save()
if form.cleaned_data.get('password1'):
user_disconnected = False
if user:
@@ -116,10 +126,45 @@ def view_manage_user(request):
if not user_disconnected:
messages.warning(request, 'User Disconnected|The user '+ user.username +' has been disconnected.')
user_disconnected = True
- if user_acl:
+
+ if user:
messages.success(request, 'User updated|The user '+ form.cleaned_data['username'] +' has been updated.')
else:
messages.success(request, 'User added|The user '+ form.cleaned_data['username'] +' has been added.')
return redirect('/user/list/')
- return render(request, 'user_manager/manage_user.html', {'form': form, 'page_title': page_title, 'user_acl': user_acl})
+ form_description = {
+ 'size': '',
+ 'content': '''
+ User Levels
+ Debugging Analyst
+ Access to basic system information and logs for troubleshooting. No access to modify settings or view sensitive data such as peer keys.
+
+ View Only User
+ Full view access, including peer keys and configuration files. Cannot modify any settings or configurations.
+
+ Peer Manager
+ Permissions to add, edit, and remove peers and IP addresses. Does not include access to modify WireGuard instance configurations or higher-level settings.
+
+ Wireguard Manager
+ Authority to add, edit, and remove configurations of WireGuard instances.
+
+ Administrator
+ Full access across the system. Can view and modify all settings, configurations and manage users.
+
+
+ Peer Groups
+ Select which peer groups this user can access. If no peer groups are selected, the user will have access to all peers.
+
+ '''
+ }
+
+ context = {
+ 'page_title': page_title,
+ 'form': form,
+ 'user_acl': user_acl,
+ 'instance': user_acl,
+ 'form_description': form_description,
+ 'delete_confirmation_message': 'Please type the username to proceed.'
+ }
+ return render(request, 'generic_form.html', context)
\ No newline at end of file