Add a dashboard for showing relevant links and apps to users

This commit is contained in:
Adam Goldsmith 2023-04-14 01:24:36 -04:00
parent 52fad7ccb0
commit 2c474bf751
14 changed files with 182 additions and 2 deletions

View File

@ -40,6 +40,7 @@ INSTALLED_APPS = [
"membershipworks.apps.MembershipworksConfig",
"paperwork.apps.PaperworkConfig",
"doorcontrol.apps.DoorControlConfig",
"dashboard.apps.DashboardConfig",
]
MIDDLEWARE = [

View File

@ -29,7 +29,7 @@ router.registry.extend(paperwork_router.registry)
router.registry.extend(membershipworks_router.registry)
urlpatterns = [
path("", lambda request: redirect("/tasks/"), name="root"),
path("", include("dashboard.urls")),
path("tasks/", include("tasks.urls")),
path("rentals/", include("rentals.urls")),
path("membershipworks/", include("membershipworks.urls")),

20
dashboard/__init__.py Normal file
View File

@ -0,0 +1,20 @@
from typing import Any
from django.http import HttpRequest
DASHBOARD_CARDS = {}
def register(fragment):
DASHBOARD_CARDS[fragment.name] = fragment
return fragment
class DashboardFragment:
name: str
template: str
context: Any = None
visible: bool = True
def __init__(self, request: HttpRequest):
self.request = request

11
dashboard/apps.py Normal file
View File

@ -0,0 +1,11 @@
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules
class DashboardConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "dashboard"
def ready(self):
super().ready()
autodiscover_modules("dashboard")

0
dashboard/dashboard.py Normal file
View File

View File

@ -0,0 +1,26 @@
{% extends "base.dj.html" %}
{% block title %}Claremont MakerSpace Management{% endblock %}
{% block content %}
{% if not user.is_authenticated %}
<div class="alert alert-warning">
You are not logged in. Much of this site is inaccessible until you <a href="{% url 'login' %}">log in</a>.
</div>
{% endif %}
<div class="container">
<div style="display: grid;
grid-template-columns: repeat(auto-fit, minmax(20em, auto));
gap: 0.5em">
{% for app, app_dash in apps.items %}
{% if app_dash.visible %}
<div>
<div class="card">
<h5 class="card-header">{{ app }}</h5>
{% include app_dash.template with ctx=app_dash.context %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,7 @@
<ul class="list-group list-group-flush">
{% for text, link in ctx.links.items %}
<li class="list-group-item">
<a class="card-link" href="{{ link }}">{{ text }}</a>
</li>
{% endfor %}
</ul>

3
dashboard/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

9
dashboard/urls.py Normal file
View File

@ -0,0 +1,9 @@
from django.urls import path
from . import views
app_name = "dashboard"
urlpatterns = [
path("", views.DashboardView.as_view(), name="dashboard"),
]

14
dashboard/views.py Normal file
View File

@ -0,0 +1,14 @@
from django.views.generic.base import TemplateView
from dashboard import DASHBOARD_CARDS
class DashboardView(TemplateView):
template_name = "dashboard/dashboard.dj.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["apps"] = {
name: card(self.request) for name, card in DASHBOARD_CARDS.items()
}
return context

30
doorcontrol/dashboard.py Normal file
View File

@ -0,0 +1,30 @@
from typing import Any
from django.urls import reverse
import dashboard
@dashboard.register
class DoorControlDashboardFragment(dashboard.DashboardFragment):
name = "Door Controls"
template = "dashboard/links_card.dj.html"
@property
def context(self) -> Any:
return {
"links": {
"Access Per Day": reverse(
"doorcontrol:access-per-unit-time", kwargs={"unit_time": "day"}
),
"Access Per Month": reverse(
"doorcontrol:access-per-unit-time", kwargs={"unit_time": "month"}
),
"Access Failures": reverse("doorcontrol:denied-access"),
"Most Active Members": reverse("doorcontrol:most-active-members"),
}
}
@property
def visible(self) -> bool:
return self.request.user.has_perm("doorcontrol.view_hidevent")

44
paperwork/dashboard.py Normal file
View File

@ -0,0 +1,44 @@
from typing import Any
from django.urls import reverse
import dashboard
from membershipworks.models import Member
from .models import Department
@dashboard.register
class PaperworkDashboardFragment(dashboard.DashboardFragment):
name = "Paperwork"
template = "dashboard/links_card.dj.html"
@property
def context(self) -> Any:
links = {}
if hasattr(self.request.user, "ldap_user"):
uid = self.request.user.ldap_user.attrs["employeeNumber"][0]
links["Member Certifications"] = reverse("paperwork:member_certifications")
else:
uid = None
departments = Department.objects.prefetch_related("shop_lead_flag__members")
if self.request.user.is_superuser:
departments = departments.all()
elif uid is not None:
user_member = Member.objects.get(uid=uid)
# TODO: could be a lot simpler if membershipworks was in the same database
# TODO: should also select children
member_flags = list(user_member.flags.all().values_list("pk", flat=True))
departments = departments.filter(shop_lead_flag__in=member_flags)
if len(departments) > 0:
links["Department Certifications"] = reverse(
"paperwork:department_certifications"
)
return {"links": links}
@property
def visible(self) -> bool:
return self.request.user.is_authenticated

15
rentals/dashboard.py Normal file
View File

@ -0,0 +1,15 @@
from typing import Any
from django.urls import reverse
import dashboard
@dashboard.register
class RentalsDashboardFragment(dashboard.DashboardFragment):
name = "Rentals"
template = "dashboard/links_card.dj.html"
@property
def context(self) -> Any:
return {"links": {"Locker Index": reverse("rentals:index")}}

View File

@ -17,7 +17,7 @@
<body>
<nav class="navbar navbar-expand-sm navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'root' %}">Claremont MakerSpace</a>
<a class="navbar-brand" href="{% url 'dashboard:dashboard' %}">Claremont MakerSpace</a>
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"