Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion jasmin_services/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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.
Expand Down
19 changes: 19 additions & 0 deletions jasmin_services/migrations/0011_auto_20210308_0936.py
Original file line number Diff line number Diff line change
@@ -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'),)},
),
]
3 changes: 3 additions & 0 deletions jasmin_services/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
<ul class="nav nav-tabs">
<li {% if active == 'service_details' %}class="active"{% endif %}>
<a href="{% url 'jasmin_services:service_details' category=service.category.name service=service.name %}">Details</a>
Expand All @@ -31,6 +32,11 @@
</a>
</li>
{% endif %}
{% if create_group %}
<li {% if active == 'service_groups' %}class="active"{% endif %}>
<a href="{% url 'jasmin_services:service_groups' category=service.category.name service=service.name %}">Create group</a>
</li>
{% endif %}
</ul>
{% endif %}
{% endwith %}
60 changes: 60 additions & 0 deletions jasmin_services/templates/jasmin_services/service_group.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{% extends 'layout.html' %}
{% load staticfiles bootstrap3 %}

{% block head_js_extra %}{{ block.super }}
<script src="{% static "jasmin_services/js/jquery.multi-select.js" %}" type="text/javascript"></script>
{% endblock %}

{% block stylesheets_extra %}{{ block.super }}
<link href="{% static "jasmin_services/css/multi-select.css" %}" media="screen" rel="stylesheet" type="text/css" />
{% endblock %}

{% block page_title %}Create a group{% endblock %}

{% block breadcrumbs %}
<ol class="breadcrumb">
<li>JASMIN Services</li>
<li>
<a href="{% url 'jasmin_services:service_list' category=service.category.name %}">{{ service.category }}</a>
</li>
<li class="active">{{ service.name }}</li>
</ol>
{% endblock %}

{% block content_header %}{{ block.super }}
<div class="row">
<div class="col-md-12">
{% include "jasmin_services/includes/service_tabs.html" %}
</div>
</div>
{% endblock %}

{% block content %}
<div class="col-md-8 col-md-offset-2">
<form method="POST" action="" class="form-horizontal" id="message-form">
{% csrf_token %}

{% bootstrap_form form layout='horizontal' %}

<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button name="submitted" type="submit" class="btn btn-primary" autocomplete="off">Create group</button>
</div>
</div>
</form>
</div>
<script type="text/javascript">
$('#message-form select').removeAttr('required').multiSelect({
selectableHeader : '<div class="ms-header"><strong>Available</strong> (<a id="select-all" href="#">select all</a>)</div>',
selectionHeader : '<div class="ms-header"><strong>Selected</strong> (<a id="select-none" href="#">remove all</a>)</div>',
});
$('#select-all').click(function() {
$('#message-form select').multiSelect('select_all');
return false;
});
$('#select-none').click(function() {
$('#message-form select').multiSelect('deselect_all');
return false;
});
</script>
{% endblock %}
1 change: 1 addition & 0 deletions jasmin_services/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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<category>[\w-]+)/(?P<service>[\w-]+)/apply/(?P<role>[\w-]+)/$',
views.role_apply,
Expand Down
130 changes: 128 additions & 2 deletions jasmin_services/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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 ``/<category>/<service>/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):
Expand Down