diff --git a/jasmin_services/forms.py b/jasmin_services/forms.py
index 4ddecdc..39f2859 100644
--- a/jasmin_services/forms.py
+++ b/jasmin_services/forms.py
@@ -22,7 +22,7 @@
from markdown_deux.templatetags.markdown_deux_tags import markdown_allowed
-from .models import Grant, RequestState, LdapGroupBehaviour
+from .models import Grant, RequestState, LdapGroupBehaviour, Role
def message_form_factory(sender, *roles):
@@ -65,6 +65,35 @@ def message_form_factory(sender, *roles):
})
+def group_form_factory(service):
+ """
+ Factory function that creates a group form for a set of roles.
+ """
+ ROLE_CHOICES = [(role, role.name) for role in service.roles.all()]
+
+ return type(uuid.uuid4().hex, (forms.Form, ), {
+ 'name' : forms.CharField(label = 'Name', required = True, max_length = 15),
+ 'description' : forms.CharField(label = 'Description'),
+ 'approver_roles' : forms.MultipleChoiceField(
+ required = False,
+ choices = ROLE_CHOICES,
+ label = 'Approver roles',
+ help_text = mark_safe(
+ 'The selected roles will be able to approve request for '
+ 'the created role.'
+ )
+ ),
+ })
+
+
+class GroupForm(forms.Form):
+ """
+ Form for creating a key LDAP group for an object store.
+ """
+ name = forms.CharField(label = 'Name', required = True, max_length = 15)
+ description = forms.CharField(label = 'Description')
+
+
class DecisionForm(forms.Form):
"""
Form for making a decision on a request.
diff --git a/jasmin_services/migrations/0011_auto_20210308_0936.py b/jasmin_services/migrations/0011_auto_20210308_0936.py
new file mode 100644
index 0000000..82d4b9d
--- /dev/null
+++ b/jasmin_services/migrations/0011_auto_20210308_0936.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.9 on 2021-03-08 09:36
+
+import django.core.validators
+from django.db import migrations
+import jasmin_ldap_django.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jasmin_services', '0010_auto_20190916_1328'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='service',
+ options={'ordering': ('category__position', 'category__long_name', 'position', 'name'), 'permissions': (('create_group_role', 'Can great a new group'),)},
+ ),
+ ]
diff --git a/jasmin_services/models/base.py b/jasmin_services/models/base.py
index ac59a5c..cb6c767 100644
--- a/jasmin_services/models/base.py
+++ b/jasmin_services/models/base.py
@@ -64,6 +64,9 @@ class Meta:
'position',
'name'
)
+ permissions = (
+ ('create_group_role', 'Can great a new group'),
+ )
#: The category that the service belongs to
category = models.ForeignKey(Category, models.CASCADE,
diff --git a/jasmin_services/templates/jasmin_services/includes/service_tabs.html b/jasmin_services/templates/jasmin_services/includes/service_tabs.html
index 5dfd2ee..26d4016 100644
--- a/jasmin_services/templates/jasmin_services/includes/service_tabs.html
+++ b/jasmin_services/templates/jasmin_services/includes/service_tabs.html
@@ -3,9 +3,10 @@
{% user_has_service_perm service request.user 'jasmin_services.view_users_role' as view_users %}
{% user_has_service_perm service request.user 'jasmin_services.decide_request' as approver %}
{% user_has_service_perm service request.user 'jasmin_services.send_message_role' as send_message %}
+{% user_has_service_perm service request.user 'jasmin_services.create_group_role' as create_group %}
{% with active=request.resolver_match.url_name %}
- {% if view_users or approver or send_message %}
+ {% if view_users or approver or send_message or create_group %}
-
Details
@@ -31,6 +32,11 @@
{% endif %}
+ {% if create_group %}
+ -
+ Create group
+
+ {% endif %}
{% endif %}
{% endwith %}
diff --git a/jasmin_services/templates/jasmin_services/service_group.html b/jasmin_services/templates/jasmin_services/service_group.html
new file mode 100644
index 0000000..162217a
--- /dev/null
+++ b/jasmin_services/templates/jasmin_services/service_group.html
@@ -0,0 +1,60 @@
+{% extends 'layout.html' %}
+{% load staticfiles bootstrap3 %}
+
+{% block head_js_extra %}{{ block.super }}
+
+{% endblock %}
+
+{% block stylesheets_extra %}{{ block.super }}
+
+{% endblock %}
+
+{% block page_title %}Create a group{% endblock %}
+
+{% block breadcrumbs %}
+
+ - JASMIN Services
+ -
+ {{ service.category }}
+
+ - {{ service.name }}
+
+{% endblock %}
+
+{% block content_header %}{{ block.super }}
+
+
+ {% include "jasmin_services/includes/service_tabs.html" %}
+
+
+{% endblock %}
+
+{% block content %}
+
+
+{% endblock %}
diff --git a/jasmin_services/urls.py b/jasmin_services/urls.py
index 989e555..6354242 100644
--- a/jasmin_services/urls.py
+++ b/jasmin_services/urls.py
@@ -26,6 +26,7 @@
url(r'^requests/$', views.service_requests, name = 'service_requests'),
url(r'^users/$', views.service_users, name = 'service_users'),
url(r'^message/$', views.service_message, name = 'service_message'),
+ url(r'^groups/$', views.service_groups, name = 'service_groups'),
])),
url(r'^(?P[\w-]+)/(?P[\w-]+)/apply/(?P[\w-]+)/$',
views.role_apply,
diff --git a/jasmin_services/views.py b/jasmin_services/views.py
index dfaf995..237a352 100644
--- a/jasmin_services/views.py
+++ b/jasmin_services/views.py
@@ -25,12 +25,15 @@
from django.template.loader import render_to_string
from django.db import transaction
from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Permission
from django.contrib.auth.decorators import user_passes_test
+from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
-from .models import Grant, Request, RequestState, Category, Service, Role
-from .forms import DecisionForm, message_form_factory
+from jasmin_metadata.models import Metadatum, Form
+from .models import Grant, Request, RequestState, Category, Service, Role, Group, RoleObjectPermission, LdapGroupBehaviour, CedaLdapGroup
+from .forms import DecisionForm, message_form_factory, group_form_factory
_log = logging.getLogger(__name__)
@@ -801,6 +804,129 @@ def service_message(request, service):
'form': form,
})
+# from . import models as service_models
+# CedaLdapGroup = getattr(models, 'CedaLdapGroup')
+@require_http_methods(['GET', 'POST'])
+@login_required
+@with_service
+def service_groups(request, service):
+ """
+ Handler for ``///groups/``.
+
+ Responds to GET and POST. The user must have the ``create_groups_role``
+ permission for the service.
+
+ Allows a user with suitable permissions to create an LDAP group which other
+ users of the service can apply for.
+ """
+ # The current user must have permission to create a group.
+ permission = 'jasmin_services.create_group_role'
+ if not request.user.has_perm(permission) and \
+ not request.user.has_perm(permission, service):
+ messages.error(request, 'Insufficient permissions')
+ return redirect_to_service(service)
+
+ GroupForm = group_form_factory(service)
+ if request.method == 'POST':
+ form = GroupForm(request.POST)
+ if form.is_valid():
+ try:
+ name = form.cleaned_data['name']
+ description = form.cleaned_data['description']
+ approver_roles = form.cleaned_data['approver_roles']
+ LDAP_group_name = (service.name + '_' + name).replace('-', '_')
+ default_form = Form.objects.get(pk = settings.JASMIN_SERVICES['DEFAULT_METADATA_FORM'])
+
+ # Check if there is already a role with this name.
+ try:
+ Role.objects.get(
+ service = service,
+ name = name,
+ )
+ raise Exception('Already exists')
+ except Role.DoesNotExist:
+ role = Role(
+ service = service,
+ name = name,
+ description = description,
+ metadata_form = default_form,
+ hidden = False,
+ )
+
+ # Check if there is already a ceda ldap group with this name.
+ try:
+ CedaLdapGroup.objects.get(name = LDAP_group_name)
+ raise Exception('Already exists')
+ except CedaLdapGroup.DoesNotExist:
+ group = CedaLdapGroup(
+ name = LDAP_group_name,
+ description = description,
+ )
+
+ # Create the LDAP group behaviour.
+ ldap_group_behaviour = LdapGroupBehaviour.objects.create(
+ ldap_model = group,
+ group_name = LDAP_group_name,
+ )
+
+ # Save both after check, as not to create only one.
+ group.save()
+ role.save()
+ role.behaviours.add(ldap_group_behaviour)
+
+ # Create relevant role_object_permissions for the approver roles.
+ permissions = [
+ Permission.objects.get(
+ content_type = ContentType.objects.get_for_model(Role),
+ codename = 'view_users_role',
+ ),
+ Permission.objects.get(
+ content_type = ContentType.objects.get_for_model(Role),
+ codename = 'send_message_role',
+ ),
+ Permission.objects.get(
+ content_type = ContentType.objects.get_for_model(Request),
+ codename = 'decide_request',
+ ),
+ ]
+
+ for approver_role in approver_roles:
+ RoleObjectPermission.objects.bulk_create([
+ RoleObjectPermission(
+ role = approver_role,
+ permission = permission,
+ content_type = ContentType.objects.get_for_model(role),
+ object_pk = role.pk
+ )
+ for permission in permissions
+ ])
+
+ messages.success(request, 'Group created')
+ return redirect_to_service(service)
+ except Exception as e:
+ print(e)
+ if str(e) == 'Already exists':
+ messages.error(request, 'Group with this name already exists')
+ else:
+ messages.error(request, 'Error creating group')
+
+ else:
+ messages.error(request, 'Error with one or more fields')
+ else:
+ form = GroupForm()
+ templates = [
+ 'jasmin_services/{}/{}/service_group.html'.format(
+ service.category.name,
+ service.name
+ ),
+ 'jasmin_services/{}/service_group.html'.format(service.category.name),
+ 'jasmin_services/service_group.html',
+ ]
+ return render(request, templates, {
+ 'service': service,
+ 'form': form,
+ })
+
@require_safe
def reverse_dns_check(request):