From 0c6faa8bb63cfbe3b82484d9ba485210d94b4fac Mon Sep 17 00:00:00 2001 From: yaemiku Date: Thu, 26 Jun 2025 15:57:42 +0200 Subject: [PATCH] =?UTF-8?q?wizyta=20oraz=20widok=20ksi=C4=99dza?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 15 + .python-version | 1 + README.md | 0 backend/__init__.py | 0 backend/admin.py | 59 ++++ backend/apps.py | 6 + backend/migrations/0001_initial.py | 30 ++ backend/migrations/0002_parish_channel.py | 18 + ...on_parish_icon_height_parish_icon_width.py | 29 ++ backend/migrations/0004_parish_visible.py | 18 + backend/migrations/0005_submission.py | 33 ++ ...rish_icon_alter_parish_streets_and_more.py | 50 +++ backend/migrations/__init__.py | 0 backend/models.py | 65 ++++ backend/templates/base.html | 94 ++++++ backend/templates/index.html | 16 + backend/templates/parish/announcements.html | 5 + backend/templates/parish/base.html | 45 +++ backend/templates/parish/intentions.html | 5 + backend/templates/parish/live.html | 14 + backend/templates/parish/manifest.json | 22 ++ backend/templates/parish/visit/auth.html | 8 + backend/templates/parish/visit/form.html | 18 + backend/templates/parish/visit/login.html | 14 + backend/templates/parish/visit/signup.html | 14 + backend/templates/parish/visit/submitted.html | 28 ++ backend/templates/parish/visit/update.html | 18 + backend/tests.py | 3 + backend/views.py | 266 +++++++++++++++ eparafia/__init__.py | 0 eparafia/asgi.py | 16 + eparafia/settings.py | 150 +++++++++ eparafia/urls.py | 34 ++ eparafia/wsgi.py | 16 + manage.py | 22 ++ pyproject.toml | 19 ++ static/icon-192x192.png | Bin 0 -> 12973 bytes static/icon-512x512.png | Bin 0 -> 52430 bytes uv.lock | 314 ++++++++++++++++++ 39 files changed, 1465 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 backend/__init__.py create mode 100644 backend/admin.py create mode 100644 backend/apps.py create mode 100644 backend/migrations/0001_initial.py create mode 100644 backend/migrations/0002_parish_channel.py create mode 100644 backend/migrations/0003_parish_icon_parish_icon_height_parish_icon_width.py create mode 100644 backend/migrations/0004_parish_visible.py create mode 100644 backend/migrations/0005_submission.py create mode 100644 backend/migrations/0006_alter_parish_icon_alter_parish_streets_and_more.py create mode 100644 backend/migrations/__init__.py create mode 100644 backend/models.py create mode 100644 backend/templates/base.html create mode 100644 backend/templates/index.html create mode 100644 backend/templates/parish/announcements.html create mode 100644 backend/templates/parish/base.html create mode 100644 backend/templates/parish/intentions.html create mode 100644 backend/templates/parish/live.html create mode 100644 backend/templates/parish/manifest.json create mode 100644 backend/templates/parish/visit/auth.html create mode 100644 backend/templates/parish/visit/form.html create mode 100644 backend/templates/parish/visit/login.html create mode 100644 backend/templates/parish/visit/signup.html create mode 100644 backend/templates/parish/visit/submitted.html create mode 100644 backend/templates/parish/visit/update.html create mode 100644 backend/tests.py create mode 100644 backend/views.py create mode 100644 eparafia/__init__.py create mode 100644 eparafia/asgi.py create mode 100644 eparafia/settings.py create mode 100644 eparafia/urls.py create mode 100644 eparafia/wsgi.py create mode 100755 manage.py create mode 100644 pyproject.toml create mode 100644 static/icon-192x192.png create mode 100644 static/icon-512x512.png create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ad6670 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv +.env + +# Django +db.sqlite3 +media \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/admin.py b/backend/admin.py new file mode 100644 index 0000000..663a38a --- /dev/null +++ b/backend/admin.py @@ -0,0 +1,59 @@ +from django.contrib import admin +from .models import Parish, Submission, Priest +from authtools.models import User + +# Register your models here. + + +@admin.register(Priest) +class PriestAdmin(admin.ModelAdmin): + list_display = ["priest", "parish"] + + def get_form(self, request, obj=None, **kwargs): + form = super(PriestAdmin, self).get_form(request, obj, **kwargs) + form.base_fields["priest"].queryset = User.objects.filter(is_staff=True) + return form + + +@admin.register(Submission) +class SubmissionAdmin(admin.ModelAdmin): + list_display = ["id", "parish", "user", "name", "phone", "adres"] + + def get_exclude(self, request, obj=None): + if not request.user.is_superuser: + return ["parish", "user"] + + return [] + + def get_queryset(self, request): + qs = super().get_queryset(request) + + if not request.user.is_superuser: + p = request.user.priest_rel.parish if request.user.priest_rel else None + return qs.filter(parish=p) + + return qs + + def get_changeform_initial_data(self, request): + initial = super(SubmissionAdmin, self).get_changeform_initial_data(request) + if not request.user.is_superuser: + p = request.user.priest_rel.parish if request.user.priest_rel else None + return {"parish": p, **initial} + + return initial + + def get_form(self, request, obj=None, **kwargs): + form = super(SubmissionAdmin, self).get_form(request, obj, **kwargs) + + return form + + def save_model(self, request, obj, form, change): + if not request.user.is_superuser: + p = request.user.priest_rel.parish if request.user.priest_rel else None + obj.parish = p + super().save_model(request, obj, form, change) + + +@admin.register(Parish) +class ParishAdmin(admin.ModelAdmin): + list_display = ["slug", "name", "visible", "submissions"] diff --git a/backend/apps.py b/backend/apps.py new file mode 100644 index 0000000..6a3779f --- /dev/null +++ b/backend/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BackendConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'backend' diff --git a/backend/migrations/0001_initial.py b/backend/migrations/0001_initial.py new file mode 100644 index 0000000..4090846 --- /dev/null +++ b/backend/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.6 on 2025-02-14 18:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Parish', + fields=[ + ('slug', models.SlugField(primary_key=True, serialize=False, verbose_name='Identyfikator')), + ('name', models.CharField(max_length=512, verbose_name='Nazwa')), + ('submissions', models.BooleanField(default=False, verbose_name='Kolęda aktywna')), + ('announcements', models.TextField(blank=True, null=True, verbose_name='Skrypt - Ogłoszenia')), + ('intentions', models.TextField(blank=True, null=True, verbose_name='Skrypt - Intencje')), + ('streets', models.JSONField(default=list, verbose_name='Ulice')), + ], + options={ + 'verbose_name': 'Parafia', + 'verbose_name_plural': 'Parafie', + 'ordering': ['slug'], + }, + ), + ] diff --git a/backend/migrations/0002_parish_channel.py b/backend/migrations/0002_parish_channel.py new file mode 100644 index 0000000..2ccde5b --- /dev/null +++ b/backend/migrations/0002_parish_channel.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-14 18:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='parish', + name='channel', + field=models.CharField(blank=True, max_length=64, null=True, verbose_name='Identyfikator kanału'), + ), + ] diff --git a/backend/migrations/0003_parish_icon_parish_icon_height_parish_icon_width.py b/backend/migrations/0003_parish_icon_parish_icon_height_parish_icon_width.py new file mode 100644 index 0000000..f37780c --- /dev/null +++ b/backend/migrations/0003_parish_icon_parish_icon_height_parish_icon_width.py @@ -0,0 +1,29 @@ +# Generated by Django 5.1.6 on 2025-02-14 19:33 + +import pictures.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0002_parish_channel'), + ] + + operations = [ + migrations.AddField( + model_name='parish', + name='icon', + field=pictures.models.PictureField(aspect_ratios=[None], breakpoints={'l': 1200, 'm': 992, 's': 768, 'xl': 1400, 'xs': 576}, container_width=1200, file_types=['WEBP', 'PNG'], grid_columns=12, height_field='icon_height', null=True, pixel_densities=[1, 2], upload_to='icons', verbose_name='Ikona', width_field='icon_width'), + ), + migrations.AddField( + model_name='parish', + name='icon_height', + field=models.PositiveIntegerField(null=True), + ), + migrations.AddField( + model_name='parish', + name='icon_width', + field=models.PositiveIntegerField(null=True), + ), + ] diff --git a/backend/migrations/0004_parish_visible.py b/backend/migrations/0004_parish_visible.py new file mode 100644 index 0000000..965abd8 --- /dev/null +++ b/backend/migrations/0004_parish_visible.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-14 21:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0003_parish_icon_parish_icon_height_parish_icon_width'), + ] + + operations = [ + migrations.AddField( + model_name='parish', + name='visible', + field=models.BooleanField(default=False, verbose_name='Parafia widoczna'), + ), + ] diff --git a/backend/migrations/0005_submission.py b/backend/migrations/0005_submission.py new file mode 100644 index 0000000..491b112 --- /dev/null +++ b/backend/migrations/0005_submission.py @@ -0,0 +1,33 @@ +# Generated by Django 5.1.6 on 2025-02-14 23:37 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0004_parish_visible'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Submission', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=256, verbose_name='Imię i nazwisko')), + ('phone', models.CharField(max_length=32, verbose_name='Numer telefonu')), + ('street', models.CharField(max_length=128, verbose_name='Ulica')), + ('street_number', models.PositiveIntegerField(verbose_name='Numer domu')), + ('apartement_number', models.PositiveIntegerField(blank=True, null=True, verbose_name='Numer mieszkania')), + ('parish', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submission', to='backend.parish', verbose_name='Parafia')), + ('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submission', to=settings.AUTH_USER_MODEL, verbose_name='Użytkownik')), + ], + options={ + 'verbose_name': 'Zgłoszenie', + 'verbose_name_plural': 'Zgłoszenia', + }, + ), + ] diff --git a/backend/migrations/0006_alter_parish_icon_alter_parish_streets_and_more.py b/backend/migrations/0006_alter_parish_icon_alter_parish_streets_and_more.py new file mode 100644 index 0000000..4fce0c7 --- /dev/null +++ b/backend/migrations/0006_alter_parish_icon_alter_parish_streets_and_more.py @@ -0,0 +1,50 @@ +# Generated by Django 5.1.6 on 2025-06-26 13:19 + +import django.core.validators +import django.db.models.deletion +import pictures.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0005_submission'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='parish', + name='icon', + field=pictures.models.PictureField(aspect_ratios=[None], blank=True, breakpoints={'l': 1200, 'm': 992, 's': 768, 'xl': 1400, 'xs': 576}, container_width=1200, file_types=['WEBP', 'PNG'], grid_columns=12, height_field='icon_height', null=True, pixel_densities=[1, 2], upload_to='icons', verbose_name='Ikona', width_field='icon_width'), + ), + migrations.AlterField( + model_name='parish', + name='streets', + field=models.JSONField(blank=True, default=list, null=True, verbose_name='Ulice'), + ), + migrations.AlterField( + model_name='submission', + name='phone', + field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator(message="Numer telefonu musi być postaci: '(+48)123456789'", regex='^\\+?1?\\d{9,15}$')], verbose_name='Numer telefonu'), + ), + migrations.AlterField( + model_name='submission', + name='user', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submission', to=settings.AUTH_USER_MODEL, verbose_name='Użytkownik'), + ), + migrations.CreateModel( + name='Priest', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('parish', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='priest', to='backend.parish', verbose_name='Parafia')), + ('priest', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Ksiądz')), + ], + options={ + 'verbose_name': 'Ksiądz', + 'verbose_name_plural': 'Księża', + }, + ), + ] diff --git a/backend/migrations/__init__.py b/backend/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/models.py b/backend/models.py new file mode 100644 index 0000000..d878f5d --- /dev/null +++ b/backend/models.py @@ -0,0 +1,65 @@ +from django.db import models +from pictures.models import PictureField +from authtools.models import User +from django.core.validators import RegexValidator + +# Create your models here. + + +class Parish(models.Model): + slug = models.SlugField("Identyfikator", primary_key=True) + name = models.CharField("Nazwa", max_length=512) + visible = models.BooleanField("Parafia widoczna", default=False) + + icon = PictureField( + "Ikona", upload_to="icons", height_field="icon_height", width_field="icon_width", null=True, blank=True + ) + icon_width = models.PositiveIntegerField(null=True) + icon_height = models.PositiveIntegerField(null=True) + + channel = models.CharField("Identyfikator kanału", max_length=64, blank=True, null=True) + submissions = models.BooleanField("Kolęda aktywna", default=False) + announcements = models.TextField("Skrypt - Ogłoszenia", blank=True, null=True) + intentions = models.TextField("Skrypt - Intencje", blank=True, null=True) + streets = models.JSONField("Ulice", default=list, null=True, blank=True) + + def __str__(self): + return self.name + + class Meta: + verbose_name = "Parafia" + verbose_name_plural = "Parafie" + ordering = ["slug"] + + +class Submission(models.Model): + user = models.OneToOneField( + User, on_delete=models.CASCADE, related_name="submission", verbose_name="Użytkownik", null=True, blank=True + ) + parish = models.ForeignKey(Parish, on_delete=models.CASCADE, related_name="submission", verbose_name="Parafia") + + name = models.CharField("Imię i nazwisko", max_length=256) + phone_regex = RegexValidator(regex=r"^\+?1?\d{9,15}$", message="Numer telefonu musi być postaci: '(+48)123456789'") + phone = models.CharField("Numer telefonu", max_length=32, validators=[phone_regex]) + street = models.CharField("Ulica", max_length=128) + street_number = models.PositiveIntegerField("Numer domu") + apartement_number = models.PositiveIntegerField("Numer mieszkania", null=True, blank=True) + + @property + def adres(self): + return ( + f"{self.street} {self.street_number}{'/' + str(self.apartement_number) if self.apartement_number else ''}" + ) + + class Meta: + verbose_name = "Zgłoszenie" + verbose_name_plural = "Zgłoszenia" + + +class Priest(models.Model): + priest = models.OneToOneField(User, on_delete=models.CASCADE, related_name="priest_rel", verbose_name="Ksiądz") + parish = models.ForeignKey(Parish, on_delete=models.CASCADE, related_name="priest_rel", verbose_name="Parafia") + + class Meta: + verbose_name = "Ksiądz" + verbose_name_plural = "Księża" diff --git a/backend/templates/base.html b/backend/templates/base.html new file mode 100644 index 0000000..8806e0f --- /dev/null +++ b/backend/templates/base.html @@ -0,0 +1,94 @@ + +{% load static i18n %} + + + + + + + + + eParafia + + + {% block head %} + + {% endblock %} + + + + + + {% comment %} {% endcomment %} + + + + + + {% block layout %} +
+ {% block content %} + {% endblock %} +
+ {% endblock %} + + diff --git a/backend/templates/index.html b/backend/templates/index.html new file mode 100644 index 0000000..1ba80f6 --- /dev/null +++ b/backend/templates/index.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block content %} +
+

eParafia

+ +

Dziękujemy za korzystanie z naszej aplikacji! Poniżej znajduje się lista odnośników do wszystkich zarejestrowanych z nami parafii. Klikając w przycisk zostaniecie państwo bezpośrednio przekierowani do aplikacji danej parafii

+ +

Zapraszamy!

+
+ {% for parish in parishes %} + {{ parish.name }} + {% endfor %} +
+
+{% endblock %} diff --git a/backend/templates/parish/announcements.html b/backend/templates/parish/announcements.html new file mode 100644 index 0000000..84f79f9 --- /dev/null +++ b/backend/templates/parish/announcements.html @@ -0,0 +1,5 @@ +{% extends 'parish/base.html' %} + +{% block content %} +
{{res | safe}}
+{% endblock %} diff --git a/backend/templates/parish/base.html b/backend/templates/parish/base.html new file mode 100644 index 0000000..a2fbe2e --- /dev/null +++ b/backend/templates/parish/base.html @@ -0,0 +1,45 @@ +{% extends 'base.html' %} +{% load pictures %} + +{% block head %} + + + +{% endblock %} + +{% block layout %} +
+ + +
+
+ {% block content %} + {% endblock %} +
+
+
+{% endblock %} diff --git a/backend/templates/parish/intentions.html b/backend/templates/parish/intentions.html new file mode 100644 index 0000000..f6a922f --- /dev/null +++ b/backend/templates/parish/intentions.html @@ -0,0 +1,5 @@ +{% extends 'parish/base.html' %} + +{% block content %} +
{{ res | safe }}
+{% endblock %} diff --git a/backend/templates/parish/live.html b/backend/templates/parish/live.html new file mode 100644 index 0000000..3a02f6a --- /dev/null +++ b/backend/templates/parish/live.html @@ -0,0 +1,14 @@ +{% extends 'parish/base.html' %} + +{% block content %} +
+
+ +
+
+ +{% endblock content %} \ No newline at end of file diff --git a/backend/templates/parish/manifest.json b/backend/templates/parish/manifest.json new file mode 100644 index 0000000..e54e54c --- /dev/null +++ b/backend/templates/parish/manifest.json @@ -0,0 +1,22 @@ +{% load pictures %} + +{ + "name": "{{ parish.name }}", + "display": "standalone", + "scope": "{% url 'parish' parish.slug %}", + "start_url": "{% url 'parish' parish.slug %}", + "icons": [ + { + "src": "{% img_url parish.icon file_type="png" width=192 %}", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable any" + }, + { + "src": "{% img_url parish.icon file_type="png" width=512 %}", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable any" + } + ] +} \ No newline at end of file diff --git a/backend/templates/parish/visit/auth.html b/backend/templates/parish/visit/auth.html new file mode 100644 index 0000000..e38fd28 --- /dev/null +++ b/backend/templates/parish/visit/auth.html @@ -0,0 +1,8 @@ +{% extends 'parish/base.html' %} + +{% block content %} +

+ Zaloguj się + Zarejestruj się +

+{% endblock %} diff --git a/backend/templates/parish/visit/form.html b/backend/templates/parish/visit/form.html new file mode 100644 index 0000000..621ab51 --- /dev/null +++ b/backend/templates/parish/visit/form.html @@ -0,0 +1,18 @@ +{% extends 'parish/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Zapisz się na wizytę duszpasterską

+
+ {% csrf_token %} + {{ form|crispy }} +

+ +

+
+
+ {% csrf_token %} + Zmień dane konta + +
+{% endblock %} diff --git a/backend/templates/parish/visit/login.html b/backend/templates/parish/visit/login.html new file mode 100644 index 0000000..d9b4617 --- /dev/null +++ b/backend/templates/parish/visit/login.html @@ -0,0 +1,14 @@ +{% extends 'parish/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Zaloguj się

+
+ {% csrf_token %} + {{ form|crispy }} +

+ + Powrót +

+
+{% endblock %} diff --git a/backend/templates/parish/visit/signup.html b/backend/templates/parish/visit/signup.html new file mode 100644 index 0000000..baa1cf9 --- /dev/null +++ b/backend/templates/parish/visit/signup.html @@ -0,0 +1,14 @@ +{% extends 'parish/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Zarejestruj się

+
+ {% csrf_token %} + {{ form | crispy }} +

+ + Powrót +

+
+{% endblock %} diff --git a/backend/templates/parish/visit/submitted.html b/backend/templates/parish/visit/submitted.html new file mode 100644 index 0000000..5918fe3 --- /dev/null +++ b/backend/templates/parish/visit/submitted.html @@ -0,0 +1,28 @@ +{% extends 'parish/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Twoje zgłoszenie

+
+

+ Imię i nazwisko: {{ submission.name }}, Telefon: {{ submission.phone }} +

+

+ Adres: {{ submission.street }} {{ submission.street_number }}{% if submission.apartement_number %}/{% endif %}{{ submission.apartement_number|default_if_none:'' }} +

+
+ +
+ {% csrf_token %} + {{ form|crispy }} +

+ +

+
+

+

+ {% csrf_token %} + +
+

+{% endblock %} diff --git a/backend/templates/parish/visit/update.html b/backend/templates/parish/visit/update.html new file mode 100644 index 0000000..13d2cec --- /dev/null +++ b/backend/templates/parish/visit/update.html @@ -0,0 +1,18 @@ +{% extends 'parish/base.html' %} +{% load crispy_forms_tags %} + +{% block content %} +

Zmień dane konta

+
+ {% csrf_token %} + {{ form|crispy }} +

+ + Powrót +

+
+ {% comment %}
+ {% csrf_token %} + +
{% endcomment %} +{% endblock %} diff --git a/backend/tests.py b/backend/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/backend/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/views.py b/backend/views.py new file mode 100644 index 0000000..a488fd5 --- /dev/null +++ b/backend/views.py @@ -0,0 +1,266 @@ +from django.shortcuts import render, redirect +from django.urls import path +from .models import Parish, Submission +import requests # noqa: F401 +from lxml import html # noqa: F401 +from django.http import HttpResponse +from django.views.generic import CreateView, DeleteView, UpdateView +from authtools.forms import UserCreationForm +from authtools.models import User +from django.contrib.auth.views import LoginView, LogoutView +from django.urls import reverse_lazy +from django import forms + + +# Create your views here. + + +def favicon(request): + return HttpResponse(None) + + +def manifest(request, slug): + return render( + request, "parish/manifest.json", {"parish": Parish.objects.get(slug=slug)}, content_type="application/json" + ) + + +def index(request): + parishes = Parish.objects.filter(visible=True) + return render(request, "index.html", {"parishes": parishes}) + + +def announcements(request, slug): + p = Parish.objects.get(slug=slug) + ldict = {} + exec(p.announcements, globals(), ldict) + + return render( + request, "parish/announcements.html", {"parish": p, "announcements": "is-active", "res": ldict.get("res", "")} + ) + + +def intentions(request, slug): + p = Parish.objects.get(slug=slug) + ldict = {} + exec(p.intentions, globals(), ldict) + + return render( + request, "parish/intentions.html", {"parish": p, "intentions": "is-active", "res": ldict.get("res", "")} + ) + + +def live(request, slug): + p = Parish.objects.get(slug=slug) + if not p.channel: + return redirect("announcements", slug=slug) + + return render(request, "parish/live.html", {"parish": p, "live": "is-active"}) + + +def visit(request, slug): + p = Parish.objects.get(slug=slug) + c = {"parish": p, "visit": "is-active"} + if not p.submissions: + return redirect("announcements", slug=slug) + + if not request.user.is_authenticated: + return render(request, "parish/visit/auth.html", c) + + if not Submission.objects.filter(user=request.user).exists(): + return VisitCreateView.as_view()(request, slug=slug) + + c["submission"] = Submission.objects.get(user=request.user) + return VisitDeleteView.as_view()(request, slug=slug) + + +class SubmissionForm(forms.ModelForm): + def __init__(self, slug, *args, **kwargs): + super(SubmissionForm, self).__init__(*args, **kwargs) + streets = Parish.objects.get(slug=slug).streets + choices = zip(streets, streets) + self.fields["street"] = forms.ChoiceField(label="Ulica", choices=choices) + + class Meta: + model = Submission + fields = [ + "name", + "phone", + "street", + "street_number", + "apartement_number", + ] + + +class VisitCreateView(CreateView): + form_class = SubmissionForm + template_name = "parish/visit/form.html" + + def form_valid(self, form): + form.instance.parish = Parish.objects.get(slug=self.kwargs["slug"]) + form.instance.user = self.request.user + return super().form_valid(form) + + def get_initial(self): + return {"name": self.request.user.name} + + def get_success_url(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.fields["name"].disabled = True + return form + + def get_form_kwargs(self): + return {**super().get_form_kwargs(), **self.kwargs} + + +class VisitDeleteView(DeleteView): + model = Submission + template_name = "parish/visit/submitted.html" + + def get_object(self): + return Submission.objects.get(user=self.request.user) + + def get_success_url(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + +class VisitLoginView(LoginView): + redirect_authenticated_user = True + template_name = "parish/visit/login.html" + + def get_success_url(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def dispatch(self, request, *args, **kwargs): + p = Parish.objects.get(slug=kwargs["slug"]) + if self.request.user.is_authenticated: + return redirect("visit", slug=p.slug) + + if not p.submissions: + return redirect("announcements", slug=p.slug) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + +class VisitSignUpView(CreateView): + form_class = UserCreationForm + template_name = "parish/visit/signup.html" + + def get_success_url(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def dispatch(self, request, *args, **kwargs): + p = Parish.objects.get(slug=kwargs["slug"]) + if self.request.user.is_authenticated: + return redirect("visit", slug=p.slug) + + if not p.submissions: + return redirect("announcements", slug=p.slug) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + +class UserUpdateForm(forms.ModelForm): + class Meta: + model = User + fields = ["email", "name"] + + +class VisitAccountView(UpdateView): + form_class = UserUpdateForm + template_name = "parish/visit/update.html" + + def get_object(self): + return User.objects.get(id=self.request.user.id) + + def get_success_url(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def dispatch(self, request, *args, **kwargs): + p = Parish.objects.get(slug=kwargs["slug"]) + # if self.request.user.is_authenticated: + # return redirect("visit", slug=p.slug) + + if not p.submissions: + return redirect("announcements", slug=p.slug) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + def get_form(self, form_class=None): + form = super().get_form(form_class) + form.fields["name"].label = "Imię i nazwisko" + return form + + +class VisitLogoutView(LogoutView): + template_name = "parish/visit/auth.html" + + def get_next_page(self): + p = Parish.objects.get(slug=self.kwargs["slug"]) + return reverse_lazy("visit", args=[p.slug]) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + p = Parish.objects.get(slug=self.kwargs["slug"]) + context["parish"] = p + context["visit"] = "is-active" + return context + + +urlpatterns = [ + path("", index, name="index"), + path("favicon.ico", favicon), + path("/", announcements, name="parish"), + path("/ogloszenia/", announcements, name="announcements"), + path("/intencje/", intentions, name="intentions"), + path("/transmisja/", live, name="live"), + path("/wizyta/", visit, name="visit"), + path("/wizyta/logowanie/", VisitLoginView.as_view(), name="visit_login"), + path("/wizyta/rejestracja/", VisitSignUpView.as_view(), name="visit_signup"), + path("/wizyta/konto/", VisitAccountView.as_view(), name="visit_account"), + path("/wizyta/wylogowanie/", VisitLogoutView.as_view(), name="visit_logout"), + path("/manifest.json", manifest, name="manifest"), +] diff --git a/eparafia/__init__.py b/eparafia/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eparafia/asgi.py b/eparafia/asgi.py new file mode 100644 index 0000000..78e181a --- /dev/null +++ b/eparafia/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for eparafia project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eparafia.settings') + +application = get_asgi_application() diff --git a/eparafia/settings.py b/eparafia/settings.py new file mode 100644 index 0000000..343eb29 --- /dev/null +++ b/eparafia/settings.py @@ -0,0 +1,150 @@ +""" +Django settings for eparafia project. + +Generated by 'django-admin startproject' using Django 5.1.6. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +import os +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.getenv("SECRET_KEY") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.getenv("DEBUG") == "True" + +ALLOWED_HOSTS = ["*"] +CSRF_TRUSTED_ORIGINS = ["http://*", "https://*"] + + +# Application definition + +INSTALLED_APPS = [ + "authtools", + "backend", + "crispy_forms", + "crispy_bulma", + "pictures", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django_browser_reload", + "django_cleanup.apps.CleanupConfig", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django_browser_reload.middleware.BrowserReloadMiddleware", +] + +ROOT_URLCONF = "eparafia.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "eparafia.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + } +] +AUTH_USER_MODEL = "authtools.User" + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = "pl-PL" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = "static/" +STATIC_ROOT = BASE_DIR / "static" + +MEDIA_URL = "media/" +MEDIA_ROOT = BASE_DIR / "media" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +PICTURES = { + "BREAKPOINTS": { + "xs": 576, + "s": 768, + "m": 992, + "l": 1200, + "xl": 1400, + }, + "GRID_COLUMNS": 12, + "CONTAINER_WIDTH": 1200, + "FILE_TYPES": ["WEBP", "PNG"], + "PIXEL_DENSITIES": [1, 2], + "USE_PLACEHOLDERS": False, + "QUEUE_NAME": "pictures", + "PROCESSOR": "pictures.tasks.process_picture", +} + +CRISPY_ALLOWED_TEMPLATE_PACKS = ("bulma",) + +CRISPY_TEMPLATE_PACK = "bulma" diff --git a/eparafia/urls.py b/eparafia/urls.py new file mode 100644 index 0000000..274821c --- /dev/null +++ b/eparafia/urls.py @@ -0,0 +1,34 @@ +""" +URL configuration for eparafia project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from django.contrib import admin +from django.urls import path, include +from pictures.conf import get_settings +from django.conf import settings +from django.conf.urls.static import static + + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", include("backend.views")), + path("__reload__/", include("django_browser_reload.urls")), +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +if get_settings().USE_PLACEHOLDERS: + urlpatterns += [ + path("_pictures/", include("pictures.urls")), + ] diff --git a/eparafia/wsgi.py b/eparafia/wsgi.py new file mode 100644 index 0000000..913ee13 --- /dev/null +++ b/eparafia/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for eparafia project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eparafia.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..e8caf0c --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eparafia.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..fd39f57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "eparafia" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "beautifulsoup4>=4.13.4", + "crispy-bulma>=0.11.0", + "django>=5.1.6", + "django-authtools>=2.0.1", + "django-browser-reload>=1.18.0", + "django-cleanup>=9.0.0", + "django-crispy-forms>=2.3", + "django-pictures>=1.4.0", + "gunicorn>=23.0.0", + "lxml>=5.3.1", + "requests>=2.32.3", +] diff --git a/static/icon-192x192.png b/static/icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..bbda80336cbfb8bb314b7aadff7660e03d54710d GIT binary patch literal 12973 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 u+-WB;r%D|n{l84}|Ihfp2gVv&;Jh*0{Vmi literal 0 HcmV?d00001 diff --git a/static/icon-512x512.png b/static/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..ec100bf6b79f072338ba0ea2bab36b2a79994505 GIT binary patch literal 52430 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
I#13GBMjsZU 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 literal 0 HcmV?d00001 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..be80242 --- /dev/null +++ b/uv.lock @@ -0,0 +1,314 @@ +version = 1 +revision = 2 +requires-python = ">=3.13" + +[[package]] +name = "asgiref" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/38/b3395cc9ad1b56d2ddac9970bc8f4141312dbaec28bc7c218b0dfafd0f42/asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590", size = 35186, upload-time = "2024-03-22T14:39:36.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828, upload-time = "2024-03-22T14:39:34.521Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, +] + +[[package]] +name = "certifi" +version = "2025.1.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577, upload-time = "2025-01-31T02:16:47.166Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393, upload-time = "2025-01-31T02:16:45.015Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188, upload-time = "2024-12-24T18:12:35.43Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698, upload-time = "2024-12-24T18:11:05.834Z" }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162, upload-time = "2024-12-24T18:11:07.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263, upload-time = "2024-12-24T18:11:08.374Z" }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966, upload-time = "2024-12-24T18:11:09.831Z" }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992, upload-time = "2024-12-24T18:11:12.03Z" }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162, upload-time = "2024-12-24T18:11:13.372Z" }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972, upload-time = "2024-12-24T18:11:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095, upload-time = "2024-12-24T18:11:17.672Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668, upload-time = "2024-12-24T18:11:18.989Z" }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073, upload-time = "2024-12-24T18:11:21.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732, upload-time = "2024-12-24T18:11:22.774Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391, upload-time = "2024-12-24T18:11:24.139Z" }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702, upload-time = "2024-12-24T18:11:26.535Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload-time = "2024-12-24T18:12:32.852Z" }, +] + +[[package]] +name = "crispy-bulma" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "django-crispy-forms" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/6b/660e9b1e6cab7a3a63434edbdba85e21e7f217e1857b3026a84219ac61a7/crispy-bulma-0.11.0.tar.gz", hash = "sha256:27eccd09a5a77754d64462f61ff585c00feb8c15f65d0d8f9676ab26f6bc3562", size = 35747, upload-time = "2023-12-06T20:39:29.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/6c/8734b21a4a0ea2dbfd563d30e9f245f81e72b7a19fb17f1ed32a3391d1e2/crispy_bulma-0.11.0-py3-none-any.whl", hash = "sha256:bc5406d64649a3da9c61d1aa969cb2c39bb3a1802ba8ee4bccebe94a84ca94e1", size = 20571, upload-time = "2023-12-06T20:39:23.992Z" }, +] + +[[package]] +name = "django" +version = "5.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/e4/901f54ee114a080371a49bd08fa688d301aaffd9751febaf4ae855fc8fcd/Django-5.1.6.tar.gz", hash = "sha256:1e39eafdd1b185e761d9fab7a9f0b9fa00af1b37b25ad980a8aa0dac13535690", size = 10700620, upload-time = "2025-02-05T14:16:25.948Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/6f/d2c216d00975e2604b10940937b0ba6b2c2d9b3cc0cc633e414ae3f14b2e/Django-5.1.6-py3-none-any.whl", hash = "sha256:8d203400bc2952fbfb287c2bbda630297d654920c72a73cc82a9ad7926feaad5", size = 8277066, upload-time = "2025-02-05T14:16:00.563Z" }, +] + +[[package]] +name = "django-authtools" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/57/6a40c459ae93032f63efae348891d0b43877126f6600e27b1c511dd03c45/django-authtools-2.0.1.tar.gz", hash = "sha256:e344cb6be7fd5155208e291eddfcb83510efd4bad3913cb5031347b000a34c4c", size = 38956, upload-time = "2024-03-19T18:46:58.316Z" } + +[[package]] +name = "django-browser-reload" +version = "1.18.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3b/41/84eaa4f2b7f764e56e01c4ee49aa12bdea30ae50fd0d3ef7c2690b0c4ec2/django_browser_reload-1.18.0.tar.gz", hash = "sha256:c5f0b134723cbf2a0dc9ae1ee1d38e42db28fe23c74cdee613ba3ef286d04735", size = 14319, upload-time = "2025-02-06T22:14:40.799Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/9d/1322dc4bce4982d1eadd3a62802c996ae0303aad13d9ad88c1d35025f73d/django_browser_reload-1.18.0-py3-none-any.whl", hash = "sha256:ed4cc2fb83c3bf6c30b54107a1a6736c0b896e62e4eba666d81005b9f2ecf6f8", size = 12230, upload-time = "2025-02-06T22:14:36.87Z" }, +] + +[[package]] +name = "django-cleanup" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/01/b15a8de8b9ec75ea157ec58f86411894ca1182305fabaee31193076e7f62/django_cleanup-9.0.0.tar.gz", hash = "sha256:bb9fb560aaf62959c81e31fa40885c36bbd5854d5aa21b90df2c7e4ba633531e", size = 17917, upload-time = "2024-09-18T21:58:06.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/d7/a83dc87c2383e125da29948f7bccf5b30126c087a5a831316482407a960f/django_cleanup-9.0.0-py3-none-any.whl", hash = "sha256:19f8b0e830233f9f0f683b17181f414672a0f48afe3ea3cc80ba47ae40ad880c", size = 10726, upload-time = "2024-09-18T21:58:04.626Z" }, +] + +[[package]] +name = "django-crispy-forms" +version = "2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/f6/5bce7ae3512171c7c0ca3de31689e2a1ced8b030f156fcf13d2870e5468e/django_crispy_forms-2.3.tar.gz", hash = "sha256:2db17ae08527201be1273f0df789e5f92819e23dd28fec69cffba7f3762e1a38", size = 278849, upload-time = "2024-07-19T13:08:16.264Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/3b/5dc3faf8739d1ce7a73cedaff508b4af8f6aa1684120ded6185ca0c92734/django_crispy_forms-2.3-py3-none-any.whl", hash = "sha256:efc4c31e5202bbec6af70d383a35e12fc80ea769d464fb0e7fe21768bb138a20", size = 31411, upload-time = "2024-07-19T13:08:14.498Z" }, +] + +[[package]] +name = "django-pictures" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/e8/65f6aa27a56c410aa84e1c32820016c3b0df84a0510d7a8686037a4c3b17/django_pictures-1.4.0.tar.gz", hash = "sha256:7133ac74a1c054cd5666c921fe76eee4d00d171c68d19d508ddf196f862f2d77", size = 20900, upload-time = "2024-12-17T13:01:09.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/cd/249c7cf59e38f60d1bdd6a3ec9151a7eafcc988487d41e814d57f6ff511a/django_pictures-1.4.0-py3-none-any.whl", hash = "sha256:4ef318525e70c1d2ae9f6f7ca370e99518283ee501ea77984cbb2da7c212c288", size = 21926, upload-time = "2024-12-17T13:01:07.965Z" }, +] + +[[package]] +name = "eparafia" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "crispy-bulma" }, + { name = "django" }, + { name = "django-authtools" }, + { name = "django-browser-reload" }, + { name = "django-cleanup" }, + { name = "django-crispy-forms" }, + { name = "django-pictures" }, + { name = "gunicorn" }, + { name = "lxml" }, + { name = "requests" }, +] + +[package.metadata] +requires-dist = [ + { name = "beautifulsoup4", specifier = ">=4.13.4" }, + { name = "crispy-bulma", specifier = ">=0.11.0" }, + { name = "django", specifier = ">=5.1.6" }, + { name = "django-authtools", specifier = ">=2.0.1" }, + { name = "django-browser-reload", specifier = ">=1.18.0" }, + { name = "django-cleanup", specifier = ">=9.0.0" }, + { name = "django-crispy-forms", specifier = ">=2.3" }, + { name = "django-pictures", specifier = ">=1.4.0" }, + { name = "gunicorn", specifier = ">=23.0.0" }, + { name = "lxml", specifier = ">=5.3.1" }, + { name = "requests", specifier = ">=2.32.3" }, +] + +[[package]] +name = "gunicorn" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "lxml" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/f6/c15ca8e5646e937c148e147244817672cf920b56ac0bf2cc1512ae674be8/lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8", size = 3678591, upload-time = "2025-02-10T07:51:41.769Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/1c/724931daa1ace168e0237b929e44062545bf1551974102a5762c349c668d/lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e", size = 8171881, upload-time = "2025-02-10T07:46:40.653Z" }, + { url = "https://files.pythonhosted.org/packages/67/0c/857b8fb6010c4246e66abeebb8639eaabba60a6d9b7c606554ecc5cbf1ee/lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd", size = 4440394, upload-time = "2025-02-10T07:46:44.037Z" }, + { url = "https://files.pythonhosted.org/packages/61/72/c9e81de6a000f9682ccdd13503db26e973b24c68ac45a7029173237e3eed/lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7", size = 5037860, upload-time = "2025-02-10T07:46:47.919Z" }, + { url = "https://files.pythonhosted.org/packages/24/26/942048c4b14835711b583b48cd7209bd2b5f0b6939ceed2381a494138b14/lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414", size = 4782513, upload-time = "2025-02-10T07:46:50.696Z" }, + { url = "https://files.pythonhosted.org/packages/e2/65/27792339caf00f610cc5be32b940ba1e3009b7054feb0c4527cebac228d4/lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e", size = 5305227, upload-time = "2025-02-10T07:46:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/25f7aa434a4d0d8e8420580af05ea49c3e12db6d297cf5435ac0a054df56/lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1", size = 4829846, upload-time = "2025-02-10T07:46:56.262Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ed/faf235e0792547d24f61ee1448159325448a7e4f2ab706503049d8e5df19/lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5", size = 4949495, upload-time = "2025-02-10T07:46:59.189Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e1/8f572ad9ed6039ba30f26dd4c2c58fb90f79362d2ee35ca3820284767672/lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423", size = 4773415, upload-time = "2025-02-10T07:47:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/a3/75/6b57166b9d1983dac8f28f354e38bff8d6bcab013a241989c4d54c72701b/lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20", size = 5337710, upload-time = "2025-02-10T07:47:06.385Z" }, + { url = "https://files.pythonhosted.org/packages/cc/71/4aa56e2daa83bbcc66ca27b5155be2f900d996f5d0c51078eaaac8df9547/lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8", size = 4897362, upload-time = "2025-02-10T07:47:09.24Z" }, + { url = "https://files.pythonhosted.org/packages/65/10/3fa2da152cd9b49332fd23356ed7643c9b74cad636ddd5b2400a9730d12b/lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9", size = 4977795, upload-time = "2025-02-10T07:47:12.101Z" }, + { url = "https://files.pythonhosted.org/packages/de/d2/e1da0f7b20827e7b0ce934963cb6334c1b02cf1bb4aecd218c4496880cb3/lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c", size = 4858104, upload-time = "2025-02-10T07:47:15.998Z" }, + { url = "https://files.pythonhosted.org/packages/a5/35/063420e1b33d3308f5aa7fcbdd19ef6c036f741c9a7a4bd5dc8032486b27/lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b", size = 5416531, upload-time = "2025-02-10T07:47:19.862Z" }, + { url = "https://files.pythonhosted.org/packages/c3/83/93a6457d291d1e37adfb54df23498101a4701834258c840381dd2f6a030e/lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5", size = 5273040, upload-time = "2025-02-10T07:47:24.29Z" }, + { url = "https://files.pythonhosted.org/packages/39/25/ad4ac8fac488505a2702656550e63c2a8db3a4fd63db82a20dad5689cecb/lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252", size = 5050951, upload-time = "2025-02-10T07:47:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/82/74/f7d223c704c87e44b3d27b5e0dde173a2fcf2e89c0524c8015c2b3554876/lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78", size = 3485357, upload-time = "2025-02-10T07:47:29.738Z" }, + { url = "https://files.pythonhosted.org/packages/80/83/8c54533b3576f4391eebea88454738978669a6cad0d8e23266224007939d/lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332", size = 3814484, upload-time = "2025-02-10T07:47:33.3Z" }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, +] + +[[package]] +name = "pillow" +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715, upload-time = "2025-01-02T08:13:58.407Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640, upload-time = "2025-01-02T08:11:58.329Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437, upload-time = "2025-01-02T08:12:01.797Z" }, + { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605, upload-time = "2025-01-02T08:12:05.224Z" }, + { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173, upload-time = "2025-01-02T08:12:08.281Z" }, + { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145, upload-time = "2025-01-02T08:12:11.411Z" }, + { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340, upload-time = "2025-01-02T08:12:15.29Z" }, + { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906, upload-time = "2025-01-02T08:12:17.485Z" }, + { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759, upload-time = "2025-01-02T08:12:20.382Z" }, + { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657, upload-time = "2025-01-02T08:12:23.922Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304, upload-time = "2025-01-02T08:12:28.069Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117, upload-time = "2025-01-02T08:12:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060, upload-time = "2025-01-02T08:12:32.362Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192, upload-time = "2025-01-02T08:12:34.361Z" }, + { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805, upload-time = "2025-01-02T08:12:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623, upload-time = "2025-01-02T08:12:41.912Z" }, + { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191, upload-time = "2025-01-02T08:12:45.186Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494, upload-time = "2025-01-02T08:12:47.098Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595, upload-time = "2025-01-02T08:12:50.47Z" }, + { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651, upload-time = "2025-01-02T08:12:53.356Z" }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999, upload-time = "2024-12-10T12:05:30.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950, upload-time = "2025-01-21T19:49:38.686Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762, upload-time = "2025-01-21T19:49:37.187Z" }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" }, +]