From 0e6a906d6eb3d68437e8a71d4305976e8b84dc32 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 14:17:41 +0100 Subject: [PATCH 01/10] view_daily_planning permission implemented --- .../web/migrations/0141_auto_20200319_1301.py | 23 +++++++++++++++++++ smash/web/models/appointment_type_link.py | 4 ++++ smash/web/templates/sidebar.html | 14 ++++++----- smash/web/tests/view/test_daily_planning.py | 20 ++++++++++++++++ smash/web/views/daily_planning.py | 9 +++++--- 5 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 smash/web/migrations/0141_auto_20200319_1301.py create mode 100644 smash/web/tests/view/test_daily_planning.py diff --git a/smash/web/migrations/0141_auto_20200319_1301.py b/smash/web/migrations/0141_auto_20200319_1301.py new file mode 100644 index 00000000..82d45afe --- /dev/null +++ b/smash/web/migrations/0141_auto_20200319_1301.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2020-03-19 13:01 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0140_auto_20190528_0953'), + ] + + operations = [ + migrations.AlterModelOptions( + name='appointmenttypelink', + options={'permissions': [('view_daily_planning', 'Can see daily planning')]}, + ), + migrations.AlterField( + model_name='appointmenttype', + name='calendar_font_color', + field=models.CharField(default=b'#00000', max_length=2000, verbose_name=b'Calendar font color'), + ), + ] diff --git a/smash/web/models/appointment_type_link.py b/smash/web/models/appointment_type_link.py index a48a5502..c2de6050 100644 --- a/smash/web/models/appointment_type_link.py +++ b/smash/web/models/appointment_type_link.py @@ -2,6 +2,10 @@ from django.db import models class AppointmentTypeLink(models.Model): + class Meta: + permissions = [ + ("view_daily_planning", "Can see daily planning"), + ] appointment = models.ForeignKey("web.Appointment", on_delete=models.CASCADE) appointment_type = models.ForeignKey("web.AppointmentType", on_delete=models.CASCADE) date_when = models.DateTimeField(null=True, default=None) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index a91be3d7..c33796da 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -16,12 +16,14 @@ </a> </li> - <li data-desc="daily_planning"> - <a href="{% url 'web.views.daily_planning' %}"> - <i class="fa fa-clock-o"></i> - <span>Daily Planning</span> - </a> - </li> + {% if "view_daily_planning" in permissions %} + <li data-desc="daily_planning"> + <a href="{% url 'web.views.daily_planning' %}"> + <i class="fa fa-clock-o"></i> + <span>Daily Planning</span> + </a> + </li> + {% endif %} {% if "change_worker" in permissions %} <li data-desc="workers"> diff --git a/smash/web/tests/view/test_daily_planning.py b/smash/web/tests/view/test_daily_planning.py new file mode 100644 index 00000000..096cc920 --- /dev/null +++ b/smash/web/tests/view/test_daily_planning.py @@ -0,0 +1,20 @@ +import logging + +from django.urls import reverse + +from web.tests import LoggedInTestCase + +logger = logging.getLogger(__name__) + + +class DailyPlanningViewTests(LoggedInTestCase): + def test_visit_details_request(self): + self.login_as_admin() + response = self.client.get(reverse('web.views.daily_planning')) + + self.assertEqual(response.status_code, 200) + + def test_visit_details_request_without_permissions(self): + self.login_as_staff() + response = self.client.get(reverse('web.views.daily_planning')) + self.assertEqual(response.status_code, 302) diff --git a/smash/web/views/daily_planning.py b/smash/web/views/daily_planning.py index 40ab776c..d720816f 100644 --- a/smash/web/views/daily_planning.py +++ b/smash/web/views/daily_planning.py @@ -1,12 +1,15 @@ # coding=utf-8 -import logging from django.views.generic import TemplateView -from . import wrap_response + +from web.decorators import PermissionDecorator from web.models.worker_study_role import STUDY_ROLE_CHOICES +from . import wrap_response + class TemplateDailyPlannerView(TemplateView): + @PermissionDecorator('view_daily_planning', 'daily_planning') def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) context['worker_study_roles'] = STUDY_ROLE_CHOICES - return wrap_response(request, 'daily_planning.html', context) \ No newline at end of file + return wrap_response(request, 'daily_planning.html', context) -- GitLab From 2a5a47c269ed36c884611b97beb25168afa41737 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 14:38:41 +0100 Subject: [PATCH 02/10] edit equipement permission added --- smash/web/templates/sidebar.html | 2 ++ smash/web/tests/view/test_equipments.py | 12 ++++++++++++ smash/web/views/equipment.py | 7 ++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index c33796da..f623b037 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -42,7 +42,9 @@ </span> </a> <ul class="treeview-menu"> + {% if "change_item" in permissions %} <li data-desc="equipment_items"><a href="{% url 'web.views.equipment' %}">Equipment items</a></li> + {% endif %} {% if "change_appointmenttype" in permissions %} <li data-desc="appointment_types"><a href="{% url 'web.views.appointment_types' %}">Appointment Types</a></li> {% endif %} diff --git a/smash/web/tests/view/test_equipments.py b/smash/web/tests/view/test_equipments.py index 99e312a8..34cba24a 100644 --- a/smash/web/tests/view/test_equipments.py +++ b/smash/web/tests/view/test_equipments.py @@ -10,7 +10,14 @@ logger = logging.getLogger(__name__) class EquipmentTests(LoggedInTestCase): + + def test_list_without_permissions(self): + self.login_as_staff() + response = self.client.get(reverse('web.views.equipment')) + self.assertEqual(response.status_code, 302) + def test_equipment_requests(self): + self.login_as_admin() pages = [ 'web.views.equipment', 'web.views.equipment_add', @@ -21,6 +28,7 @@ class EquipmentTests(LoggedInTestCase): self.assertEqual(response.status_code, 200) def test_equipment_edit_request(self): + self.login_as_admin() item = create_item() page = reverse('web.views.equipment_edit', kwargs={'equipment_id': str(item.id)}) @@ -28,6 +36,7 @@ class EquipmentTests(LoggedInTestCase): self.assertEqual(response.status_code, 200) def test_equipment_delete_request(self): + self.login_as_admin() item = create_item() page = reverse('web.views.equipment_delete', kwargs={'equipment_id': str(item.id)}) @@ -35,6 +44,7 @@ class EquipmentTests(LoggedInTestCase): self.assertEqual(response.status_code, 302) def test_equipment_add(self): + self.login_as_admin() page = reverse('web.views.equipment_add') data = { 'name': 'The mysterious potion', @@ -48,6 +58,7 @@ class EquipmentTests(LoggedInTestCase): self.assertEqual(len(freshly_created), 1) def test_equipment_edit(self): + self.login_as_admin() item = create_item() page = reverse('web.views.equipment_edit', kwargs={'equipment_id': str(item.id)}) @@ -64,6 +75,7 @@ class EquipmentTests(LoggedInTestCase): self.assertEqual(getattr(freshly_edited, key, ''), data[key]) def test_equipment_delete(self): + self.login_as_admin() item = create_item() page = reverse('web.views.equipment_delete', kwargs={'equipment_id': str(item.id)}) diff --git a/smash/web/views/equipment.py b/smash/web/views/equipment.py index ff498134..a4c36568 100644 --- a/smash/web/views/equipment.py +++ b/smash/web/views/equipment.py @@ -1,11 +1,13 @@ # coding=utf-8 from django.shortcuts import redirect, get_object_or_404 +from web.decorators import PermissionDecorator from . import wrap_response -from ..models import Item from ..forms.forms import ItemForm +from ..models import Item +@PermissionDecorator('change_item', 'item') def equipment(request): equipment_list = Item.objects.order_by('-name') context = { @@ -15,6 +17,7 @@ def equipment(request): return wrap_response(request, "equipment_and_rooms/equipment/index.html", context) +@PermissionDecorator('change_item', 'item') def equipment_add(request): if request.method == 'POST': form = ItemForm(request.POST) @@ -27,6 +30,7 @@ def equipment_add(request): return wrap_response(request, 'equipment_and_rooms/equipment/add.html', {'form': form}) +@PermissionDecorator('change_item', 'item') def equipment_edit(request, equipment_id): the_item = get_object_or_404(Item, id=equipment_id) if request.method == 'POST': @@ -40,6 +44,7 @@ def equipment_edit(request, equipment_id): return wrap_response(request, 'equipment_and_rooms/equipment/edit.html', {'form': form}) +@PermissionDecorator('change_item', 'item') def equipment_delete(request, equipment_id): the_item = get_object_or_404(Item, id=equipment_id) the_item.delete() -- GitLab From 2972e59b8808655b42f9225a72dfbbb906addfa9 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 14:58:31 +0100 Subject: [PATCH 03/10] modif_flyingteam permission implemented --- smash/web/templates/sidebar.html | 2 ++ smash/web/tests/view/test_flying_teams.py | 14 ++++++++++++++ smash/web/views/flying_teams.py | 7 ++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index f623b037..e96f912d 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -48,7 +48,9 @@ {% if "change_appointmenttype" in permissions %} <li data-desc="appointment_types"><a href="{% url 'web.views.appointment_types' %}">Appointment Types</a></li> {% endif %} + {% if "change_flyingteam" in permissions %} <li data-desc="flying_teams"><a href="{% url 'web.views.equipment_and_rooms.flying_teams' %}">Flying teams</a></li> + {% endif %} <li data-desc="kit_requests"><a href="{% url 'web.views.kit_requests' %}">Kit requests</a></li> <li data-desc="rooms"><a href="{% url 'web.views.equipment_and_rooms.rooms' %}">Rooms</a></li> </ul> diff --git a/smash/web/tests/view/test_flying_teams.py b/smash/web/tests/view/test_flying_teams.py index 32cfe22f..e282c3e9 100644 --- a/smash/web/tests/view/test_flying_teams.py +++ b/smash/web/tests/view/test_flying_teams.py @@ -17,6 +17,7 @@ class FlyingTeamTests(LoggedInTestCase): return 'Random' + ''.join(random.choice(letters) for x in range(15)) def test_flying_team_requests(self): + self.login_as_admin() pages = [ 'web.views.equipment_and_rooms.flying_teams', 'web.views.equipment_and_rooms.flying_teams_add', @@ -26,7 +27,18 @@ class FlyingTeamTests(LoggedInTestCase): response = self.client.get(reverse(page)) self.assertEqual(response.status_code, 200) + def test_flying_team_requests_without_permission(self): + pages = [ + 'web.views.equipment_and_rooms.flying_teams', + 'web.views.equipment_and_rooms.flying_teams_add', + ] + + for page in pages: + response = self.client.get(reverse(page)) + self.assertEqual(response.status_code, 302) + def test_flying_team_add(self): + self.login_as_admin() page = reverse('web.views.equipment_and_rooms.flying_teams_add') data = { 'place': self.generate_more_or_less_random_name() @@ -38,6 +50,7 @@ class FlyingTeamTests(LoggedInTestCase): self.assertEqual(len(freshly_created), 1) def test_flying_team_edit(self): + self.login_as_admin() flying_team = create_flying_team() page = reverse('web.views.equipment_and_rooms.flying_teams_edit', kwargs={'flying_team_id': str(flying_team.id)}) @@ -51,6 +64,7 @@ class FlyingTeamTests(LoggedInTestCase): self.assertEqual(freshly_edited.place, data["place"]) def test_flying_team_edit_request(self): + self.login_as_admin() flying_team = create_flying_team() page = reverse('web.views.equipment_and_rooms.flying_teams_edit', kwargs={'flying_team_id': str(flying_team.id)}) diff --git a/smash/web/views/flying_teams.py b/smash/web/views/flying_teams.py index dc6c4752..f4e3cb78 100644 --- a/smash/web/views/flying_teams.py +++ b/smash/web/views/flying_teams.py @@ -1,11 +1,13 @@ # coding=utf-8 from django.shortcuts import redirect, get_object_or_404 +from web.decorators import PermissionDecorator from . import wrap_response -from ..models import FlyingTeam from ..forms.forms import FlyingTeamAddForm, FlyingTeamEditForm +from ..models import FlyingTeam +@PermissionDecorator('change_flyingteam', 'item') def flying_teams(request): flying_team_list = FlyingTeam.objects.order_by('-place') context = { @@ -16,6 +18,8 @@ def flying_teams(request): "equipment_and_rooms/flying_teams/index.html", context) + +@PermissionDecorator('change_flyingteam', 'item') def flying_teams_add(request): if request.method == 'POST': form = FlyingTeamAddForm(request.POST) @@ -28,6 +32,7 @@ def flying_teams_add(request): return wrap_response(request, 'equipment_and_rooms/flying_teams/add.html', {'form': form}) +@PermissionDecorator('change_flyingteam', 'item') def flying_teams_edit(request, flying_team_id): the_flying_team = get_object_or_404(FlyingTeam, id=flying_team_id) if request.method == 'POST': -- GitLab From f9c713c1fe0bd239d493466b495d592150667d3b Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 15:06:53 +0100 Subject: [PATCH 04/10] modify_room permission implemented --- smash/web/templates/sidebar.html | 2 ++ smash/web/tests/view/test_rooms.py | 20 ++++++++++++++++++-- smash/web/views/flying_teams.py | 6 +++--- smash/web/views/rooms.py | 5 +++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index e96f912d..e465b4af 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -52,7 +52,9 @@ <li data-desc="flying_teams"><a href="{% url 'web.views.equipment_and_rooms.flying_teams' %}">Flying teams</a></li> {% endif %} <li data-desc="kit_requests"><a href="{% url 'web.views.kit_requests' %}">Kit requests</a></li> + {% if "change_room" in permissions %} <li data-desc="rooms"><a href="{% url 'web.views.equipment_and_rooms.rooms' %}">Rooms</a></li> + {% endif %} </ul> </li> diff --git a/smash/web/tests/view/test_rooms.py b/smash/web/tests/view/test_rooms.py index ecf11616..b607e810 100644 --- a/smash/web/tests/view/test_rooms.py +++ b/smash/web/tests/view/test_rooms.py @@ -2,15 +2,16 @@ import logging from django.urls import reverse -from web.tests.functions import create_room, create_item -from web.models import Item, Room +from web.models import Room from web.tests import LoggedInTestCase +from web.tests.functions import create_room, create_item logger = logging.getLogger(__name__) class RoomsTests(LoggedInTestCase): def test_rooms_requests(self): + self.login_as_admin() pages = [ 'web.views.equipment_and_rooms.rooms', 'web.views.equipment_and_rooms.rooms_add', @@ -20,7 +21,18 @@ class RoomsTests(LoggedInTestCase): response = self.client.get(reverse(page)) self.assertEqual(response.status_code, 200) + def test_rooms_requests_without_permission(self): + pages = [ + 'web.views.equipment_and_rooms.rooms', + 'web.views.equipment_and_rooms.rooms_add', + ] + + for page in pages: + response = self.client.get(reverse(page)) + self.assertEqual(response.status_code, 302) + def test_rooms_edit_request(self): + self.login_as_admin() room = create_room() page = reverse('web.views.equipment_and_rooms.rooms_edit', kwargs={'room_id': str(room.id)}) @@ -28,6 +40,7 @@ class RoomsTests(LoggedInTestCase): self.assertEqual(response.status_code, 200) def test_rooms_delete_request(self): + self.login_as_admin() room = create_room() page = reverse('web.views.equipment_and_rooms.rooms_delete', kwargs={'room_id': str(room.id)}) @@ -35,6 +48,7 @@ class RoomsTests(LoggedInTestCase): self.assertEqual(response.status_code, 302) def test_rooms_add(self): + self.login_as_admin() page = reverse('web.views.equipment_and_rooms.rooms_add') item = create_item() data = { @@ -53,6 +67,7 @@ class RoomsTests(LoggedInTestCase): self.assertEqual(len(freshly_created), 1) def test_rooms_edit(self): + self.login_as_admin() room = create_room() page = reverse('web.views.equipment_and_rooms.rooms_edit', kwargs={'room_id': str(room.id)}) @@ -72,6 +87,7 @@ class RoomsTests(LoggedInTestCase): self.assertEqual(getattr(freshly_edited, key, ''), data[key]) def test_rooms_delete(self): + self.login_as_admin() room = create_room() page = reverse('web.views.equipment_and_rooms.rooms_delete', kwargs={'room_id': str(room.id)}) diff --git a/smash/web/views/flying_teams.py b/smash/web/views/flying_teams.py index f4e3cb78..e96fe301 100644 --- a/smash/web/views/flying_teams.py +++ b/smash/web/views/flying_teams.py @@ -7,7 +7,7 @@ from ..forms.forms import FlyingTeamAddForm, FlyingTeamEditForm from ..models import FlyingTeam -@PermissionDecorator('change_flyingteam', 'item') +@PermissionDecorator('change_flyingteam', 'flyingteam') def flying_teams(request): flying_team_list = FlyingTeam.objects.order_by('-place') context = { @@ -19,7 +19,7 @@ def flying_teams(request): context) -@PermissionDecorator('change_flyingteam', 'item') +@PermissionDecorator('change_flyingteam', 'flyingteam') def flying_teams_add(request): if request.method == 'POST': form = FlyingTeamAddForm(request.POST) @@ -32,7 +32,7 @@ def flying_teams_add(request): return wrap_response(request, 'equipment_and_rooms/flying_teams/add.html', {'form': form}) -@PermissionDecorator('change_flyingteam', 'item') +@PermissionDecorator('change_flyingteam', 'flyingteam') def flying_teams_edit(request, flying_team_id): the_flying_team = get_object_or_404(FlyingTeam, id=flying_team_id) if request.method == 'POST': diff --git a/smash/web/views/rooms.py b/smash/web/views/rooms.py index 2ff626e9..5c20463b 100644 --- a/smash/web/views/rooms.py +++ b/smash/web/views/rooms.py @@ -1,11 +1,13 @@ # coding=utf-8 from django.shortcuts import redirect, get_object_or_404 +from web.decorators import PermissionDecorator from . import wrap_response from ..forms.forms import RoomForm from ..models import Room +@PermissionDecorator('change_room', 'room') def rooms(request): rooms_list = Room.objects.order_by('-city') context = { @@ -17,6 +19,7 @@ def rooms(request): context) +@PermissionDecorator('change_room', 'room') def rooms_add(request): if request.method == 'POST': form = RoomForm(request.POST) @@ -29,6 +32,7 @@ def rooms_add(request): return wrap_response(request, 'equipment_and_rooms/rooms/add.html', {'form': form}) +@PermissionDecorator('change_room', 'room') def rooms_edit(request, room_id): the_room = get_object_or_404(Room, id=room_id) if request.method == 'POST': @@ -42,6 +46,7 @@ def rooms_edit(request, room_id): return wrap_response(request, 'equipment_and_rooms/rooms/edit.html', {'form': form}) +@PermissionDecorator('change_room', 'room') def rooms_delete(request, room_id): the_room = get_object_or_404(Room, id=room_id) the_room.delete() -- GitLab From 290e82b7e37ba68d32478f3ec827ce0b55561ea7 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 15:35:14 +0100 Subject: [PATCH 05/10] permission to send sample list email --- .../web/migrations/0142_auto_20200319_1415.py | 19 ++++++++ smash/web/models/appointment.py | 3 ++ smash/web/templates/sidebar.html | 48 +++++++++++-------- smash/web/tests/view/test_kit_request.py | 15 +++++- smash/web/views/kit.py | 12 +++-- 5 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 smash/web/migrations/0142_auto_20200319_1415.py diff --git a/smash/web/migrations/0142_auto_20200319_1415.py b/smash/web/migrations/0142_auto_20200319_1415.py new file mode 100644 index 00000000..ea5d4620 --- /dev/null +++ b/smash/web/migrations/0142_auto_20200319_1415.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2020-03-19 14:15 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0141_auto_20200319_1301'), + ] + + operations = [ + migrations.AlterModelOptions( + name='appointment', + options={'permissions': [('send_sample_mail_for_appointments', 'Can send sample collection list')]}, + ), + ] diff --git a/smash/web/models/appointment.py b/smash/web/models/appointment.py index 9b5b3944..ad4e9ff6 100644 --- a/smash/web/models/appointment.py +++ b/smash/web/models/appointment.py @@ -11,6 +11,9 @@ from . import ConfigurationItem class Appointment(models.Model): class Meta: app_label = 'web' + permissions = [ + ("send_sample_mail_for_appointments", "Can send sample collection list"), + ] APPOINTMENT_STATUS_SCHEDULED = 'SCHEDULED' APPOINTMENT_STATUS_FINISHED = 'FINISHED' diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index e465b4af..7857b135 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -34,29 +34,35 @@ </li> {% endif %} - <li data-desc="equipment_and_rooms" class="treeview"> - <a href="{% url 'web.views.equipment_and_rooms' %}"> - <i class="fa fa-building-o"></i> <span>Equipment & Rooms</span> - <span class="pull-right-container"> + {% if "change_item" in permissions or "change_appointmenttype" in permissions or "change_appointmenttype" in permissions or "change_flyingteam" in permissions or "send_sample_mail_for_appointments" in permissions or "change_room" in permissions %} + <li data-desc="equipment_and_rooms" class="treeview"> + <a href="{% url 'web.views.equipment_and_rooms' %}"> + <i class="fa fa-building-o"></i> <span>Equipment & Rooms</span> + <span class="pull-right-container"> <i class="fa fa-angle-left pull-right"></i> </span> - </a> - <ul class="treeview-menu"> - {% if "change_item" in permissions %} - <li data-desc="equipment_items"><a href="{% url 'web.views.equipment' %}">Equipment items</a></li> - {% endif %} - {% if "change_appointmenttype" in permissions %} - <li data-desc="appointment_types"><a href="{% url 'web.views.appointment_types' %}">Appointment Types</a></li> - {% endif %} - {% if "change_flyingteam" in permissions %} - <li data-desc="flying_teams"><a href="{% url 'web.views.equipment_and_rooms.flying_teams' %}">Flying teams</a></li> - {% endif %} - <li data-desc="kit_requests"><a href="{% url 'web.views.kit_requests' %}">Kit requests</a></li> - {% if "change_room" in permissions %} - <li data-desc="rooms"><a href="{% url 'web.views.equipment_and_rooms.rooms' %}">Rooms</a></li> - {% endif %} - </ul> - </li> + </a> + <ul class="treeview-menu"> + {% if "change_item" in permissions %} + <li data-desc="equipment_items"><a href="{% url 'web.views.equipment' %}">Equipment items</a></li> + {% endif %} + {% if "change_appointmenttype" in permissions %} + <li data-desc="appointment_types"><a href="{% url 'web.views.appointment_types' %}">Appointment + Types</a></li> + {% endif %} + {% if "change_flyingteam" in permissions %} + <li data-desc="flying_teams"><a href="{% url 'web.views.equipment_and_rooms.flying_teams' %}">Flying + teams</a></li> + {% endif %} + {% if "send_sample_mail_for_appointments" in permissions %} + <li data-desc="kit_requests"><a href="{% url 'web.views.kit_requests' %}">Kit requests</a></li> + {% endif %} + {% if "change_room" in permissions %} + <li data-desc="rooms"><a href="{% url 'web.views.equipment_and_rooms.rooms' %}">Rooms</a></li> + {% endif %} + </ul> + </li> + {% endif %} <li data-desc="statistics"> <a href="{% url 'web.views.statistics' %}"> diff --git a/smash/web/tests/view/test_kit_request.py b/smash/web/tests/view/test_kit_request.py index 387001f3..72222f5d 100644 --- a/smash/web/tests/view/test_kit_request.py +++ b/smash/web/tests/view/test_kit_request.py @@ -5,7 +5,8 @@ from django.urls import reverse from web.models import Item, Appointment, AppointmentTypeLink from web.tests import LoggedInTestCase -from web.tests.functions import create_appointment_type, create_appointment, create_visit, create_appointment_without_visit +from web.tests.functions import create_appointment_type, create_appointment, create_visit, \ + create_appointment_without_visit from web.views.kit import get_kit_requests from web.views.notifications import get_today_midnight_date @@ -13,10 +14,16 @@ from web.views.notifications import get_today_midnight_date class ViewFunctionsTests(LoggedInTestCase): def test_kit_requests(self): + self.login_as_admin() response = self.client.get(reverse('web.views.kit_requests')) self.assertEqual(response.status_code, 200) + def test_kit_requests_without_permission(self): + response = self.client.get(reverse('web.views.kit_requests')) + self.assertEqual(response.status_code, 302) + def test_kit_requests_2(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() @@ -35,6 +42,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertTrue(item_name in response.content) def test_kit_requests_4(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() @@ -54,6 +62,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertFalse(item_name in response.content) def test_kit_requests_3(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() @@ -72,6 +81,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertTrue(item_name in response.content) def test_kit_requests_order(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() @@ -104,6 +114,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertEqual(appointment2, result['appointments'][2]) def test_kit_requests_for_appointment_with_two_types(self): + self.login_as_admin() item = Item.objects.create(disposable=True, name="item 1") appointment_type = create_appointment_type() appointment_type.required_equipment.add(item) @@ -129,6 +140,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertEqual(1, len(result["appointments"])) def test_kit_requests_send_email(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() @@ -150,6 +162,7 @@ class ViewFunctionsTests(LoggedInTestCase): self.assertEqual(1, len(mail.outbox)) def test_kit_request_send_mail_with_general_appointment(self): + self.login_as_admin() item_name = "Test item to be ordered" item = Item.objects.create(disposable=True, name=item_name) appointment_type = create_appointment_type() diff --git a/smash/web/views/kit.py b/smash/web/views/kit.py index 79c42ef5..159338fa 100644 --- a/smash/web/views/kit.py +++ b/smash/web/views/kit.py @@ -13,6 +13,7 @@ from django_cron import CronJobBase, Schedule from django_cron.models import CronJobLog from notifications import get_filter_locations, get_today_midnight_date +from web.decorators import PermissionDecorator from web.models import ConfigurationItem, Language, Worker from web.models.constants import KIT_EMAIL_HOUR_CONFIGURATION_TYPE, \ KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_TYPE, CRON_JOB_TIMEOUT @@ -60,6 +61,7 @@ def get_kit_requests(user, start_date=None, end_date=None): return result +@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') def get_kit_requests_data(request, start_date=None, end_date=None): form = KitRequestForm() if request.method == 'POST': @@ -76,6 +78,7 @@ def get_kit_requests_data(request, start_date=None, end_date=None): return params +@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') def kit_requests(request): return wrap_response(request, 'equipment_and_rooms/kit_requests/kit_requests.html', get_kit_requests_data(request)) @@ -85,7 +88,7 @@ def send_mail(data): if data["end_date"] is not None: end_date_str = data["end_date"].strftime('%Y-%m-%d') title = "Samples between " + \ - data["start_date"].strftime('%Y-%m-%d') + " and " + end_date_str + data["start_date"].strftime('%Y-%m-%d') + " and " + end_date_str cell_style = "padding: 8px; line-height: 1.42857143; vertical-align: top; " \ "font-size: 14px; font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,Arial,sans-serif;" @@ -109,10 +112,10 @@ def send_mail(data): row_style = ' background-color: #f9f9f9;' email_body += "<tr style='" + row_style + "'>" email_body += "<td style='" + cell_style + "'>" + \ - appointment.datetime_when.strftime('%Y-%m-%d %H:%M') + "</td>" + appointment.datetime_when.strftime('%Y-%m-%d %H:%M') + "</td>" if appointment.visit is not None and appointment.visit.subject is not None: email_body += "<td style='" + cell_style + "'>" + \ - appointment.visit.subject.nd_number + "</td>" + appointment.visit.subject.nd_number + "</td>" else: email_body += "<td style='" + cell_style + "'>" + '-' + "</td>" email_body += "<td style='" + cell_style + "'>" @@ -126,7 +129,7 @@ def send_mail(data): location += " (" + unicode(appointment.flying_team) + ")" email_body += "<td style='" + cell_style + "'>" + location + "</td>" email_body += "<td style='" + cell_style + "'>" + \ - unicode(appointment.worker_assigned) + "</td>" + unicode(appointment.worker_assigned) + "</td>" email_body += "</tr>" email_body += "</tbody></table>" recipients = ConfigurationItem.objects.get( @@ -136,6 +139,7 @@ def send_mail(data): EmailSender().send_email(title, email_body, recipients, cc_recipients) +@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') def kit_requests_send_mail(request, start_date, end_date=None): data = get_kit_requests_data(request, start_date, end_date) try: -- GitLab From 896bcfc96ea091ca79a89b1ffc0acbb36130c3f2 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 15:53:57 +0100 Subject: [PATCH 06/10] view_statistics permission implemented --- .../web/migrations/0143_auto_20200319_1446.py | 19 +++++++++++++++++++ smash/web/models/appointment.py | 1 + smash/web/templates/sidebar.html | 14 ++++++++------ smash/web/tests/view/test_statistics.py | 6 ++++++ smash/web/views/statistics.py | 2 ++ 5 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 smash/web/migrations/0143_auto_20200319_1446.py diff --git a/smash/web/migrations/0143_auto_20200319_1446.py b/smash/web/migrations/0143_auto_20200319_1446.py new file mode 100644 index 00000000..d6c74b0c --- /dev/null +++ b/smash/web/migrations/0143_auto_20200319_1446.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2020-03-19 14:46 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0142_auto_20200319_1415'), + ] + + operations = [ + migrations.AlterModelOptions( + name='appointment', + options={'permissions': [('send_sample_mail_for_appointments', 'Can send sample collection list'), ('view_statistics', 'Can see statistics')]}, + ), + ] diff --git a/smash/web/models/appointment.py b/smash/web/models/appointment.py index ad4e9ff6..c7a52d41 100644 --- a/smash/web/models/appointment.py +++ b/smash/web/models/appointment.py @@ -13,6 +13,7 @@ class Appointment(models.Model): app_label = 'web' permissions = [ ("send_sample_mail_for_appointments", "Can send sample collection list"), + ("view_statistics", "Can see statistics"), ] APPOINTMENT_STATUS_SCHEDULED = 'SCHEDULED' diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index 7857b135..00aa8ca8 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -64,12 +64,14 @@ </li> {% endif %} - <li data-desc="statistics"> - <a href="{% url 'web.views.statistics' %}"> - <i class="fa fa-bar-chart" aria-hidden="true"></i> - <span>Statistics</span> - </a> - </li> + {% if "view_statistics" in permissions %} + <li data-desc="statistics"> + <a href="{% url 'web.views.statistics' %}"> + <i class="fa fa-bar-chart" aria-hidden="true"></i> + <span>Statistics</span> + </a> + </li> + {% endif %} <li data-desc="mail_templates"> <a href="{% url 'web.views.mail_templates' %}"> diff --git a/smash/web/tests/view/test_statistics.py b/smash/web/tests/view/test_statistics.py index 73737107..aa7fee20 100644 --- a/smash/web/tests/view/test_statistics.py +++ b/smash/web/tests/view/test_statistics.py @@ -10,6 +10,7 @@ __author__ = 'Valentin Grouès' class TestStatisticsView(LoggedInTestCase): def test_statistics_request(self): + self.login_as_admin() url = reverse('web.views.statistics') response = self.client.get(url) self.assertEqual(response.status_code, 200) @@ -19,3 +20,8 @@ class TestStatisticsView(LoggedInTestCase): response = self.client.get(url, {"month": 10, "year": 2017, "subject_type": -1, "visit": -1}) content = response.content self.assertIn('<option value="10" selected>October', content) + + def test_statistics_request_without_permission(self): + url = reverse('web.views.statistics') + response = self.client.get(url) + self.assertEqual(response.status_code, 302) diff --git a/smash/web/views/statistics.py b/smash/web/views/statistics.py index 67bdb79c..b8cd84cc 100644 --- a/smash/web/views/statistics.py +++ b/smash/web/views/statistics.py @@ -1,9 +1,11 @@ # coding=utf-8 +from web.decorators import PermissionDecorator from . import wrap_response from ..forms import StatisticsForm from ..statistics import StatisticsManager, get_previous_year_and_month +@PermissionDecorator('view_statistics', 'appointment') def statistics(request): statistics_manager = StatisticsManager() visit_choices = [("-1", "all")] -- GitLab From 916865ab956731c59cb177d4a27e0666bfec3738 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 16:13:03 +0100 Subject: [PATCH 07/10] modify_mailtemplate permission implemented --- smash/web/templates/sidebar.html | 15 +++++++++------ smash/web/tests/view/test_mail.py | 11 ++++++++++- smash/web/views/mails.py | 10 +++++++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index 00aa8ca8..5aceea8b 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -73,12 +73,15 @@ </li> {% endif %} - <li data-desc="mail_templates"> - <a href="{% url 'web.views.mail_templates' %}"> - <i class="fa fa-envelope-o"></i> - <span>Mail templates</span> - </a> - </li> + + {% if "change_mailtemplate" in permissions %} + <li data-desc="mail_templates"> + <a href="{% url 'web.views.mail_templates' %}"> + <i class="fa fa-envelope-o"></i> + <span>Mail templates</span> + </a> + </li> + {% endif %} <li data-desc="export"> <a href="{% url 'web.views.export' %}"> diff --git a/smash/web/tests/view/test_mail.py b/smash/web/tests/view/test_mail.py index 900c84a7..1f11340a 100644 --- a/smash/web/tests/view/test_mail.py +++ b/smash/web/tests/view/test_mail.py @@ -4,8 +4,8 @@ from django.urls import reverse from web.models import MailTemplate from web.models.constants import MAIL_TEMPLATE_CONTEXT_VOUCHER -from web.tests.functions import create_voucher, get_resource_path from web.tests import LoggedInTestCase +from web.tests.functions import create_voucher, get_resource_path logger = logging.getLogger(__name__) @@ -20,3 +20,12 @@ class MailTests(LoggedInTestCase): page = reverse('web.views.mail_template_generate_for_vouchers') + "?voucher_id=" + str(voucher.id) response = self.client.get(page) self.assertEqual(response.status_code, 200) + + def test_list_mail_templates(self): + self.login_as_admin() + response = self.client.get(reverse("web.views.mail_templates")) + self.assertEqual(response.status_code, 200) + + def test_list_mail_templates_without_permission(self): + response = self.client.get(reverse("web.views.mail_templates")) + self.assertEqual(response.status_code, 302) diff --git a/smash/web/views/mails.py b/smash/web/views/mails.py index ef4cf0b3..7b49409c 100644 --- a/smash/web/views/mails.py +++ b/smash/web/views/mails.py @@ -9,6 +9,7 @@ from django.urls import reverse_lazy from django.views.generic import DeleteView from django.views.generic import ListView +from web.decorators import PermissionDecorator from web.docx_helper import merge_files from . import WrappedView from . import wrap_response @@ -32,7 +33,11 @@ class MailTemplatesListView(ListView, WrappedView): context_object_name = "mail_templates" template_name = 'mail_templates/list.html' - def get_context_data(self, **kwargs): + @PermissionDecorator('change_mailtemplate', 'mailtemplate') + def dispatch(self, *args, **kwargs): + return super(MailTemplatesListView, self).dispatch(*args, **kwargs) + + def get_context_data(self, *args, **kwargs): context = super(MailTemplatesListView, self).get_context_data() context['explanations'] = {"generic": MailTemplate.MAILS_TEMPLATE_GENERIC_TAGS, "subject": MailTemplate.MAILS_TEMPLATE_SUBJECT_TAGS, @@ -43,6 +48,7 @@ class MailTemplatesListView(ListView, WrappedView): return context +@PermissionDecorator('change_mailtemplate', 'mailtemplate') def mail_template_add(request): if request.method == 'POST': form = MailTemplateForm(request.POST, request.FILES) @@ -59,6 +65,7 @@ def mail_template_add(request): return wrap_response(request, 'mail_templates/add.html', {'form': form}) +@PermissionDecorator('change_mailtemplate', 'mailtemplate') def mail_template_edit(request, pk): template = get_object_or_404(MailTemplate, pk=pk) if request.method == 'POST': @@ -82,6 +89,7 @@ class MailTemplatesDeleteView(DeleteView, WrappedView): success_url = reverse_lazy('web.views.mail_templates') template_name = 'mail_templates/confirm_delete.html' + @PermissionDecorator('change_mailtemplate', 'mailtemplate') def delete(self, request, *args, **kwargs): messages.success(request, "Template deleted") try: -- GitLab From cd02637c7b89a4fbfdf90ae35cb81d04d7b82dab Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 16:29:07 +0100 Subject: [PATCH 08/10] export_subjects permission implemented --- .../web/migrations/0144_auto_20200319_1518.py | 19 +++++++ smash/web/models/subject.py | 19 ++++--- smash/web/templates/sidebar.html | 14 +++--- smash/web/tests/view/test_export.py | 21 ++++++++ smash/web/views/export.py | 50 +++++++++++-------- 5 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 smash/web/migrations/0144_auto_20200319_1518.py diff --git a/smash/web/migrations/0144_auto_20200319_1518.py b/smash/web/migrations/0144_auto_20200319_1518.py new file mode 100644 index 00000000..bdb5b3ee --- /dev/null +++ b/smash/web/migrations/0144_auto_20200319_1518.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2020-03-19 15:18 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0143_auto_20200319_1446'), + ] + + operations = [ + migrations.AlterModelOptions( + name='subject', + options={'permissions': [('send_sample_mail_for_appointments', 'Can send sample collection list'), ('export_subjects', 'Can export subject data to excel/csv')]}, + ), + ] diff --git a/smash/web/models/subject.py b/smash/web/models/subject.py index b762bfe3..0d0eb57f 100644 --- a/smash/web/models/subject.py +++ b/smash/web/models/subject.py @@ -1,19 +1,24 @@ # coding=utf-8 import logging + from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver from constants import SEX_CHOICES, COUNTRY_OTHER_ID from web.models import Country, Visit, Appointment from . import Language -from django.db.models.signals import post_save -from django.dispatch import receiver logger = logging.getLogger(__name__) -class Subject(models.Model): +class Subject(models.Model): class Meta: app_label = 'web' + permissions = [ + ("send_sample_mail_for_appointments", "Can send sample collection list"), + ("export_subjects", "Can export subject data to excel/csv"), + ] sex = models.CharField(max_length=1, choices=SEX_CHOICES, @@ -103,7 +108,7 @@ class Subject(models.Model): ) def pretty_address(self): - return u'{} ({}), {}. {}'.format(self.address, self.postal_code, self.city, self.country) + return u'{} ({}), {}. {}'.format(self.address, self.postal_code, self.city, self.country) def mark_as_dead(self): self.dead = True @@ -130,8 +135,8 @@ class Subject(models.Model): return "%s %s" % (self.first_name, self.last_name) -#SIGNALS +# SIGNALS @receiver(post_save, sender=Subject) def set_as_deceased(sender, instance, **kwargs): - if instance.dead: - instance.mark_as_dead() \ No newline at end of file + if instance.dead: + instance.mark_as_dead() diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index 5aceea8b..9d215925 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -83,12 +83,14 @@ </li> {% endif %} - <li data-desc="export"> - <a href="{% url 'web.views.export' %}"> - <i class="fa fa-file-excel-o"></i> - <span>Export</span> - </a> - </li> + {% if "export_subjects" in permissions %} + <li data-desc="export"> + <a href="{% url 'web.views.export' %}"> + <i class="fa fa-file-excel-o"></i> + <span>Export</span> + </a> + </li> + {% endif %} {% if study.has_vouchers and "change_voucher" in permissions%} <li data-desc="vouchers"> diff --git a/smash/web/tests/view/test_export.py b/smash/web/tests/view/test_export.py index d6938476..3f6a5c99 100644 --- a/smash/web/tests/view/test_export.py +++ b/smash/web/tests/view/test_export.py @@ -9,26 +9,47 @@ from web.views.export import subject_to_row_for_fields, DROP_OUT_FIELD class TestExportView(LoggedInTestCase): def test_export_subjects_to_csv(self): + self.login_as_admin() create_study_subject() response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "subjects"})) self.assertEqual(response.status_code, 200) + def test_export_subjects_to_csv_without_permission(self): + response = self.client.get(reverse("web.views.mail_templates")) + create_study_subject() + response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "subjects"})) + self.assertEqual(response.status_code, 302) + def test_render_export(self): + self.login_as_admin() create_study_subject() response = self.client.get(reverse('web.views.export')) self.assertEqual(response.status_code, 200) + def test_render_export_without_permission(self): + create_study_subject() + response = self.client.get(reverse('web.views.export')) + self.assertEqual(response.status_code, 302) + def test_export_appointments_to_csv(self): + self.login_as_admin() create_appointment() response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "appointments"})) self.assertEqual(response.status_code, 200) def test_export_subjects_to_excel(self): + self.login_as_admin() create_study_subject() response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "subjects"})) self.assertEqual(response.status_code, 200) + def test_export_subjects_to_excel_without_permission(self): + create_study_subject() + response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "subjects"})) + self.assertEqual(response.status_code, 302) + def test_export_appointments_to_excel(self): + self.login_as_admin() appointment = create_appointment() appointment.visit = None appointment.save() diff --git a/smash/web/views/export.py b/smash/web/views/export.py index 02fc1a82..1cb62712 100644 --- a/smash/web/views/export.py +++ b/smash/web/views/export.py @@ -5,10 +5,12 @@ import django_excel as excel from django.http import HttpResponse from notifications import get_today_midnight_date +from web.decorators import PermissionDecorator from . import e500_error, wrap_response from ..models import Subject, StudySubject, Appointment +@PermissionDecorator('export_subjects', 'subject') def export_to_csv(request, data_type="subjects"): # Create the HttpResponse object with the appropriate CSV header. selected_fields = request.GET.get('fields', None) @@ -29,6 +31,7 @@ def export_to_csv(request, data_type="subjects"): return response +@PermissionDecorator('export_subjects', 'subject') def export_to_excel(request, data_type="subjects"): selected_fields = request.GET.get('fields', None) filename = data_type + '-' + get_today_midnight_date().strftime("%Y-%m-%d") + ".xls" @@ -53,26 +56,27 @@ class CustomField: DROP_OUT_FIELD = CustomField({'verbose_name': "DROP OUT", 'name': "custom-drop-out"}) APPOINTMENT_TYPE_FIELD = CustomField({ - 'name': 'appointment_types', - 'verbose_name': 'Appointment Types' - }) + 'name': 'appointment_types', + 'verbose_name': 'Appointment Types' +}) STUDY_SUBJECT_FIELDS = [CustomField({ - 'name': 'nd_number', - 'verbose_name' : 'ND number' - })] + 'name': 'nd_number', + 'verbose_name': 'ND number' +})] SUBJECT_FIELDS = [CustomField({ - 'name': 'last_name', - 'verbose_name': 'Family name' - }), + 'name': 'last_name', + 'verbose_name': 'Family name' +}), CustomField({ 'name': 'first_name', 'verbose_name': 'Name' })] VISIT_FIELDS = [CustomField({ - 'name': 'visit_number', - 'verbose_name': 'Visit' - })] + 'name': 'visit_number', + 'verbose_name': 'Visit' +})] + def filter_fields_from_selected_fields(fields, selected_fields): if selected_fields is None: @@ -80,6 +84,7 @@ def filter_fields_from_selected_fields(fields, selected_fields): selected_fields = set(selected_fields.split(',')) return [field for field in fields if field.name in selected_fields] + def get_default_subject_fields(): subject_fields = [] for field in Subject._meta.fields: @@ -91,12 +96,13 @@ def get_default_subject_fields(): subject_fields.append(DROP_OUT_FIELD) return subject_fields + def get_subjects_as_array(selected_fields=None): result = [] - subject_fields = get_default_subject_fields() + subject_fields = get_default_subject_fields() subject_fields = filter_fields_from_selected_fields(subject_fields, selected_fields) - field_names = [field.verbose_name for field in subject_fields] #faster than loop + field_names = [field.verbose_name for field in subject_fields] # faster than loop result.append(field_names) subjects = StudySubject.objects.order_by('-subject__last_name') @@ -105,6 +111,7 @@ def get_subjects_as_array(selected_fields=None): result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row]) return result + def subject_to_row_for_fields(study_subject, subject_fields): row = [] for field in subject_fields: @@ -128,31 +135,33 @@ def subject_to_row_for_fields(study_subject, subject_fields): row.append(cell) return row + def get_appointment_fields(): appointments_fields = [] for field in Appointment._meta.fields: if field.name.upper() != "VISIT" and field.name.upper() != "ID" and \ - field.name.upper() != "WORKER_ASSIGNED" and field.name.upper() != "APPOINTMENT_TYPES" and \ - field.name.upper() != "ROOM" and field.name.upper() != "FLYING_TEAM": + field.name.upper() != "WORKER_ASSIGNED" and field.name.upper() != "APPOINTMENT_TYPES" and \ + field.name.upper() != "ROOM" and field.name.upper() != "FLYING_TEAM": appointments_fields.append(field) all_fields = STUDY_SUBJECT_FIELDS + SUBJECT_FIELDS + VISIT_FIELDS + appointments_fields + [APPOINTMENT_TYPE_FIELD] return all_fields, appointments_fields + def get_appointments_as_array(selected_fields=None): result = [] all_fields, appointments_fields = get_appointment_fields() all_fields = filter_fields_from_selected_fields(all_fields, selected_fields) appointments_fields = filter_fields_from_selected_fields(appointments_fields, selected_fields) - field_names = [field.verbose_name for field in all_fields] #faster than loop + field_names = [field.verbose_name for field in all_fields] # faster than loop result.append(field_names) appointments = Appointment.objects.order_by('-datetime_when') for appointment in appointments: - #add field_names ['ND number', 'Family name', 'Name', 'Visit'] first + # add field_names ['ND number', 'Family name', 'Name', 'Visit'] first row = [] for field in STUDY_SUBJECT_FIELDS: if field.verbose_name in field_names: @@ -175,15 +184,16 @@ def get_appointments_as_array(selected_fields=None): for field in appointments_fields: row.append(getattr(appointment, field.name)) if APPOINTMENT_TYPE_FIELD.verbose_name in field_names: - #avoid last comma in the list of appointment types + # avoid last comma in the list of appointment types type_string = ','.join([appointment_type.code for appointment_type in appointment.appointment_types.all()]) row.append(type_string) result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row]) return result +@PermissionDecorator('export_subjects', 'subject') def export(request): return wrap_response(request, 'export/index.html', { 'subject_fields': get_default_subject_fields(), 'appointment_fields': get_appointment_fields()[0] - }) \ No newline at end of file + }) -- GitLab From 19258de343bc6d459a410660421ba707709bfe04 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 19 Mar 2020 16:29:25 +0100 Subject: [PATCH 09/10] default permission for existing workers --- ...145_add_permissions_to_existing_workers.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 smash/web/migrations/0145_add_permissions_to_existing_workers.py diff --git a/smash/web/migrations/0145_add_permissions_to_existing_workers.py b/smash/web/migrations/0145_add_permissions_to_existing_workers.py new file mode 100644 index 00000000..877a3754 --- /dev/null +++ b/smash/web/migrations/0145_add_permissions_to_existing_workers.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2020-03-19 13:01 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0144_auto_20200319_1518'), + ] + + operations = [ + migrations.RunSQL("insert into web_workerstudyrole_permissions(workerstudyrole_id, permission_id) " + "select web_workerstudyrole.id, auth_permission.id from web_workerstudyrole,auth_permission " + "where codename='view_daily_planning';"), + migrations.RunSQL("insert into web_workerstudyrole_permissions(workerstudyrole_id, permission_id) " + "select web_workerstudyrole.id, auth_permission.id from web_workerstudyrole,auth_permission " + "where codename='change_flyingteam';"), + migrations.RunSQL("insert into web_workerstudyrole_permissions(workerstudyrole_id, permission_id) " + "select web_workerstudyrole.id, auth_permission.id from web_workerstudyrole,auth_permission " + "where codename='export_subjects';"), + + ] -- GitLab From 1af70bd096bccb9406f6f692b2f9cc81563a0ac4 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Fri, 20 Mar 2020 08:40:05 +0100 Subject: [PATCH 10/10] permissions grouped --- smash/web/templates/sidebar.html | 2 +- smash/web/views/__init__.py | 3 ++- smash/web/views/appointment_type.py | 8 ++++---- smash/web/views/equipment.py | 8 ++++---- smash/web/views/flying_teams.py | 6 +++--- smash/web/views/kit.py | 6 +++--- smash/web/views/rooms.py | 8 ++++---- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/smash/web/templates/sidebar.html b/smash/web/templates/sidebar.html index 9d215925..a5753199 100644 --- a/smash/web/templates/sidebar.html +++ b/smash/web/templates/sidebar.html @@ -34,7 +34,7 @@ </li> {% endif %} - {% if "change_item" in permissions or "change_appointmenttype" in permissions or "change_appointmenttype" in permissions or "change_flyingteam" in permissions or "send_sample_mail_for_appointments" in permissions or "change_room" in permissions %} + {% if equipment_perms %} <li data-desc="equipment_and_rooms" class="treeview"> <a href="{% url 'web.views.equipment_and_rooms' %}"> <i class="fa fa-building-o"></i> <span>Equipment & Rooms</span> diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py index 6fc26504..f662f7e7 100644 --- a/smash/web/views/__init__.py +++ b/smash/web/views/__init__.py @@ -52,7 +52,7 @@ def extend_context(params, request): else: #use full name if available, username otherwise if len(request.user.get_full_name()) > 1: - person = request.user.get_full_name() + person = request.user.get_full_name() else: person = request.user.get_username() role = '<No worker information>' @@ -61,6 +61,7 @@ def extend_context(params, request): final_params.update({ 'permissions' : permissions, 'conf_perms' : permissions & PermissionDecorator.codename_groups['configuration'], + 'equipment_perms' : permissions & PermissionDecorator.codename_groups['equipment'], 'person': person, 'role': role, 'notifications': notifications, diff --git a/smash/web/views/appointment_type.py b/smash/web/views/appointment_type.py index 9aa924d1..2637c26a 100644 --- a/smash/web/views/appointment_type.py +++ b/smash/web/views/appointment_type.py @@ -11,7 +11,7 @@ class AppointmentTypeListView(ListView, WrappedView): template_name = 'appointment_types/index.html' context_object_name = "appointment_types" - @PermissionDecorator('change_appointmenttype', 'configuration') + @PermissionDecorator('change_appointmenttype', 'equipment') def dispatch(self, *args, **kwargs): return super(AppointmentTypeListView, self).dispatch(*args, **kwargs) @@ -22,7 +22,7 @@ class AppointmentTypeCreateView(CreateView, WrappedView): success_url = reverse_lazy('web.views.appointment_types') success_message = "Appointment type created" - @PermissionDecorator('change_appointmenttype', 'configuration') + @PermissionDecorator('change_appointmenttype', 'equipment') def dispatch(self, *args, **kwargs): return super(AppointmentTypeCreateView, self).dispatch(*args, **kwargs) @@ -34,7 +34,7 @@ class AppointmentTypeEditView(UpdateView, WrappedView): template_name = "appointment_types/edit.html" context_object_name = "appointment_types" - @PermissionDecorator('change_appointmenttype', 'configuration') + @PermissionDecorator('change_appointmenttype', 'equipment') def dispatch(self, *args, **kwargs): return super(AppointmentTypeEditView, self).dispatch(*args, **kwargs) @@ -47,6 +47,6 @@ class AppointmentTypeDeleteView(DeleteView, WrappedView): messages.success(request, "Appointment Type deleted") return super(AppointmentTypeDeleteView, self).delete(request, *args, **kwargs) - @PermissionDecorator('change_appointmenttype', 'configuration') + @PermissionDecorator('change_appointmenttype', 'equipment') def dispatch(self, *args, **kwargs): return super(AppointmentTypeDeleteView, self).dispatch(*args, **kwargs) \ No newline at end of file diff --git a/smash/web/views/equipment.py b/smash/web/views/equipment.py index a4c36568..4d006e41 100644 --- a/smash/web/views/equipment.py +++ b/smash/web/views/equipment.py @@ -7,7 +7,7 @@ from ..forms.forms import ItemForm from ..models import Item -@PermissionDecorator('change_item', 'item') +@PermissionDecorator('change_item', 'equipment') def equipment(request): equipment_list = Item.objects.order_by('-name') context = { @@ -17,7 +17,7 @@ def equipment(request): return wrap_response(request, "equipment_and_rooms/equipment/index.html", context) -@PermissionDecorator('change_item', 'item') +@PermissionDecorator('change_item', 'equipment') def equipment_add(request): if request.method == 'POST': form = ItemForm(request.POST) @@ -30,7 +30,7 @@ def equipment_add(request): return wrap_response(request, 'equipment_and_rooms/equipment/add.html', {'form': form}) -@PermissionDecorator('change_item', 'item') +@PermissionDecorator('change_item', 'equipment') def equipment_edit(request, equipment_id): the_item = get_object_or_404(Item, id=equipment_id) if request.method == 'POST': @@ -44,7 +44,7 @@ def equipment_edit(request, equipment_id): return wrap_response(request, 'equipment_and_rooms/equipment/edit.html', {'form': form}) -@PermissionDecorator('change_item', 'item') +@PermissionDecorator('change_item', 'equipment') def equipment_delete(request, equipment_id): the_item = get_object_or_404(Item, id=equipment_id) the_item.delete() diff --git a/smash/web/views/flying_teams.py b/smash/web/views/flying_teams.py index e96fe301..b0f5c7b0 100644 --- a/smash/web/views/flying_teams.py +++ b/smash/web/views/flying_teams.py @@ -7,7 +7,7 @@ from ..forms.forms import FlyingTeamAddForm, FlyingTeamEditForm from ..models import FlyingTeam -@PermissionDecorator('change_flyingteam', 'flyingteam') +@PermissionDecorator('change_flyingteam', 'equipment') def flying_teams(request): flying_team_list = FlyingTeam.objects.order_by('-place') context = { @@ -19,7 +19,7 @@ def flying_teams(request): context) -@PermissionDecorator('change_flyingteam', 'flyingteam') +@PermissionDecorator('change_flyingteam', 'equipment') def flying_teams_add(request): if request.method == 'POST': form = FlyingTeamAddForm(request.POST) @@ -32,7 +32,7 @@ def flying_teams_add(request): return wrap_response(request, 'equipment_and_rooms/flying_teams/add.html', {'form': form}) -@PermissionDecorator('change_flyingteam', 'flyingteam') +@PermissionDecorator('change_flyingteam', 'equipment') def flying_teams_edit(request, flying_team_id): the_flying_team = get_object_or_404(FlyingTeam, id=flying_team_id) if request.method == 'POST': diff --git a/smash/web/views/kit.py b/smash/web/views/kit.py index 159338fa..c099d903 100644 --- a/smash/web/views/kit.py +++ b/smash/web/views/kit.py @@ -61,7 +61,7 @@ def get_kit_requests(user, start_date=None, end_date=None): return result -@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') +@PermissionDecorator('send_sample_mail_for_appointments', 'equipment') def get_kit_requests_data(request, start_date=None, end_date=None): form = KitRequestForm() if request.method == 'POST': @@ -78,7 +78,7 @@ def get_kit_requests_data(request, start_date=None, end_date=None): return params -@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') +@PermissionDecorator('send_sample_mail_for_appointments', 'equipment') def kit_requests(request): return wrap_response(request, 'equipment_and_rooms/kit_requests/kit_requests.html', get_kit_requests_data(request)) @@ -139,7 +139,7 @@ def send_mail(data): EmailSender().send_email(title, email_body, recipients, cc_recipients) -@PermissionDecorator('send_sample_mail_for_appointments', 'appointment') +@PermissionDecorator('send_sample_mail_for_appointments', 'equipment') def kit_requests_send_mail(request, start_date, end_date=None): data = get_kit_requests_data(request, start_date, end_date) try: diff --git a/smash/web/views/rooms.py b/smash/web/views/rooms.py index 5c20463b..a5ca9193 100644 --- a/smash/web/views/rooms.py +++ b/smash/web/views/rooms.py @@ -7,7 +7,7 @@ from ..forms.forms import RoomForm from ..models import Room -@PermissionDecorator('change_room', 'room') +@PermissionDecorator('change_room', 'equipment') def rooms(request): rooms_list = Room.objects.order_by('-city') context = { @@ -19,7 +19,7 @@ def rooms(request): context) -@PermissionDecorator('change_room', 'room') +@PermissionDecorator('change_room', 'equipment') def rooms_add(request): if request.method == 'POST': form = RoomForm(request.POST) @@ -32,7 +32,7 @@ def rooms_add(request): return wrap_response(request, 'equipment_and_rooms/rooms/add.html', {'form': form}) -@PermissionDecorator('change_room', 'room') +@PermissionDecorator('change_room', 'equipment') def rooms_edit(request, room_id): the_room = get_object_or_404(Room, id=room_id) if request.method == 'POST': @@ -46,7 +46,7 @@ def rooms_edit(request, room_id): return wrap_response(request, 'equipment_and_rooms/rooms/edit.html', {'form': form}) -@PermissionDecorator('change_room', 'room') +@PermissionDecorator('change_room', 'equipment') def rooms_delete(request, room_id): the_room = get_object_or_404(Room, id=room_id) the_room.delete() -- GitLab