From 27c785160028c37c1f15d7f0259c072fd82adb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexa=20Valentov=C3=A1?= <git@imaniti.org> Date: Wed, 11 Dec 2024 09:33:30 +0100 Subject: [PATCH] finish basic career page --- .../commands/octopus_people_import.py | 2 +- ...uspersonpage_originating_group_and_more.py | 33 ++-- .../0305_alter_districtcustompage_options.py | 10 +- .../0063_alter_electionssimplepage_options.py | 7 +- main/forms.py | 85 ++++++++- .../0132_alter_mainsimplepage_options.py | 7 +- .../0133_maincareerpage_maincareerspage.py | 80 +++++++-- ...4_alter_maincareerpage_options_and_more.py | 11 +- ...35_maincareerpage_created_date_and_more.py | 62 ++++--- .../0136_maincareerpage_category.py | 13 +- ...37_maincareerspage_perex_col_1_and_more.py | 31 ++-- .../migrations/0138_maincareerpage_content.py | 9 +- .../0139_maincareerpage_recipient_emails.py | 19 ++ main/models.py | 162 ++++++++++++------ main/templates/main/main_career_page.html | 114 +++--------- majak/settings/base.py | 1 + ..._octopuspersonoriginatinggroup_and_more.py | 31 +++- shared/people_import.py | 4 +- shared/static/styleguide2/pirati-ui.svg | 2 +- .../molecules/boxes/main/career_box.html | 2 +- .../organisms/header/main/career_header.html | 2 +- uniweb/migrations/0114_auto_20241122_1238.py | 7 +- 22 files changed, 447 insertions(+), 247 deletions(-) create mode 100644 main/migrations/0139_maincareerpage_recipient_emails.py diff --git a/district/management/commands/octopus_people_import.py b/district/management/commands/octopus_people_import.py index 16e331a4..83b7bc70 100644 --- a/district/management/commands/octopus_people_import.py +++ b/district/management/commands/octopus_people_import.py @@ -36,7 +36,7 @@ class Command(BaseCommand): if not hasattr(people_page.root_page, "image_collection_id"): # FIXME: This should not be UniwebHomePage, but sometimes it is. continue - + collection_id = people_page.root_page.image_collection_id if collection_id is None: diff --git a/district/migrations/0304_remove_districtoctopuspersonpage_originating_group_and_more.py b/district/migrations/0304_remove_districtoctopuspersonpage_originating_group_and_more.py index 4696fa53..96075507 100644 --- a/district/migrations/0304_remove_districtoctopuspersonpage_originating_group_and_more.py +++ b/district/migrations/0304_remove_districtoctopuspersonpage_originating_group_and_more.py @@ -4,29 +4,36 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('district', '0303_alter_districtcenterpage_content'), - ('shared', '0014_octopuspersonoriginatinggroup_and_more'), + ("district", "0303_alter_districtcenterpage_content"), + ("shared", "0014_octopuspersonoriginatinggroup_and_more"), ] operations = [ migrations.RemoveField( - model_name='districtoctopuspersonpage', - name='originating_group', + model_name="districtoctopuspersonpage", + name="originating_group", ), migrations.RemoveField( - model_name='districtoctopuspersonpage', - name='originating_team', + model_name="districtoctopuspersonpage", + name="originating_team", ), migrations.AddField( - model_name='districtoctopuspersonpage', - name='originating_groups', - field=models.ManyToManyField(help_text='Skupiny, ze kterĂ˝ch byla tato osba importována.', to='shared.octopuspersonoriginatinggroup', verbose_name='Skupiny'), + model_name="districtoctopuspersonpage", + name="originating_groups", + field=models.ManyToManyField( + help_text="Skupiny, ze kterĂ˝ch byla tato osba importována.", + to="shared.octopuspersonoriginatinggroup", + verbose_name="Skupiny", + ), ), migrations.AddField( - model_name='districtoctopuspersonpage', - name='originating_teams', - field=models.ManyToManyField(help_text='TĂ˝my, ze kterĂ˝ch byla tato osba importována.', to='shared.octopuspersonoriginatingteam', verbose_name='TĂ˝m'), + model_name="districtoctopuspersonpage", + name="originating_teams", + field=models.ManyToManyField( + help_text="TĂ˝my, ze kterĂ˝ch byla tato osba importována.", + to="shared.octopuspersonoriginatingteam", + verbose_name="TĂ˝m", + ), ), ] diff --git a/district/migrations/0305_alter_districtcustompage_options.py b/district/migrations/0305_alter_districtcustompage_options.py index 6b20ce54..b7ee5563 100644 --- a/district/migrations/0305_alter_districtcustompage_options.py +++ b/district/migrations/0305_alter_districtcustompage_options.py @@ -4,14 +4,16 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('district', '0304_remove_districtoctopuspersonpage_originating_group_and_more'), + ( + "district", + "0304_remove_districtoctopuspersonpage_originating_group_and_more", + ), ] operations = [ migrations.AlterModelOptions( - name='districtcustompage', - options={'verbose_name': 'Jednoduchá stránka'}, + name="districtcustompage", + options={"verbose_name": "Jednoduchá stránka"}, ), ] diff --git a/elections/migrations/0063_alter_electionssimplepage_options.py b/elections/migrations/0063_alter_electionssimplepage_options.py index 085f69f1..76a8469b 100644 --- a/elections/migrations/0063_alter_electionssimplepage_options.py +++ b/elections/migrations/0063_alter_electionssimplepage_options.py @@ -4,14 +4,13 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('elections', '0062_alter_electionsarticlepage_content'), + ("elections", "0062_alter_electionsarticlepage_content"), ] operations = [ migrations.AlterModelOptions( - name='electionssimplepage', - options={'verbose_name': 'Jednoduchá stránka'}, + name="electionssimplepage", + options={"verbose_name": "Jednoduchá stránka"}, ), ] diff --git a/main/forms.py b/main/forms.py index fb710b04..51f89000 100644 --- a/main/forms.py +++ b/main/forms.py @@ -1,5 +1,6 @@ import os import tempfile + from django import forms from shared.forms import ArticlesPageForm as SharedArticlesPageForm @@ -8,8 +9,90 @@ from shared.forms import JekyllImportForm as SharedJekyllImportForm from .tasks import import_jekyll_articles +class MultipleFileInput(forms.ClearableFileInput): + allow_multiple_selected = True + + +class MultipleFileField(forms.FileField): + def __init__(self, *args, **kwargs): + kwargs.setdefault("widget", MultipleFileInput()) + super().__init__(*args, **kwargs) + + def clean(self, data, initial=None): + single_file_clean = super().clean + if isinstance(data, (list, tuple)): + result = [single_file_clean(d, initial) for d in data] + else: + result = [single_file_clean(data, initial)] + return result + + class CareerSubmissionForm(forms.Form): - pass + name = forms.CharField( + min_length=1, + max_length=256, + required=True, + widget=forms.TextInput( + attrs={"placeholder": "JmĂ©no", "class": "lg:w-auto w-full"} + ), + ) + + surname = forms.CharField( + min_length=1, + max_length=256, + required=True, + widget=forms.TextInput( + attrs={"placeholder": "PĹ™ĂjmenĂ", "class": "lg:w-auto w-full"} + ), + ) + + email = forms.EmailField( + min_length=1, + max_length=256, + required=True, + widget=forms.EmailInput(attrs={"placeholder": "Email", "class": "w-full"}), + ) + + phone = forms.IntegerField( + required=True, + widget=forms.NumberInput( + attrs={"type": "tel", "placeholder": "Telefon", "class": "w-full"} + ), + ) + + own_text = forms.CharField( + widget=forms.Textarea( + attrs={ + "placeholder": "VlastnĂ text (nepovinnĂ˝)", + "class": "w-full", + "rows": 3, + } + ), + max_length=65535, + required=False, + ) + + cv_file = forms.FileField( + required=True, + widget=forms.FileInput( + attrs={"class": "max-w-64 mr-auto overflow-hidden break-words"} + ), + ) + + cover_letter_file = forms.FileField( + required=True, + widget=forms.FileInput( + attrs={"class": "max-w-64 mr-auto overflow-hidden break-words"} + ), + ) + + other_files = MultipleFileField( + widget=MultipleFileInput( + attrs={"class": "max-w-64 mr-auto overflow-hidden break-words"} + ) + ) + + personal_data_agreement = forms.BooleanField(required=True) class JekyllImportForm(SharedJekyllImportForm): diff --git a/main/migrations/0132_alter_mainsimplepage_options.py b/main/migrations/0132_alter_mainsimplepage_options.py index 9c491cb2..645cd00a 100644 --- a/main/migrations/0132_alter_mainsimplepage_options.py +++ b/main/migrations/0132_alter_mainsimplepage_options.py @@ -4,14 +4,13 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('main', '0131_alter_mainarticlepage_content_and_more'), + ("main", "0131_alter_mainarticlepage_content_and_more"), ] operations = [ migrations.AlterModelOptions( - name='mainsimplepage', - options={'verbose_name': 'Jednoduchá stránka'}, + name="mainsimplepage", + options={"verbose_name": "Jednoduchá stránka"}, ), ] diff --git a/main/migrations/0133_maincareerpage_maincareerspage.py b/main/migrations/0133_maincareerpage_maincareerspage.py index 8861b37f..3dd36516 100644 --- a/main/migrations/0133_maincareerpage_maincareerspage.py +++ b/main/migrations/0133_maincareerpage_maincareerspage.py @@ -1,40 +1,90 @@ # Generated by Django 5.0.7 on 2024-12-09 15:00 import django.db.models.deletion -import shared.models.main import wagtailmetadata.models from django.db import migrations, models +import shared.models.main + class Migration(migrations.Migration): - dependencies = [ - ('main', '0132_alter_mainsimplepage_options'), - ('wagtailcore', '0094_alter_page_locale'), - ('wagtailimages', '0026_delete_uploadedimage'), + ("main", "0132_alter_mainsimplepage_options"), + ("wagtailcore", "0094_alter_page_locale"), + ("wagtailimages", "0026_delete_uploadedimage"), ] operations = [ migrations.CreateModel( - name='MainCareerPage', + name="MainCareerPage", fields=[ - ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), - ('search_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Search image')), + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.page", + ), + ), + ( + "search_image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.image", + verbose_name="Search image", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(shared.models.main.SubpageMixin, wagtailmetadata.models.WagtailImageMetadataMixin, 'wagtailcore.page', models.Model), + bases=( + shared.models.main.SubpageMixin, + wagtailmetadata.models.WagtailImageMetadataMixin, + "wagtailcore.page", + models.Model, + ), ), migrations.CreateModel( - name='MainCareersPage', + name="MainCareersPage", fields=[ - ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), - ('search_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Search image')), + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.page", + ), + ), + ( + "search_image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.image", + verbose_name="Search image", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=(shared.models.main.SubpageMixin, wagtailmetadata.models.WagtailImageMetadataMixin, 'wagtailcore.page', models.Model), + bases=( + shared.models.main.SubpageMixin, + wagtailmetadata.models.WagtailImageMetadataMixin, + "wagtailcore.page", + models.Model, + ), ), ] diff --git a/main/migrations/0134_alter_maincareerpage_options_and_more.py b/main/migrations/0134_alter_maincareerpage_options_and_more.py index d393524d..fc77624c 100644 --- a/main/migrations/0134_alter_maincareerpage_options_and_more.py +++ b/main/migrations/0134_alter_maincareerpage_options_and_more.py @@ -4,18 +4,17 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('main', '0133_maincareerpage_maincareerspage'), + ("main", "0133_maincareerpage_maincareerspage"), ] operations = [ migrations.AlterModelOptions( - name='maincareerpage', - options={'verbose_name': 'PracovnĂ nabĂdka'}, + name="maincareerpage", + options={"verbose_name": "PracovnĂ nabĂdka"}, ), migrations.AlterModelOptions( - name='maincareerspage', - options={'verbose_name': 'KariĂ©ry'}, + name="maincareerspage", + options={"verbose_name": "KariĂ©ry"}, ), ] diff --git a/main/migrations/0135_maincareerpage_created_date_and_more.py b/main/migrations/0135_maincareerpage_created_date_and_more.py index 9d496acf..7d7958a5 100644 --- a/main/migrations/0135_maincareerpage_created_date_and_more.py +++ b/main/migrations/0135_maincareerpage_created_date_and_more.py @@ -1,49 +1,71 @@ # Generated by Django 5.0.7 on 2024-12-09 15:36 import datetime + from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('main', '0134_alter_maincareerpage_options_and_more'), + ("main", "0134_alter_maincareerpage_options_and_more"), ] operations = [ migrations.AddField( - model_name='maincareerpage', - name='created_date', - field=models.DateField(default=datetime.date.today, verbose_name='Datum vytvoĹ™enĂ'), + model_name="maincareerpage", + name="created_date", + field=models.DateField( + default=datetime.date.today, verbose_name="Datum vytvoĹ™enĂ" + ), ), migrations.AddField( - model_name='maincareerpage', - name='employment_relationship', - field=models.CharField(default=None, help_text="NapĹ™. 'Rámcová smlouva na dobu urÄŤitou'", max_length=128, verbose_name='PomÄ›r'), + model_name="maincareerpage", + name="employment_relationship", + field=models.CharField( + default=None, + help_text="NapĹ™. 'Rámcová smlouva na dobu urÄŤitou'", + max_length=128, + verbose_name="PomÄ›r", + ), preserve_default=False, ), migrations.AddField( - model_name='maincareerpage', - name='location', - field=models.CharField(default=None, help_text="NapĹ™. 'StĹ™edoÄŤeskĂ˝ kraj'", max_length=64, verbose_name='MĂsto vĂ˝konu práce'), + model_name="maincareerpage", + name="location", + field=models.CharField( + default=None, + help_text="NapĹ™. 'StĹ™edoÄŤeskĂ˝ kraj'", + max_length=64, + verbose_name="MĂsto vĂ˝konu práce", + ), preserve_default=False, ), migrations.AddField( - model_name='maincareerpage', - name='pay_rate', - field=models.CharField(default=None, help_text="NapĹ™. '300-350 KÄŤ/h'", max_length=64, verbose_name='OdmÄ›na'), + model_name="maincareerpage", + name="pay_rate", + field=models.CharField( + default=None, + help_text="NapĹ™. '300-350 KÄŤ/h'", + max_length=64, + verbose_name="OdmÄ›na", + ), preserve_default=False, ), migrations.AddField( - model_name='maincareerpage', - name='submission_end_date', - field=models.DateField(default=None, verbose_name='Datum konce pĹ™ihlášek'), + model_name="maincareerpage", + name="submission_end_date", + field=models.DateField(default=None, verbose_name="Datum konce pĹ™ihlášek"), preserve_default=False, ), migrations.AddField( - model_name='maincareerpage', - name='time_cost', - field=models.CharField(default=None, help_text="NapĹ™. '8h dennÄ›'", max_length=64, verbose_name='ÄŚasová nároÄŤnost'), + model_name="maincareerpage", + name="time_cost", + field=models.CharField( + default=None, + help_text="NapĹ™. '8h dennÄ›'", + max_length=64, + verbose_name="ÄŚasová nároÄŤnost", + ), preserve_default=False, ), ] diff --git a/main/migrations/0136_maincareerpage_category.py b/main/migrations/0136_maincareerpage_category.py index 67b5a7e1..775263fd 100644 --- a/main/migrations/0136_maincareerpage_category.py +++ b/main/migrations/0136_maincareerpage_category.py @@ -4,16 +4,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('main', '0135_maincareerpage_created_date_and_more'), + ("main", "0135_maincareerpage_created_date_and_more"), ] operations = [ migrations.AddField( - model_name='maincareerpage', - name='category', - field=models.CharField(default='Bez kategorie', help_text="NapĹ™. 'Koordinátor/ka', 'Programátor/ka', 'VolebnĂ manaĹľer/ka', ...", verbose_name='Kategorie pracovnĂ pozice'), + model_name="maincareerpage", + name="category", + field=models.CharField( + default="Bez kategorie", + help_text="NapĹ™. 'Koordinátor/ka', 'Programátor/ka', 'VolebnĂ manaĹľer/ka', ...", + verbose_name="Kategorie pracovnĂ pozice", + ), preserve_default=False, ), ] diff --git a/main/migrations/0137_maincareerspage_perex_col_1_and_more.py b/main/migrations/0137_maincareerspage_perex_col_1_and_more.py index 89f09a9c..9f923809 100644 --- a/main/migrations/0137_maincareerspage_perex_col_1_and_more.py +++ b/main/migrations/0137_maincareerspage_perex_col_1_and_more.py @@ -4,25 +4,34 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('main', '0136_maincareerpage_category'), + ("main", "0136_maincareerpage_category"), ] operations = [ migrations.AddField( - model_name='maincareerspage', - name='perex_col_1', - field=models.TextField(blank=True, null=True, verbose_name='Perex - prvnĂ sloupec'), + model_name="maincareerspage", + name="perex_col_1", + field=models.TextField( + blank=True, null=True, verbose_name="Perex - prvnĂ sloupec" + ), ), migrations.AddField( - model_name='maincareerspage', - name='perex_col_2', - field=models.TextField(blank=True, null=True, verbose_name='Perex - druhĂ˝ sloupec'), + model_name="maincareerspage", + name="perex_col_2", + field=models.TextField( + blank=True, null=True, verbose_name="Perex - druhĂ˝ sloupec" + ), ), migrations.AddField( - model_name='maincareerspage', - name='subheading', - field=models.CharField(blank=True, help_text='Text pod hlavnĂm nadpisem stránky', max_length=32, null=True, verbose_name='Podtitulek'), + model_name="maincareerspage", + name="subheading", + field=models.CharField( + blank=True, + help_text="Text pod hlavnĂm nadpisem stránky", + max_length=32, + null=True, + verbose_name="Podtitulek", + ), ), ] diff --git a/main/migrations/0138_maincareerpage_content.py b/main/migrations/0138_maincareerpage_content.py index 283c67b8..2be821d3 100644 --- a/main/migrations/0138_maincareerpage_content.py +++ b/main/migrations/0138_maincareerpage_content.py @@ -5,15 +5,14 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('main', '0137_maincareerspage_perex_col_1_and_more'), + ("main", "0137_maincareerspage_perex_col_1_and_more"), ] operations = [ migrations.AddField( - model_name='maincareerpage', - name='content', - field=wagtail.fields.RichTextField(blank=True, verbose_name='Text nabĂdky'), + model_name="maincareerpage", + name="content", + field=wagtail.fields.RichTextField(blank=True, verbose_name="Text nabĂdky"), ), ] diff --git a/main/migrations/0139_maincareerpage_recipient_emails.py b/main/migrations/0139_maincareerpage_recipient_emails.py new file mode 100644 index 00000000..59783e9e --- /dev/null +++ b/main/migrations/0139_maincareerpage_recipient_emails.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.7 on 2024-12-10 16:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0138_maincareerpage_content'), + ] + + operations = [ + migrations.AddField( + model_name='maincareerpage', + name='recipient_emails', + field=models.CharField(default='', help_text='Zadej buÄŹ jednu adresu, nebo vĂc, oddÄ›lenĂ˝ch čárkami.', verbose_name='PĹ™Ăjemci emailĹŻ o novĂ˝ch pĹ™ihláškách'), + preserve_default=False, + ), + ] diff --git a/main/models.py b/main/models.py index 0a59148c..e9c2f00c 100644 --- a/main/models.py +++ b/main/models.py @@ -1,4 +1,9 @@ +from datetime import date, datetime + +from django.contrib import messages +from django.core.mail import EmailMessage from django.db import models +from django.shortcuts import render from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.fields import ParentalKey, ParentalManyToManyField from taggit.models import TaggedItemBase @@ -8,9 +13,6 @@ from wagtail.contrib.routable_page.models import route from wagtail.fields import RichTextField, StreamField from wagtail.models import Page from wagtailmetadata.models import MetadataPageMixin -from datetime import date -from django.contrib import messages -from django.shortcuts import render from shared import blocks as shared_blocks from shared.const import RICH_TEXT_DEFAULT_FEATURES @@ -34,7 +36,7 @@ from shared.models import ( # MenuMixin, from shared.utils import make_promote_panels from . import blocks -from .forms import MainArticlesPageForm, CareerSubmissionForm +from .forms import CareerSubmissionForm, MainArticlesPageForm class MainHomePage(MainHomePageMixin): @@ -95,7 +97,6 @@ class MainHomePage(MainHomePageMixin): class Meta: verbose_name = "HomePage pirati.cz" - @property def careers_page(self): return self._first_subpage_of_type(MainCareersPage) @@ -383,7 +384,7 @@ class MainCareersPage( help_text="Text pod hlavnĂm nadpisem stránky", max_length=32, blank=True, - null=True + null=True, ) perex_col_1 = models.TextField( @@ -416,26 +417,16 @@ class MainCareersPage( def get_career_categories(self) -> list[str]: return ( - MainCareerPage. - objects. - child_of(self). - live(). - distinct("category"). - values_list("category", flat=True). - order_by("category"). - all() + MainCareerPage.objects.child_of(self) + .live() + .distinct("category") + .values_list("category", flat=True) + .order_by("category") + .all() ) - def get_career_pages(self): - return ( - MainCareerPage. - objects. - child_of(self). - live(). - all() - ) - + return MainCareerPage.objects.child_of(self).live().all() class Meta: verbose_name = "KariĂ©ry" @@ -444,11 +435,18 @@ class MainCareersPage( class MainCareerPage( ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, PageInMenuMixin, Page ): + recipient_emails = models.CharField( + verbose_name="PĹ™Ăjemci emailĹŻ o novĂ˝ch pĹ™ihláškách", + help_text="Zadej buÄŹ jednu adresu, nebo vĂc, oddÄ›lenĂ˝ch čárkami.", + blank=False, + null=False, + ) + category = models.CharField( verbose_name="Kategorie pracovnĂ pozice", help_text="NapĹ™. 'Koordinátor/ka', 'Programátor/ka', 'VolebnĂ manaĹľer/ka', ...", blank=False, - null=False + null=False, ) location = models.CharField( @@ -456,7 +454,7 @@ class MainCareerPage( help_text="NapĹ™. 'StĹ™edoÄŤeskĂ˝ kraj'", max_length=64, blank=False, - null=False + null=False, ) time_cost = models.CharField( @@ -464,7 +462,7 @@ class MainCareerPage( help_text="NapĹ™. '8h dennÄ›'", max_length=64, blank=False, - null=False + null=False, ) employment_relationship = models.CharField( @@ -472,7 +470,7 @@ class MainCareerPage( help_text="NapĹ™. 'Rámcová smlouva na dobu urÄŤitou'", max_length=128, blank=False, - null=False + null=False, ) pay_rate = models.CharField( @@ -480,7 +478,7 @@ class MainCareerPage( help_text="NapĹ™. '300-350 KÄŤ/h'", max_length=64, blank=False, - null=False + null=False, ) submission_end_date = models.DateField( @@ -488,18 +486,13 @@ class MainCareerPage( blank=False, null=False, ) - + created_date = models.DateField( - verbose_name="Datum vytvoĹ™enĂ", - blank=False, - null=False, - default=date.today + verbose_name="Datum vytvoĹ™enĂ", blank=False, null=False, default=date.today ) content = RichTextField( - "Text nabĂdky", - blank=True, - features=RICH_TEXT_DEFAULT_FEATURES + "Text nabĂdky", blank=True, features=RICH_TEXT_DEFAULT_FEATURES ) content_panels = Page.content_panels + [ @@ -508,15 +501,14 @@ class MainCareerPage( FieldPanel("submission_end_date"), FieldPanel("created_date"), ], - "Datumy" + "Datumy", ), - + FieldPanel("recipient_emails"), FieldPanel("category"), FieldPanel("location"), FieldPanel("time_cost"), FieldPanel("employment_relationship"), FieldPanel("pay_rate"), - FieldPanel("content"), ] @@ -524,27 +516,93 @@ class MainCareerPage( def serve(self, request): form = None + current_time = datetime.now() - if request.method == 'POST': - form = CareerSubmissionForm(request.POST) + if request.method == "POST": + form = CareerSubmissionForm(request.POST, request.FILES) if form.is_valid(): - # TODO - pass - + other_files_names = "" + + for file in form.cleaned_data["other_files"]: + other_files_names += f" - {file.name}\n" + + email = EmailMessage( + # Subject + f"Nová pĹ™ihláška k pracovnĂ pozici {self.title} - {form.cleaned_data['name']} {form.cleaned_data['surname']}", + # Message + ( + f""" +K pracovnĂ pozici {self.title} se {current_time} pĹ™ihlásil novĂ˝ zájemce. + +VyplnÄ›nĂ© Ăşdaje: + + JmĂ©no: {form.cleaned_data['name']} + PĹ™ĂjmenĂ: {form.cleaned_data['surname']} + E-mail: {form.cleaned_data['email']} + Telefon: {form.cleaned_data['phone']} + VlastnĂ text: {form.cleaned_data['own_text'] if form.cleaned_data['own_text'] else '(nevyplnÄ›n)'} + +CV, motivaÄŤnĂ dopis a ostatnĂ soubory jsou v pĹ™Ălohách. Názvy souborĹŻ: + + CV: {form.cleaned_data["cv_file"].name} + Mot. dopis: {form.cleaned_data["cover_letter_file"].name} + OstatnĂ soubory: +{other_files_names} + +PĹ™i otevĂránĂ souborĹŻ buÄŹte opatrnĂ, virovĂ˝ sken neprobÄ›hl! + """ + ), + # From email + "vyberka@pirati.cz", + # Recipient list + self.recipient_emails.split(","), + ) + + email.attach( + form.cleaned_data["cv_file"].name, + form.cleaned_data["cv_file"].read(), + form.cleaned_data["cv_file"].content_type, + ) + email.attach( + form.cleaned_data["cover_letter_file"].name, + form.cleaned_data["cover_letter_file"].read(), + form.cleaned_data["cover_letter_file"].content_type, + ) + + for file in form.cleaned_data["other_files"]: + email.attach(file.name, file.read(), file.content_type) + + sent_successfully = email.send(fail_silently=True) + + if sent_successfully: + messages.add_message( + request, messages.SUCCESS, "PĹ™ihláška odeslána." + ) + else: + messages.add_message( + request, + messages.ERROR, + "Chyba serveru pĹ™i odesĂlánĂ pĹ™ihlášky.", + ) + else: messages.add_message( request, - messages.SUCCESS, - "PĹ™ihláška odeslána." + messages.ERROR, + "Chyba pĹ™i odeslánĂ pĹ™ihlášky - prohlĂĹľeÄŤ odeslal chybná data.", ) else: form = CareerSubmissionForm() - return render(request, self.template, { - 'page': self, - 'self': self, - 'form': form, - }) + return render( + request, + self.template, + { + "page": self, + "self": self, + "form": form, + }, + ) class Meta: verbose_name = "PracovnĂ nabĂdka" @@ -560,4 +618,4 @@ class MainSearchPage(MainSearchPageMixin): MainArticlePage, MainPersonPage, MainSimplePage, - ] \ No newline at end of file + ] diff --git a/main/templates/main/main_career_page.html b/main/templates/main/main_career_page.html index 98503165..06719098 100644 --- a/main/templates/main/main_career_page.html +++ b/main/templates/main/main_career_page.html @@ -34,6 +34,7 @@ role="dialog" aria-modal="true" aria-labelledby="modal-1-title" + enctype="multipart/form-data" method="POST" action="" > @@ -48,134 +49,71 @@ <section class=" flex gap-4 flex-nowrap flex-col w-full - + lg:flex-row lg:gap-2 " > + {% csrf_token %} + <div class="lg:w-auto w-full"> - <input - type="text" - name="name" - maxlength="256" - placeholder="JmĂ©no" - id="id_name" - class="lg:w-auto w-full" - required - > + {{ form.name }} </div> <div class="lg:w-auto w-full"> - <input - type="text" - name="surname" - maxlength="256" - placeholder="PĹ™ĂjmenĂ" - id="id_surname" - class="lg:w-auto w-full" - required - > + {{ form.surname }} </div> </section> <section> <div class="w-full"> - <input - class="w-full" - type="email" - name="email" - maxlength="256" - id="id_email" - placeholder="E-mail" - required - > + {{ form.email }} </div> </section> <section> <div class="w-full"> - <input - class="w-full" - type="tel" - name="phone" - maxlength="19" - id="id_phone" - placeholder="Telefon" - required - > + {{ form.phone }} </div> </section> <section> <div class="w-full"> - <textarea - class="w-full" - name="custom_text" - maxlength="65535" - id="id_custom_text" - placeholder="VlastnĂ text (nepovinnĂ˝)" - ></textarea> + {{ form.own_text }} </div> </section> <section class="flex flex-col gap-3 lg:items-center lg:flex-row"> <label class="w-36" - for="cv" + for="id_cv" id="cv_label" >CV: </label> - - <input - type="file" - id="cv" - name="cv" - aria-labelledby="cv_label" - class="max-w-64 mr-auto overflow-hidden break-words" - required - > - + + {{ form.cv_file }} + <small class="text-grey-300">(PovinnĂ©)</small> </section> <section class="flex flex-col gap-3 lg:items-center lg:flex-row"> <label class="w-36" id="cover_letter_label" - for="cover_letter" + for="id_cover_letter_file" >Mot. dopis: </label> - - <input - type="file" - id="cover_letter" - name="cover_letter" - aria-labelledby="cover_letter_label" - class="max-w-64 mr-auto overflow-hidden break-words" - required - > - + + {{ form.cover_letter_file }} + <small class="text-grey-300">(PovinnĂ˝)</small> </section> <section class="flex flex-col gap-3 lg:items-center lg:flex-row"> <label class="w-36" id="other_files_label" - for="other_files" + for="id_other_files" >OstatnĂ soubory: </label> - - <input - type="file" - id="other_files" - name="other_files" - aria-labelledby="other_files_label" - class="max-w-64 mr-auto overflow-hidden break-words" - multiple - > + + {{ form.other_files }} </section> - + <section class="flex flex-row gap-3 items-start leading-none"> - <input - type="checkbox" - id="personal_data_agreement" - name="personal_data_agreement" - aria-labelledby="personal_data_agreement_label" - required - > - + {{ form.personal_data_agreement }} + <label - for="personal_data_agreement" + for="id_personal_data_agreement" >SouhlasĂm se zpracovánĂm osobnĂm ĂşdajĹŻ (povinnĂ©)</label> </section> </div> @@ -183,7 +121,7 @@ <footer class=" modal__footer flex gap-2 justify-end flex-col items-end - + lg:items-start lg:gap-4 lg:flex-row " > @@ -191,7 +129,7 @@ {% include "styleguide2/includes/atoms/buttons/round_button_form.html" with type="button" text="Zrušit" show_arrow_on_hover=True %} </div> <div> - {% include "styleguide2/includes/atoms/buttons/round_button_form.html" with type="submit" fill="#fff" classes="bg-pirati-yellow text-black" text="Odeslat pĹ™ihlášku" %} + {% include "styleguide2/includes/atoms/buttons/round_button_form.html" with type="submit" fill="#fff" classes="bg-pirati-yellow text-black" text="Odeslat pĹ™ihlášku" show_arrow_on_hover=True %} </div> </footer> </form> diff --git a/majak/settings/base.py b/majak/settings/base.py index 939d0729..3012a6e8 100644 --- a/majak/settings/base.py +++ b/majak/settings/base.py @@ -173,6 +173,7 @@ EMAIL_HOST_USER = env.str("EMAIL_HOST_USER", "") EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD", "") EMAIL_PORT = env.str("EMAIL_PORT", "") EMAIL_SUBJECT_PREFIX = env.str("EMAIL_SUBJECT_PREFIX", "[Piráti] ") +EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", False) # LOGGING diff --git a/shared/migrations/0014_octopuspersonoriginatinggroup_and_more.py b/shared/migrations/0014_octopuspersonoriginatinggroup_and_more.py index 02c5c6e3..a2d5843d 100644 --- a/shared/migrations/0014_octopuspersonoriginatinggroup_and_more.py +++ b/shared/migrations/0014_octopuspersonoriginatinggroup_and_more.py @@ -4,24 +4,39 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('shared', '0013_alter_octopusperson_order'), + ("shared", "0013_alter_octopusperson_order"), ] operations = [ migrations.CreateModel( - name='OctopusPersonOriginatingGroup', + name="OctopusPersonOriginatingGroup", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=128)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=128)), ], ), migrations.CreateModel( - name='OctopusPersonOriginatingTeam', + name="OctopusPersonOriginatingTeam", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=128)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=128)), ], ), ] diff --git a/shared/people_import.py b/shared/people_import.py index 2d210e92..81877be9 100644 --- a/shared/people_import.py +++ b/shared/people_import.py @@ -7,8 +7,8 @@ import requests from django.conf import settings from django.core.files.images import ImageFile from gql import Client, gql -from gql.transport.exceptions import TransportServerError from gql.transport.aiohttp import AIOHTTPTransport +from gql.transport.exceptions import TransportServerError from wagtail.images.models import Image from wagtail.models.media import Collection @@ -480,7 +480,7 @@ class PeopleTeamImporter(ImporterMixin): logger.warning( f"Error getting data for group %s: %s", self.team_shortcut, - str(exception) + str(exception), ) return [] diff --git a/shared/static/styleguide2/pirati-ui.svg b/shared/static/styleguide2/pirati-ui.svg index ffc20ecc..c6e3a71a 100644 --- a/shared/static/styleguide2/pirati-ui.svg +++ b/shared/static/styleguide2/pirati-ui.svg @@ -127,4 +127,4 @@ <glyph unicode="" glyph-name="price-tags" horiz-adv-x="1280" d="M1232 960h-384c-26.4 0-63.274-15.274-81.942-33.942l-476.116-476.116c-18.668-18.668-18.668-49.214 0-67.882l412.118-412.118c18.668-18.668 49.214-18.668 67.882 0l476.118 476.118c18.666 18.666 33.94 55.54 33.94 81.94v384c0 26.4-21.6 48-48 48zM992 576c-53.020 0-96 42.98-96 96s42.98 96 96 96 96-42.98 96-96-42.98-96-96-96zM128 416l544 544h-80c-26.4 0-63.274-15.274-81.942-33.942l-476.116-476.116c-18.668-18.668-18.668-49.214 0-67.882l412.118-412.118c18.668-18.668 49.214-18.668 67.882 0l30.058 30.058-416 416z" /> <glyph unicode="" glyph-name="twitter" horiz-adv-x="1001" d="M596.009 526.629l372.819 433.371h-88.346l-323.718-376.29-258.553 376.29h-298.21l390.983-569.018-390.983-454.457h88.351l341.855 397.375 273.051-397.375h298.21l-405.458 590.103zM475 385.969l-354.815 507.521h135.702l624.636-893.48h-135.702l-269.821 385.959z" /> <glyph unicode="" glyph-name="stats-dots" d="M128 64h896v-128h-1024v1024h128zM288 128c-53.020 0-96 42.98-96 96s42.98 96 96 96c2.828 0 5.622-0.148 8.388-0.386l103.192 171.986c-9.84 15.070-15.58 33.062-15.58 52.402 0 53.020 42.98 96 96 96s96-42.98 96-96c0-19.342-5.74-37.332-15.58-52.402l103.192-171.986c2.766 0.238 5.56 0.386 8.388 0.386 2.136 0 4.248-0.094 6.35-0.23l170.356 298.122c-10.536 15.408-16.706 34.036-16.706 54.11 0 53.020 42.98 96 96 96s96-42.98 96-96c0-53.020-42.98-96-96-96-2.14 0-4.248 0.094-6.35 0.232l-170.356-298.124c10.536-15.406 16.706-34.036 16.706-54.11 0-53.020-42.98-96-96-96s-96 42.98-96 96c0 19.34 5.74 37.332 15.578 52.402l-103.19 171.984c-2.766-0.238-5.56-0.386-8.388-0.386s-5.622 0.146-8.388 0.386l-103.192-171.986c9.84-15.068 15.58-33.060 15.58-52.4 0-53.020-42.98-96-96-96z" /> -</font></defs></svg> \ No newline at end of file +</font></defs></svg> diff --git a/shared/templates/styleguide2/includes/molecules/boxes/main/career_box.html b/shared/templates/styleguide2/includes/molecules/boxes/main/career_box.html index 6107ce37..0a139c46 100644 --- a/shared/templates/styleguide2/includes/molecules/boxes/main/career_box.html +++ b/shared/templates/styleguide2/includes/molecules/boxes/main/career_box.html @@ -23,4 +23,4 @@ {% include "styleguide2/includes/atoms/buttons/round_button.html" with fill="#fff" classes="bg-pirati-yellow text-black" text="VĂce" url=career.url show_arrow_on_hover=True %} </div> </div> -</div> \ No newline at end of file +</div> diff --git a/shared/templates/styleguide2/includes/organisms/header/main/career_header.html b/shared/templates/styleguide2/includes/organisms/header/main/career_header.html index 23898c67..9070aae3 100644 --- a/shared/templates/styleguide2/includes/organisms/header/main/career_header.html +++ b/shared/templates/styleguide2/includes/organisms/header/main/career_header.html @@ -4,4 +4,4 @@ {% include 'styleguide2/includes/atoms/header/navigation.html' with classes='mb-6' first_text="PracovnĂ nabĂdky" first_link=page.root_page.careers_page.url second_text=page.created_date %} {% endblock %} -{% block heading_classes %}head-8xl{% endblock %} \ No newline at end of file +{% block heading_classes %}head-8xl{% endblock %} diff --git a/uniweb/migrations/0114_auto_20241122_1238.py b/uniweb/migrations/0114_auto_20241122_1238.py index ad98c190..a7655234 100644 --- a/uniweb/migrations/0114_auto_20241122_1238.py +++ b/uniweb/migrations/0114_auto_20241122_1238.py @@ -21,11 +21,8 @@ def fix_po_people_page(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('uniweb', '0113_alter_uniwebhomepage_dark_logo_and_more'), + ("uniweb", "0113_alter_uniwebhomepage_dark_logo_and_more"), ] - operations = [ - migrations.RunPython(fix_po_people_page) - ] + operations = [migrations.RunPython(fix_po_people_page)] -- GitLab