Compare commits
14 Commits
19d8e888f4
...
eec1420ee9
Author | SHA1 | Date | |
---|---|---|---|
eec1420ee9 | |||
d3215a6588 | |||
e10bcd5b49 | |||
334f8d4bf8 | |||
29e87c4468 | |||
dafd8cc620 | |||
21fe7f66cd | |||
0eab482893 | |||
60b8510961 | |||
240ebc710d | |||
a1a9cb2890 | |||
9f732d9b43 | |||
968a47c723 | |||
f20d85e2e4 |
@ -11,6 +11,7 @@ repos:
|
||||
rev: v1.34.1
|
||||
hooks:
|
||||
- id: djlint-django
|
||||
- id: djlint-reformat-django
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.13
|
||||
|
@ -39,6 +39,7 @@ INSTALLED_APPS = [
|
||||
"django_q",
|
||||
"django_nh3",
|
||||
"django_tables2",
|
||||
"django_filters",
|
||||
"tasks.apps.TasksConfig",
|
||||
"rentals.apps.RentalsConfig",
|
||||
"membershipworks.apps.MembershipworksConfig",
|
||||
|
@ -3,6 +3,7 @@
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}{{ selected_report }} | Door Controls | CMS{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="vstack align-items-center">
|
||||
<ul class="nav nav-tabs">
|
||||
@ -13,28 +14,30 @@
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<form method="get" class="container-fluid">
|
||||
<div class="row g-2 align-items-center justify-content-center">
|
||||
<div class="col-6 col-sm-auto">
|
||||
<div class="form-floating">
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="startDate"
|
||||
name="timestamp__gte"
|
||||
value="{{ timestamp__gte|date:'Y-m-d' }}">
|
||||
<label for="startDate">Start Date</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-auto">
|
||||
<div class="form-floating">
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="endDate"
|
||||
name="timestamp__lte"
|
||||
value="{{ timestamp__lte|date:'Y-m-d' }}">
|
||||
<label for="endDate">End Date</label>
|
||||
<div class="col-auto">
|
||||
<div class="input-group">
|
||||
<div class="form-floating">
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="startDate"
|
||||
name="timestamp_after"
|
||||
value="{{ filter.form.timestamp.value.0 }}">
|
||||
<label for="startDate">Start Date</label>
|
||||
</div>
|
||||
<div class="form-floating">
|
||||
<input type="date"
|
||||
class="form-control"
|
||||
id="endDate"
|
||||
name="timestamp_before"
|
||||
value="{{ filter.form.timestamp.value.1 }}">
|
||||
<label for="endDate">End Date</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-auto">
|
||||
<div class="form-floating">
|
||||
<input type="number"
|
||||
@ -49,15 +52,16 @@
|
||||
<label for="itemsPerPage">Items Per Page</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group col-auto" role="group" aria-label="Form Controls">
|
||||
<button type="submit" class="btn btn-sm btn-primary">Submit</button>
|
||||
<a href="?" class="btn btn-sm btn-warning">Reset</a>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
{% include "cmsmanage/components/download_table.dj.html" %}
|
||||
</div>
|
||||
|
||||
<div class="col-auto">{% include "cmsmanage/components/download_table.dj.html" %}</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% render_table table %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -7,12 +7,12 @@ from django.core.paginator import Page
|
||||
from django.db.models import Count, F, FloatField, Window
|
||||
from django.db.models.functions import Lead, Trunc
|
||||
from django.urls import path, reverse_lazy
|
||||
from django.utils import dateparse
|
||||
from django.utils.text import slugify
|
||||
from django.utils.timezone import localtime
|
||||
from django.views.generic.list import ListView
|
||||
|
||||
import django_filters
|
||||
import django_tables2 as tables
|
||||
from django_filters.views import BaseFilterView
|
||||
from django_tables2 import SingleTableMixin
|
||||
from django_tables2.export.views import ExportMixin
|
||||
|
||||
@ -26,8 +26,12 @@ def register_report(cls: "BaseAccessReport"):
|
||||
return cls
|
||||
|
||||
|
||||
class DateTimeFilters(django_filters.FilterSet):
|
||||
timestamp = django_filters.DateFromToRangeFilter()
|
||||
|
||||
|
||||
class BaseAccessReport(
|
||||
ExportMixin, SingleTableMixin, PermissionRequiredMixin, ListView
|
||||
BaseFilterView, ExportMixin, SingleTableMixin, PermissionRequiredMixin, ListView
|
||||
):
|
||||
model = HIDEvent
|
||||
permission_required = "doorcontrol.view_hidevent"
|
||||
@ -37,6 +41,8 @@ class BaseAccessReport(
|
||||
|
||||
export_formats = ("csv", "xlsx", "ods")
|
||||
|
||||
filterset_class = DateTimeFilters
|
||||
|
||||
_report_name = None
|
||||
|
||||
@classmethod
|
||||
@ -58,30 +64,13 @@ class BaseAccessReport(
|
||||
def _selected_report(self):
|
||||
return self._report_name
|
||||
|
||||
def _get_timestamp_range(self):
|
||||
timestamp__gte = dateparse.parse_datetime(
|
||||
self.request.GET.get("timestamp__gte") or "2019-01-01"
|
||||
)
|
||||
timestamp__lte = self.request.GET.get("timestamp__lte")
|
||||
if timestamp__lte:
|
||||
timestamp__lte = dateparse.parse_datetime(timestamp__lte)
|
||||
else:
|
||||
timestamp__lte = localtime()
|
||||
|
||||
return timestamp__gte, timestamp__lte
|
||||
|
||||
def get_paginate_by(self, queryset) -> int:
|
||||
if "items_per_page" in self.request.GET:
|
||||
return int(self.request.GET.get("items_per_page"))
|
||||
return super().get_paginate_by(queryset)
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.filter(timestamp__range=self._get_timestamp_range())
|
||||
.select_related("door")
|
||||
)
|
||||
return super().get_queryset().select_related("door")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
@ -94,10 +83,6 @@ class BaseAccessReport(
|
||||
context["selected_report"] = self._selected_report()
|
||||
context["items_per_page"] = self.get_paginate_by(None)
|
||||
|
||||
timestamp__gte, timestamp__lte = self._get_timestamp_range()
|
||||
context["timestamp__gte"] = timestamp__gte
|
||||
context["timestamp__lte"] = timestamp__lte
|
||||
|
||||
query_params = self.request.GET.copy()
|
||||
if "page" in query_params:
|
||||
query_params.pop("page")
|
||||
|
@ -2,7 +2,11 @@ from django.contrib import admin
|
||||
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||
from django.utils.html import format_html
|
||||
|
||||
from django_object_actions import DjangoObjectActions, action
|
||||
from django_object_actions import (
|
||||
DjangoObjectActions,
|
||||
action,
|
||||
takes_instance_or_queryset,
|
||||
)
|
||||
from django_q.models import Task
|
||||
from django_q.tasks import async_task
|
||||
|
||||
@ -15,7 +19,10 @@ from .models import (
|
||||
Member,
|
||||
Transaction,
|
||||
)
|
||||
from .tasks.scrape import scrape_membershipworks
|
||||
from .tasks.scrape import (
|
||||
scrape_event_details,
|
||||
scrape_membershipworks,
|
||||
)
|
||||
|
||||
|
||||
class ReadOnlyAdmin(admin.ModelAdmin):
|
||||
@ -100,11 +107,11 @@ class EventMeetingTimeInline(admin.TabularInline):
|
||||
@admin.register(EventInstructor)
|
||||
class EventInstructorAdmin(admin.ModelAdmin):
|
||||
autocomplete_fields = ["member"]
|
||||
search_fields = ["name", "member"]
|
||||
search_fields = ["name", "member__account_name"]
|
||||
|
||||
|
||||
@admin.register(EventExt)
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
class EventAdmin(DjangoObjectActions, admin.ModelAdmin):
|
||||
inlines = [EventMeetingTimeInline]
|
||||
list_display = [
|
||||
"title",
|
||||
@ -123,8 +130,10 @@ class EventAdmin(admin.ModelAdmin):
|
||||
show_facets = admin.ShowFacets.ALWAYS
|
||||
search_fields = ["eid", "title", "url"]
|
||||
date_hierarchy = "start"
|
||||
exclude = ["url"]
|
||||
exclude = ["url", "details"]
|
||||
autocomplete_fields = ["instructor"]
|
||||
change_actions = ["fetch_details"]
|
||||
actions = ["fetch_details"]
|
||||
|
||||
@property
|
||||
def readonly_fields(self):
|
||||
@ -137,6 +146,7 @@ class EventAdmin(admin.ModelAdmin):
|
||||
else:
|
||||
fields.append(field.name)
|
||||
fields.insert(fields.index("end") + 1, "duration")
|
||||
fields.append("details_timestamp")
|
||||
return fields
|
||||
|
||||
@admin.display(ordering="duration")
|
||||
@ -150,6 +160,10 @@ class EventAdmin(admin.ModelAdmin):
|
||||
obj.url,
|
||||
)
|
||||
|
||||
@takes_instance_or_queryset
|
||||
def fetch_details(self, request, queryset):
|
||||
scrape_event_details(queryset)
|
||||
|
||||
def has_add_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
|
16
membershipworks/migrations/0010_alter_eventext_options.py
Normal file
16
membershipworks/migrations/0010_alter_eventext_options.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by Django 5.0.1 on 2024-01-29 19:17
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("membershipworks", "0009_eventext_materials_fee_included_in_price"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="eventext",
|
||||
options={"ordering": ["-start"], "verbose_name": "event"},
|
||||
),
|
||||
]
|
29
membershipworks/migrations/0011_eventext_details.py
Normal file
29
membershipworks/migrations/0011_eventext_details.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.0.1 on 2024-01-29 19:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("membershipworks", "0010_alter_eventext_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="eventext",
|
||||
name="details",
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="eventext",
|
||||
name="details_timestamp",
|
||||
field=models.GeneratedField(
|
||||
db_persist=False,
|
||||
expression=models.Func(
|
||||
models.Func(models.F("details___ts"), function="FROM_UNIXTIME"),
|
||||
template="CONVERT_TZ(%(expressions)s, @@session.time_zone, 'UTC')",
|
||||
),
|
||||
output_field=models.DateTimeField(),
|
||||
),
|
||||
),
|
||||
]
|
@ -9,6 +9,7 @@ from django.db.models import (
|
||||
Exists,
|
||||
ExpressionWrapper,
|
||||
F,
|
||||
Func,
|
||||
OuterRef,
|
||||
Q,
|
||||
Subquery,
|
||||
@ -438,7 +439,7 @@ class EventExtQuerySet(models.QuerySet["EventExt"]):
|
||||
return method(
|
||||
count__sum=Sum("count", filter=F("occurred")),
|
||||
instructor__count=Count("instructor", distinct=True, filter=F("occurred")),
|
||||
meeting_times__count__sum=Sum("meeting_times__count", filter=F("occurred")),
|
||||
meetings__sum=Sum("meetings", filter=F("occurred")),
|
||||
duration__sum=Sum("duration", filter=F("occurred")),
|
||||
person_hours__sum=Sum("person_hours", filter=F("occurred")),
|
||||
event_count=Count("eid", filter=F("occurred")),
|
||||
@ -448,32 +449,37 @@ class EventExtQuerySet(models.QuerySet["EventExt"]):
|
||||
|
||||
class EventExtManager(models.Manager["EventExt"]):
|
||||
def get_queryset(self) -> models.QuerySet["EventExt"]:
|
||||
return EventExtQuerySet(self.model, using=self._db).annotate(
|
||||
meeting_times__count=Subquery(
|
||||
EventMeetingTime.objects.filter(event=OuterRef("pk"))
|
||||
.values("event__pk")
|
||||
.annotate(d=Count("pk"))
|
||||
.values("d")[:1],
|
||||
output_field=models.IntegerField(),
|
||||
),
|
||||
duration=Subquery(
|
||||
EventMeetingTime.objects.filter(event=OuterRef("pk"))
|
||||
.values("event__pk")
|
||||
.annotate(d=Sum("duration"))
|
||||
.values("d")[:1],
|
||||
output_field=models.DurationField(),
|
||||
),
|
||||
person_hours=ExpressionWrapper(
|
||||
ExpressionWrapper(F("duration"), models.IntegerField()) * F("count"),
|
||||
models.DurationField(),
|
||||
),
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.annotate(
|
||||
meetings=Subquery(
|
||||
EventMeetingTime.objects.filter(event=OuterRef("pk"))
|
||||
.values("event__pk")
|
||||
.annotate(d=Count("pk"))
|
||||
.values("d")[:1],
|
||||
output_field=models.IntegerField(),
|
||||
),
|
||||
duration=Subquery(
|
||||
EventMeetingTime.objects.filter(event=OuterRef("pk"))
|
||||
.values("event__pk")
|
||||
.annotate(d=Sum("duration"))
|
||||
.values("d")[:1],
|
||||
output_field=models.DurationField(),
|
||||
),
|
||||
person_hours=ExpressionWrapper(
|
||||
ExpressionWrapper(F("duration"), models.IntegerField())
|
||||
* F("count"),
|
||||
models.DurationField(),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class EventExt(Event):
|
||||
"""Extension of `Event` to capture some fields not supported in MembershipWorks"""
|
||||
|
||||
objects = EventExtManager()
|
||||
objects = EventExtManager.from_queryset(EventExtQuerySet)()
|
||||
|
||||
instructor = models.ForeignKey(
|
||||
EventInstructor, on_delete=models.PROTECT, null=True, blank=True
|
||||
@ -488,9 +494,19 @@ class EventExt(Event):
|
||||
instructor_flat_rate = models.DecimalField(
|
||||
max_digits=13, decimal_places=4, default=0
|
||||
)
|
||||
details = models.JSONField(null=True, blank=True)
|
||||
details_timestamp = models.GeneratedField(
|
||||
expression=Func(
|
||||
Func(F("details___ts"), function="FROM_UNIXTIME"),
|
||||
template="CONVERT_TZ(%(expressions)s, @@session.time_zone, 'UTC')",
|
||||
),
|
||||
output_field=models.DateTimeField(),
|
||||
db_persist=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "event"
|
||||
ordering = ["-start"]
|
||||
|
||||
|
||||
class EventMeetingTime(models.Model):
|
||||
|
@ -3,6 +3,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from membershipworks.membershipworks_api import FieldType, MembershipWorks
|
||||
from membershipworks.models import (
|
||||
@ -99,6 +100,17 @@ def scrape_membershipworks(*args, **options):
|
||||
scrape_transactions(membershipworks)
|
||||
|
||||
|
||||
def scrape_event_details(queryset: QuerySet[EventExt]):
|
||||
membershipworks = MembershipWorks()
|
||||
membershipworks.login(
|
||||
settings.MEMBERSHIPWORKS_USERNAME, settings.MEMBERSHIPWORKS_PASSWORD
|
||||
)
|
||||
|
||||
for event in queryset:
|
||||
event.details = membershipworks.get_event_by_eid(event.eid)
|
||||
event.save()
|
||||
|
||||
|
||||
def scrape_events():
|
||||
membershipworks = MembershipWorks()
|
||||
membershipworks.login(
|
||||
@ -150,3 +162,10 @@ def scrape_events():
|
||||
# if there is exactly one meeting time, it should match the event start/end
|
||||
elif meeting_times_count == 1:
|
||||
event_ext.meeting_times.update(start=event_ext.start, end=event_ext.end)
|
||||
|
||||
# event has no details, or last retrieval was before the event happened
|
||||
if event_ext.details is None or event_ext.details_timestamp < (
|
||||
event_ext.end or event_ext.start
|
||||
):
|
||||
event_ext.details = membershipworks.get_event_by_eid(event.eid)
|
||||
event_ext.save()
|
||||
|
@ -14,7 +14,9 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% include "cmsmanage/components/download_table.dj.html" %}
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if previous_month %}
|
||||
|
@ -11,7 +11,9 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% include "cmsmanage/components/download_table.dj.html" %}
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if previous_year %}
|
||||
|
@ -15,6 +15,7 @@
|
||||
class="wp-image-2319" />
|
||||
</figure>
|
||||
<!-- /wp:image -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>Greetings Upper Valley Makers:</p>
|
||||
<!-- /wp:paragraph -->
|
||||
@ -41,6 +42,7 @@
|
||||
<strong>Tours:</strong> Want to see what the Claremont MakerSpace is all about? Tours are by appointment only.
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p>
|
||||
<a data-wpel-link="external"
|
||||
@ -49,6 +51,7 @@
|
||||
rel="noreferrer noopener external">Contact Us</a> to schedule your tour where you can learn about all the awesome tools that the CMS offers access to, as well as how membership, classes, and studio spaces work.
|
||||
</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
||||
<!-- wp:separator {"className":"is-style-wide"} -->
|
||||
<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" />
|
||||
<!-- /wp:separator -->
|
||||
@ -62,6 +65,7 @@
|
||||
<i>{{ section.blurb }}</i>
|
||||
</h4>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
{% for event in section.events %}
|
||||
{% with url="https://claremontmakerspace.org/events/#!event/register/"|add:event.url %}
|
||||
<!-- wp:group {"tagName":"section","layout":{"type":"constrained"}} -->
|
||||
@ -109,6 +113,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<!-- wp:paragraph -->
|
||||
<p style="clear: both;">Happy Makin’!</p>
|
||||
<!-- /wp:paragraph -->
|
||||
|
@ -133,7 +133,7 @@ class EventTable(tables.Table):
|
||||
start = tables.DateColumn("N d, Y")
|
||||
duration = DurationColumn()
|
||||
person_hours = DurationColumn()
|
||||
meeting_times__count = tables.Column("Meetings")
|
||||
meetings = tables.Column()
|
||||
|
||||
class Meta:
|
||||
model = EventExt
|
||||
@ -145,7 +145,7 @@ class EventTable(tables.Table):
|
||||
"category",
|
||||
"count",
|
||||
"cap",
|
||||
"meeting_times__count",
|
||||
"meetings",
|
||||
"duration",
|
||||
"person_hours",
|
||||
)
|
||||
@ -161,7 +161,7 @@ class EventSummaryTable(tables.Table):
|
||||
canceled_event_count = tables.Column("Canceled Events")
|
||||
count__sum = tables.Column("Tickets")
|
||||
instructor__count = tables.Column("Unique Instructors")
|
||||
meeting_times__count__sum = tables.Column("Meetings")
|
||||
meetings__sum = tables.Column("Meetings")
|
||||
duration__sum = DurationColumn("Class Hours")
|
||||
person_hours__sum = DurationColumn("Person Hours")
|
||||
|
||||
@ -178,6 +178,15 @@ class EventIndexReport(
|
||||
export_formats = ("csv", "xlsx", "ods")
|
||||
export_name = "mw_events_index"
|
||||
|
||||
def get_table_data(self):
|
||||
return (
|
||||
super()
|
||||
.get_table_data()
|
||||
.values(year=TruncYear("start"))
|
||||
.summarize()
|
||||
.order_by("year")
|
||||
)
|
||||
|
||||
def get_table_kwargs(self):
|
||||
year_column = tables.DateColumn(
|
||||
"Y",
|
||||
@ -191,15 +200,6 @@ class EventIndexReport(
|
||||
"extra_columns": (("year", year_column),),
|
||||
}
|
||||
|
||||
def get_dated_queryset(self, **lookup):
|
||||
return (
|
||||
super()
|
||||
.get_dated_queryset(**lookup)
|
||||
.values(year=TruncYear("start"))
|
||||
.summarize()
|
||||
.order_by("year")
|
||||
)
|
||||
|
||||
|
||||
class EventYearReport(
|
||||
ExportMixin, SingleTableMixin, PermissionRequiredMixin, YearArchiveView
|
||||
@ -212,6 +212,15 @@ class EventYearReport(
|
||||
table_class = EventSummaryTable
|
||||
export_formats = ("csv", "xlsx", "ods")
|
||||
|
||||
def get_table_data(self):
|
||||
return (
|
||||
super()
|
||||
.get_table_data()
|
||||
.values(month=TruncMonth("start"))
|
||||
.summarize()
|
||||
.order_by("month")
|
||||
)
|
||||
|
||||
def get_export_filename(self, export_format):
|
||||
return f"mw_events_{self.get_year()}.{export_format}"
|
||||
|
||||
@ -228,25 +237,19 @@ class EventYearReport(
|
||||
"extra_columns": (("month", month_column),),
|
||||
}
|
||||
|
||||
def get_dated_queryset(self, **lookup):
|
||||
return (
|
||||
super()
|
||||
.get_dated_queryset(**lookup)
|
||||
.values(month=TruncMonth("start"))
|
||||
.summarize()
|
||||
.order_by("month")
|
||||
)
|
||||
|
||||
|
||||
class EventMonthReport(
|
||||
ExportMixin, SingleTableMixin, PermissionRequiredMixin, MonthArchiveView
|
||||
):
|
||||
permission_required = "membershipworks.view_eventext"
|
||||
queryset = EventExt.objects.select_related("category", "instructor").all()
|
||||
queryset = EventExt.objects.all()
|
||||
date_field = "start"
|
||||
template_name = "membershipworks/event_month_report.dj.html"
|
||||
table_class = EventTable
|
||||
export_formats = ("csv", "xlsx", "ods")
|
||||
|
||||
def get_table_data(self):
|
||||
return super().get_table_data().select_related("category", "instructor")
|
||||
|
||||
def get_export_filename(self, export_format):
|
||||
return f"mw_events_{self.get_year()}-{self.get_month():02}.{export_format}"
|
||||
|
@ -24,7 +24,8 @@ class PaperworkDashboardFragment(dashboard.DashboardFragment):
|
||||
)
|
||||
|
||||
if self.request.user.is_superuser or (
|
||||
member is not None and Department.filter_by_shop_lead(member).exists()
|
||||
member is not None
|
||||
and Department.objects.filter_by_shop_lead(member).exists()
|
||||
):
|
||||
links["Department Certifications"] = reverse(
|
||||
"paperwork:department_certifications"
|
||||
|
159
pdm.lock
generated
159
pdm.lock
generated
@ -5,7 +5,7 @@
|
||||
groups = ["default", "debug", "lint", "server", "typing", "dev"]
|
||||
strategy = ["cross_platform"]
|
||||
lock_version = "4.4.1"
|
||||
content_hash = "sha256:c0e5c80b47118152c5b0167a588d3d1d078b0f2a710b8fc97869052ca04e7874"
|
||||
content_hash = "sha256:16af371b3e9b9b16889ab6dc4e3bd5d84e0119a6804a6081ad64f86f45a2259f"
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
@ -459,6 +459,19 @@ files = [
|
||||
{file = "django_extensions-3.2.3-py3-none-any.whl", hash = "sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-filter"
|
||||
version = "23.5"
|
||||
requires_python = ">=3.7"
|
||||
summary = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
|
||||
dependencies = [
|
||||
"Django>=3.2",
|
||||
]
|
||||
files = [
|
||||
{file = "django-filter-23.5.tar.gz", hash = "sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c"},
|
||||
{file = "django_filter-23.5-py3-none-any.whl", hash = "sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-markdownx"
|
||||
version = "4.0.7"
|
||||
@ -881,7 +894,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "8.19.0"
|
||||
version = "8.20.0"
|
||||
requires_python = ">=3.10"
|
||||
summary = "IPython: Productive Interactive Computing"
|
||||
dependencies = [
|
||||
@ -896,8 +909,8 @@ dependencies = [
|
||||
"traitlets>=5",
|
||||
]
|
||||
files = [
|
||||
{file = "ipython-8.19.0-py3-none-any.whl", hash = "sha256:2f55d59370f59d0d2b2212109fe0e6035cfea436b1c0e6150ad2244746272ec5"},
|
||||
{file = "ipython-8.19.0.tar.gz", hash = "sha256:ac4da4ecf0042fb4e0ce57c60430c2db3c719fa8bdf92f8631d6bd8a5785d1f0"},
|
||||
{file = "ipython-8.20.0-py3-none-any.whl", hash = "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619"},
|
||||
{file = "ipython-8.20.0.tar.gz", hash = "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -936,50 +949,52 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
version = "5.0.0"
|
||||
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
|
||||
version = "5.1.0"
|
||||
requires_python = ">=3.6"
|
||||
summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
|
||||
files = [
|
||||
{file = "lxml-5.0.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5382612ba2424cea5d2c89e2c29077023d8de88f8d60d5ceff5f76334516df9e"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:07a900735bad9af7be3085480bf384f68ed5580ba465b39a098e6a882c060d6b"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:980ba47c8db4b9d870014c7040edb230825b79017a6a27aa54cdb6fcc02d8cc0"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6507c58431dbd95b50654b3313c5ad54f90e54e5f2cdacf733de61eae478eec5"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4a45a278518e4308865c1e9dbb2c42ce84fb154efb03adeb16fdae3c1687c7c9"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:59cea9ba1c675fbd6867ca1078fc717a113e7f5b7644943b74137b7cc55abebf"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dd39ef87fd1f7bb5c4aa53454936e6135cbfe03fe3744e8218be193f9e4fef16"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e6bb39d91bf932e7520cb5718ae3c2f498052aca53294d5d59fdd9068fe1a7f2"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-win32.whl", hash = "sha256:21af2c3862db6f4f486cddf73ec1157b40d5828876c47cd880edcbad8240ea1b"},
|
||||
{file = "lxml-5.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:c1249aa4eaced30b59ecf8b8cae0b1ccede04583c74ca7d10b6f8bbead908b2c"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f30e697b6215e759d0824768b2c5b0618d2dc19abe6c67eeed2b0460f52470d1"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d1bb64646480c36a4aa1b6a44a5b6e33d0fcbeab9f53f1b39072cd3bb2c6243a"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4e69c36c8618707a90ed3fb6f48a6cc9254ffcdbf7b259e439a5ae5fbf9c5206"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9ca498f8554a09fbc3a2f8fc4b23261e07bc27bef99b3df98e2570688033f6fc"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0326e9b8176ea77269fb39e7af4010906e73e9496a9f8eaf06d253b1b1231ceb"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-win32.whl", hash = "sha256:5fb988e15378d6e905ca8f60813950a0c56da9469d0e8e5d8fe785b282684ec5"},
|
||||
{file = "lxml-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:bb58e8f4b2cfe012cd312239b8d5139995fe8f5945c7c26d5fbbbb1ddb9acd47"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:96095bfc0c02072fc89afa67626013a253596ea5118b8a7f4daaae049dafa096"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:992029258ed719f130d5a9c443d142c32843046f1263f2c492862b2a853be570"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:db40e85cffd22f7d65dcce30e85af565a66401a6ed22fc0c56ed342cfa4ffc43"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:cfa8a4cdc3765574b7fd0c7cfa5fbd1e2108014c9dfd299c679e5152bea9a55e"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:049fef98d02513c34f5babd07569fc1cf1ed14c0f2fbff18fe72597f977ef3c2"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a85136d0ee18a41c91cc3e2844c683be0e72e6dda4cb58da9e15fcaef3726af7"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:766868f729f3ab84125350f1a0ea2594d8b1628a608a574542a5aff7355b9941"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99cad5c912f359e59e921689c04e54662cdd80835d80eeaa931e22612f515df7"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:c90c593aa8dd57d5dab0ef6d7d64af894008971d98e6a41b320fdd75258fbc6e"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8134d5441d1ed6a682e3de3d7a98717a328dce619ee9c4c8b3b91f0cb0eb3e28"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f298ac9149037d6a3d5c74991bded39ac46292520b9c7c182cb102486cc87677"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:894c5f71186b410679aaab5774543fcb9cbabe8893f0b31d11cf28a0740e80be"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9cd3d6c2c67d4fdcd795e4945e2ba5434909c96640b4cc09453bd0dc7e8e1bac"},
|
||||
{file = "lxml-5.0.0.zip", hash = "sha256:2219cbf790e701acf9a21a31ead75f983e73daf0eceb9da6990212e4d20ebefe"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"},
|
||||
{file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"},
|
||||
{file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"},
|
||||
{file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"},
|
||||
{file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"},
|
||||
{file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"},
|
||||
{file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"},
|
||||
{file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"},
|
||||
{file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"},
|
||||
{file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"},
|
||||
{file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"},
|
||||
{file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"},
|
||||
{file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"},
|
||||
{file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lxml-stubs"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
summary = "Type annotations for the lxml package"
|
||||
files = [
|
||||
{file = "lxml-stubs-0.4.0.tar.gz", hash = "sha256:184877b42127256abc2b932ba8bd0ab5ea80bd0b0fee618d16daa40e0b71abee"},
|
||||
{file = "lxml_stubs-0.4.0-py3-none-any.whl", hash = "sha256:3b381e9e82397c64ea3cc4d6f79d1255d015f7b114806d4826218805c10ec003"},
|
||||
{file = "lxml-stubs-0.5.1.tar.gz", hash = "sha256:e0ec2aa1ce92d91278b719091ce4515c12adc1d564359dfaf81efa7d4feab79d"},
|
||||
{file = "lxml_stubs-0.5.1-py3-none-any.whl", hash = "sha256:1f689e5dbc4b9247cb09ae820c7d34daeb1fdbd1db06123814b856dae7787272"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1577,27 +1592,27 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
requires_python = ">=3.7"
|
||||
summary = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
files = [
|
||||
{file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e3fd36e0d48aeac672aa850045e784673449ce619afc12823ea7868fcc41d8ba"},
|
||||
{file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9fb6b3b86450d4ec6a6732f9f60c4406061b6851c4b29f944f8c9d91c3611c7a"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b13ba5d7156daaf3fd08b6b993360a96060500aca7e307d95ecbc5bb47a69296"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ebb40442f7b531e136d334ef0851412410061e65d61ca8ce90d894a094feb22"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226b517f42d59a543d6383cfe03cccf0091e3e0ed1b856c6824be03d2a75d3b6"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f0312ba1061e9b8c724e9a702d3c8621e3c6e6c2c9bd862550ab2951ac75c16"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2f59bcf5217c661254bd6bc42d65a6fd1a8b80c48763cb5c2293295babd945dd"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6894b00495e00c27b6ba61af1fc666f17de6140345e5ef27dd6e08fb987259d"},
|
||||
{file = "ruff-0.1.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1600942485c6e66119da294c6294856b5c86fd6df591ce293e4a4cc8e72989"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ee3febce7863e231a467f90e681d3d89210b900d49ce88723ce052c8761be8c7"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dcaab50e278ff497ee4d1fe69b29ca0a9a47cd954bb17963628fa417933c6eb1"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f57de973de4edef3ad3044d6a50c02ad9fc2dff0d88587f25f1a48e3f72edf5e"},
|
||||
{file = "ruff-0.1.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a36fa90eb12208272a858475ec43ac811ac37e91ef868759770b71bdabe27b6"},
|
||||
{file = "ruff-0.1.13-py3-none-win32.whl", hash = "sha256:a623349a505ff768dad6bd57087e2461be8db58305ebd5577bd0e98631f9ae69"},
|
||||
{file = "ruff-0.1.13-py3-none-win_amd64.whl", hash = "sha256:f988746e3c3982bea7f824c8fa318ce7f538c4dfefec99cd09c8770bd33e6539"},
|
||||
{file = "ruff-0.1.13-py3-none-win_arm64.whl", hash = "sha256:6bbbc3042075871ec17f28864808540a26f0f79a4478c357d3e3d2284e832998"},
|
||||
{file = "ruff-0.1.13.tar.gz", hash = "sha256:e261f1baed6291f434ffb1d5c6bd8051d1c2a26958072d38dfbec39b3dda7352"},
|
||||
{file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"},
|
||||
{file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"},
|
||||
{file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"},
|
||||
{file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"},
|
||||
{file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"},
|
||||
{file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"},
|
||||
{file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"},
|
||||
{file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"},
|
||||
{file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"},
|
||||
{file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"},
|
||||
{file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1766,15 +1781,15 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.31.0.20231231"
|
||||
requires_python = ">=3.7"
|
||||
version = "2.31.0.20240125"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Typing stubs for requests"
|
||||
dependencies = [
|
||||
"urllib3>=2",
|
||||
]
|
||||
files = [
|
||||
{file = "types-requests-2.31.0.20231231.tar.gz", hash = "sha256:0f8c0c9764773384122813548d9eea92a5c4e1f33ed54556b508968ec5065cee"},
|
||||
{file = "types_requests-2.31.0.20231231-py3-none-any.whl", hash = "sha256:2e2230c7bc8dd63fa3153c1c0ae335f8a368447f0582fc332f17d54f88e69027"},
|
||||
{file = "types-requests-2.31.0.20240125.tar.gz", hash = "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5"},
|
||||
{file = "types_requests-2.31.0.20240125-py3-none-any.whl", hash = "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1808,7 +1823,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "udm-rest-client"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
requires_python = ">=3.6"
|
||||
summary = "Python library to interact with the Univention UDM REST API. Implements the simple Python UDM API."
|
||||
dependencies = [
|
||||
@ -1819,8 +1834,8 @@ dependencies = [
|
||||
"requests<3,>=2.26",
|
||||
]
|
||||
files = [
|
||||
{file = "udm-rest-client-1.2.2.tar.gz", hash = "sha256:219fc5646cd33f158cc595579f58fdcb7de085a8bae44a0f83481a607202d1c0"},
|
||||
{file = "udm_rest_client-1.2.2-py2.py3-none-any.whl", hash = "sha256:add1d551b89161a8d06663b8fe92385747e1d780f67d2c882b7a023c1bfc7966"},
|
||||
{file = "udm-rest-client-1.2.3.tar.gz", hash = "sha256:80724cafa3498d23849124f27f965bc56f10f1dd09b8c2e61e89670c40931a5e"},
|
||||
{file = "udm_rest_client-1.2.3-py2.py3-none-any.whl", hash = "sha256:ee29e94e3ba5fba63a694e33d119b1af7450afcdce3a44301d4cd5ddfa1f980b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1835,7 +1850,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.25.0"
|
||||
version = "0.27.0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "The lightning-fast ASGI server."
|
||||
dependencies = [
|
||||
@ -1843,13 +1858,13 @@ dependencies = [
|
||||
"h11>=0.8",
|
||||
]
|
||||
files = [
|
||||
{file = "uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c"},
|
||||
{file = "uvicorn-0.25.0.tar.gz", hash = "sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2"},
|
||||
{file = "uvicorn-0.27.0-py3-none-any.whl", hash = "sha256:890b00f6c537d58695d3bb1f28e23db9d9e7a17cbcc76d7457c499935f933e24"},
|
||||
{file = "uvicorn-0.27.0.tar.gz", hash = "sha256:c855578045d45625fd027367f7653d249f7c49f9361ba15cf9624186b26b8eb6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.25.0"
|
||||
version = "0.27.0"
|
||||
extras = ["standard"]
|
||||
requires_python = ">=3.8"
|
||||
summary = "The lightning-fast ASGI server."
|
||||
@ -1858,14 +1873,14 @@ dependencies = [
|
||||
"httptools>=0.5.0",
|
||||
"python-dotenv>=0.13",
|
||||
"pyyaml>=5.1",
|
||||
"uvicorn==0.25.0",
|
||||
"uvicorn==0.27.0",
|
||||
"uvloop!=0.15.0,!=0.15.1,>=0.14.0; (sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\"",
|
||||
"watchfiles>=0.13",
|
||||
"websockets>=10.4",
|
||||
]
|
||||
files = [
|
||||
{file = "uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c"},
|
||||
{file = "uvicorn-0.25.0.tar.gz", hash = "sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2"},
|
||||
{file = "uvicorn-0.27.0-py3-none-any.whl", hash = "sha256:890b00f6c537d58695d3bb1f28e23db9d9e7a17cbcc76d7457c499935f933e24"},
|
||||
{file = "uvicorn-0.27.0.tar.gz", hash = "sha256:c855578045d45625fd027367f7653d249f7c49f9361ba15cf9624186b26b8eb6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -23,7 +23,7 @@ dependencies = [
|
||||
"semver~=3.0",
|
||||
"djangorestframework~=3.14",
|
||||
"django-q2~=1.6",
|
||||
"lxml~=5.0",
|
||||
"lxml~=5.1",
|
||||
"django-object-actions~=4.2",
|
||||
"udm-rest-client~=1.2",
|
||||
"openapi-client-udm~=1.0",
|
||||
@ -31,12 +31,13 @@ dependencies = [
|
||||
"nh3~=0.2",
|
||||
"django-tables2~=2.7",
|
||||
"tablib[ods,xlsx]~=3.5",
|
||||
"django-filter~=23.5",
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[project.optional-dependencies]
|
||||
server = [
|
||||
"uvicorn[standard]~=0.25",
|
||||
"uvicorn[standard]~=0.27",
|
||||
"setuptools~=69.0",
|
||||
]
|
||||
|
||||
@ -67,6 +68,7 @@ profile="django"
|
||||
extension = ".dj.html"
|
||||
indent = 2
|
||||
blank_line_after_tag = "load,extends"
|
||||
max_blank_lines = 1
|
||||
ignore = "T003,H017,H021,H030,H031"
|
||||
format_css = true
|
||||
format_js = true
|
||||
@ -111,14 +113,14 @@ typing = [
|
||||
"types-requests~=2.31",
|
||||
"types-urllib3~=1.26",
|
||||
"djangorestframework-stubs[compatible-mypy]~=3.14",
|
||||
"lxml-stubs~=0.4",
|
||||
"lxml-stubs~=0.5",
|
||||
]
|
||||
debug = [
|
||||
"django-debug-toolbar~=4.2",
|
||||
]
|
||||
dev = [
|
||||
"django-extensions~=3.2",
|
||||
"ipython~=8.19",
|
||||
"ipython~=8.20",
|
||||
]
|
||||
|
||||
[tool.pdm.scripts]
|
||||
|
Loading…
Reference in New Issue
Block a user