diff --git a/managers/static/managers/scripts/delete_project_popup.js b/managers/static/managers/scripts/delete_project_popup.js new file mode 100644 index 000000000..2a87b46f6 --- /dev/null +++ b/managers/static/managers/scripts/delete_project_popup.js @@ -0,0 +1,24 @@ +$(function () { + $("#dialog").dialog ({ + modal: true, + autoOpen: false, + buttons : [ + { + text: "No", + click: function () { + $(this).dialog('close'); + } + }, + { + text: "Yes", + click: function () { + window.location.href = delete_project_path; + } + } + ] + }).prev().find(".ui-dialog-titlebar-close").hide (); + + $("#opener").click(function () { + $('#dialog').dialog('open'); + }); +}); diff --git a/managers/templates/managers/project_form.html b/managers/templates/managers/project_form.html index b0d7a3c9f..ae81c6a43 100644 --- a/managers/templates/managers/project_form.html +++ b/managers/templates/managers/project_form.html @@ -6,7 +6,6 @@ {% load crispy_forms_tags %} {% block content %} -

@@ -23,8 +22,26 @@

+ +{% if request.user.is_admin and object %} +
+ + + +{% endif %} {% endblock %} {% block extra_script %} {{ form.media }} +{% if request.user.is_admin and object %} + + +{% endif %} {% endblock %} diff --git a/managers/tests/test_views.py b/managers/tests/test_views.py index 92cdfd977..bf41c71a6 100644 --- a/managers/tests/test_views.py +++ b/managers/tests/test_views.py @@ -1,12 +1,14 @@ import datetime from django.shortcuts import reverse +from parameterized import parameterized from managers.factories import ProjectFactory from managers.models import Project from managers.tests.test_api import ProjectTest from managers.views import ProjectCreateView from managers.views import ProjectUpdateView +from users.models import CustomUser class ProjectCreateTests(ProjectTest): @@ -74,3 +76,24 @@ def test_project_update_view_should_update_project_on_post_if_data_is_invalid(se self.assertEqual(response.status_code, 200) self.project.refresh_from_db() self.assertFormError(response, "form", "name", "This field is required.") + + +class DeleteProjectTests(ProjectTest): + def setUp(self): + super().setUp() + self.project = ProjectFactory() + self.url = reverse("custom-project-delete", kwargs={"pk": self.project.pk}) + + def test_delete_project_function_view_should_delete_project_on_admin_type_user_post(self): + response = self.client.post(self.url) + self.assertEqual(response.status_code, 302) + self.assertEqual(Project.objects.all().count(), 0) + + @parameterized.expand([(CustomUser.UserType.EMPLOYEE.name,), (CustomUser.UserType.MANAGER.name,)]) + def test_delete_project_function_view_should_not_delete_project_on_non_admin_request(self, user_type): + self.user.user_type = user_type + self.user.full_clean() + self.user.save() + response = self.client.post(self.url) + self.assertEqual(response.status_code, 302) + self.assertEqual(Project.objects.all().count(), 1) diff --git a/managers/urls.py b/managers/urls.py index 34bb2b9db..d950787d0 100644 --- a/managers/urls.py +++ b/managers/urls.py @@ -13,4 +13,5 @@ url("^projects/create/$", views.ProjectCreateView.as_view(), name="custom-project-create"), url("^projects/(?P[0-9]+)/$", views.ProjectDetail.as_view(), name="custom-project-detail"), url("^projects/(?P[0-9]+)/update/$", views.ProjectUpdateView.as_view(), name="custom-project-update"), + url("^projects/(?P[0-9]+)/delete/$", views.ProjectDeleteView.as_view(), name="custom-project-delete"), ] diff --git a/managers/views.py b/managers/views.py index 9c9c0378c..376d48021 100644 --- a/managers/views.py +++ b/managers/views.py @@ -4,10 +4,13 @@ from django.db.models.functions import Lower from django.db.models.query import QuerySet from django.http import HttpRequest +from django.http import HttpResponse from django.shortcuts import get_object_or_404 +from django.shortcuts import redirect from django.shortcuts import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView +from django.views.generic import DeleteView from django.views.generic import ListView from django.views.generic import UpdateView from rest_framework import renderers @@ -87,3 +90,16 @@ def get_context_data(self, **kwargs: Any) -> dict: def get_success_url(self) -> str: return reverse("custom-project-detail", kwargs={"pk": self.kwargs["pk"]}) + + +class ProjectDeleteView(DeleteView): + model = Project + + def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + if not request.user.is_admin: + return redirect(reverse("home")) + + return super().dispatch(request, *args, **kwargs) + + def get_success_url(self) -> str: + return reverse("custom-projects-list") diff --git a/requirements.lock b/requirements.lock index 3f765fb44..e9b6cdef8 100644 --- a/requirements.lock +++ b/requirements.lock @@ -38,10 +38,12 @@ more-itertools==5.0.0 mypy==0.700 mypy-extensions==0.4.1 oauthlib==2.1.0 +parameterized==0.7.0 parso==0.3.4 pbr==5.1.2 pexpect==4.6.0 pickleshare==0.7.5 +pipdeptree==0.13.0 pluggy==0.8.1 prompt-toolkit==2.0.9 psycopg2==2.7.5 diff --git a/requirements.txt b/requirements.txt index 03dcfb923..a753d3f4a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,6 +18,7 @@ mypy oauthlib psycopg2 pylint +parameterized pytest pytest-cov pytest-django diff --git a/users/models.py b/users/models.py index 1e335daf8..546c078b3 100644 --- a/users/models.py +++ b/users/models.py @@ -128,6 +128,10 @@ def email_user(self, subject: str, message: str, from_email: str = None) -> None """ send_mail(subject, message, from_email, [self.email]) + @property + def is_admin(self) -> bool: + return self.user_type == CustomUser.UserType.ADMIN.name + @receiver(post_save, sender=CustomUser) def update_from_manager_to_employee(sender: "CustomUser", **kwargs: Any) -> None: