Skip to content
Merged
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
27 changes: 21 additions & 6 deletions employees/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from managers.factories import ProjectFactory
from managers.models import Project
from users.factories import AdminUserFactory
from users.factories import ManagerUserFactory
from users.factories import UserFactory


Expand Down Expand Up @@ -155,14 +156,10 @@ def test_project_report_detail_view_should_not_update_report_on_post_if_form_is_
class ReportDetailViewTests(TestCase):
def setUp(self):
super().setUp()
self.task_type = TaskActivityType(pk=1, name="Other")
self.task_type.full_clean()
self.task_type.save()
self.user = UserFactory()
self.project = ProjectFactory()
self.project.members.add(self.user)
self.client.force_login(self.user)
self.report = ReportFactory(author=self.user, project=self.project)
self.report = ReportFactory(author=self.user)
self.report.project.members.add(self.user)
self.url = reverse("custom-report-detail", args=(self.report.pk,))
self.data = {
"date": self.report.date,
Expand Down Expand Up @@ -227,6 +224,24 @@ def test_custom_report_detail_view_project_field_should_not_display_projects_the
self.assertEqual(response.status_code, 200)
self.assertTrue(other_project not in response.context_data["form"].fields["project"].queryset)

def test_manager_should_be_able_to_update_his_reports_in_project_in_which_he_is_not_manager(self):
user_manager = ManagerUserFactory()
self.client.force_login(user_manager)
report_manager = ReportFactory(author=user_manager)
report_manager.project.members.add(user_manager)
data = {
"date": report_manager.date,
"description": "report_manager other description",
"project": report_manager.project.pk,
"author": report_manager.author,
"task_activities": report_manager.task_activities.pk,
"work_hours": report_manager.work_hours_str,
}
response = self.client.post(path=reverse("custom-report-detail", args=(report_manager.pk,)), data=data)
report_manager.refresh_from_db()
self.assertEqual(response.status_code, 302)
self.assertEqual(report_manager.description, data["description"])


class ReportDeleteViewTests(TestCase):
def setUp(self):
Expand Down
17 changes: 12 additions & 5 deletions employees/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
from utils.decorators import check_permissions
from utils.mixins import UserIsAuthorOfCurrentReportMixin
from utils.mixins import UserIsManagerOfCurrentProjectMixin
from utils.mixins import UserIsManagerOfCurrentReportProjectMixin
from utils.mixins import UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -166,7 +166,10 @@ def redirect_to_current_month(self) -> HttpResponseRedirectBase:
name="dispatch",
)
class ReportList(
UserIsManagerOfCurrentReportProjectMixin, UserIsAuthorOfCurrentReportMixin, APIView, MonthNavigationMixin
UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin,
UserIsAuthorOfCurrentReportMixin,
APIView,
MonthNavigationMixin,
):
serializer_class = ReportSerializer
renderer_classes = [renderers.TemplateHTMLRenderer]
Expand Down Expand Up @@ -334,7 +337,9 @@ def form_valid(self, form: ReportForm) -> HttpResponseRedirectBase:
),
name="dispatch",
)
class ReportDetailView(UserIsManagerOfCurrentReportProjectMixin, UserIsAuthorOfCurrentReportMixin, UpdateView):
class ReportDetailView(
UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin, UserIsAuthorOfCurrentReportMixin, UpdateView
):
template_name = "employees/report_detail.html"
form_class = ReportForm
model = Report
Expand Down Expand Up @@ -365,7 +370,9 @@ def form_valid(self, form: ReportForm) -> HttpResponseRedirectBase:
),
name="dispatch",
)
class ReportDeleteView(UserIsAuthorOfCurrentReportMixin, UserIsManagerOfCurrentReportProjectMixin, DeleteView):
class ReportDeleteView(
UserIsAuthorOfCurrentReportMixin, UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin, DeleteView
):
model = Report

def get_success_url(self) -> str:
Expand Down Expand Up @@ -454,7 +461,7 @@ def post( # pylint: disable=unused-argument
check_permissions(allowed_user_types=[CustomUser.UserType.MANAGER.name, CustomUser.UserType.ADMIN.name]),
name="dispatch",
)
class ProjectReportDetail(UserIsManagerOfCurrentReportProjectMixin, ReportDetailBase):
class ProjectReportDetail(UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin, ReportDetailBase):
template_post_url = "project-report-detail"
redirect_url = "project-report-list"
url_pk = "project"
Expand Down
9 changes: 7 additions & 2 deletions utils/mixins.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.db.models import Q
from django.db.models import QuerySet


Expand All @@ -13,10 +14,14 @@ def get_queryset(self) -> QuerySet:
return super().get_queryset() # type: ignore


class UserIsManagerOfCurrentReportProjectMixin:
class UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin:
def get_queryset(self) -> QuerySet:
if self.request.user.is_manager: # type: ignore
return super().get_queryset().filter(project__managers=self.request.user.pk) # type: ignore
return (
super() # type: ignore
.get_queryset()
.filter(Q(project__managers=self.request.user.pk) | Q(author=self.request.user.pk)) # type: ignore
)
else:
return super().get_queryset() # type: ignore

Expand Down
12 changes: 7 additions & 5 deletions utils/tests/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from users.models import CustomUser
from utils.mixins import UserIsAuthorOfCurrentReportMixin
from utils.mixins import UserIsManagerOfCurrentProjectMixin
from utils.mixins import UserIsManagerOfCurrentReportProjectMixin
from utils.mixins import UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin


class UserIsAuthorOfCurrentReportMixinTestCase(TestCase):
Expand Down Expand Up @@ -103,17 +103,19 @@ def test_that_user_is_manager_of_current_project_mixin_should_not_limit_view_pro
self.assertEqual(len(response.context_data["object_list"]), 2)


class UserIsManagerOfCurrentReportProjectMixinTestCase(TestCase):
class UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixinTestCase(TestCase):
def setUp(self):
super().setUp()

class TestView(UserIsManagerOfCurrentReportProjectMixin, ListView):
class TestView(UserIsManagerOfCurrentReportProjectOrAuthorOfCurrentReportMixin, ListView):
model = Report

self.view = TestView.as_view()
self.request_factory = RequestFactory()

def test_that_user_is_manager_of_current_project_mixin_should_limit_view_project_queryset_if_user_is_manager(self):
def test_that_user_is_manager_of_current_project_or_author_of_current_report_mixin_should_limit_view_project_queryset_if_user_is_manager(
self
):
user = UserFactory(user_type=CustomUser.UserType.MANAGER.name)

report = ReportFactory()
Expand All @@ -130,7 +132,7 @@ def test_that_user_is_manager_of_current_project_mixin_should_limit_view_project
self.assertEqual(len(response.context_data["object_list"]), 1)
self.assertEqual(response.context_data["object_list"][0].pk, report.pk)

def test_that_user_is_manager_of_current_project_mixin_should_not_limit_view_project_queryset_if_user_is_not_manager(
def test_that_user_is_manager_of_current_project_or_author_of_current_report_mixin_should_not_limit_view_project_queryset_if_user_is_not_manager(
self
):
user = UserFactory(user_type=CustomUser.UserType.EMPLOYEE.name)
Expand Down