mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-23 00:12:15 +00:00
Permissions work
This commit is contained in:
@@ -12,4 +12,5 @@ class Command(BaseCommand):
|
|||||||
call_command('generateSampleUserData')
|
call_command('generateSampleUserData')
|
||||||
call_command('generateSampleRIGSData')
|
call_command('generateSampleRIGSData')
|
||||||
call_command('generateSampleAssetsData')
|
call_command('generateSampleAssetsData')
|
||||||
call_command('generateSampleTrainingData')
|
call_command('import_old_db')
|
||||||
|
call_command('generate_sample_training_users')
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ class Profile(AbstractUser):
|
|||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic', 'riskassessment', 'invoice').prefetch_related('checklists')
|
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic', 'riskassessment', 'invoice').prefetch_related('checklists')
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def as_trainee(self):
|
||||||
|
from training.models import Trainee
|
||||||
|
return Trainee.objects.get(pk=self.pk)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def admins(cls):
|
def admins(cls):
|
||||||
return Profile.objects.filter(email__in=[y for x in settings.ADMINS for y in x])
|
return Profile.objects.filter(email__in=[y for x in settings.ADMINS for y in x])
|
||||||
|
|||||||
4
training/decorators.py
Normal file
4
training/decorators.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from PyRIGS.decorators import user_passes_test_with_403
|
||||||
|
|
||||||
|
def has_perm_or_supervisor(perm, login_url=None, oembed_view=None):
|
||||||
|
return user_passes_test_with_403(lambda u: (hasattr(u, 'as_trainee') and u.as_trainee.is_supervisor) or u.has_perm(perm), login_url=login_url, oembed_view=oembed_view)
|
||||||
@@ -2,6 +2,7 @@ import datetime
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from django.contrib.auth.models import Group, Permission
|
from django.contrib.auth.models import Group, Permission
|
||||||
|
from django.core.management import call_command
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@@ -31,7 +32,7 @@ class Command(BaseCommand):
|
|||||||
self.setup_categories()
|
self.setup_categories()
|
||||||
self.setup_items()
|
self.setup_items()
|
||||||
self.setup_levels()
|
self.setup_levels()
|
||||||
self.setup_supervisor()
|
call_command('generate_sample_training_users')
|
||||||
print("Done generating training data")
|
print("Done generating training data")
|
||||||
|
|
||||||
def setup_categories(self):
|
def setup_categories(self):
|
||||||
@@ -192,20 +193,3 @@ class Command(BaseCommand):
|
|||||||
models.TrainingLevelRequirement.objects.create(level=supervisor, item=item, depth=random.choice(models.TrainingItemQualification.CHOICES)[0])
|
models.TrainingLevelRequirement.objects.create(level=supervisor, item=item, depth=random.choice(models.TrainingItemQualification.CHOICES)[0])
|
||||||
self.levels.append(technician)
|
self.levels.append(technician)
|
||||||
self.levels.append(supervisor)
|
self.levels.append(supervisor)
|
||||||
|
|
||||||
def setup_supervisor(self):
|
|
||||||
supervisor = models.Profile.objects.create(username="supervisor", first_name="Super", last_name="Visor",
|
|
||||||
initials="SV",
|
|
||||||
email="supervisor@example.com", is_active=True,
|
|
||||||
is_staff=True, is_approved=True)
|
|
||||||
supervisor.set_password('supervisor')
|
|
||||||
supervisor.groups.add(Group.objects.get(name="Keyholders"))
|
|
||||||
supervisor.save()
|
|
||||||
models.TrainingLevelQualification.objects.create(
|
|
||||||
trainee=supervisor,
|
|
||||||
level=models.TrainingLevel.objects.filter(
|
|
||||||
level__gte=models.TrainingLevel.SUPERVISOR).exclude(
|
|
||||||
department=models.TrainingLevel.HAULAGE).exclude(
|
|
||||||
department__isnull=True).first(),
|
|
||||||
confirmed_on=timezone.now(),
|
|
||||||
confirmed_by=models.Trainee.objects.first())
|
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group, Permission
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.db import transaction
|
||||||
|
from django.utils import timezone
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
from training import models
|
||||||
|
from RIGS.models import Profile
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Adds training users'
|
||||||
|
can_import_settings = True
|
||||||
|
|
||||||
|
profiles = []
|
||||||
|
committee_group = None
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
print("Generating useful training users")
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
if not (settings.DEBUG or settings.STAGING):
|
||||||
|
raise CommandError('You cannot run this command in production')
|
||||||
|
|
||||||
|
random.seed('otherwise it is done by time, which could lead to inconsistent tests')
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
self.setup_groups()
|
||||||
|
self.setup_useful_profiles()
|
||||||
|
print("Done generating useful training users")
|
||||||
|
|
||||||
|
def setup_groups(self):
|
||||||
|
self.committee_group = Group.objects.create(name='Committee')
|
||||||
|
|
||||||
|
perms = ["add_trainingitemqualification", "change_trainingitemqualification", "delete_trainingitemqualification", "add_traininglevelqualification", "change_traininglevelqualification", "delete_traininglevelqualification", "add_traininglevelrequirement", "change_traininglevelrequirement", "delete_traininglevelrequirement"]
|
||||||
|
|
||||||
|
for permId in perms:
|
||||||
|
self.committee_group.permissions.add(Permission.objects.get(codename=permId))
|
||||||
|
|
||||||
|
self.committee_group.save()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_useful_profiles(self):
|
||||||
|
supervisor = Profile.objects.create(username="supervisor", first_name="Super", last_name="Visor",
|
||||||
|
initials="SV",
|
||||||
|
email="supervisor@example.com", is_active=True,
|
||||||
|
is_staff=True, is_approved=True)
|
||||||
|
supervisor.set_password('supervisor')
|
||||||
|
supervisor.groups.add(Group.objects.get(name="Keyholders"))
|
||||||
|
supervisor.save()
|
||||||
|
models.TrainingLevelQualification.objects.create(
|
||||||
|
trainee=supervisor,
|
||||||
|
level=models.TrainingLevel.objects.filter(
|
||||||
|
level__gte=models.TrainingLevel.SUPERVISOR).exclude(
|
||||||
|
department=models.TrainingLevel.HAULAGE).exclude(
|
||||||
|
department__isnull=True).first(),
|
||||||
|
confirmed_on=timezone.now(),
|
||||||
|
confirmed_by=models.Trainee.objects.first())
|
||||||
|
|
||||||
|
committee_user = Profile.objects.create(username="committee", first_name="Committee", last_name="Member",
|
||||||
|
initials="CM",
|
||||||
|
email="committee@example.com", is_active=True, is_approved=True)
|
||||||
|
committee_user.groups.add(self.committee_group)
|
||||||
|
supervisor.groups.add(Group.objects.get(name="Keyholders"))
|
||||||
|
committee_user.set_password('committee')
|
||||||
|
committee_user.save()
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if request.user.is_supervisor or perms.training.change_traininglevel %}
|
{% if request.user.as_trainee.is_supervisor or perms.training.add_traininglevelrequirement %}
|
||||||
<div class="col-sm-12 text-right pr-0">
|
<div class="col-sm-12 text-right pr-0">
|
||||||
<a type="button" class="btn btn-success mb-3" href="{% url 'add_requirement' pk=object.pk %}" id="requirement_button">
|
<a type="button" class="btn btn-success mb-3" href="{% url 'add_requirement' pk=object.pk %}" id="requirement_button">
|
||||||
<span class="fas fa-plus"></span> Add New Requirement
|
<span class="fas fa-plus"></span> Add New Requirement
|
||||||
@@ -78,9 +78,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr><th colspan="3" class="text-center">{{object}}</th></tr>
|
<tr><th colspan="3" class="text-center">{{object}}</th></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><ul class="list-unstyled">{% for req in object.started_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 0 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
<td><ul class="list-unstyled">{% for req in object.started_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 0 %} {% if request.user.as_trainee.is_supervisor or perms.training.delete_traininglevelrequirement %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
||||||
<td><ul class="list-unstyled">{% for req in object.complete_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 1 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
<td><ul class="list-unstyled">{% for req in object.complete_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 1 %} {% if request.user.as_trainee.is_supervisor or perms.training.delete_traininglevelrequirement %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
||||||
<td><ul class="list-unstyled">{% for req in object.passed_out_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 2 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline"" href="{% url 'remove_requirement' pk=req.pk %}" title="Delete requirement"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
<td><ul class="list-unstyled">{% for req in object.passed_out_requirements %}<li>{{ req.item }} {% user_has_qualification u req.item 2 %} {% if request.user.as_trainee.is_supervisor or perms.training.delete_traininglevelrequirement %}<a type="button" class="btn btn-link tn-sm p-0 align-baseline"" href="{% url 'remove_requirement' pk=req.pk %}" title="Delete requirement"><span class="fas fa-trash-alt text-danger"></span></a>{%endif%}</li>{% endfor %}</ul></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% for level in object_list %}
|
{% for level in object_list %}
|
||||||
<div class="card mb-2">
|
<div class="card mb-2">
|
||||||
<div class="card-header">{{level}}</div>
|
<div class="card-header"><a href="{{level.get_absolute_url}}">{{level}}</a></div>
|
||||||
<div class="card-body">{{level.description|markdown}}</div>
|
<div class="card-body">{{level.description|markdown}}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -43,9 +43,11 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% include 'partials/add_qualification.html' %}
|
<div class="btn-group">
|
||||||
<a href="{% url 'trainee_item_detail' object.pk %}" class="btn btn-info"><span class="fas fa-info-circle"></span> View Detailed Record</a>
|
{% include 'partials/add_qualification.html' %}
|
||||||
<a href="{% url 'profile_detail' object.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> View User Profile</a>
|
<a href="{% url 'trainee_item_detail' object.pk %}" class="btn btn-info"><span class="fas fa-info-circle"></span> View Detailed Record</a>
|
||||||
|
<a href="{% url 'profile_detail' object.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> View User Profile</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Supervisor</th>
|
<th>Supervisor</th>
|
||||||
<th>Notes</th>
|
<th>Notes</th>
|
||||||
{% if request.user.is_supervisor or perms.training.change_trainingitemqualification %}
|
{% if request.user.as_trainee.is_supervisor or perms.training.change_trainingitemqualification %}
|
||||||
<th></th>
|
<th></th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
<td>{{ object.date }}</td>
|
<td>{{ object.date }}</td>
|
||||||
<td><a href="{{ object.supervisor.get_absolute_url}}">{{ object.supervisor }}</a></td>
|
<td><a href="{{ object.supervisor.get_absolute_url}}">{{ object.supervisor }}</a></td>
|
||||||
<td>{{ object.notes }}</td>
|
<td>{{ object.notes }}</td>
|
||||||
{% if request.user.is_supervisor or perms.training.change_trainingitemqualification %}
|
{% if request.user.as_trainee.is_supervisor or perms.training.change_trainingitemqualification %}
|
||||||
<td>{% button 'edit' 'edit_qualification' object.pk %}</td>
|
<td>{% button 'edit' 'edit_qualification' trainee.pk %}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from PyRIGS.decorators import permission_required_with_403
|
from training.decorators import has_perm_or_supervisor
|
||||||
|
|
||||||
from training import views, models
|
from training import views, models
|
||||||
from versioning.views import VersionHistory
|
from versioning.views import VersionHistory
|
||||||
@@ -10,12 +10,12 @@ urlpatterns = [
|
|||||||
path('items/', login_required(views.ItemList.as_view()), name='item_list'),
|
path('items/', login_required(views.ItemList.as_view()), name='item_list'),
|
||||||
path('trainee/list/', login_required(views.TraineeList.as_view()), name='trainee_list'),
|
path('trainee/list/', login_required(views.TraineeList.as_view()), name='trainee_list'),
|
||||||
path('trainee/<int:pk>/',
|
path('trainee/<int:pk>/',
|
||||||
permission_required_with_403('RIGS.view_profile')(views.TraineeDetail.as_view()),
|
has_perm_or_supervisor('RIGS.view_profile')(views.TraineeDetail.as_view()),
|
||||||
name='trainee_detail'),
|
name='trainee_detail'),
|
||||||
path('trainee/<int:pk>/history', permission_required_with_403('RIGS.view_profile')(VersionHistory.as_view()), name='trainee_history', kwargs={'model': models.Trainee, 'app': 'training'}), # Not picked up automatically because proxy model (I think)
|
path('trainee/<int:pk>/history', has_perm_or_supervisor('RIGS.view_profile')(VersionHistory.as_view()), name='trainee_history', kwargs={'model': models.Trainee, 'app': 'training'}), # Not picked up automatically because proxy model (I think)
|
||||||
path('trainee/<int:pk>/add_qualification/', login_required(views.AddQualification.as_view()),
|
path('trainee/<int:pk>/add_qualification/', has_perm_or_supervisor('training.add_trainingitemqualificaiton')(views.AddQualification.as_view()),
|
||||||
name='add_qualification'),
|
name='add_qualification'),
|
||||||
path('trainee/<int:pk>/edit_qualification/', permission_required_with_403('training.change_trainingitemqualification')(views.EditQualification.as_view()),
|
path('trainee/<int:pk>/edit_qualification/', has_perm_or_supervisor('training.change_trainingitemqualification')(views.EditQualification.as_view()),
|
||||||
name='edit_qualification'),
|
name='edit_qualification'),
|
||||||
|
|
||||||
path('levels/', login_required(views.LevelList.as_view()), name='level_list'),
|
path('levels/', login_required(views.LevelList.as_view()), name='level_list'),
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class TraineeItemDetail(generic.ListView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
trainee = models.Trainee.objects.get(pk=self.kwargs['pk'])
|
trainee = models.Trainee.objects.get(pk=self.kwargs['pk'])
|
||||||
|
context["trainee"] = models.Trainee.objects.get(pk=self.kwargs['pk'])
|
||||||
context["page_title"] = "Detailed Training Record for <a href='{}'>{}</a>".format(trainee.get_absolute_url(), trainee)
|
context["page_title"] = "Detailed Training Record for <a href='{}'>{}</a>".format(trainee.get_absolute_url(), trainee)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user