paperwork: Add a view to show shop leads issued certifications in their shops

This commit is contained in:
Adam Goldsmith 2023-02-02 15:08:48 -05:00
parent 86000be17b
commit 4aaa1db3a8
7 changed files with 189 additions and 2 deletions

View File

@ -77,6 +77,13 @@ class Department(models.Model):
else: else:
return None return None
@property
def list_address(self):
if self.has_mailing_list:
return self.list_name + "@claremontmakerspace.org"
else:
return None
class CertificationDefinition(models.Model): class CertificationDefinition(models.Model):
certification_identifier = models.AutoField( certification_identifier = models.AutoField(

View File

@ -0,0 +1,134 @@
{% extends "base.dj.html" %}
{% block content %}
{% if departments %}
<h2>Departments for which you are a lead</h2>
<table class="table table-bordered table-striped table-hover" border="1">
<thead>
<tr>
<th>Department</th>
<th>Shop Leads</th>
<th>Mailing list</th>
</tr>
</thead>
<tbody>
{% for department in departments %}
<tr>
<td>{{ department.name }}</td>
<td>{{ department.shop_lead_flag.members.all|join:", " }}</td>
<td>{{ department.list_address }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="d-flex flex-wrap justify-content-between">
<h2>Certifications in those departments</h2>
<div class="form-check form-switch">
<label class="form-check-label" for="flexSwitchCheckDefault">
<input id="showOutdated"
class="form-check-input"
type="checkbox"
role="switch">
Show Outdated
</label>
</div>
</div>
<table class="certifications">
<thead>
<tr>
<th>Department</th>
<th>Certification</th>
<th>Member/Name</th>
<th>Version</th>
<th>Certified By</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for certification in certifications %}
<tr>
<td>{{ certification.certification_version.definition.department.name }}</td>
<td>{{ certification.certification_version.definition.certification_name }}</td>
<td>{{ certification.member|default:certification.name }}</td>
<td>
{% if not certification.certification_version.is_current %}[OUTDATED]{% endif %}
{{ certification.certification_version.semantic_version }}
</td>
<td>{{ certification.certified_by }}</td>
<td>{{ certification.date.isoformat }}</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<p>You are not a lead for any departments</p>
{% endif %}
</table>
{% endblock %}
{% block script %}
<script>
const certification_table_el = document.querySelector('table.certifications');
const certification_table = new Tabulator(certification_table_el, {
layout: "fitDataFill",
responsiveLayout: "collapse",
pagination: true,
paginationSize: 50,
columnDefaults: {
headerFilter: true
},
rowFormatter: function(row) {
const data = row.getData();
if (data.version.includes("[OUTDATED]")) {
row.getElement().classList.add("table-warning");
}
},
columns: [{
title: "Department",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, {
title: "Certification",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, {
title: "Member/Name"
}, {
title: "Version",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, ]
});
function outdatedFilter(data) {
return !data.version.includes("[OUTDATED]");
}
function setOutdatedFilter(showOutdated) {
if (showOutdated) {
certification_table.removeFilter(outdatedFilter);
} else {
certification_table.addFilter(outdatedFilter);
}
}
certification_table.on("tableBuilt", () => {
const outdatedToggle = document.getElementById("showOutdated");
setOutdatedFilter(outdatedFilter.checked);
outdatedToggle.addEventListener("change", (event) => setOutdatedFilter(event.target.checked));
});
</script>
{% endblock %}

View File

@ -10,6 +10,11 @@ urlpatterns = [
views.MemberCertificationListView.as_view(), views.MemberCertificationListView.as_view(),
name="member_certifications", name="member_certifications",
), ),
path(
"certifications/departments/",
views.department_certifications,
name="department_certifications",
),
path( path(
"certifications/<str:cert_name>_Certification.pdf", "certifications/<str:cert_name>_Certification.pdf",
views.certification_pdf, views.certification_pdf,

View File

@ -1,14 +1,15 @@
from django.conf import settings from django.conf import settings
from django.contrib import staticfiles from django.contrib import staticfiles
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404, render
from django.views.generic import ListView from django.views.generic import ListView
import requests import requests
import weasyprint import weasyprint
from membershipworks.models import Member from membershipworks.models import Member
from .models import Certification from .models import Certification, Department
WIKI_URL = settings.WIKI_URL WIKI_URL = settings.WIKI_URL
@ -29,6 +30,36 @@ class MemberCertificationListView(ListView):
return Certification.objects.filter(member=self.member) return Certification.objects.filter(member=self.member)
@login_required
def department_certifications(request):
departments = Department.objects.prefetch_related("shop_lead_flag__members")
if request.user.is_superuser:
departments = departments.all()
elif hasattr(request.user, "ldap_user"):
user_member = Member.objects.get(
uid=request.user.ldap_user.attrs["employeeNumber"][0]
)
# 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)
else:
departments = []
certifications = Certification.objects.filter(
certification_version__definition__department__in=departments
).prefetch_related(
"certification_version__definition__department",
"member",
)
return render(
request,
"paperwork/department_certifications.dj.html",
{"departments": departments, "certifications": certifications},
)
def certification_pdf(request, cert_name): def certification_pdf(request, cert_name):
wiki_page = f"{cert_name.replace('_', ' ')} Certification" wiki_page = f"{cert_name.replace('_', ' ')} Certification"

3
static/tabulator.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
static/tabulator_bootstrap5.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,8 @@
content="width=device-width, initial-scale=1, shrink-to-fit=no"> content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS --> <!-- Bootstrap CSS -->
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'bootstrap.min.css' %}" rel="stylesheet">
<!-- Tabulator CSS -->
<link href="{% static 'tabulator_bootstrap5.min.css' %}" rel="stylesheet">
<title> <title>
{% block title %}Claremont MakerSpace{% endblock %} {% block title %}Claremont MakerSpace{% endblock %}
</title> </title>
@ -65,5 +67,8 @@
{% block footer %}{% endblock %} {% block footer %}{% endblock %}
<!-- Bootstrap JS --> <!-- Bootstrap JS -->
<script src="{% static 'bootstrap.bundle.min.js' %}"></script> <script src="{% static 'bootstrap.bundle.min.js' %}"></script>
<!-- Tabulator JS -->
<script src="{% static 'tabulator.min.js' %}"></script>
{% block script %}{% endblock %}
</body> </body>
</html> </html>