verejny kontaktnicek #71

Merged
ticvac merged 10 commits from kontaktnicek_pro_vsecny into master 2024-11-12 21:15:25 +01:00
7 changed files with 109 additions and 2 deletions

View file

@ -342,6 +342,7 @@ SEMINAR_KONFERY_DIR = os.path.join('konfery')
KOREKTURY_PDF_DIR = os.path.join('korektury', 'pdf')
KOREKTURY_IMG_DIR = os.path.join('korektury', 'img')
CISLO_IMG_DIR = os.path.join('cislo', 'img')
SOUSTREDENI_KONTAKTNICKY_DIR = os.path.join('soustredeni', 'kontaktnicky')

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-11-05 21:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('soustredeni', '0010_tvorba_post'),
]
operations = [
migrations.AddField(
model_name='soustredeni',
name='kontaktnicek_pdf',
field=models.FileField(blank=True, upload_to='kontaktnicky', verbose_name='kontaktníček'),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.13 on 2024-11-05 21:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('soustredeni', '0011_soustredeni_kontaktnicek_pdf'),
]
operations = [
migrations.AddField(
model_name='soustredeni',
name='kontaktnicek_vcf',
field=models.FileField(blank=True, upload_to='kontaktnicky', verbose_name='kontaktníček vcf'),
),
migrations.AlterField(
model_name='soustredeni',
name='kontaktnicek_pdf',
field=models.FileField(blank=True, upload_to='kontaktnicky', verbose_name='kontaktníček pdf'),
),
]

View file

@ -11,6 +11,17 @@ from personalni.models import Resitel, Organizator
from various.models import SeminarModelBase
from tvorba.models import Rocnik, Problem, aux_generate_filename
import secrets
import string
from django.utils import timezone
def generate_filename_kontaktnicek(self, filename, file_type):
# generate random string
length = 32
fname = timezone.now().strftime('%Y-%m-%d-%H_%M') + "-"
fname += ''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(length))

Tohle nezachvá příponu, což je spíš bug – když se dívám na soubory na Gimlim, tak chci vědět, co jsou zač.

Tohle nezachvá příponu, což je spíš bug – když se dívám na soubory na Gimlim, tak chci vědět, co jsou zač.
fname += '.' + file_type

Prosím ne KOREKTURY_PDF_DIR!!

Prosím ne `KOREKTURY_PDF_DIR`!!

Also: možná je snazší a bezpečnější použít pathlib než os.path.join

Also: možná je snazší a bezpečnější použít `pathlib` než `os.path.join`…
return os.path.join(settings.SOUSTREDENI_KONTAKTNICKY_DIR, fname)
logger = logging.getLogger(__name__)
@ -65,7 +76,9 @@ class Soustredeni(SeminarModelBase):
exportovat = models.BooleanField('export do AESOPa', db_column='exportovat', default=False,
help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti)')
#using lambda to avoid circular import
kontaktnicek_vcf = models.FileField('kontaktníček vcf', upload_to=lambda instance, filename: generate_filename_kontaktnicek(instance, filename, 'vcf'), blank=True, null=True)

Nemá to být null=True? (Ale já tomu nerozumím…)

Nemá to být `null=True`? (Ale já tomu nerozumím…)
kontaktnicek_pdf = models.FileField('kontaktníček pdf', upload_to=lambda instance, filename: generate_filename_kontaktnicek(instance, filename, 'pdf'), blank=True, null=True)
def __str__(self):
return '{} ({})'.format(self.misto, self.datum_zacatku)

View file

@ -35,6 +35,14 @@
{% endif %}
{% endfor %}
{% endif %}
{% for i in soustredeni.ucastnici.all %}
{% if i.osoba.user == user %}
<li><a href="../{{soustredeni.pk}}/kontaktnicek_pdf">kontaktnicek pdf</a></li>
<li><a href="../{{soustredeni.pk}}/kontaktnicek_vcf">kontaktnicek vcf</a></li>
{% endif %}
{% endfor %}
</ul>
{% if user.je_org %}
<div class="mam-org-only">

View file

@ -44,6 +44,16 @@ urlpatterns = [
org_required(views.SoustredeniAbstraktyView.as_view()),
name='soustredeni_abstrakty'
),
path(
'kontaktnicek_pdf',
views.soustredeniKontaktnicekPdfView,
name='soustredeni_kontaktnicek_pdf'
),
path(
'kontaktnicek_vcf',
views.soustredeniKontaktnicekVcfView,
name='soustredeni_kontaktnicek_vcf'

Stejný name pro obě URL nevypadá moc správně :-(

Stejný `name` pro obě URL nevypadá moc správně :-(
),
zelvuska marked this conversation as resolved
Review

Tady je nějaké divné odsazení…

Tady je nějaké divné odsazení…
path(
'fotogalerie/',
include('galerie.urls')

View file

@ -2,6 +2,8 @@ from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from django.views import generic
from django.contrib.staticfiles.finders import find
from django.http import Http404
from django.core.exceptions import PermissionDenied
import csv
@ -107,3 +109,35 @@ class SoustredeniAbstraktyView(generic.DetailView):
model = Soustredeni
template_name = 'soustredeni/export_do_abstraktu.html'
pk_url_kwarg = 'soustredeni' # v url bude <int:soustredeni> místo defaultně požadovaného <int:pk>
zelvuska marked this conversation as resolved Outdated

Diakritika maybe?

Diakritika maybe?
# Kontaktníčky
def soustredeniKontaktnicekPdfView(request, soustredeni):
return soustredeniKontaktnicekView(request, soustredeni, "pdf")
ledoian marked this conversation as resolved
Review

Ty views jsou OK-ish. (Šlo by mít URL typu kontaktnicek_<typ:str> a rovnou používat výsledný view, ale asi to nepřidává moc a spíš to zhoršuje čitelnost…)

Ty views jsou OK-ish. (Šlo by mít URL typu `kontaktnicek_<typ:str>` a rovnou používat výsledný view, ale asi to nepřidává moc a spíš to zhoršuje čitelnost…)
def soustredeniKontaktnicekVcfView(request, soustredeni):
return soustredeniKontaktnicekView(request, soustredeni, "vcf")
def soustredeniKontaktnicekView(request, soustredeni, typ):
soustredeni = get_object_or_404(Soustredeni, id=soustredeni)
# nebyl jsi tam, nebo nejsi org

Asi bych napsal popisnější hlášku, vynechal bych tu část z orgem, a naopak bych tam připsal, že nejsi přihlášený (to se stane asi častěji než že bych se dostal na špatný kontaktníček).

Také si nejsem jistý, jestli HttpResponse je to správné. (Jakože vrátí to něco, co moc nevypadá jako M&M stránky, ne?)

Asi bych napsal popisnější hlášku, vynechal bych tu část z orgem, a naopak bych tam připsal, že nejsi přihlášený (to se stane asi častěji než že bych se dostal na špatný kontaktníček). Také si nejsem jistý, jestli HttpResponse je to správné. (Jakože vrátí to něco, co moc nevypadá jako M&M stránky, ne?)

Uh, je to ekvivalentní s if request.user not in […] and not request.user.is_org:?

Uh, je to ekvivalentní s `if request.user not in […] and not request.user.is_org:`?
if (not request.user in [u.osoba.user for u in soustredeni.ucastnici.all()]) and not request.user.je_org:
raise PermissionDenied()

404 není správný návratový kód (kontaktníček zjevně existuje, ale nemám k němu přístup), má být 403 (PermissionDenied se myslím jmenuje ta Djangová výjimka).

404 není správný návratový kód (kontaktníček zjevně existuje, ale nemám k němu přístup), má být 403 (`PermissionDenied` se myslím jmenuje ta Djangová výjimka).
kontaktnicky = {

Poněkud se mi nelíbí místní duplikace kódu, když se tam mění dohromady tři věci (až přidáme další, tak někde něco zapomeneme přepsat a bude to bug…). Co třeba:

# typ -> (field, mime_type, otevreni)
kontaktnicky = {
|   'pdf': (soustredeni.kontaktnicek_pdf, 'applcation/pdf', 'rb'),
|   'vcf': (soustredeni.kontaktnicek_vcf, 'text/vcard', 'r'), # vcf je texťák, nevím, jestli je potřeba ho otevítat binárně.
}
try:
	field, mime, otevreni = kontaktnicky[typ]
except KeyError as e:
	raise ValueError("Neznámý typ kontaktníčku") from e
if not field:
|   ...
with open(field.path, otevreni) as soubor:
|   return HttpResponse(soubor.read(), content_type=mime)
Poněkud se mi nelíbí místní duplikace kódu, když se tam mění dohromady tři věci (až přidáme další, tak někde něco zapomeneme přepsat a bude to bug…). Co třeba: ```python3 # typ -> (field, mime_type, otevreni) kontaktnicky = { | 'pdf': (soustredeni.kontaktnicek_pdf, 'applcation/pdf', 'rb'), | 'vcf': (soustredeni.kontaktnicek_vcf, 'text/vcard', 'r'), # vcf je texťák, nevím, jestli je potřeba ho otevítat binárně. } try: field, mime, otevreni = kontaktnicky[typ] except KeyError as e: raise ValueError("Neznámý typ kontaktníčku") from e if not field: | ... with open(field.path, otevreni) as soubor: | return HttpResponse(soubor.read(), content_type=mime) ```

Uh, ten if not field: ... byl náznak toho, že není potřeba výčet typů v if (not soustredeni.kontaktnicek_pdf and typ == "pdf") or (not soustredeni.kontaktnicek_vcf and typ == "vcf"):, sorry za neexplicitnost.

Uh, ten `if not field: ...` byl náznak toho, že není potřeba výčet typů v `if (not soustredeni.kontaktnicek_pdf and typ == "pdf") or (not soustredeni.kontaktnicek_vcf and typ == "vcf"):`, sorry za neexplicitnost.
'pdf': (soustredeni.kontaktnicek_pdf, 'applcation/pdf', 'rb'),
'vcf': (soustredeni.kontaktnicek_vcf, 'text/vcard', 'rb'),
}
try:
field, mime, otevreni = kontaktnicky[typ]

Možno rovnou:

with open() as whatever:
	return HttpResponse()
Možno rovnou: ```python3 with open(…) as whatever: return HttpResponse(…) ```
except KeyError as e:
raise ValueError("Neznámý typ kontaktníčku") from e
# není k dispozici
if not field:
raise Http404()
with open(field.path, otevreni) as kontaktnicek:
response = HttpResponse(kontaktnicek.read(), content_type=mime)
response['Content-Disposition'] = 'attachment; filename="kontaktnicek.{}"'.format(typ)
return response