Skip to content

Commit

Permalink
feat: add permissions checking
Browse files Browse the repository at this point in the history
  • Loading branch information
ngurenyaga committed Jul 19, 2021
1 parent 09b71a0 commit 21475e9
Show file tree
Hide file tree
Showing 21 changed files with 1,946 additions and 59 deletions.
20 changes: 10 additions & 10 deletions pepfar_mle/common/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
pytestmark = pytest.mark.django_db


def test_approved_mixin_approved_user(rf, django_user_model):
approved_user = baker.make(django_user_model, is_approved=True)
def test_approved_mixin_approved_user(rf, user_with_all_permissions):
approved_user = user_with_all_permissions
url = "/"
request = rf.get(url)
request.user = approved_user
Expand All @@ -32,29 +32,29 @@ def test_approved_mixin_non_approved_authenticated_user(rf, django_user_model):
assert "PermissionDenied" in str(e)


def test_home_view(user, client):
client.force_login(user)
def test_home_view(user_with_all_permissions, client):
client.force_login(user_with_all_permissions)
url = reverse("home")
response = client.get(url)
assert response.status_code == status.HTTP_200_OK


def test_about_view(user, client):
client.force_login(user)
def test_about_view(user_with_all_permissions, client):
client.force_login(user_with_all_permissions)
url = reverse("about")
response = client.get(url)
assert response.status_code == status.HTTP_200_OK


def test_facility_view(user, client):
client.force_login(user)
def test_facility_view(user_with_all_permissions, client):
client.force_login(user_with_all_permissions)
url = reverse("common:facilities")
response = client.get(url)
assert response.status_code == status.HTTP_200_OK


def test_systems_view(user, client):
client.force_login(user)
def test_systems_view(user_with_all_permissions, client):
client.force_login(user_with_all_permissions)
url = reverse("common:systems")
response = client.get(url)
assert response.status_code == status.HTTP_200_OK
14 changes: 11 additions & 3 deletions pepfar_mle/common/views.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
UserPassesTestMixin,
)
from django.views.generic import TemplateView, View


class ApprovedMixin(UserPassesTestMixin, View):
permission_denied_message = "Your account is pending approval"
class ApprovedMixin(UserPassesTestMixin, PermissionRequiredMixin, View):
permission_denied_message = "Permission Denied"

def test_func(self):
return self.request.user.is_authenticated and self.request.user.is_approved


class HomeView(LoginRequiredMixin, ApprovedMixin, TemplateView):
template_name = "pages/home.html"
permission_required = "users.can_view_dashboard"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand All @@ -20,6 +25,7 @@ def get_context_data(self, **kwargs):

class AboutView(LoginRequiredMixin, ApprovedMixin, TemplateView):
template_name = "pages/about.html"
permission_required = "users.can_view_about"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand All @@ -29,6 +35,7 @@ def get_context_data(self, **kwargs):

class FacilityView(LoginRequiredMixin, ApprovedMixin, TemplateView):
template_name = "pages/common/facilities.html"
permission_required = "common.view_facility"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand All @@ -39,6 +46,7 @@ def get_context_data(self, **kwargs):

class SystemsView(LoginRequiredMixin, ApprovedMixin, TemplateView):
template_name = "pages/common/systems.html"
permission_required = "common.view_system"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand Down
29 changes: 29 additions & 0 deletions pepfar_mle/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import pytest
from django.contrib.auth.models import Group, Permission
from model_bakery import baker

from pepfar_mle.users.models import User
from pepfar_mle.users.tests.factories import UserFactory
Expand All @@ -12,3 +14,30 @@ def media_storage(settings, tmpdir):
@pytest.fixture
def user() -> User:
return UserFactory()


@pytest.fixture
def user_with_all_permissions(user) -> User:
all_perms = Permission.objects.all()
for perm in all_perms:
user.user_permissions.add(perm)
user.save()
return user


@pytest.fixture
def group_with_all_permissions() -> Group:
group = baker.make(Group)
all_perms = Permission.objects.all()
for perm in all_perms:
group.permissions.add(perm)

group.save()
return group


@pytest.fixture
def user_with_group(user, group_with_all_permissions) -> User:
user.groups.add(group_with_all_permissions)
user.save()
return user
166 changes: 166 additions & 0 deletions pepfar_mle/ops/migrations/0002_auto_20210719_1249.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Generated by Django 3.2.5 on 2021-07-19 09:49

from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import uuid


class Migration(migrations.Migration):

dependencies = [
('common', '0007_alter_system_options'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('ops', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Activity',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('name', models.CharField(max_length=64)),
('description', models.TextField()),
('deadline', models.DateField()),
('is_complete', models.BooleanField(default=False)),
],
options={
'ordering': ('-updated', '-created'),
'abstract': False,
},
),
migrations.CreateModel(
name='WeeklyProgramUpdate',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('date', models.DateField()),
('attendees', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), size=None)),
('comments', models.TextField()),
('activity', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='ops.activity')),
('organisation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_weeklyprogramupdate_related', to='common.organisation')),
],
options={
'ordering': ('-updated', '-created'),
'abstract': False,
},
),
migrations.CreateModel(
name='SiteMentorship',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('day', models.DateField()),
('start', models.TimeField()),
('end', models.TimeField()),
('objective', models.TextField()),
('pick_up_point', models.TextField()),
('drop_off_point', models.TextField()),
('organisation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_sitementorship_related', to='common.organisation')),
('site', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='common.facility')),
('staff_member', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-day', '-end', '-start', 'site__name'),
},
),
migrations.CreateModel(
name='OperationalArea',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('name', models.CharField(max_length=64)),
('description', models.TextField()),
('organisation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_operationalarea_related', to='common.organisation')),
],
options={
'ordering': ('-updated', '-created'),
'abstract': False,
},
),
migrations.CreateModel(
name='DailyUpdate',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('date', models.DateField()),
('total', models.IntegerField()),
('clients_booked', models.IntegerField()),
('kept_appointment', models.IntegerField()),
('missed_appointment', models.IntegerField()),
('came_early', models.IntegerField()),
('unscheduled', models.IntegerField()),
('new_ft', models.IntegerField()),
('ipt_new_adults', models.IntegerField()),
('ipt_new_paeds', models.IntegerField()),
('facility', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='common.facility')),
('organisation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_dailyupdate_related', to='common.organisation')),
],
options={
'ordering': ('-updated', '-created'),
'abstract': False,
},
),
migrations.CreateModel(
name='ActivityLog',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('active', models.BooleanField(default=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('created_by', models.UUIDField(blank=True, null=True)),
('updated', models.DateTimeField(default=django.utils.timezone.now)),
('updated_by', models.UUIDField(blank=True, null=True)),
('activity', models.TextField(help_text='Activity as budgeted for')),
('planned_date', models.DateField(help_text='Planned date for the activity')),
('requested_date', models.DateField(help_text='Date requested')),
('procurement_date', models.DateField(help_text='Date received by procurement')),
('finance_approval_date', models.DateField(help_text='Date received by Finance for approvals')),
('final_approval_date', models.DateField(help_text='Date approved by COP/DCOP/FAD')),
('done_date', models.DateField(help_text='Date when activity/procurement done')),
('invoiced_date', models.DateField(help_text='Date when payment invoice was submitted to Finance')),
('remarks', models.TextField()),
('organisation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_activitylog_related', to='common.organisation')),
],
options={
'ordering': ('-requested_date', '-planned_date', '-procurement_date'),
},
),
migrations.AddField(
model_name='activity',
name='area',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='ops.operationalarea'),
),
migrations.AddField(
model_name='activity',
name='organisation',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ops_activity_related', to='common.organisation'),
),
migrations.AddField(
model_name='activity',
name='responsibility',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]
Loading

0 comments on commit 21475e9

Please sign in to comment.