From ab15ccebab42e4ea0649c6d91e31fbf130bf2756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Wed, 10 Jul 2024 11:29:46 +0200 Subject: [PATCH] Fixes several things and clean up after merge. - Fix teardown in client fixture not working (ForeignKey error). - Adjust view `download_general_file` to work with the new SearchableFile --- src/privatim/__init__.py | 2 +- src/privatim/forms/fields/fields.py | 7 +- src/privatim/forms/filter_form.py | 2 +- .../locale/de/LC_MESSAGES/privatim.mo | Bin 0 -> 10310 bytes .../locale/de/LC_MESSAGES/privatim.po | 45 +- .../locale/fr/LC_MESSAGES/privatim.mo | Bin 0 -> 10672 bytes .../locale/fr/LC_MESSAGES/privatim.po | 44 +- src/privatim/locale/privatim.pot | 701 ++++++++++++++++++ src/privatim/models/searchable.py | 20 +- src/privatim/route_factories/__init__.py | 20 + src/privatim/static/js/init-tom-select.js | 2 +- src/privatim/utils.py | 2 +- src/privatim/views/__init__.py | 8 +- src/privatim/views/consultations.py | 4 +- src/privatim/views/general_file.py | 7 +- src/privatim/views/search.py | 11 +- tests/cli/test_upgrade.py | 8 - tests/conftest.py | 8 +- tests/views/client/test_views_comments.py | 2 +- tests/views/client/test_views_consultation.py | 11 +- tests/views/client/test_views_meeting.py | 10 +- .../views/client/test_views_working_group.py | 9 +- 22 files changed, 834 insertions(+), 89 deletions(-) create mode 100644 src/privatim/locale/de/LC_MESSAGES/privatim.mo create mode 100644 src/privatim/locale/fr/LC_MESSAGES/privatim.mo create mode 100644 src/privatim/locale/privatim.pot diff --git a/src/privatim/__init__.py b/src/privatim/__init__.py index a2ec1c1..6eec6c8 100644 --- a/src/privatim/__init__.py +++ b/src/privatim/__init__.py @@ -71,7 +71,7 @@ def profile_pic(request: 'IRequest') -> str: user = request.user if not user: return '' - return request.route_url('download_general_file', id=user.picture.id) + return request.route_url('download_file', id=user.picture.id) config.add_request_method(profile_pic, 'profile_pic', property=True) config.add_request_method(MessageQueue, 'messages', reify=True) diff --git a/src/privatim/forms/fields/fields.py b/src/privatim/forms/fields/fields.py index efbf483..477d5dc 100644 --- a/src/privatim/forms/fields/fields.py +++ b/src/privatim/forms/fields/fields.py @@ -169,9 +169,12 @@ class SearchableSelectField(SelectMultipleField): Note: you need to call form.raw_data() to actually get the choices as list """ - def __call__(self, *args: Any, **kwargs: Any) -> Any: + widget = ChosenSelectWidget(multiple=True) + + def __call__(self, **kwargs: Any) -> Any: init_tom_select.need() - return super().__call__(*args, **kwargs) + self.data: list[str] = [] + return super().__call__(**kwargs) def process_data(self, value: list[object]) -> None: if value: diff --git a/src/privatim/forms/filter_form.py b/src/privatim/forms/filter_form.py index 3b53819..c01830c 100644 --- a/src/privatim/forms/filter_form.py +++ b/src/privatim/forms/filter_form.py @@ -37,7 +37,7 @@ def get_date_fields(self) -> list[tuple[str, DateField]]: return [('datumVon', self.start_date), ('datumBis', self.end_date)] canton: SelectField = SelectField( - _('Kanton'), + _('Canton'), choices=[('all', _('all'))] + cantons_named, validators=[Optional()], render_kw={'class': 'form-select', 'id': 'kanton'}, diff --git a/src/privatim/locale/de/LC_MESSAGES/privatim.mo b/src/privatim/locale/de/LC_MESSAGES/privatim.mo new file mode 100644 index 0000000000000000000000000000000000000000..daf2d332c5d93575fa5055dd7c8c8d5fb3777f09 GIT binary patch literal 10310 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 literal 0 HcmV?d00001 diff --git a/src/privatim/locale/de/LC_MESSAGES/privatim.po b/src/privatim/locale/de/LC_MESSAGES/privatim.po index 3709695..ccf3d7b 100644 --- a/src/privatim/locale/de/LC_MESSAGES/privatim.po +++ b/src/privatim/locale/de/LC_MESSAGES/privatim.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE 1.0\n" -"POT-Creation-Date: 2024-07-10 01:22+0200\n" +"POT-Creation-Date: 2024-07-10 10:22+0200\n" "PO-Revision-Date: 2024-05-21 21:20+0200\n" "Last-Translator: cyrill \n" "Language-Team: German \n" @@ -335,6 +335,11 @@ msgstr "Beschreibung:" msgid "Recommendation:" msgstr "Empfehlung:" +#: src/privatim/views/templates/consultation.pt +#: src/privatim/forms/add_comment.py +msgid "Add Comment" +msgstr "Kommentar hinzufügen" + #: src/privatim/views/templates/consultation.pt #: src/privatim/forms/consultation_form.py msgid "Documents" @@ -345,11 +350,6 @@ msgstr "Dokumente" msgid "Status" msgstr "Status" -#: src/privatim/views/templates/consultation.pt -#: src/privatim/forms/add_comment.py -msgid "Add Comment" -msgstr "Kommentar hinzufügen" - #: src/privatim/views/templates/search_results.pt msgid "Search Results" msgstr "Suchergebnisse" @@ -392,17 +392,21 @@ msgstr "Gremium:" msgid "Show Meeting" msgstr "Sitzung anzeigen" -#: src/privatim/views/templates/activities.pt +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py msgid "Meeting" msgstr "Sitzung" -#: src/privatim/views/templates/activities.pt +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py msgid "Consultation" msgstr "Vernehmlassung" #: src/privatim/views/templates/activities.pt -msgid "Choose..." -msgstr "Auswählen..." +msgid "Type" +msgstr "Art" + +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py +msgid "Filter" +msgstr "Filter" #: src/privatim/views/templates/login.pt msgid "Sign in" @@ -590,7 +594,7 @@ msgstr "Beschluss" msgid "Cantons" msgstr "Kantone" -#: src/privatim/forms/add_comment.py +#: src/privatim/forms/add_comment.py src/privatim/forms/filter_form.py msgid "Comment" msgstr "Kommentar" @@ -617,6 +621,22 @@ msgstr "Dieses Feld ist deaktiviert." msgid "This field is read only." msgstr "Dieses Feld ist schreibgeschützt." +#: src/privatim/forms/filter_form.py +msgid "Canton" +msgstr "Kanton" + +#: src/privatim/forms/filter_form.py +msgid "all" +msgstr "Alle" + +#: src/privatim/forms/filter_form.py +msgid "Date from" +msgstr "Datum von" + +#: src/privatim/forms/filter_form.py +msgid "Date to" +msgstr "Datum bis" + #: src/privatim/forms/meeting_form.py msgid "Edit meeting" msgstr "Sitzung bearbeiten" @@ -691,3 +711,6 @@ msgstr "Protokoll der Sitzung ${title}" #: src/privatim/reporting/template/report.pt msgid "Attendees:" msgstr "Teilnehmende:" + +#~ msgid "Kanton" +#~ msgstr "Canton" diff --git a/src/privatim/locale/fr/LC_MESSAGES/privatim.mo b/src/privatim/locale/fr/LC_MESSAGES/privatim.mo new file mode 100644 index 0000000000000000000000000000000000000000..172ac511c6ff9dff6acff305ec450d87b455a6ae GIT binary patch literal 10672 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\n" "Language-Team: French \n" @@ -349,11 +349,6 @@ msgstr "Documents" msgid "Status" msgstr "Statut" -#: src/privatim/views/templates/consultation.pt -#: src/privatim/forms/add_comment.py -msgid "Add Comment" -msgstr "Ajouter un commentaire" - #: src/privatim/views/templates/search_results.pt msgid "Search Results" msgstr "Résultats de la recherche" @@ -375,7 +370,6 @@ msgstr "Correspondance de fichier" msgid "File Content" msgstr "Contenu du fichier" - #: src/privatim/views/templates/password_change.pt msgid "Change Password" msgstr "Changer le mot de passe" @@ -396,17 +390,21 @@ msgstr "Comité:" msgid "Show Meeting" msgstr "Afficher la réunion" -#: src/privatim/views/templates/activities.pt +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py msgid "Meeting" msgstr "Réunion" -#: src/privatim/views/templates/activities.pt +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py msgid "Consultation" msgstr "Consultation" #: src/privatim/views/templates/activities.pt -msgid "Choose..." -msgstr "Choisir..." +msgid "Type" +msgstr "Variété" + +#: src/privatim/views/templates/activities.pt src/privatim/forms/filter_form.py +msgid "Filter" +msgstr "Filtre" #: src/privatim/views/templates/login.pt msgid "Sign in" @@ -594,7 +592,7 @@ msgstr "Décision" msgid "Cantons" msgstr "Les cantons" -#: src/privatim/forms/add_comment.py +#: src/privatim/forms/add_comment.py src/privatim/forms/filter_form.py msgid "Comment" msgstr "Commentaire" @@ -619,6 +617,22 @@ msgstr "Ce champ est désactivé." msgid "This field is read only." msgstr "Ce champ est en lecture seule." +#: src/privatim/forms/filter_form.py +msgid "Canton" +msgstr "Canton" + +#: src/privatim/forms/filter_form.py +msgid "all" +msgstr "tous" + +#: src/privatim/forms/filter_form.py +msgid "Date from" +msgstr "Date de" + +#: src/privatim/forms/filter_form.py +msgid "Date to" +msgstr "Date à" + #: src/privatim/forms/meeting_form.py msgid "Edit meeting" msgstr "Modifier la réunion" @@ -691,9 +705,3 @@ msgstr "Procès-verbal de la réunion ${title}" #: src/privatim/reporting/template/report.pt msgid "Attendees:" msgstr "Participants:" - -#~ msgid "Unbekannter Ersteller" -#~ msgstr "Créateur inconnu" - -#~ msgid "Search..." -#~ msgstr "Recherche" diff --git a/src/privatim/locale/privatim.pot b/src/privatim/locale/privatim.pot new file mode 100644 index 0000000..9c6219f --- /dev/null +++ b/src/privatim/locale/privatim.pot @@ -0,0 +1,701 @@ +# +# SOME DESCRIPTIVE TITLE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , 2024. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE 1.0\n" +"POT-Creation-Date: 2024-07-10 10:22+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Lingua 4.15.0\n" + +#. translation strings used for testing +#: ./src/privatim/testing.py +msgid "Just a test" +msgstr "" + +#: ./src/privatim/testing.py +msgid "bold" +msgstr "" + +#: ./src/privatim/layouts/footer.pt +msgid "About us" +msgstr "" + +#: ./src/privatim/layouts/footer.pt +msgid "Contact" +msgstr "" + +#. Default: Close +#: ./src/privatim/layouts/flash.pt +msgid "Close" +msgstr "" + +#: ./src/privatim/layouts/action_menu.pt +msgid "Actions" +msgstr "" + +#: ./src/privatim/layouts/macros.pt +msgid "Message" +msgstr "" + +#: ./src/privatim/layouts/macros.pt ./src/privatim/forms/add_comment.py +msgid "Answer" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt ./src/privatim/views/activities.py +msgid "Activities" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt ./src/privatim/views/consultations.py +#: ./src/privatim/views/templates/person.pt +msgid "Consultations" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt +#: ./src/privatim/views/templates/working_groups.pt +msgid "Working Groups" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt +#: ./src/privatim/views/templates/working_groups.pt +msgid "People" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt +msgid " Profile" +msgstr "" + +#: ./src/privatim/layouts/navbar.pt +msgid " Sign out" +msgstr "" + +#: ./src/privatim/views/profile.py +msgid "Upload a photo..." +msgstr "" + +#: ./src/privatim/views/profile.py +msgid "Delete photo" +msgstr "" + +#: ./src/privatim/views/profile.py +msgid "Successfully updated profile picture" +msgstr "" + +#: ./src/privatim/views/login.py +msgid "Login failed." +msgstr "" + +#: ./src/privatim/views/general_file.py +#, python-format +msgid "Successfully deleted file \"${title}\"" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Edit Meeting" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Delete Meeting" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Copy Agenda Items" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Export meeting protocol" +msgstr "" + +#: ./src/privatim/views/meetings.py ./src/privatim/forms/agenda_item_form.py +msgid "Edit Agenda Item" +msgstr "" + +#: ./src/privatim/views/meetings.py ./src/privatim/forms/meeting_form.py +#: ./src/privatim/forms/working_group_forms.py +msgid "Members" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Details" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Delete" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Delete Working Group" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Participants" +msgstr "" + +#: ./src/privatim/views/meetings.py +#, python-format +msgid "Successfully added meeting \"${name}\"" +msgstr "" + +#: ./src/privatim/views/meetings.py +msgid "Successfully edited meeting." +msgstr "" + +#: ./src/privatim/views/meetings.py +#, python-format +msgid "Successfully deleted meeting \"${name}\"" +msgstr "" + +#: ./src/privatim/views/consultations.py +#: ./src/privatim/forms/consultation_form.py +msgid "Edit Consultation" +msgstr "" + +#: ./src/privatim/views/consultations.py +msgid "Delete Consultation" +msgstr "" + +#: ./src/privatim/views/consultations.py +#, python-format +msgid "Successfully added consultation \"${name}\"" +msgstr "" + +#: ./src/privatim/views/consultations.py +#: ./src/privatim/views/templates/activities.pt +msgid "Add Consultation" +msgstr "" + +#: ./src/privatim/views/consultations.py +msgid "Successfully edited consultation." +msgstr "" + +#: ./src/privatim/views/consultations.py +msgid "Successfully deleted consultation." +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "Email" +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "New Password" +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "Confirm New Password" +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "Password changed" +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "" +"There was a problem with your submission. Errors have been highlighted below." +msgstr "" + +#: ./src/privatim/views/password_change.py +msgid "" +"Password must have minimal length of 8 characters, contain one upper case " +"letter, one lower case letter, one digit and one special character." +msgstr "" + +#: ./src/privatim/views/comment.py +msgid "Successfully added comment" +msgstr "" + +#: ./src/privatim/views/working_groups.py +#, python-format +msgid "Successfully added working group \"${name}\"" +msgstr "" + +#: ./src/privatim/views/working_groups.py +#: ./src/privatim/views/templates/working_groups.pt +msgid "Add Working Group" +msgstr "" + +#: ./src/privatim/views/working_groups.py +#, python-format +msgid "" +"Cannot delete working group \"${name}\" because it has associated meetings. " +"Please delete all meetings first." +msgstr "" + +#: ./src/privatim/views/working_groups.py +#, python-format +msgid "Successfully deleted working group \"${name}\"" +msgstr "" + +#: ./src/privatim/views/agenda_items.py +#, python-format +msgid "Successfully added agend item \"${title}\"" +msgstr "" + +#: ./src/privatim/views/agenda_items.py +#, python-format +msgid "Successfully edited agenda_item \"${title}\"" +msgstr "" + +#: ./src/privatim/views/agenda_items.py +#, python-format +msgid "Successfully deleted agena_item \"${title}\"" +msgstr "" + +#: ./src/privatim/views/agenda_items.py +#, python-format +msgid "Successfully copied agenda item \"${name}\"" +msgstr "" + +#: ./src/privatim/views/password_retrieval.py +msgid "" +"An email has been sent to the requested account with further information. If " +"you do not receive an email then please confirm you have entered the correct " +"email address." +msgstr "" + +#: ./src/privatim/views/templates/form.pt ./src/privatim/forms/add_comment.py +msgid "Cancel" +msgstr "" + +#: ./src/privatim/views/templates/form.pt +msgid "Save" +msgstr "" + +#: ./src/privatim/views/templates/meeting.pt +#: ./src/privatim/reporting/template/report.pt +msgid "Date / Time:" +msgstr "" + +#: ./src/privatim/views/templates/meeting.pt +#: ./src/privatim/reporting/template/report.pt +msgid "Agenda Items" +msgstr "" + +#: ./src/privatim/views/templates/meeting.pt +#: ./src/privatim/forms/agenda_item_form.py +msgid "Add Agenda Item" +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +#: ./src/privatim/reporting/template/report.pt +msgid "Working Group" +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +#: ./src/privatim/forms/working_group_forms.py +msgid "Leader" +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +#: ./src/privatim/forms/meeting_form.py +msgid "Add Meeting" +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +msgid "" +"Here you can add meetings in the context of a working group. Click \"Add " +"meeting\" to get started." +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +#: ./src/privatim/views/templates/person.pt +msgid "Meetings" +msgstr "" + +#: ./src/privatim/views/templates/working_group.pt +#: ./src/privatim/views/templates/profile.pt +#: ./src/privatim/views/templates/people.pt +#: ./src/privatim/forms/meeting_form.py +#: ./src/privatim/forms/working_group_forms.py +msgid "Name" +msgstr "" + +#: ./src/privatim/views/templates/consultation.pt +msgid "Description:" +msgstr "" + +#: ./src/privatim/views/templates/consultation.pt +msgid "Recommendation:" +msgstr "" + +#: ./src/privatim/views/templates/consultation.pt +#: ./src/privatim/forms/add_comment.py +msgid "Add Comment" +msgstr "" + +#: ./src/privatim/views/templates/consultation.pt +#: ./src/privatim/forms/consultation_form.py +msgid "Documents" +msgstr "" + +#: ./src/privatim/views/templates/consultation.pt +#: ./src/privatim/forms/consultation_form.py +msgid "Status" +msgstr "" + +#: ./src/privatim/views/templates/search_results.pt +msgid "Search Results" +msgstr "" + +#: ./src/privatim/views/templates/search_results.pt +msgid "No results containing all your search terms were found." +msgstr "" + +#: ./src/privatim/views/templates/search_results.pt +#: ./src/privatim/views/templates/activities.pt +msgid "Show Details" +msgstr "" + +#: ./src/privatim/views/templates/search_results.pt +msgid "File Match" +msgstr "" + +#: ./src/privatim/views/templates/search_results.pt +msgid "File Content" +msgstr "" + +#: ./src/privatim/views/templates/password_change.pt +msgid "Change Password" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +msgid "Unknown Creator" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +msgid "No leader" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +msgid "Working Group:" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +msgid "Show Meeting" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +#: ./src/privatim/forms/filter_form.py +msgid "Meeting" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +#: ./src/privatim/forms/filter_form.py +msgid "Consultation" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +msgid "Type" +msgstr "" + +#: ./src/privatim/views/templates/activities.pt +#: ./src/privatim/forms/filter_form.py +msgid "Filter" +msgstr "" + +#: ./src/privatim/views/templates/login.pt +msgid "Sign in" +msgstr "" + +#: ./src/privatim/views/templates/login.pt +msgid "→ Forgot your password / Activate account" +msgstr "" + +#: ./src/privatim/views/templates/profile.pt +msgid "Profile" +msgstr "" + +#: ./src/privatim/views/templates/profile.pt +msgid "Profile Picture" +msgstr "" + +#: ./src/privatim/views/templates/profile.pt +msgid " Edit" +msgstr "" + +#: ./src/privatim/views/templates/profile.pt +msgid "Personal information" +msgstr "" + +#: ./src/privatim/views/templates/profile.pt +msgid "E-Mail-Address" +msgstr "" + +#: ./src/privatim/views/templates/people.pt +msgid "List of Persons" +msgstr "" + +#: ./src/privatim/views/templates/people.pt +msgid "No people added yet." +msgstr "" + +#: ./src/privatim/views/templates/password_retrieval.pt +msgid "Password Retrieval" +msgstr "" + +#: ./src/privatim/views/templates/working_groups.pt +msgid "Committee" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Aargau" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Appenzell Innerrhoden" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Appenzell Ausserrhoden" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Bern" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Basel-Landschaft" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Basel-Stadt" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Fribourg" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Geneva" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Glarus" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Graubünden" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Jura" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Lucerne" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Neuchâtel" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Nidwalden" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Obwalden" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "St. Gallen" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Schaffhausen" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Solothurn" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Schwyz" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Thurgau" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Ticino" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Uri" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Waadt" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Valais" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Zug" +msgstr "" + +#: ./src/privatim/forms/constants.py +msgid "Zurich" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Open" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Closed" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "In Progress" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +#: ./src/privatim/forms/agenda_item_form.py +msgid "Title" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +#: ./src/privatim/forms/agenda_item_form.py +msgid "Description" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Recommendation" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Evaluation Result" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Decision" +msgstr "" + +#: ./src/privatim/forms/consultation_form.py +msgid "Cantons" +msgstr "" + +#: ./src/privatim/forms/add_comment.py ./src/privatim/forms/filter_form.py +msgid "Comment" +msgstr "" + +#: ./src/privatim/forms/add_comment.py +msgid "Add comment" +msgstr "" + +#: ./src/privatim/forms/validators.py +msgid "This field is required." +msgstr "" + +#: ./src/privatim/forms/validators.py +#, python-format +msgid "File does not have an approved extension: {extensions}" +msgstr "" + +#: ./src/privatim/forms/validators.py +msgid "This field is disabled." +msgstr "" + +#: ./src/privatim/forms/validators.py +msgid "This field is read only." +msgstr "" + +#: ./src/privatim/forms/filter_form.py +msgid "Canton" +msgstr "" + +#: ./src/privatim/forms/filter_form.py +msgid "all" +msgstr "" + +#: ./src/privatim/forms/filter_form.py +msgid "Date from" +msgstr "" + +#: ./src/privatim/forms/filter_form.py +msgid "Date to" +msgstr "" + +#: ./src/privatim/forms/meeting_form.py +msgid "Edit meeting" +msgstr "" + +#: ./src/privatim/forms/meeting_form.py +msgid "Time" +msgstr "" + +#: ./src/privatim/forms/meeting_form.py +msgid "A meeting with this name already exists." +msgstr "" + +#: ./src/privatim/forms/agenda_item_form.py +msgid "Select Destionation for Agenda Item" +msgstr "" + +#: ./src/privatim/forms/agenda_item_form.py +msgid "No valid destination meetings available." +msgstr "" + +#: ./src/privatim/forms/agenda_item_form.py +msgid "Copy to" +msgstr "" + +#: ./src/privatim/forms/working_group_forms.py +msgid "Edit Working Group" +msgstr "" + +#: ./src/privatim/forms/working_group_forms.py +msgid "No Leader" +msgstr "" + +#: ./src/privatim/forms/working_group_forms.py +msgid "Contact Chairman" +msgstr "" + +#: ./src/privatim/forms/search_form.py +msgid "Search" +msgstr "" + +#: ./src/privatim/forms/widgets/widgets.py +msgid "Uploaded file" +msgstr "" + +#: ./src/privatim/forms/widgets/widgets.py +msgid "Keep file" +msgstr "" + +#: ./src/privatim/forms/widgets/widgets.py +msgid "Delete file" +msgstr "" + +#: ./src/privatim/forms/widgets/widgets.py +msgid "Replace file" +msgstr "" + +#: ./src/privatim/forms/widgets/widgets.py +msgid "Upload additional files" +msgstr "" + +#: ./src/privatim/forms/fields/fields.py +msgid "Select..." +msgstr "" + +#: ./src/privatim/reporting/report.py +#, python-format +msgid "Protocol of meeting ${title}" +msgstr "" + +#: ./src/privatim/reporting/template/report.pt +msgid "Attendees:" +msgstr "" diff --git a/src/privatim/models/searchable.py b/src/privatim/models/searchable.py index 6f79a84..de5e30a 100644 --- a/src/privatim/models/searchable.py +++ b/src/privatim/models/searchable.py @@ -21,7 +21,7 @@ class SearchableMixin: @classmethod def is_primary_search_field( - cls: type[F], field: 'InstrumentedAttribute'[Any] + cls: type[F], field: 'InstrumentedAttribute[Any]' ) -> bool: return field.key == _primary_search_fields.get(cls) @@ -50,12 +50,12 @@ def searchable_models() -> tuple[type[SearchableMixin], ...]: def prioritize_search_field( primary_field: str, ) -> Callable[ - [Callable[[type[T]], Iterator['InstrumentedAttribute'[Any]]]], - Callable[[type[T]], Iterator['InstrumentedAttribute'[Any]]], + [Callable[[type[T]], Iterator['InstrumentedAttribute[Any]']]], + Callable[[type[T]], Iterator['InstrumentedAttribute[Any]']], ]: - """ Annotate the `searchable_fields` method of a model (typically on it's - title), indicating which field should be considered a more important field - in search compared to other searchable fields. + """ Annotate the `searchable_fields` method of a model indicating which + field should be considered a more important field in search compared to + other searchable fields. For example: class YourModel(Base): @@ -64,7 +64,7 @@ class YourModel(Base): description: Mapped[str] - @is_primary_search_field('title) + @prioritize_search_field('title) def searchable_fields(self): yield cls.title yield cls.description @@ -77,12 +77,12 @@ def searchable_fields(self): """ def decorator( - func: Callable[[type[T]], Iterator['InstrumentedAttribute'[Any]]] - ) -> Callable[[type[T]], Iterator['InstrumentedAttribute'[Any]]]: + func: Callable[[type[T]], Iterator['InstrumentedAttribute[Any]']] + ) -> Callable[[type[T]], Iterator['InstrumentedAttribute[Any]']]: @wraps(func) def wrapper( cls: type[T], *args: Any, **kwargs: Any - ) -> Iterator['InstrumentedAttribute'[Any]]: + ) -> Iterator['InstrumentedAttribute[Any]']: _primary_search_fields[cls] = primary_field return func(cls, *args, **kwargs) diff --git a/src/privatim/route_factories/__init__.py b/src/privatim/route_factories/__init__.py index 0e7bae4..6d92fdb 100644 --- a/src/privatim/route_factories/__init__.py +++ b/src/privatim/route_factories/__init__.py @@ -3,10 +3,12 @@ from privatim.models import AgendaItem, GeneralFile from privatim.models.commentable import Comment from privatim.models import WorkingGroup, Consultation, User, Meeting +from privatim.models.file import SearchableFile from typing import TYPE_CHECKING if TYPE_CHECKING: + from privatim.orm.abstract import AbstractFile from pyramid.interfaces import IRequest from privatim.models.root import Root @@ -55,6 +57,24 @@ def person_factory(request: 'IRequest') -> 'User | Root': return _person_factory(request) +def file_factory(request: 'IRequest') -> 'AbstractFile | None': + file_id = request.matchdict['id'] + dbsession = request.dbsession + + general_file = ( + dbsession.query(GeneralFile).filter(GeneralFile.id == file_id).first() + ) + if general_file is not None: + return general_file + + searchable_file = ( + dbsession.query(SearchableFile) + .filter(SearchableFile.id == file_id) + .first() + ) + return searchable_file + + def general_file_factory(request: 'IRequest') -> GeneralFile: factory = create_uuid_factory(GeneralFile) return factory(request) diff --git a/src/privatim/static/js/init-tom-select.js b/src/privatim/static/js/init-tom-select.js index c7c78c3..e06e317 100644 --- a/src/privatim/static/js/init-tom-select.js +++ b/src/privatim/static/js/init-tom-select.js @@ -1,8 +1,8 @@ document.addEventListener('DOMContentLoaded', (event) => { document.querySelectorAll('.searchable-select').forEach((el)=>{ + console.log('setting up tomselect') let settings = {}; new TomSelect(el,settings); }); }); - diff --git a/src/privatim/utils.py b/src/privatim/utils.py index bcb47fc..573703b 100644 --- a/src/privatim/utils.py +++ b/src/privatim/utils.py @@ -198,7 +198,7 @@ def handle_comment_picture( else: pic = ( request.route_url( - 'download_general_file', id=comment.user.profile_pic.id + 'download_file', id=comment.user.profile_pic.id ) if comment.user.profile_pic is not None else fallback_profile_pic_link diff --git a/src/privatim/views/__init__.py b/src/privatim/views/__init__.py index 839f7d9..4090d97 100644 --- a/src/privatim/views/__init__.py +++ b/src/privatim/views/__init__.py @@ -3,7 +3,7 @@ from pyramid.security import NO_PERMISSION_REQUIRED from privatim.route_factories import (agenda_item_factory, - general_file_factory) + general_file_factory, file_factory) from privatim.route_factories import consultation_factory from privatim.route_factories import default_meeting_factory from privatim.route_factories import meeting_factory @@ -520,13 +520,13 @@ def includeme(config: 'Configurator') -> None: # General file config.add_route( - 'download_general_file', + 'download_file', '/download/file/{id}', - general_file_factory, + file_factory, ) config.add_view( download_general_file_view, - route_name='download_general_file', + route_name='download_file', request_method='GET', ) diff --git a/src/privatim/views/consultations.py b/src/privatim/views/consultations.py index f8ff44d..ddc25c4 100644 --- a/src/privatim/views/consultations.py +++ b/src/privatim/views/consultations.py @@ -36,7 +36,7 @@ def consultation_view( ) top_level_comments = (c for c in context.comments if c.parent_id is None) fallback_pic = request.route_url( - 'download_general_file', id=get_or_create_default_profile_pic( + 'download_file', id=get_or_create_default_profile_pic( request.dbsession).id ) return { @@ -46,7 +46,7 @@ def consultation_view( 'display_filename': trim_filename(doc.filename), 'doc_content_type': doc.content_type, 'download_url': request.route_url( - 'download_general_file', id=doc.id + 'download_file', id=doc.id ), } for doc in context.files diff --git a/src/privatim/views/general_file.py b/src/privatim/views/general_file.py index 08c2d42..d611a76 100644 --- a/src/privatim/views/general_file.py +++ b/src/privatim/views/general_file.py @@ -6,17 +6,20 @@ from typing import TYPE_CHECKING + +from privatim.orm.abstract import AbstractFile + if TYPE_CHECKING: from pyramid.interfaces import IRequest from privatim.types import XHRDataOrRedirect def download_general_file_view( - file: GeneralFile, request: 'IRequest' + file: AbstractFile, request: 'IRequest' ) -> Response: """ Downloads any file. Anyone who knows the link can download the file.""" - assert isinstance(file, GeneralFile) + assert isinstance(file, AbstractFile) response = Response(body=file.content, request=request) response.headers['Content-Disposition'] = ( f"inline; filename={file.filename}" diff --git a/src/privatim/views/search.py b/src/privatim/views/search.py index 273a146..d82c03a 100644 --- a/src/privatim/views/search.py +++ b/src/privatim/views/search.py @@ -58,10 +58,11 @@ class FileSearchResultType(TypedDict): class SearchCollection: - """Integrates PostgreSQL full-text search. Models can derive from + """ + Integrates PostgreSQL full-text search. Models can derive from `SearchableMixin` and implement `searchable_fields` for column searches. - Additionally, models may use `SearchableAssociatedFiles` to search in - their files. + Additionally, models may use `SearchableAssociatedFiles` to search in + their files. Key features: @@ -159,9 +160,9 @@ def build_file_query( 1. Generate headline expressions for all searchable fields of the model. Headlines in this context are snippets of text from the - fiel, with the matching search terms highlighted. They + file, with the matching search terms highlighted. They provide context around where the search term appears in each field. - ts_headlines requires the original document text, not tsvector. + Note: ts_headlines requires the original document text, not tsvector. 2. The actual search happens in the tsvector type searchable_text_{ diff --git a/tests/cli/test_upgrade.py b/tests/cli/test_upgrade.py index 86a4d6d..0caf3fc 100644 --- a/tests/cli/test_upgrade.py +++ b/tests/cli/test_upgrade.py @@ -7,14 +7,6 @@ def test_has_table(pg_config): assert not upgrade.has_table('bogus') -def test_drop_table(pg_config): - upgrade = UpgradeContext(pg_config.dbsession) - assert upgrade.has_table('agenda_items') - assert upgrade.drop_table('agenda_items') - assert not upgrade.has_table('meetings') - assert not upgrade.drop_table('bogus') - - def test_has_column(pg_config): upgrade = UpgradeContext(pg_config.dbsession) assert upgrade.has_column('meetings', 'id') diff --git a/tests/conftest.py b/tests/conftest.py index 28b4b81..deb4d78 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -181,12 +181,8 @@ def client(app, engine): yield client - # Remove user, if not already done within a test. - if user := client.db.get(User, user.id): - client.db.delete(user) - client.db.commit() - - client.reset() + # Teardown + client.db.close() Base.metadata.drop_all(bind=engine) diff --git a/tests/views/client/test_views_comments.py b/tests/views/client/test_views_comments.py index b81e8a5..9ea8568 100644 --- a/tests/views/client/test_views_comments.py +++ b/tests/views/client/test_views_comments.py @@ -7,7 +7,7 @@ def test_add_comment(client): client.login_admin() session.add(consultation) - session.flush() + session.commit() session.refresh(consultation) page = client.get(f'/consultation/{consultation.id}') assert page.status_code == 200 diff --git a/tests/views/client/test_views_consultation.py b/tests/views/client/test_views_consultation.py index 24dff2b..3ad627a 100644 --- a/tests/views/client/test_views_consultation.py +++ b/tests/views/client/test_views_consultation.py @@ -35,7 +35,7 @@ def test_view_consultation(client): ) db.add(consultation) db.add(status) - db.flush() + db.commit() db.refresh(consultation) page = client.get('/consultations') @@ -151,7 +151,6 @@ def test_view_edit_consultation(client): # todo: thi needs to select the other form for file updload and use the # find the right field by checking where the value is 'keep': - # def find_replace_file_checkbox(page, radio_btn_value='replace', # add_additional_files=False): # """ Find the upload file form field which is used to replace the @@ -167,7 +166,6 @@ def test_view_edit_consultation(client): # form_index = 1 if add_additional_files else 0 # if add_additional_files is False: # radio_options = list(expected_file_form_in_page[form_index]) - # print(f"Available radio options: {[radio.value for radio in radio_options]}") # breakpoint() # # checkbox = next( @@ -192,14 +190,15 @@ def test_view_edit_consultation(client): def find_replace_file_checkbox(page): correct_file_form = page.form.fields['files-1'] checkbox_replace_file = next( - radio for radio in correct_file_form if radio.value == 'replace') + radio for radio in correct_file_form if radio.value == 'replace' + ) return checkbox_replace_file - breakpoint() + # breakpoint() # checkbox_replace_file = next(radio for radio in correct_file_form if # radio.value == 'replace') - breakpoint() + # breakpoint() page.form['files'] = Upload( 'UpdatedTest.txt', b'Updated file ' b'content.' diff --git a/tests/views/client/test_views_meeting.py b/tests/views/client/test_views_meeting.py index 56f66ab..7f4e72f 100644 --- a/tests/views/client/test_views_meeting.py +++ b/tests/views/client/test_views_meeting.py @@ -1,7 +1,6 @@ from datetime import timedelta from sedate import utcnow from privatim.models import User, WorkingGroup, Meeting -from sqlalchemy import select from privatim.utils import fix_utc_to_local_time @@ -18,12 +17,12 @@ def test_view_edit_meeting(client): for user in users: user.set_password('test') client.db.add(user) - client.db.flush() + client.db.commit() working_group = WorkingGroup(name='Test Group', leader=users[0]) working_group.users.extend(users) client.db.add(working_group) - client.db.flush() + client.db.commit() meeting_time = fix_utc_to_local_time(utcnow()) # Create a meeting iwth Max and Alexa @@ -34,13 +33,12 @@ def test_view_edit_meeting(client): working_group=working_group, ) client.db.add(meeting) - client.db.flush() + client.db.commit() client.db.refresh(meeting) client.login_admin() page = client.get(f'/meetings/{meeting.id}/edit') - assert page.status_code == 200 def get_attendees(page, field='attendees'): @@ -79,7 +77,7 @@ def get_attendees(page, field='attendees'): working_group=working_group, ) client.db.add(dest_meeting) - client.db.flush() + client.db.commit() page = client.get(f'/meetings/{meeting.id}/add') page.form['title'] = 'my title' diff --git a/tests/views/client/test_views_working_group.py b/tests/views/client/test_views_working_group.py index 53e37de..93dc05c 100644 --- a/tests/views/client/test_views_working_group.py +++ b/tests/views/client/test_views_working_group.py @@ -21,7 +21,8 @@ def test_view_add_working_group(client): user.set_password('test') client.db.add(user) - client.db.flush() + client.db.commit() + client.login_admin() page = client.get('/working_groups/add') assert page.status_code == 200 @@ -38,7 +39,7 @@ def test_view_add_working_group(client): u = User(email='a@vivaldi.org', first_name='Vintonio', last_name='Avaldi') client.db.add(u) - client.db.flush() + client.db.commit() page = client.get('/working_groups/add') page.form['name'] = 'Test Group2' @@ -76,7 +77,7 @@ def test_view_add_working_group_with_meeting_and_leader(client): for user in users: user.set_password('test') client.db.add(user) - client.db.flush() + client.db.commit() client.login_admin() page = client.get('/working_groups/add') @@ -135,7 +136,7 @@ def test_view_delete_working_group_with_meetings(client): for user in users: user.set_password('test') client.db.add(user) - client.db.flush() + client.db.commit() client.login_admin() page = client.get('/working_groups/add')