Skip to content

Commit

Permalink
Make the service_details view a class based view. (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanning9 authored Feb 28, 2024
1 parent 36357c6 commit 70fa088
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 121 deletions.
6 changes: 2 additions & 4 deletions jasmin_services/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"""
URL configuration for the JASMIN services app.
"""
"""URL configuration for the JASMIN services app."""

__author__ = "Matt Pryor"
__copyright__ = "Copyright 2015 UK Science and Technology Facilities Council"
Expand All @@ -25,7 +23,7 @@
"<slug:category>/<slug:service>/",
include(
[
path("", views.service_details, name="service_details"),
path("", views.ServiceDetailsView.as_view(), name="service_details"),
path("requests/", views.service_requests, name="service_requests"),
path("users/", views.service_users, name="service_users"),
path("message/", views.service_message, name="service_message"),
Expand Down
5 changes: 3 additions & 2 deletions jasmin_services/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .request_decide import request_decide
from .reverse_dns_check import reverse_dns_check
from .role_apply import RoleApplyView
from .service_details import service_details
from .service_details import ServiceDetailsView
from .service_list import service_list
from .service_message import service_message
from .service_requests import service_requests
Expand All @@ -16,10 +16,11 @@
"my_services",
"request_decide",
"reverse_dns_check",
"RoleApplyView",
"service_details",
"service_list",
"service_message",
"service_requests",
"service_users",
"RoleApplyView",
"ServiceDetailsView",
]
1 change: 1 addition & 0 deletions jasmin_services/views/common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Common functions for jasmin_services views."""

import functools
import logging

Expand Down
26 changes: 26 additions & 0 deletions jasmin_services/views/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import django.http

from .. import models


class WithServiceMixin:
"""Mixin to add service to class-based view attributes."""

@staticmethod
def get_service(category_name, service_name):
"""Get a service from it's category and name."""
try:
return models.Service.objects.get(name=service_name, category__name=category_name)
except models.Service.DoesNotExist as err:
raise django.http.Http404("Service does not exist.") from err

def setup(self, request, *args, **kwargs):
"""Add service to class atrributes."""
# pylint: disable=attribute-defined-outside-init

# Get the service from the request.
self.service = self.get_service(kwargs["category"], kwargs["service"])
if self.service.disabled:
raise django.http.Http404("Service has been retired.")

super().setup(request, *args, **kwargs)
25 changes: 5 additions & 20 deletions jasmin_services/views/role_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,28 @@

import django.contrib.auth.mixins
import django.core.exceptions
import django.http
import django.views.generic
import django.views.generic.edit
import requests
from dateutil.relativedelta import relativedelta
from django.conf import settings
from django.contrib import messages
from django.db import transaction

from .. import models
from ..models import Access, Grant, Group, Request, RequestState, Role
from . import common
from ..models import Access, Grant, Request, RequestState, Role
from . import common, mixins

_log = logging.getLogger(__name__)


class RoleApplyView(
django.contrib.auth.mixins.LoginRequiredMixin, django.views.generic.edit.FormView
django.contrib.auth.mixins.LoginRequiredMixin,
mixins.WithServiceMixin,
django.views.generic.edit.FormView,
):
"""Handle for ``/<category>/<service>/apply/<role>/``.
Collects the necessary information to raise a request for a role.
"""

@staticmethod
def get_service(category_name, service_name):
"""Get a service from it's category and name."""
try:
return models.Service.objects.get(name=service_name, category__name=category_name)
except models.Service.DoesNotExist as err:
raise django.http.Http404("Service does not exist.") from err

@staticmethod
def get_previous_request_and_grant(bool_grant, previous):
"""Get the previous request or grant from the id supplied."""
Expand Down Expand Up @@ -74,11 +64,6 @@ def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.redirect_to_service = True

# Get the service from the request.
self.service = self.get_service(kwargs["category"], kwargs["service"])
if self.service.disabled:
raise django.http.Http404("Service has been retired.")

# Prevent users who are not allowed to apply for this service from doing so.
user_may_apply = common.user_may_apply(request.user, self.service)
if not user_may_apply[0]:
Expand Down
184 changes: 92 additions & 92 deletions jasmin_services/views/service_details.py
Original file line number Diff line number Diff line change
@@ -1,119 +1,119 @@
from datetime import date

import django.views.generic
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.views.decorators.http import require_safe

from ..models import Grant, Request
from . import common
from . import common, mixins


@require_safe
@login_required
@common.with_service
def service_details(request, service):
class ServiceDetailsView(
django.contrib.auth.mixins.LoginRequiredMixin,
mixins.WithServiceMixin,
django.views.generic.TemplateView,
):
"""Handle ``/<category>/<service>/``.
Responds to GET requests only. The user must be authenticated.
Displays details for a service, including details of current access and requests.
"""

# Get the active grants and requests for the service as a whole
all_grants = Grant.objects.filter(
access__role__service=service, access__user=request.user
).filter_active()
all_requests = Request.objects.filter(
access__role__service=service, access__user=request.user
).filter_active()

# roles is a list of the roles of the service that have an active grant
# or request or aren't hidden
roles = []
grants = []
requests = []
for role in service.roles.all():
role_grants = all_grants.filter(access__role=role)
role_requests = all_requests.filter(access__role=role)
if role_grants:
# Add metadata so users can tell grants apart
role_grants = [
(
rg,
getattr(
rg.metadata.filter(key="supporting_information").first(),
"value",
None,
),
rg.next_requests.all(),
)
for rg in role_grants
]
grants.append((role, role_grants))
if role_requests:
# Add metadata so users can tell requests apart
role_requests = [
(
rr,
getattr(
rr.metadata.filter(key="supporting_information").first(),
"value",
None,
),
)
for rr in role_requests
]
requests.append((role, role_requests))
if not role.hidden or role_requests or role_grants:
# if multiple requests aren't allowed only add to "apply list"
# if there isn't an existing request or grant
if not settings.MULTIPLE_REQUESTS_ALLOWED and (role_requests or role_grants):
continue
roles.append(role)

if grants:
# Get all the current managers and deputies of a services so that
# we can display this information to users of the service.
managers = (
Grant.objects.filter(
access__role__service=service,
expires__gt=date.today(),
revoked=False,
)
.filter_active()
.filter(access__role__name="MANAGER")
)
managers = [x.access.user for x in managers]
deputies = (
@staticmethod
def get_service_roleholders(service, role_name):
"""Get the holders of a given role for a service."""
holders = (
Grant.objects.filter(
access__role__service=service,
expires__gt=date.today(),
revoked=False,
)
.filter_active()
.filter(access__role__name="DEPUTY")
.filter(access__role__name=role_name)
)
deputies = [x.access.user for x in deputies]
else:
managers = []
deputies = []
return [x.access.user for x in holders]

def get_context_data(self, **kwargs):
"""Add information about service to the context."""
context = super().get_context_data(**kwargs)

# Get the active grants and requests for the service as a whole
all_grants = Grant.objects.filter(
access__role__service=self.service, access__user=self.request.user
).filter_active()
all_requests = Request.objects.filter(
access__role__service=self.service, access__user=self.request.user
).filter_active()

templates = [
f"jasmin_services/{service.category.name}/{service.name}/service_details.html",
f"jasmin_services/{service.category.name}/service_details.html",
"jasmin_services/service_details.html",
]
return render(
request,
templates,
{
"service": service,
# roles is a list of the roles of the service that have an active grant
# or request or aren't hidden
roles = []
grants = []
requests = []
for role in self.service.roles.all():
role_grants = all_grants.filter(access__role=role)
role_requests = all_requests.filter(access__role=role)
if role_grants:
# Add metadata so users can tell grants apart
role_grants = [
(
rg,
getattr(
rg.metadata.filter(key="supporting_information").first(),
"value",
None,
),
rg.next_requests.all(),
)
for rg in role_grants
]
grants.append((role, role_grants))
if role_requests:
# Add metadata so users can tell requests apart
role_requests = [
(
rr,
getattr(
rr.metadata.filter(key="supporting_information").first(),
"value",
None,
),
)
for rr in role_requests
]
requests.append((role, role_requests))
if not role.hidden or role_requests or role_grants:
# if multiple requests aren't allowed only add to "apply list"
# if there isn't an existing request or grant
if not settings.MULTIPLE_REQUESTS_ALLOWED and (role_requests or role_grants):
continue
roles.append(role)

# If the user holds an active grant in the service
# get all the current managers and deputies of a services so that
# we can display this information to users of the service.
if grants:
managers = self.get_service_roleholders(self.service, "MANAGER")
deputies = self.get_service_roleholders(self.service, "DEPUTY")
else:
managers = []
deputies = []

context |= {
"service": self.service,
"requests": requests,
"grants": grants,
"roles": roles,
"managers": managers,
"deputies": deputies,
"user_may_apply": common.user_may_apply(request.user, service),
},
)
"user_may_apply": common.user_may_apply(self.request.user, self.service),
}
return context

def get_template_names(self):
"""Allow overriding the template at multiple levels."""
return [
f"jasmin_services/{self.service.category.name}/{self.service.name}/service_details.html",
f"jasmin_services/{self.service.category.name}/service_details.html",
"jasmin_services/service_details.html",
]
8 changes: 5 additions & 3 deletions jasmin_services/views/service_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,10 @@ def service_list(request, category):
for service in page
],
"page": page,
"preserved_filters": "query={}".format(urllib.parse.quote(request.GET["query"]))
if "query" in request.GET
else "",
"preserved_filters": (
"query={}".format(urllib.parse.quote(request.GET["query"]))
if "query" in request.GET
else ""
),
},
)

0 comments on commit 70fa088

Please sign in to comment.