wizyta oraz widok księdza

This commit is contained in:
2025-06-26 15:57:42 +02:00
commit 0c6faa8bb6
39 changed files with 1465 additions and 0 deletions

0
backend/__init__.py Normal file
View File

59
backend/admin.py Normal file
View File

@ -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"]

6
backend/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class BackendConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'backend'

View File

@ -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'],
},
),
]

View File

@ -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'),
),
]

View File

@ -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),
),
]

View File

@ -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'),
),
]

View File

@ -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',
},
),
]

View File

@ -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',
},
),
]

View File

65
backend/models.py Normal file
View File

@ -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"

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
{% load static i18n %}
<html lang="pl" dir="ltr" data-theme="light">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="author" content="Nikola Kubiczek" />
<title>eParafia</title>
<base href="/" />
{% block head %}
{% endblock %}
<meta name="mobile-web-app-capable" content="yes" />
<meta name="x5-page-mode" content="app" />
<meta name="browsermode" content="application" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css" />
{% comment %} <link rel="stylesheet" href="/background.css" /> {% endcomment %}
<script>
document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0)
// Add a click event on each of them
$navbarBurgers.forEach((el) => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target
const $target = document.getElementById(target)
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active')
$target.classList.toggle('is-active')
})
})
// main.js
let installPrompt = null
const installButton = document.querySelector('#install')
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault()
installPrompt = event
installButton.classList.remove('is-hidden')
})
installButton.addEventListener('click', async () => {
if (!installPrompt) {
return
}
const result = await installPrompt.prompt()
console.log(`Install prompt was: ${result.outcome}`)
disableInAppInstallPrompt()
})
function disableInAppInstallPrompt() {
installPrompt = null
installButton.classList.add('is-hidden')
}
window.addEventListener('appinstalled', disableInAppInstallPrompt)
})
</script>
<style>
.navbar-link.is-active,
a.navbar-item.is-active {
color: #0a0a0a;
}
.navbar-link.is-active:not(:focus):not(:hover),
a.navbar-item.is-active:not(:focus):not(:hover) {
background-color: initial;
}
.navbar-item.has-dropdown.is-active .navbar-link,
.navbar-item.has-dropdown:focus .navbar-link,
.navbar-item.has-dropdown:hover .navbar-link {
background-color: #fafafa;
}
</style>
</head>
<body class="container section">
{% block layout %}
<main class="section container">
{% block content %}
{% endblock %}
</main>
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% block content %}
<div class="has-text-centered is-flex is-flex-direction-column">
<p class="is-size-2 has-text-weight-semibold is-family-monospace">eParafia</p>
<p class="is-family-monospace">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</p>
<p class="is-size-4 has-text-weight-light">Zapraszamy!</p>
<div class="is-flex is-flex-direction-column mt-6">
{% for parish in parishes %}
<a class="button has-text-weight-semibold mx-auto my-2" href="{% url 'parish' parish.slug %}">{{ parish.name }}</a>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'parish/base.html' %}
{% block content %}
<div class="content">{{res | safe}}</div>
{% endblock %}

View File

@ -0,0 +1,45 @@
{% extends 'base.html' %}
{% load pictures %}
{% block head %}
<link href="{% img_url parish.icon file_type='png' width=512 %}" rel="icon" type="image/png" sizes="512x512" />
<link href="{% img_url parish.icon file_type='png' width=192 %}" rel="icon" type="image/png" sizes="192x192" />
<link rel="manifest" href="{% url 'manifest' parish.slug %}" />
{% endblock %}
{% block layout %}
<div class="container">
<nav class="navbar is-transparent" role="navigation" aria-label="menu">
<div class="navbar-brand is-flex is-flex-wrap-wrap is-justify-content-space-between is-flex-shrink-1">
<span class="navbar-item is-is-active is-flex-shrink-1"><span class="title is-4 is-unselectable">{{ parish.name }}</span></span>
<a role="button" class="navbar-burger" data-target="navMenu" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" id="navMenu">
<h5 class="navbar-end has-text-weight-bold">
<a class="navbar-item {{ announcements }}" href="{% url 'announcements' parish.slug %}">Ogłoszenia parafialne</a>
<a class="navbar-item {{ intentions }}" href="{% url 'intentions' parish.slug %}">Intencje</a>
{% if parish.channel %}
<a class="navbar-item {{ live }}" href="{% url 'live' parish.slug %}">Transmisja on-line</a>
{% endif %}
{% if parish.submissions %}
<a class="navbar-item {{ visit }}" href="{% url 'visit' parish.slug %}">Wizyta Duszpasterska</a>
{% endif %}
<a class="navbar-item is-clickable is-hidden" id="install">Zainstaluj</a>
</h5>
</div>
</nav>
<main class="section">
<div id="backgroundDesktop"></div>
{% block content %}
{% endblock %}
</main>
<div id="backgroundMobile"></div>
</div>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'parish/base.html' %}
{% block content %}
<div class="content">{{ res | safe }}</div>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'parish/base.html' %}
{% block content %}
<div class="is-flex-shrink-0">
<figure class="image is-16by9">
<iframe
class="has-ratio"
src="https://www.youtube-nocookie.com/embed/live_stream?channel={{parish.channel}}"
allowFullScreen
></iframe>
</figure>
</div>
{% endblock content %}

View File

@ -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"
}
]
}

View File

@ -0,0 +1,8 @@
{% extends 'parish/base.html' %}
{% block content %}
<p class="has-text-centered">
<a class="button is-light" href="{% url 'visit_login' parish.slug %}">Zaloguj się</a>
<a class="button is-light" href="{% url 'visit_signup' parish.slug %}">Zarejestruj się</a>
</p>
{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends 'parish/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p class="is-size-3 has-text-centered">Zapisz się na wizytę duszpasterską</p>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<p class="has-text-centered">
<button type="submit" class="button is-success">Zatwierdź</button>
</p>
</form>
<form action="{% url 'visit_logout' parish.slug %}" method="post" class="is-flex is-justify-content-flex-end is-gap-2">
{% csrf_token %}
<a href="{% url 'visit_account' parish.slug %}" class="button is-info">Zmień dane konta</a>
<button type="submit" class="button is-danger">Wyloguj się</button>
</form>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'parish/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p class="is-size-2 has-text-centered">Zaloguj się</p>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<p class="has-text-centered">
<button type="submit" class="button is-success">Zaloguj się</button>
<a href="{% url 'visit' parish.slug %}" class="button is-light">Powrót</a>
</p>
</form>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'parish/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p class="is-size-2 has-text-centered">Zarejestruj się</p>
<form method="post" class="form">
{% csrf_token %}
{{ form | crispy }}
<p class="has-text-centered">
<button type="submit" class="button is-success">Zarejestruj się</button>
<a href="{% url 'visit' parish.slug %}" class="button is-light">Powrót</a>
</p>
</form>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'parish/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p class="is-size-3 has-text-centered">Twoje zgłoszenie</p>
<div class="is-size-5 has-text-centered mb-2">
<p>
<b>Imię i nazwisko:</b> {{ submission.name }}, <b>Telefon:</b> {{ submission.phone }}
</p>
<p>
<b>Adres:</b> {{ submission.street }} {{ submission.street_number }}{% if submission.apartement_number %}/{% endif %}{{ submission.apartement_number|default_if_none:'' }}
</p>
</div>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<p class="has-text-centered">
<button type="submit" class="button is-success">Wycofaj zgłoszenie</button>
</p>
</form>
<p>
<form action="{% url 'visit_logout' parish.slug %}" method="post" class="is-flex is-justify-content-flex-end">
{% csrf_token %}
<button type="submit" class="button is-danger">Wyloguj się</button>
</form>
</p>
{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends 'parish/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<p class="is-size-3 has-text-centered">Zmień dane konta</p>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<p class="has-text-centered">
<button type="submit" class="button is-success">Zatwierdź</button>
<a href="{% url 'visit' parish.slug %}" class="button is-secondary">Powrót</a>
</p>
</form>
{% comment %} <form action="{% url 'visit_logout' parish.slug %}" method="post" class="is-flex is-justify-content-flex-end">
{% csrf_token %}
<button type="submit" class="button is-danger">Wyloguj się</button>
</form> {% endcomment %}
{% endblock %}

3
backend/tests.py Normal file
View File

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

266
backend/views.py Normal file
View File

@ -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("<str:slug>/", announcements, name="parish"),
path("<str:slug>/ogloszenia/", announcements, name="announcements"),
path("<str:slug>/intencje/", intentions, name="intentions"),
path("<str:slug>/transmisja/", live, name="live"),
path("<str:slug>/wizyta/", visit, name="visit"),
path("<str:slug>/wizyta/logowanie/", VisitLoginView.as_view(), name="visit_login"),
path("<str:slug>/wizyta/rejestracja/", VisitSignUpView.as_view(), name="visit_signup"),
path("<str:slug>/wizyta/konto/", VisitAccountView.as_view(), name="visit_account"),
path("<str:slug>/wizyta/wylogowanie/", VisitLogoutView.as_view(), name="visit_logout"),
path("<str:slug>/manifest.json", manifest, name="manifest"),
]