From cbe651957dce98df953c1d2e3c702296d8d814bf Mon Sep 17 00:00:00 2001 From: Arona Jones Date: Sat, 23 Sep 2023 19:47:00 +0000 Subject: [PATCH] Create 'upcoming events list' with very limited data UoN users (with nottingham.ac.uk emails) are allowed to access this page only. Not a huge fan of the implementation, hoping someone (maybe future me) comes up with a less nasty implementation --- PyRIGS/decorators.py | 4 + PyRIGS/urls.py | 12 +-- .../templates/estates/estates_event_list.html | 5 ++ .../estates/estates_event_table.html | 78 +++++++++++++++++++ RIGS/urls.py | 27 +++---- RIGS/views/rigboard.py | 15 ++++ assets/urls.py | 20 ++--- training/urls.py | 25 +++--- users/urls.py | 8 +- 9 files changed, 150 insertions(+), 44 deletions(-) create mode 100644 RIGS/templates/estates/estates_event_list.html create mode 100644 RIGS/templates/estates/estates_event_table.html diff --git a/PyRIGS/decorators.py b/PyRIGS/decorators.py index ca7cd8ea..d18acd81 100644 --- a/PyRIGS/decorators.py +++ b/PyRIGS/decorators.py @@ -121,3 +121,7 @@ def nottinghamtec_address_required(function): return function(request, *args, **kwargs) return wrap + + +def not_estates(): + return user_passes_test_with_403(lambda u: not u.email.endswith('@nottingham.ac.uk')) \ No newline at end of file diff --git a/PyRIGS/urls.py b/PyRIGS/urls.py index 03d42b50..ea8d4a82 100644 --- a/PyRIGS/urls.py +++ b/PyRIGS/urls.py @@ -6,6 +6,8 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.urls import path from django.views.generic import TemplateView +from PyRIGS.decorators import not_estates + from PyRIGS import views urlpatterns = [ @@ -14,17 +16,17 @@ urlpatterns = [ path('assets/', include('assets.urls')), path('training/', include('training.urls')), - path('', login_required(views.Index.as_view()), name='index'), + path('', not_estates()(views.Index.as_view()), name='index'), # API - path('api//', login_required(views.SecureAPIRequest.as_view()), + path('api//', not_estates()(views.SecureAPIRequest.as_view()), name="api_secure"), - path('api///', login_required(views.SecureAPIRequest.as_view()), + path('api///', not_estates()(views.SecureAPIRequest.as_view()), name="api_secure"), path('closemodal/', views.CloseModal.as_view(), name='closemodal'), - path('search/', login_required(views.Search.as_view()), name='search'), - path('search_help/', login_required(views.SearchHelp.as_view()), name='search_help'), + path('search/', not_estates()(views.Search.as_view()), name='search'), + path('search_help/', not_estates()(views.SearchHelp.as_view()), name='search_help'), path('', include('users.urls')), diff --git a/RIGS/templates/estates/estates_event_list.html b/RIGS/templates/estates/estates_event_list.html new file mode 100644 index 00000000..2fb8fce0 --- /dev/null +++ b/RIGS/templates/estates/estates_event_list.html @@ -0,0 +1,5 @@ +{% extends 'base_client.html' %} + +{% block content %} +{% include 'estates/estates_event_table.html' %} +{% endblock %} diff --git a/RIGS/templates/estates/estates_event_table.html b/RIGS/templates/estates/estates_event_table.html new file mode 100644 index 00000000..aec9d34a --- /dev/null +++ b/RIGS/templates/estates/estates_event_table.html @@ -0,0 +1,78 @@ +{% load namewithnotes from filters %} +{% load markdown_tags %} +
+ + + + + + + + + + + + + {% for event in events %} + + + + + + + + + + + + + {% empty %} + + + + {% endfor %} + +
#Dates & TimesEvent DetailsStatusMember In ChargePower Plan
{{ event.display_id }} + Start: {{ event.start_date|date:"D d/m/Y" }} + {% if event.has_start_time %} + {{ event.start_time|date:"H:i" }} + {% endif %} + + {% if event.end_date %} +
+ End: {% if event.end_date != event.start_date %}{{ event.end_date|date:"D d/m/Y" }}{% endif %} + {% if event.has_end_time %} + {{ event.end_time|date:"H:i" }} + {% endif %} + + {% endif %} +
+

+ {{ event.name }} + {% if event.venue %} + at {{ event.venue }} + {% endif %} +

+ {% if event.is_rig and not event.cancelled %} +
+ {{ event.person.name }} + {% if event.organisation %} + for {{ event.organisation.name }} + {% endif %} +
+ {% endif %} + {% if not event.cancelled and event.description %} +

{{ event.description|markdown }}

+ {% endif %} +
+ {{ event.get_status_display }} + + {% if event.mic %} + {{ event.mic }} + {% elif event.is_rig %} + + {% endif %} + + {{ event.riskassessment.power_plan|default:"Pending" }} +
No events found
+
diff --git a/RIGS/urls.py b/RIGS/urls.py index 8793b741..8c30e5d1 100644 --- a/RIGS/urls.py +++ b/RIGS/urls.py @@ -4,7 +4,7 @@ from django.views.decorators.clickjacking import xframe_options_exempt from django.views.generic import RedirectView from PyRIGS.decorators import (api_key_required, has_oembed, - permission_required_with_403) + permission_required_with_403, not_estates) from . import views urlpatterns = [ @@ -42,21 +42,22 @@ urlpatterns = [ name='venue_update'), # Rigboard - path('rigboard/', login_required(views.RigboardIndex.as_view()), name='rigboard'), - path('rigboard/calendar/', login_required()(views.WebCalendar.as_view()), + path('rigboard/', not_estates()(views.RigboardIndex.as_view()), name='rigboard'), + path('rigboard/calendar/', not_estates()(views.WebCalendar.as_view()), name='web_calendar'), re_path(r'^rigboard/calendar/(?P(month|week|day))/$', - login_required()(views.WebCalendar.as_view()), name='web_calendar'), + not_estates()(views.WebCalendar.as_view()), name='web_calendar'), re_path(r'^rigboard/calendar/(?P(month|week|day))/(?P(\d{4}-\d{2}-\d{2}))/$', - login_required()(views.WebCalendar.as_view()), name='web_calendar'), + not_estates()(views.WebCalendar.as_view()), name='web_calendar'), path('rigboard/archive/', RedirectView.as_view(permanent=True, pattern_name='event_archive')), + path('estates/', login_required()(views.EstatesEventList.as_view()), name='estates'), path('event//', has_oembed(oembed_view="event_oembed")(views.EventDetail.as_view()), name='event_detail'), path('event/create/', permission_required_with_403('RIGS.add_event')(views.EventCreate.as_view()), name='event_create'), - path('event/archive/', login_required()(views.EventArchive.as_view()), + path('event/archive/', not_estates()(views.EventArchive.as_view()), name='event_archive'), path('event//embed/', xframe_options_exempt(login_required(login_url='/user/login/embed/')(views.EventEmbed.as_view())), @@ -75,7 +76,7 @@ urlpatterns = [ path('event//ra/', permission_required_with_403('RIGS.add_riskassessment')(views.EventRiskAssessmentCreate.as_view()), name='event_ra'), - path('event/ra//', login_required(views.EventRiskAssessmentDetail.as_view()), + path('event/ra//', not_estates()(views.EventRiskAssessmentDetail.as_view()), name='ra_detail'), path('event/ra//edit/', permission_required_with_403('RIGS.change_riskassessment')(views.EventRiskAssessmentEdit.as_view()), name='ra_edit'), @@ -85,7 +86,7 @@ urlpatterns = [ path('event//checklist/', permission_required_with_403('RIGS.add_eventchecklist')(views.EventChecklistCreate.as_view()), name='event_ec'), - path('event/checklist//', login_required(views.EventChecklistDetail.as_view()), + path('event/checklist//', not_estates()(views.EventChecklistDetail.as_view()), name='ec_detail'), path('event/checklist//edit/', permission_required_with_403('RIGS.change_eventchecklist')(views.EventChecklistEdit.as_view()), name='ec_edit'), @@ -94,20 +95,20 @@ urlpatterns = [ path('event//power/', permission_required_with_403('RIGS.add_powertestrecord')(views.PowerTestCreate.as_view()), name='event_pt'), - path('event/power//', login_required(views.PowerTestDetail.as_view()), + path('event/power//', not_estates()(views.PowerTestDetail.as_view()), name='pt_detail'), path('event/power//edit/', permission_required_with_403('RIGS.change_powertestrecord')(views.PowerTestEdit.as_view()), name='pt_edit'), path('event/power//review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()), name='pt_review', kwargs={'model': 'PowerTestRecord'}), - path('event//checkin/', login_required(views.EventCheckIn.as_view()), + path('event//checkin/', not_estates()(views.EventCheckIn.as_view()), name='event_checkin'), - path('event/checkout/', login_required(views.EventCheckOut.as_view()), + path('event/checkout/', not_estates()(views.EventCheckOut.as_view()), name='event_checkout'), - path('event//checkin/edit/', login_required(views.EventCheckInEdit.as_view()), + path('event//checkin/edit/', not_estates()(views.EventCheckInEdit.as_view()), name='edit_checkin'), - path('event//checkin/add/', login_required(views.EventCheckInOverride.as_view()), + path('event//checkin/add/', not_estates()(views.EventCheckInOverride.as_view()), name='event_checkin_override'), path('event//thread/', permission_required_with_403('RIGS.change_event')(views.CreateForumThread.as_view()), name='event_thread'), diff --git a/RIGS/views/rigboard.py b/RIGS/views/rigboard.py index 6a9072a0..6a14a613 100644 --- a/RIGS/views/rigboard.py +++ b/RIGS/views/rigboard.py @@ -26,6 +26,7 @@ from django.utils import timezone from django.utils.decorators import method_decorator from django.views import generic from django.views.decorators.csrf import csrf_exempt +from django.contrib.auth.mixins import UserPassesTestMixin from PyRIGS import decorators from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin, PrintView, get_related @@ -422,3 +423,17 @@ class RecieveForumWebhook(generic.View): event.save() return HttpResponse(status=202) return HttpResponse(status=204) + +class EstatesEventList(UserPassesTestMixin, generic.TemplateView): + template_name = 'estates/estates_event_list.html' + + def get_context_data(self, **kwargs): + # get super context + context = super().get_context_data(**kwargs) + # call out method to get current events + context['events'] = models.Event.objects.current_events().filter(venue__on_campus=True, dry_hire=False, is_rig=True) + context['page_title'] = "Upcoming Campus Events" + return context + + def test_func(self): + return self.request.user.email.endswith('@nottingham.ac.uk') \ No newline at end of file diff --git a/assets/urls.py b/assets/urls.py index 3091b84b..d8360f22 100644 --- a/assets/urls.py +++ b/assets/urls.py @@ -2,7 +2,7 @@ from django.contrib.auth.decorators import login_required from django.urls import path, register_converter from django.views.decorators.clickjacking import xframe_options_exempt -from PyRIGS.decorators import has_oembed, permission_required_with_403 +from PyRIGS.decorators import has_oembed, permission_required_with_403, not_estates from PyRIGS.views import OEmbedView from . import views, converters @@ -10,8 +10,8 @@ register_converter(converters.AssetIDConverter, 'asset') register_converter(converters.ListConverter, 'list') urlpatterns = [ - path('', login_required(views.AssetList.as_view()), name='asset_index'), - path('asset/list/', login_required(views.AssetList.as_view()), name='asset_list'), + path('', not_estates()(views.AssetList.as_view()), name='asset_index'), + path('asset/list/', not_estates()(views.AssetList.as_view()), name='asset_list'), path('asset/id//', has_oembed(oembed_view="asset_oembed")(views.AssetDetail.as_view()), name='asset_detail'), path('asset/create/', permission_required_with_403('assets.add_asset') (views.AssetCreate.as_view()), name='asset_create'), @@ -19,26 +19,26 @@ urlpatterns = [ (views.AssetEdit.as_view()), name='asset_update'), path('asset/id//duplicate/', permission_required_with_403('assets.add_asset') (views.AssetDuplicate.as_view()), name='asset_duplicate'), - path('asset/id//label', login_required(views.GenerateLabel.as_view()), name='generate_label'), + path('asset/id//label', not_estates()(views.GenerateLabel.as_view()), name='generate_label'), path('asset//list/label', views.GenerateLabels.as_view(), name='generate_labels'), - path('cables/list/', login_required(views.CableList.as_view()), name='cable_list'), - path('cabletype/list/', login_required(views.CableTypeList.as_view()), name='cable_type_list'), + path('cables/list/', not_estates()(views.CableList.as_view()), name='cable_list'), + path('cabletype/list/', not_estates()(views.CableTypeList.as_view()), name='cable_type_list'), path('cabletype/create/', permission_required_with_403('assets.add_cable_type')(views.CableTypeCreate.as_view()), name='cable_type_create'), path('cabletype//update/', permission_required_with_403('assets.change_cable_type')(views.CableTypeUpdate.as_view()), name='cable_type_update'), - path('cabletype//detail/', login_required(views.CableTypeDetail.as_view()), name='cable_type_detail'), + path('cabletype//detail/', not_estates()(views.CableTypeDetail.as_view()), name='cable_type_detail'), path('asset/id//embed/', xframe_options_exempt( - login_required(login_url='/user/login/embed/')(views.AssetEmbed.as_view())), + login_required(login_url='/user/login/embed/')(views.AssetEmbed.as_view())), name='asset_embed'), path('asset/id//oembed_json/', views.AssetOEmbed.as_view(), name='asset_oembed'), path('asset/audit/', permission_required_with_403('assets.change_asset')(views.AssetAuditList.as_view()), name='asset_audit_list'), path('asset/id//audit/', permission_required_with_403('assets.change_asset')(views.AssetAudit.as_view()), name='asset_audit'), - path('supplier/list/', login_required(views.SupplierList.as_view()), name='supplier_list'), - path('supplier//', login_required(views.SupplierDetail.as_view()), name='supplier_detail'), + path('supplier/list/', not_estates()(views.SupplierList.as_view()), name='supplier_list'), + path('supplier//', not_estates()(views.SupplierDetail.as_view()), name='supplier_detail'), path('supplier/create/', permission_required_with_403('assets.add_supplier') (views.SupplierCreate.as_view()), name='supplier_create'), path('supplier//edit/', permission_required_with_403('assets.change_supplier') diff --git a/training/urls.py b/training/urls.py index 55ab7523..024fda65 100644 --- a/training/urls.py +++ b/training/urls.py @@ -1,33 +1,34 @@ from django.urls import path -from django.contrib.auth.decorators import login_required from training.decorators import is_supervisor from training import views, models from versioning.views import VersionHistory -urlpatterns = [ - path('items/', login_required(views.ItemList.as_view()), name='item_list'), - path('items/export/', login_required(views.ItemListExport.as_view()), name='item_list_export'), - path('item//qualified_users/', login_required(views.ItemQualifications.as_view()), name='item_qualification'), +from PyRIGS.decorators import not_estates - path('trainee/list/', login_required(views.TraineeList.as_view()), name='trainee_list'), - path('trainee//', login_required(views.TraineeDetail.as_view()), +urlpatterns = [ + path('items/', not_estates()(views.ItemList.as_view()), name='item_list'), + path('items/export/', not_estates()(views.ItemListExport.as_view()), name='item_list_export'), + path('item//qualified_users/', not_estates()(views.ItemQualifications.as_view()), name='item_qualification'), + + path('trainee/list/', not_estates()(views.TraineeList.as_view()), name='trainee_list'), + path('trainee//', not_estates()(views.TraineeDetail.as_view()), name='trainee_detail'), - path('trainee//history', login_required(VersionHistory.as_view()), name='trainee_history', kwargs={'model': models.Trainee, 'app': 'training'}), # Not picked up automatically because proxy model (I think) + path('trainee//history', not_estates()(VersionHistory.as_view()), name='trainee_history', kwargs={'model': models.Trainee, 'app': 'training'}), # Not picked up automatically because proxy model (I think) path('trainee//add_qualification/', is_supervisor()(views.AddQualification.as_view()), name='add_qualification'), path('trainee/edit_qualification//', is_supervisor()(views.EditQualification.as_view()), name='edit_qualification'), - path('levels/', login_required(views.LevelList.as_view()), name='level_list'), - path('level//', login_required(views.LevelDetail.as_view()), name='level_detail'), - path('level//user//', login_required(views.LevelDetail.as_view()), name='level_detail'), + path('levels/', not_estates()(views.LevelList.as_view()), name='level_list'), + path('level//', not_estates()(views.LevelDetail.as_view()), name='level_detail'), + path('level//user//', not_estates()(views.LevelDetail.as_view()), name='level_detail'), path('level//add_requirement/', is_supervisor()(views.AddLevelRequirement.as_view()), name='add_requirement'), path('level/remove_requirement//', is_supervisor()(views.RemoveRequirement.as_view()), name='remove_requirement'), path('trainee//level//confirm', is_supervisor()(views.ConfirmLevel.as_view()), name='confirm_level'), - path('trainee//item_record', login_required(views.TraineeItemDetail.as_view()), name='trainee_item_detail'), + path('trainee//item_record', not_estates()(views.TraineeItemDetail.as_view()), name='trainee_item_detail'), path('session_log', is_supervisor()(views.SessionLog.as_view()), name='session_log'), ] diff --git a/users/urls.py b/users/urls.py index c723297d..b13d3074 100644 --- a/users/urls.py +++ b/users/urls.py @@ -5,7 +5,7 @@ from django.urls import path from django.views.decorators.clickjacking import xframe_options_exempt from registration.backends.default.views import RegistrationView -from PyRIGS.decorators import permission_required_with_403 +from PyRIGS.decorators import permission_required_with_403, not_estates from users import forms, views urlpatterns = [ @@ -14,11 +14,11 @@ urlpatterns = [ path('user/login/', LoginView.as_view(authentication_form=forms.CheckApprovedForm), name='login'), path('user/login/embed/', xframe_options_exempt(views.LoginEmbed.as_view()), name='login_embed'), # User editing - path('user/edit/', login_required(views.ProfileUpdateSelf.as_view()), + path('user/edit/', not_estates()(views.ProfileUpdateSelf.as_view()), name='profile_update_self'), - path('user/reset_api_key', login_required(views.ResetApiKey.as_view(permanent=False)), + path('user/reset_api_key', not_estates()(views.ResetApiKey.as_view(permanent=False)), name='reset_api_key'), - path('user/', login_required(views.ProfileDetail.as_view()), name='profile_detail'), + path('user/', not_estates()(views.ProfileDetail.as_view()), name='profile_detail'), path('user//', permission_required_with_403('RIGS.view_profile')(views.ProfileDetail.as_view()), name='profile_detail'),