diff --git a/cmsmanage/settings/base.py b/cmsmanage/settings/base.py index c51636e..ef9fe61 100644 --- a/cmsmanage/settings/base.py +++ b/cmsmanage/settings/base.py @@ -40,6 +40,7 @@ INSTALLED_APPS = [ "membershipworks.apps.MembershipworksConfig", "paperwork.apps.PaperworkConfig", "doorcontrol.apps.DoorControlConfig", + "dashboard.apps.DashboardConfig", ] MIDDLEWARE = [ diff --git a/cmsmanage/urls.py b/cmsmanage/urls.py index d46cfd5..4ab64dc 100644 --- a/cmsmanage/urls.py +++ b/cmsmanage/urls.py @@ -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")), diff --git a/dashboard/__init__.py b/dashboard/__init__.py new file mode 100644 index 0000000..e54b45e --- /dev/null +++ b/dashboard/__init__.py @@ -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 diff --git a/dashboard/apps.py b/dashboard/apps.py new file mode 100644 index 0000000..d89acb8 --- /dev/null +++ b/dashboard/apps.py @@ -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") diff --git a/dashboard/dashboard.py b/dashboard/dashboard.py new file mode 100644 index 0000000..e69de29 diff --git a/dashboard/templates/dashboard/dashboard.dj.html b/dashboard/templates/dashboard/dashboard.dj.html new file mode 100644 index 0000000..b799b9d --- /dev/null +++ b/dashboard/templates/dashboard/dashboard.dj.html @@ -0,0 +1,26 @@ +{% extends "base.dj.html" %} + +{% block title %}Claremont MakerSpace Management{% endblock %} +{% block content %} + {% if not user.is_authenticated %} +
+ You are not logged in. Much of this site is inaccessible until you log in. +
+ {% endif %} +
+
+ {% for app, app_dash in apps.items %} + {% if app_dash.visible %} +
+
+
{{ app }}
+ {% include app_dash.template with ctx=app_dash.context %} +
+
+ {% endif %} + {% endfor %} +
+
+{% endblock %} diff --git a/dashboard/templates/dashboard/links_card.dj.html b/dashboard/templates/dashboard/links_card.dj.html new file mode 100644 index 0000000..4dc8ca6 --- /dev/null +++ b/dashboard/templates/dashboard/links_card.dj.html @@ -0,0 +1,7 @@ + diff --git a/dashboard/tests.py b/dashboard/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dashboard/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dashboard/urls.py b/dashboard/urls.py new file mode 100644 index 0000000..047aecb --- /dev/null +++ b/dashboard/urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from . import views + +app_name = "dashboard" + +urlpatterns = [ + path("", views.DashboardView.as_view(), name="dashboard"), +] diff --git a/dashboard/views.py b/dashboard/views.py new file mode 100644 index 0000000..b89f7d5 --- /dev/null +++ b/dashboard/views.py @@ -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 diff --git a/doorcontrol/dashboard.py b/doorcontrol/dashboard.py new file mode 100644 index 0000000..6050753 --- /dev/null +++ b/doorcontrol/dashboard.py @@ -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") diff --git a/paperwork/dashboard.py b/paperwork/dashboard.py new file mode 100644 index 0000000..6b01057 --- /dev/null +++ b/paperwork/dashboard.py @@ -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 diff --git a/rentals/dashboard.py b/rentals/dashboard.py new file mode 100644 index 0000000..47abea2 --- /dev/null +++ b/rentals/dashboard.py @@ -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")}} diff --git a/templates/base.dj.html b/templates/base.dj.html index 5cb14a2..c84ef4b 100644 --- a/templates/base.dj.html +++ b/templates/base.dj.html @@ -17,7 +17,7 @@