From 0295da717f55b1e4abdea0cffd33e66b96af949e Mon Sep 17 00:00:00 2001 From: Daniel Grams Date: Sun, 15 Aug 2021 19:06:27 +0200 Subject: [PATCH] Introduce draft for events #265 --- .vscode/settings.json | 3 + cypress/integration/event.js | 37 +- messages.pot | 326 +++++++++-------- migrations/versions/6893de0cb15b_.py | 35 ++ project/__init__.py | 1 - project/access.py | 26 +- project/api/event/resources.py | 43 ++- project/api/event/schemas.py | 7 + project/api/event_date/resources.py | 20 +- project/api/organization/resources.py | 26 +- project/api/organizer/resources.py | 6 +- project/api/place/resources.py | 6 +- project/cli/dump.py | 7 +- project/cli/seo.py | 3 +- project/forms/event.py | 18 +- project/models.py | 11 + project/services/event.py | 19 + project/services/event_search.py | 1 + project/templates/_macros.html | 8 +- project/templates/event/create.html | 5 +- project/templates/event/update.html | 1 + .../translations/de/LC_MESSAGES/messages.mo | Bin 28633 -> 29082 bytes .../translations/de/LC_MESSAGES/messages.po | 336 ++++++++++-------- .../translations/en/LC_MESSAGES/messages.mo | Bin 3225 -> 3225 bytes .../translations/en/LC_MESSAGES/messages.po | 332 +++++++++-------- project/views/api.py | 44 --- project/views/event.py | 11 +- project/views/event_date.py | 3 + project/views/manage.py | 1 + project/views/widget.py | 3 +- tests/api/test_event.py | 52 ++- tests/api/test_event_date.py | 24 +- tests/api/test_organization.py | 47 ++- tests/seeder.py | 23 +- tests/test___init__.py | 38 ++ tests/utils.py | 10 + tests/views/test_api.py | 38 -- tests/views/test_event.py | 20 +- tests/views/test_event_date.py | 20 +- tests/views/test_manage.py | 6 + tests/views/test_oauth2_token.py | 2 + tests/views/test_widget.py | 20 +- 42 files changed, 1041 insertions(+), 598 deletions(-) create mode 100644 migrations/versions/6893de0cb15b_.py delete mode 100644 project/views/api.py delete mode 100644 tests/views/test_api.py diff --git a/.vscode/settings.json b/.vscode/settings.json index e945e3c..3a68692 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,8 @@ }, "[yaml]": { "editor.formatOnSave": false + }, + "[sql]": { + "editor.formatOnSave": false } } \ No newline at end of file diff --git a/cypress/integration/event.js b/cypress/integration/event.js index 1a32b3b..a91ec84 100644 --- a/cypress/integration/event.js +++ b/cypress/integration/event.js @@ -22,7 +22,7 @@ describe("Event", () => { cy.url().should("include", "/actions"); cy.get("div.alert").should( "contain", - "Veranstaltung erfolgreich erstellt" + "Veranstaltung erfolgreich veröffentlicht" ); cy.contains("a", "Veranstaltung bearbeiten").click(); @@ -40,4 +40,39 @@ describe("Event", () => { }); }); }); + + it("saves draft", () => { + cy.login(); + cy.createAdminUnit().then(function (adminUnitId) { + cy.visit("/admin_unit/" + adminUnitId + "/events/create"); + + cy.get("#name").type("Stadtfest"); + cy.select2("event_place_id", "Gos", "Goslar, 38640 Goslar"); + cy.select2("organizer_id", "Mei", "Meine Crew"); + + cy.get("#submit_draft").click(); + cy.url().should("include", "/actions"); + cy.get("div.alert").should( + "contain", + "Entwurf erfolgreich gespeichert" + ); + + cy.contains("a", "Veranstaltung bearbeiten").click(); + cy.url().should("include", "/update"); + cy.get("#public_status").should('have.value', '1') + cy.get("#submit").click(); + cy.url().should( + "include", + "/manage/admin_unit/" + adminUnitId + "/events" + ); + cy.get("div.alert").should( + "contain", + "Veranstaltung erfolgreich aktualisiert" + ); + + cy.visit("/manage/admin_unit/" + adminUnitId + "/events"); + cy.get('main .badge-pill').should('contain', 'Entwurf') + }); + }); + }); diff --git a/messages.pot b/messages.pot index 2cfd936..2cf03dc 100644 --- a/messages.pot +++ b/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-12 23:45+0200\n" +"POT-Creation-Date: 2021-08-15 14:50+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -175,7 +175,7 @@ msgstr "" msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1322 +#: project/forms/admin.py:12 project/templates/_macros.html:1328 #: project/templates/layout.html:339 #: project/templates/widget/event_suggestion/create.html:199 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -246,8 +246,8 @@ msgstr "" msgid "Longitude" msgstr "" -#: project/forms/admin_unit.py:28 project/forms/event.py:35 -#: project/forms/event.py:64 project/forms/event.py:359 +#: project/forms/admin_unit.py:28 project/forms/event.py:36 +#: project/forms/event.py:65 project/forms/event.py:375 #: project/forms/event_place.py:25 project/forms/event_place.py:50 #: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66 #: project/forms/organizer.py:25 project/forms/organizer.py:52 @@ -268,32 +268,32 @@ msgstr "" msgid "The short name is used to create a unique identifier for your events" msgstr "" -#: project/forms/admin_unit.py:40 project/templates/_macros.html:1452 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1458 msgid "Short name must contain only letters numbers or underscore" msgstr "" -#: project/forms/admin_unit.py:46 project/forms/event.py:56 -#: project/forms/event.py:90 project/forms/event_place.py:26 +#: project/forms/admin_unit.py:46 project/forms/event.py:57 +#: project/forms/event.py:91 project/forms/event_place.py:26 #: project/forms/organizer.py:26 msgid "Link URL" msgstr "" #: project/forms/admin_unit.py:47 project/forms/admin_unit_member.py:11 #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 -#: project/forms/event.py:57 project/forms/event_suggestion.py:38 +#: project/forms/event.py:58 project/forms/event_suggestion.py:38 #: project/forms/organizer.py:27 project/templates/_macros.html:262 -#: project/templates/_macros.html:1412 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1418 project/templates/admin/users.html:19 msgid "Email" msgstr "" -#: project/forms/admin_unit.py:48 project/forms/event.py:58 +#: project/forms/admin_unit.py:48 project/forms/event.py:59 #: project/forms/event_suggestion.py:31 project/forms/organizer.py:28 -#: project/templates/_macros.html:305 +#: project/templates/_macros.html:311 msgid "Phone" msgstr "" -#: project/forms/admin_unit.py:49 project/forms/event.py:59 -#: project/forms/organizer.py:29 project/templates/_macros.html:313 +#: project/forms/admin_unit.py:49 project/forms/event.py:60 +#: project/forms/organizer.py:29 project/templates/_macros.html:319 msgid "Fax" msgstr "" @@ -432,230 +432,230 @@ msgstr "" msgid "100 km" msgstr "" -#: project/forms/event.py:53 +#: project/forms/event.py:54 msgid "Organizator" msgstr "" -#: project/forms/event.py:66 +#: project/forms/event.py:67 msgid "Enter a short, meaningful name for the event." msgstr "" -#: project/forms/event.py:69 +#: project/forms/event.py:70 msgid "Start" msgstr "" -#: project/forms/event.py:71 +#: project/forms/event.py:72 msgid "Indicate when the event will take place." msgstr "" -#: project/forms/event.py:74 +#: project/forms/event.py:75 msgid "End" msgstr "" -#: project/forms/event.py:76 +#: project/forms/event.py:77 msgid "Indicate when the event will end. An event can last a maximum of 14 days." msgstr "" -#: project/forms/event.py:81 project/templates/event/create.html:244 +#: project/forms/event.py:82 project/templates/event/create.html:244 #: project/templates/event/update.html:135 #: project/templates/widget/event_suggestion/create.html:234 msgid "Recurring event" msgstr "" -#: project/forms/event.py:85 project/forms/event_place.py:28 +#: project/forms/event.py:86 project/forms/event_place.py:28 msgid "Description" msgstr "" -#: project/forms/event.py:87 +#: project/forms/event.py:88 msgid "Add an description of the event." msgstr "" -#: project/forms/event.py:92 +#: project/forms/event.py:93 msgid "" "Enter a link to an external website containing more information about the" " event." msgstr "" -#: project/forms/event.py:97 +#: project/forms/event.py:98 msgid "Ticket Link URL" msgstr "" -#: project/forms/event.py:99 +#: project/forms/event.py:100 msgid "Enter a link where tickets can be purchased." msgstr "" -#: project/forms/event.py:102 project/templates/_macros.html:244 +#: project/forms/event.py:103 project/templates/_macros.html:244 msgid "Tags" msgstr "" -#: project/forms/event.py:104 +#: project/forms/event.py:105 msgid "" "Enter keywords with which the event should be found. Words do not need to" " be entered if they are already in the name or description." msgstr "" -#: project/forms/event.py:109 +#: project/forms/event.py:110 msgid "Kid friendly" msgstr "" -#: project/forms/event.py:111 +#: project/forms/event.py:112 msgid "If the event is particularly suitable for children." msgstr "" -#: project/forms/event.py:114 +#: project/forms/event.py:115 msgid "Accessible for free" msgstr "" -#: project/forms/event.py:116 +#: project/forms/event.py:117 msgid "If the event is accessible for free." msgstr "" -#: project/forms/event.py:119 +#: project/forms/event.py:120 msgid "Typical Age from" msgstr "" -#: project/forms/event.py:121 +#: project/forms/event.py:122 msgid "The minimum age that participants should be." msgstr "" -#: project/forms/event.py:124 +#: project/forms/event.py:125 msgid "Typical Age to" msgstr "" -#: project/forms/event.py:126 +#: project/forms/event.py:127 msgid "The maximum age that participants should be." msgstr "" -#: project/forms/event.py:129 +#: project/forms/event.py:130 msgid "Registration required" msgstr "" -#: project/forms/event.py:131 +#: project/forms/event.py:132 msgid "If the participants needs to register for the event." msgstr "" -#: project/forms/event.py:136 project/templates/_macros.html:276 +#: project/forms/event.py:137 project/templates/_macros.html:276 #: project/templates/layout.html:159 msgid "Booked up" msgstr "" -#: project/forms/event.py:138 +#: project/forms/event.py:139 msgid "If the event is booked up or sold out." msgstr "" -#: project/forms/event.py:141 +#: project/forms/event.py:142 msgid "Expected number of participants" msgstr "" -#: project/forms/event.py:143 +#: project/forms/event.py:144 msgid "The estimated expected attendance." msgstr "" -#: project/forms/event.py:146 +#: project/forms/event.py:147 msgid "Price info" msgstr "" -#: project/forms/event.py:148 +#: project/forms/event.py:149 msgid "" "Enter price information in textual form. E.g., different prices for " "adults and children." msgstr "" -#: project/forms/event.py:153 +#: project/forms/event.py:154 msgid "Target group origin" msgstr "" -#: project/forms/event.py:158 +#: project/forms/event.py:159 msgid "EventTargetGroupOrigin.both" msgstr "" -#: project/forms/event.py:162 +#: project/forms/event.py:163 msgid "EventTargetGroupOrigin.tourist" msgstr "" -#: project/forms/event.py:166 +#: project/forms/event.py:167 msgid "EventTargetGroupOrigin.resident" msgstr "" -#: project/forms/event.py:169 +#: project/forms/event.py:170 msgid "" "Choose whether the event is particularly suitable for tourists or " "residents." msgstr "" -#: project/forms/event.py:174 +#: project/forms/event.py:175 msgid "Attendance mode" msgstr "" -#: project/forms/event.py:179 +#: project/forms/event.py:180 msgid "EventAttendanceMode.offline" msgstr "" -#: project/forms/event.py:183 project/templates/layout.html:147 +#: project/forms/event.py:184 project/templates/layout.html:147 msgid "EventAttendanceMode.online" msgstr "" -#: project/forms/event.py:185 project/templates/layout.html:150 +#: project/forms/event.py:186 project/templates/layout.html:150 msgid "EventAttendanceMode.mixed" msgstr "" -#: project/forms/event.py:187 +#: project/forms/event.py:188 msgid "Choose how people can attend the event." msgstr "" -#: project/forms/event.py:191 project/forms/event_place.py:27 +#: project/forms/event.py:192 project/forms/event_place.py:27 #: project/templates/widget/event_suggestion/create.html:252 msgid "Photo" msgstr "" -#: project/forms/event.py:193 +#: project/forms/event.py:194 msgid "" "We recommend uploading a photo for the event. It looks a lot more, but of" " course it works without it." msgstr "" -#: project/forms/event.py:203 project/templates/_macros.html:1193 +#: project/forms/event.py:204 project/templates/_macros.html:1199 msgid "The start must be before the end." msgstr "" -#: project/forms/event.py:209 project/templates/_macros.html:1210 +#: project/forms/event.py:210 project/templates/_macros.html:1216 msgid "An event can last a maximum of 14 days." msgstr "" -#: project/forms/event.py:217 project/templates/_macros.html:423 -#: project/templates/_macros.html:582 +#: project/forms/event.py:218 project/templates/_macros.html:429 +#: project/templates/_macros.html:588 msgid "Previous start date" msgstr "" -#: project/forms/event.py:219 +#: project/forms/event.py:220 msgid "Enter when the event should have taken place before it was postponed." msgstr "" -#: project/forms/event.py:224 project/forms/event_suggestion.py:71 +#: project/forms/event.py:225 project/forms/event_suggestion.py:71 msgid "Categories" msgstr "" -#: project/forms/event.py:227 project/forms/event_suggestion.py:74 +#: project/forms/event.py:228 project/forms/event_suggestion.py:74 msgid "Choose categories that fit the event." msgstr "" -#: project/forms/event.py:230 project/forms/reference.py:14 +#: project/forms/event.py:231 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:75 #: project/templates/event/create.html:358 #: project/templates/event/update.html:214 msgid "Rating" msgstr "" -#: project/forms/event.py:234 project/forms/reference.py:18 +#: project/forms/event.py:235 project/forms/reference.py:18 #: project/forms/reference.py:31 project/forms/reference_request.py:79 msgid "" "Choose how relevant the event is to your organization. The value is not " "visible and is used for sorting." msgstr "" -#: project/forms/event.py:242 project/forms/event.py:251 -#: project/forms/event.py:315 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:462 project/templates/_macros.html:618 +#: project/forms/event.py:243 project/forms/event.py:252 +#: project/forms/event.py:321 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:468 project/templates/_macros.html:624 #: project/templates/event/create.html:283 #: project/templates/event/update.html:164 #: project/templates/event_place/create.html:21 @@ -664,18 +664,18 @@ msgstr "" msgid "Place" msgstr "" -#: project/forms/event.py:244 +#: project/forms/event.py:245 msgid "Select existing place" msgstr "" -#: project/forms/event.py:245 +#: project/forms/event.py:246 msgid "Enter new place" msgstr "" -#: project/forms/event.py:258 project/forms/event.py:267 -#: project/forms/event.py:323 project/forms/event.py:373 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:500 -#: project/templates/_macros.html:655 project/templates/event/create.html:254 +#: project/forms/event.py:259 project/forms/event.py:268 +#: project/forms/event.py:329 project/forms/event.py:389 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:506 +#: project/templates/_macros.html:661 project/templates/event/create.html:254 #: project/templates/event/update.html:155 #: project/templates/organizer/create.html:17 #: project/templates/organizer/delete.html:13 @@ -683,110 +683,127 @@ msgstr "" msgid "Organizer" msgstr "" -#: project/forms/event.py:260 +#: project/forms/event.py:261 msgid "Select existing organizer" msgstr "" -#: project/forms/event.py:261 +#: project/forms/event.py:262 msgid "Enter new organizer" msgstr "" -#: project/forms/event.py:273 project/templates/event/create.html:4 -#: project/templates/event/create.html:221 project/templates/layout.html:256 -#: project/templates/manage/events.html:12 -#: project/templates/manage/organizers.html:21 -msgid "Create event" +#: project/forms/event.py:274 +msgid "Save as draft" msgstr "" -#: project/forms/event.py:299 +#: project/forms/event.py:275 +msgid "Publish event" +msgstr "" + +#: project/forms/event.py:305 msgid "Select existing place or enter new place" msgstr "" -#: project/forms/event.py:306 +#: project/forms/event.py:312 msgid "Select existing organizer or enter new organizer" msgstr "" -#: project/forms/event.py:318 +#: project/forms/event.py:324 msgid "" "Choose where the event takes place. You can add and modify places at " "Manage > Places." msgstr "" -#: project/forms/event.py:326 +#: project/forms/event.py:332 msgid "" "Select the organizer. You can add and modify organizers at Manage > " "Organizers." msgstr "" -#: project/forms/event.py:332 project/templates/event/update.html:145 +#: project/forms/event.py:338 project/templates/event/update.html:145 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "" -#: project/forms/event.py:335 +#: project/forms/event.py:341 msgid "EventStatus.scheduled" msgstr "" -#: project/forms/event.py:336 project/templates/layout.html:113 +#: project/forms/event.py:342 project/templates/layout.html:113 #: project/templates/layout.html:128 msgid "EventStatus.cancelled" msgstr "" -#: project/forms/event.py:337 project/templates/layout.html:116 +#: project/forms/event.py:343 project/templates/layout.html:116 #: project/templates/layout.html:131 msgid "EventStatus.movedOnline" msgstr "" -#: project/forms/event.py:338 project/templates/layout.html:119 +#: project/forms/event.py:344 project/templates/layout.html:119 #: project/templates/layout.html:134 msgid "EventStatus.postponed" msgstr "" -#: project/forms/event.py:339 project/templates/layout.html:122 +#: project/forms/event.py:345 project/templates/layout.html:122 #: project/templates/layout.html:137 msgid "EventStatus.rescheduled" msgstr "" -#: project/forms/event.py:341 +#: project/forms/event.py:347 msgid "Select the status of the event." msgstr "" -#: project/forms/event.py:344 project/templates/event/update.html:4 +#: project/forms/event.py:351 +msgid "Public status" +msgstr "" + +#: project/forms/event.py:354 +msgid "PublicStatus.published" +msgstr "" + +#: project/forms/event.py:355 project/templates/_macros.html:282 +msgid "PublicStatus.draft" +msgstr "" + +#: project/forms/event.py:357 +msgid "Select the public status of the event." +msgstr "" + +#: project/forms/event.py:360 project/templates/event/update.html:4 #: project/templates/event/update.html:112 msgid "Update event" msgstr "" -#: project/forms/event.py:358 project/templates/_macros.html:1165 +#: project/forms/event.py:374 project/templates/_macros.html:1171 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "" -#: project/forms/event.py:366 project/forms/event_date.py:15 +#: project/forms/event.py:382 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "" -#: project/forms/event.py:367 project/forms/event_date.py:16 +#: project/forms/event.py:383 project/forms/event_date.py:16 #: project/forms/planing.py:15 msgid "to" msgstr "" -#: project/forms/event.py:368 project/forms/event_date.py:17 +#: project/forms/event.py:384 project/forms/event_date.py:17 msgid "Keyword" msgstr "" -#: project/forms/event.py:370 project/forms/event_date.py:19 -#: project/forms/planing.py:17 project/templates/_macros.html:386 +#: project/forms/event.py:386 project/forms/event_date.py:19 +#: project/forms/planing.py:17 project/templates/_macros.html:392 msgid "Category" msgstr "" -#: project/forms/event.py:376 +#: project/forms/event.py:392 msgid "Find events" msgstr "" #: project/forms/event_date.py:22 project/forms/planing.py:20 -#: project/templates/_macros.html:137 project/templates/_macros.html:320 +#: project/templates/_macros.html:137 project/templates/_macros.html:326 #: project/templates/admin_unit/create.html:29 #: project/templates/admin_unit/update.html:30 #: project/templates/event_place/create.html:30 @@ -926,7 +943,7 @@ msgid "Weekdays" msgstr "" #: project/forms/reference.py:11 project/forms/reference_request.py:15 -#: project/templates/_macros.html:521 project/templates/_macros.html:681 +#: project/templates/_macros.html:527 project/templates/_macros.html:687 #: project/templates/admin_unit/create.html:19 #: project/templates/admin_unit/update.html:20 #: project/templates/layout.html:286 @@ -954,7 +971,7 @@ msgstr "" msgid "Delete request" msgstr "" -#: project/forms/reference_request.py:27 project/templates/_macros.html:1334 +#: project/forms/reference_request.py:27 project/templates/_macros.html:1340 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1016,8 +1033,8 @@ msgstr "" msgid "This field is required." msgstr "" -#: project/templates/_macros.html:134 project/templates/_macros.html:409 -#: project/templates/_macros.html:416 project/templates/_macros.html:861 +#: project/templates/_macros.html:134 project/templates/_macros.html:415 +#: project/templates/_macros.html:422 project/templates/_macros.html:867 msgid "Date" msgstr "" @@ -1037,27 +1054,27 @@ msgstr "" msgid "Link" msgstr "" -#: project/templates/_macros.html:363 +#: project/templates/_macros.html:369 #, python-format msgid "Created at %(created_at)s by %(created_by)s." msgstr "" -#: project/templates/_macros.html:365 +#: project/templates/_macros.html:371 #, python-format msgid "Created at %(created_at)s." msgstr "" -#: project/templates/_macros.html:370 +#: project/templates/_macros.html:376 #, python-format msgid "Last updated at %(updated_at)s by %(updated_by)s." msgstr "" -#: project/templates/_macros.html:372 +#: project/templates/_macros.html:378 #, python-format msgid "Last updated at %(updated_at)s." msgstr "" -#: project/templates/_macros.html:402 project/templates/_macros.html:578 +#: project/templates/_macros.html:408 project/templates/_macros.html:584 #: project/templates/event/actions.html:12 #: project/templates/event/create.html:228 #: project/templates/event/delete.html:13 @@ -1067,45 +1084,45 @@ msgstr "" msgid "Event" msgstr "" -#: project/templates/_macros.html:412 project/templates/_macros.html:564 +#: project/templates/_macros.html:418 project/templates/_macros.html:570 #, python-format msgid "%(count)d event dates" msgstr "" -#: project/templates/_macros.html:445 project/templates/_macros.html:600 -#: project/templates/_macros.html:1397 project/templates/event/actions.html:32 +#: project/templates/_macros.html:451 project/templates/_macros.html:606 +#: project/templates/_macros.html:1403 project/templates/event/actions.html:32 msgid "Share" msgstr "" -#: project/templates/_macros.html:449 project/templates/_macros.html:604 -#: project/templates/_macros.html:1427 +#: project/templates/_macros.html:455 project/templates/_macros.html:610 +#: project/templates/_macros.html:1433 msgid "Add to calendar" msgstr "" -#: project/templates/_macros.html:483 project/templates/_macros.html:637 +#: project/templates/_macros.html:489 project/templates/_macros.html:643 msgid "Show directions" msgstr "" -#: project/templates/_macros.html:488 project/templates/_macros.html:642 +#: project/templates/_macros.html:494 project/templates/_macros.html:648 msgid "The event takes place online." msgstr "" -#: project/templates/_macros.html:490 project/templates/_macros.html:644 +#: project/templates/_macros.html:496 project/templates/_macros.html:650 msgid "The event takes place both offline and online." msgstr "" -#: project/templates/_macros.html:705 project/templates/event_date/list.html:4 +#: project/templates/_macros.html:711 project/templates/event_date/list.html:4 #: project/templates/event_date/list.html:258 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "" -#: project/templates/_macros.html:778 +#: project/templates/_macros.html:784 msgid "Search location on Google" msgstr "" -#: project/templates/_macros.html:811 project/templates/_macros.html:813 +#: project/templates/_macros.html:817 project/templates/_macros.html:819 #: project/templates/event_date/list.html:279 #: project/templates/widget/event_suggestion/create.html:188 #: project/templates/widget/event_suggestion/create.html:213 @@ -1116,12 +1133,12 @@ msgstr "" msgid "Previous" msgstr "" -#: project/templates/_macros.html:815 +#: project/templates/_macros.html:821 #, python-format msgid "Page %(page)d of %(pages)d (%(total)d total)" msgstr "" -#: project/templates/_macros.html:817 project/templates/_macros.html:819 +#: project/templates/_macros.html:823 project/templates/_macros.html:825 #: project/templates/event_date/list.html:281 #: project/templates/widget/event_suggestion/create.html:189 #: project/templates/widget/event_suggestion/create.html:214 @@ -1131,68 +1148,68 @@ msgstr "" msgid "Next" msgstr "" -#: project/templates/_macros.html:884 +#: project/templates/_macros.html:890 msgid "Radius" msgstr "" -#: project/templates/_macros.html:1094 +#: project/templates/_macros.html:1100 msgid "Edit image" msgstr "" -#: project/templates/_macros.html:1115 +#: project/templates/_macros.html:1121 msgid "Close" msgstr "" -#: project/templates/_macros.html:1116 +#: project/templates/_macros.html:1122 msgid "Okay" msgstr "" -#: project/templates/_macros.html:1128 +#: project/templates/_macros.html:1134 msgid "Choose image file" msgstr "" -#: project/templates/_macros.html:1164 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1170 project/templates/event/actions.html:46 msgid "Edit event" msgstr "" -#: project/templates/_macros.html:1167 project/templates/manage/events.html:30 +#: project/templates/_macros.html:1173 project/templates/manage/events.html:30 msgid "More" msgstr "" -#: project/templates/_macros.html:1214 +#: project/templates/_macros.html:1220 msgid "Please enter a valid time, between 00:00 and 23:59." msgstr "" -#: project/templates/_macros.html:1242 +#: project/templates/_macros.html:1248 #, python-format msgid "Just use %(term)s" msgstr "" -#: project/templates/_macros.html:1294 +#: project/templates/_macros.html:1300 msgid "Event suggestion" msgstr "" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Link copied" msgstr "" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Copy link" msgstr "" -#: project/templates/_macros.html:1435 +#: project/templates/_macros.html:1441 msgid "Google calendar" msgstr "" -#: project/templates/_macros.html:1436 +#: project/templates/_macros.html:1442 msgid "Apple calendar" msgstr "" -#: project/templates/_macros.html:1437 +#: project/templates/_macros.html:1443 msgid "Yahoo calendar" msgstr "" -#: project/templates/_macros.html:1438 +#: project/templates/_macros.html:1444 msgid "Other calendar" msgstr "" @@ -1201,7 +1218,7 @@ msgid "Manage" msgstr "" #: project/templates/home.html:29 project/templates/security/login_user.html:35 -#: project/views/widget.py:179 +#: project/views/widget.py:180 msgid "Register for free" msgstr "" @@ -1251,6 +1268,13 @@ msgstr "" msgid "Show events" msgstr "" +#: project/templates/event/create.html:4 +#: project/templates/event/create.html:221 project/templates/layout.html:256 +#: project/templates/manage/events.html:12 +#: project/templates/manage/organizers.html:21 +msgid "Create event" +msgstr "" + #: project/templates/layout.html:258 msgid "Review suggestions" msgstr "" @@ -1725,7 +1749,7 @@ msgstr "" msgid "Organization successfully updated" msgstr "" -#: project/views/admin.py:68 project/views/manage.py:259 +#: project/views/admin.py:68 project/views/manage.py:260 msgid "Settings successfully updated" msgstr "" @@ -1783,23 +1807,27 @@ msgstr "" msgid "Invitation successfully deleted" msgstr "" -#: project/views/event.py:167 -msgid "Event successfully created" +#: project/views/event.py:171 +msgid "Event successfully published" msgstr "" -#: project/views/event.py:207 +#: project/views/event.py:173 +msgid "Draft successfully saved" +msgstr "" + +#: project/views/event.py:216 msgid "Event successfully updated" msgstr "" -#: project/views/event.py:230 project/views/reference.py:162 +#: project/views/event.py:239 project/views/reference.py:162 msgid "Entered name does not match event name" msgstr "" -#: project/views/event.py:236 +#: project/views/event.py:245 msgid "Event successfully deleted" msgstr "" -#: project/views/event.py:383 +#: project/views/event.py:392 msgid "Referenced event changed" msgstr "" @@ -1933,17 +1961,17 @@ msgstr "" msgid "You do not have permission for this action" msgstr "" -#: project/views/widget.py:171 +#: project/views/widget.py:172 msgid "Thank you so much! The event is being verified." msgstr "" -#: project/views/widget.py:175 +#: project/views/widget.py:176 msgid "" "For more options and your own calendar of events, you can register for " "free." msgstr "" -#: project/views/widget.py:238 +#: project/views/widget.py:239 msgid "New event review" msgstr "" diff --git a/migrations/versions/6893de0cb15b_.py b/migrations/versions/6893de0cb15b_.py new file mode 100644 index 0000000..1344e6e --- /dev/null +++ b/migrations/versions/6893de0cb15b_.py @@ -0,0 +1,35 @@ +"""empty message + +Revision ID: 6893de0cb15b +Revises: 1fb9f679defb +Create Date: 2021-08-13 08:28:00.156404 + +""" +import sqlalchemy as sa +import sqlalchemy_utils +from alembic import op + +from project import dbtypes +from project.models import PublicStatus + +# revision identifiers, used by Alembic. +revision = "6893de0cb15b" +down_revision = "1fb9f679defb" +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column( + "event", + sa.Column( + "public_status", + dbtypes.IntegerEnum(PublicStatus), + server_default=str(PublicStatus.published.value), + nullable=False, + ), + ) + + +def downgrade(): + op.drop_column("event", "public_status") diff --git a/project/__init__.py b/project/__init__.py index e9a97f7..4139706 100644 --- a/project/__init__.py +++ b/project/__init__.py @@ -170,7 +170,6 @@ from project.views import ( admin_unit, admin_unit_member, admin_unit_member_invitation, - api, dump, event, event_date, diff --git a/project/access.py b/project/access.py index 9c59c3b..561bb61 100644 --- a/project/access.py +++ b/project/access.py @@ -6,7 +6,7 @@ from flask_security.utils import FsPermNeed from sqlalchemy import and_ from project import app -from project.models import AdminUnit, AdminUnitMember +from project.models import AdminUnit, AdminUnitMember, Event, PublicStatus from project.services.admin_unit import get_member_for_admin_unit_by_user_id @@ -29,8 +29,12 @@ def owner_access_or_401(user_id): abort(401) -def login_api_user_or_401(user): - if not login_user(user): +def login_api_user(token) -> bool: + return token and login_user(token.user) + + +def login_api_user_or_401(token) -> bool: + if not login_api_user(token): abort(401) @@ -175,3 +179,19 @@ def can_create_admin_unit(): return True return has_current_user_role("admin") + + +def can_read_event(event: Event) -> bool: + if event.public_status == PublicStatus.published: + return True + + return has_access(event.admin_unit, "event:read") + + +def can_read_event_or_401(event: Event): + if not can_read_event(event): + abort(401) + + +def can_read_private_events(admin_unit: AdminUnit) -> bool: + return has_access(admin_unit, "event:read") diff --git a/project/api/event/resources.py b/project/api/event/resources.py index c463d11..55f6476 100644 --- a/project/api/event/resources.py +++ b/project/api/event/resources.py @@ -4,7 +4,13 @@ from flask_apispec import doc, marshal_with, use_kwargs from sqlalchemy.orm import lazyload, load_only from project import db -from project.access import access_or_401, login_api_user_or_401 +from project.access import ( + access_or_401, + can_read_event_or_401, + can_read_private_events, + login_api_user, + login_api_user_or_401, +) from project.api import add_api_resource from project.api.event.schemas import ( EventListRequestSchema, @@ -20,7 +26,7 @@ from project.api.event_date.schemas import ( EventDateListResponseSchema, ) from project.api.resources import BaseResource -from project.models import Event, EventDate +from project.models import AdminUnit, Event, EventDate, PublicStatus from project.oauth2 import require_oauth from project.services.event import ( get_event_with_details_or_404, @@ -32,20 +38,36 @@ from project.services.event_search import EventSearchParams from project.views.event import send_referenced_event_changed_mails +def api_can_read_event_or_401(event: Event): + if event.public_status != PublicStatus.published: + login_api_user(current_token) + can_read_event_or_401(event) + + +def api_can_read_private_events(admin_unit: AdminUnit): + login_api_user(current_token) + return can_read_private_events(admin_unit) + + class EventListResource(BaseResource): @doc(summary="List events", tags=["Events"]) @use_kwargs(EventListRequestSchema, location=("query")) @marshal_with(EventListResponseSchema) def get(self, **kwargs): - pagination = Event.query.paginate() + pagination = Event.query.filter( + Event.public_status == PublicStatus.published + ).paginate() return pagination class EventResource(BaseResource): @doc(summary="Get event", tags=["Events"]) @marshal_with(EventSchema) + @require_oauth(optional=True) def get(self, id): - return get_event_with_details_or_404(id) + event = get_event_with_details_or_404(id) + api_can_read_event_or_401(event) + return event @doc( summary="Update event", tags=["Events"], security=[{"oauth2": ["event:write"]}] @@ -54,7 +76,7 @@ class EventResource(BaseResource): @marshal_with(None, 204) @require_oauth("event:write") def put(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) event = Event.query.get_or_404(id) access_or_401(event.admin_unit, "event:update") @@ -73,7 +95,7 @@ class EventResource(BaseResource): @marshal_with(None, 204) @require_oauth("event:write") def patch(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) event = Event.query.get_or_404(id) access_or_401(event.admin_unit, "event:update") @@ -93,7 +115,7 @@ class EventResource(BaseResource): @marshal_with(None, 204) @require_oauth("event:write") def delete(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) event = Event.query.get_or_404(id) access_or_401(event.admin_unit, "event:delete") @@ -107,8 +129,13 @@ class EventDatesResource(BaseResource): @doc(summary="List dates for event", tags=["Events", "Event Dates"]) @use_kwargs(EventDateListRequestSchema, location=("query")) @marshal_with(EventDateListResponseSchema) + @require_oauth(optional=True) def get(self, id): - event = Event.query.options(load_only(Event.id)).get_or_404(id) + event = Event.query.options( + load_only(Event.id, Event.public_status) + ).get_or_404(id) + api_can_read_event_or_401(event) + return ( EventDate.query.options(lazyload(EventDate.event)) .filter(EventDate.event_id == event.id) diff --git a/project/api/event/schemas.py b/project/api/event/schemas.py index 0ae9371..bcd0508 100644 --- a/project/api/event/schemas.py +++ b/project/api/event/schemas.py @@ -34,6 +34,7 @@ from project.models import ( EventAttendanceMode, EventStatus, EventTargetGroupOrigin, + PublicStatus, ) @@ -149,6 +150,11 @@ class EventBaseSchemaMixin(TrackableSchemaMixin): "description": "When the event will end. An event can last a maximum of 14 days. If the event takes place regularly, enter when the first date will end." }, ) + public_status = EnumField( + PublicStatus, + missing=PublicStatus.published, + metadata={"description": "Public status of the event."}, + ) class EventSchema(EventIdSchema, EventBaseSchemaMixin): @@ -186,6 +192,7 @@ class EventSearchItemSchema(EventRefSchema): organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit") categories = fields.List(fields.Nested(EventCategoryRefSchema)) attendance_mode = EnumField(EventAttendanceMode) + public_status = EnumField(PublicStatus) class EventListRequestSchema(PaginationRequestSchema): diff --git a/project/api/event_date/resources.py b/project/api/event_date/resources.py index 419ecc4..571d5cd 100644 --- a/project/api/event_date/resources.py +++ b/project/api/event_date/resources.py @@ -2,6 +2,7 @@ from flask_apispec import doc, marshal_with, use_kwargs from sqlalchemy.orm import defaultload, lazyload from project.api import add_api_resource +from project.api.event.resources import api_can_read_event_or_401 from project.api.event_date.schemas import ( EventDateListRequestSchema, EventDateListResponseSchema, @@ -10,7 +11,8 @@ from project.api.event_date.schemas import ( EventDateSearchResponseSchema, ) from project.api.resources import BaseResource -from project.models import Event, EventDate +from project.models import Event, EventDate, PublicStatus +from project.oauth2 import require_oauth from project.services.event import get_event_dates_query from project.services.event_search import EventSearchParams @@ -20,17 +22,27 @@ class EventDateListResource(BaseResource): @use_kwargs(EventDateListRequestSchema, location=("query")) @marshal_with(EventDateListResponseSchema) def get(self, **kwargs): - pagination = EventDate.query.options(lazyload(EventDate.event)).paginate() + pagination = ( + EventDate.query.join(EventDate.event) + .options(lazyload(EventDate.event)) + .filter(Event.public_status == PublicStatus.published) + .paginate() + ) return pagination class EventDateResource(BaseResource): @doc(summary="Get event date", tags=["Event Dates"]) @marshal_with(EventDateSchema) + @require_oauth(optional=True) def get(self, id): - return EventDate.query.options( - defaultload(EventDate.event).load_only(Event.id, Event.name) + event_date = EventDate.query.options( + defaultload(EventDate.event).load_only( + Event.id, Event.name, Event.public_status + ) ).get_or_404(id) + api_can_read_event_or_401(event_date.event) + return event_date class EventDateSearchResource(BaseResource): diff --git a/project/api/organization/resources.py b/project/api/organization/resources.py index 22b9262..07b64f9 100644 --- a/project/api/organization/resources.py +++ b/project/api/organization/resources.py @@ -1,3 +1,5 @@ +from operator import and_ + from authlib.integrations.flask_oauth2 import current_token from flask_apispec import doc, marshal_with, use_kwargs @@ -8,6 +10,7 @@ from project.access import ( login_api_user_or_401, ) from project.api import add_api_resource +from project.api.event.resources import api_can_read_private_events from project.api.event.schemas import ( EventIdSchema, EventListRequestSchema, @@ -42,7 +45,7 @@ from project.api.place.schemas import ( PlacePostRequestSchema, ) from project.api.resources import BaseResource -from project.models import AdminUnit, Event +from project.models import AdminUnit, Event, PublicStatus from project.oauth2 import require_oauth from project.services.admin_unit import ( get_admin_unit_query, @@ -72,12 +75,14 @@ class OrganizationEventDateSearchResource(BaseResource): ) @use_kwargs(EventDateSearchRequestSchema, location=("query")) @marshal_with(EventDateSearchResponseSchema) + @require_oauth(optional=True) def get(self, id, **kwargs): admin_unit = AdminUnit.query.get_or_404(id) params = EventSearchParams() params.load_from_request() params.admin_unit_id = admin_unit.id + params.can_read_private_events = api_can_read_private_events(admin_unit) pagination = get_event_dates_query(params).paginate() return pagination @@ -87,12 +92,14 @@ class OrganizationEventSearchResource(BaseResource): @doc(summary="Search for events of organization", tags=["Organizations", "Events"]) @use_kwargs(EventSearchRequestSchema, location=("query")) @marshal_with(EventSearchResponseSchema) + @require_oauth(optional=True) def get(self, id, **kwargs): admin_unit = AdminUnit.query.get_or_404(id) params = EventSearchParams() params.load_from_request() params.admin_unit_id = admin_unit.id + params.can_read_private_events = api_can_read_private_events(admin_unit) pagination = get_events_query(params).paginate() return pagination @@ -102,9 +109,18 @@ class OrganizationEventListResource(BaseResource): @doc(summary="List events of organization", tags=["Organizations", "Events"]) @use_kwargs(EventListRequestSchema, location=("query")) @marshal_with(EventListResponseSchema) + @require_oauth(optional=True) def get(self, id, **kwargs): admin_unit = AdminUnit.query.get_or_404(id) - pagination = Event.query.filter(Event.admin_unit_id == admin_unit.id).paginate() + + event_filter = Event.admin_unit_id == admin_unit.id + + if not api_can_read_private_events(admin_unit): + event_filter = and_( + event_filter, Event.public_status == PublicStatus.published + ) + + pagination = Event.query.filter(event_filter).paginate() return pagination @doc( @@ -116,7 +132,7 @@ class OrganizationEventListResource(BaseResource): @marshal_with(EventIdSchema, 201) @require_oauth("event:write") def post(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) admin_unit = get_admin_unit_for_manage_or_404(id) access_or_401(admin_unit, "event:create") @@ -161,7 +177,7 @@ class OrganizationOrganizerListResource(BaseResource): @marshal_with(OrganizerIdSchema, 201) @require_oauth("organizer:write") def post(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) admin_unit = get_admin_unit_for_manage_or_404(id) access_or_401(admin_unit, "organizer:create") @@ -194,7 +210,7 @@ class OrganizationPlaceListResource(BaseResource): @marshal_with(PlaceIdSchema, 201) @require_oauth("place:write") def post(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) admin_unit = get_admin_unit_for_manage_or_404(id) access_or_401(admin_unit, "place:create") diff --git a/project/api/organizer/resources.py b/project/api/organizer/resources.py index 454aadc..b9a7202 100644 --- a/project/api/organizer/resources.py +++ b/project/api/organizer/resources.py @@ -30,7 +30,7 @@ class OrganizerResource(BaseResource): @marshal_with(None, 204) @require_oauth("organizer:write") def put(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) organizer = EventOrganizer.query.get_or_404(id) access_or_401(organizer.adminunit, "organizer:update") @@ -48,7 +48,7 @@ class OrganizerResource(BaseResource): @marshal_with(None, 204) @require_oauth("organizer:write") def patch(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) organizer = EventOrganizer.query.get_or_404(id) access_or_401(organizer.adminunit, "organizer:update") @@ -67,7 +67,7 @@ class OrganizerResource(BaseResource): @marshal_with(None, 204) @require_oauth("organizer:write") def delete(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) organizer = EventOrganizer.query.get_or_404(id) access_or_401(organizer.adminunit, "organizer:delete") diff --git a/project/api/place/resources.py b/project/api/place/resources.py index 316240f..ac8f08c 100644 --- a/project/api/place/resources.py +++ b/project/api/place/resources.py @@ -28,7 +28,7 @@ class PlaceResource(BaseResource): @marshal_with(None, 204) @require_oauth("place:write") def put(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) place = EventPlace.query.get_or_404(id) access_or_401(place.adminunit, "place:update") @@ -42,7 +42,7 @@ class PlaceResource(BaseResource): @marshal_with(None, 204) @require_oauth("place:write") def patch(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) place = EventPlace.query.get_or_404(id) access_or_401(place.adminunit, "place:update") @@ -57,7 +57,7 @@ class PlaceResource(BaseResource): @marshal_with(None, 204) @require_oauth("place:write") def delete(self, id): - login_api_user_or_401(current_token.user) + login_api_user_or_401(current_token) place = EventPlace.query.get_or_404(id) access_or_401(place.adminunit, "place:delete") diff --git a/project/cli/dump.py b/project/cli/dump.py index 35313e4..8e3eb3b 100644 --- a/project/cli/dump.py +++ b/project/cli/dump.py @@ -20,6 +20,7 @@ from project.models import ( EventOrganizer, EventPlace, EventReference, + PublicStatus, ) from project.utils import make_dir @@ -43,7 +44,11 @@ def dump_all(): make_dir(tmp_path) # Events - events = Event.query.options(joinedload(Event.categories)).all() + events = ( + Event.query.options(joinedload(Event.categories)) + .filter(Event.public_status == PublicStatus.published) + .all() + ) dump_items(events, EventDumpSchema(many=True), "events", tmp_path) # Places diff --git a/project/cli/seo.py b/project/cli/seo.py index 47fb7f5..0cd4a84 100644 --- a/project/cli/seo.py +++ b/project/cli/seo.py @@ -10,7 +10,7 @@ from sqlalchemy.orm import load_only from project import app, cache_path, robots_txt_path, sitemap_path from project.dateutils import get_today -from project.models import Event, EventDate +from project.models import Event, EventDate, PublicStatus from project.utils import make_dir seo_cli = AppGroup("seo") @@ -31,6 +31,7 @@ def generate_sitemap(pinggoogle): events = ( Event.query.options(load_only(Event.id, Event.updated_at)) .filter(Event.dates.any(EventDate.start >= today)) + .filter(Event.public_status == PublicStatus.published) .all() ) click.echo(f"Found {len(events)} events") diff --git a/project/forms/event.py b/project/forms/event.py index 056ebd6..832ebf8 100644 --- a/project/forms/event.py +++ b/project/forms/event.py @@ -27,6 +27,7 @@ from project.models import ( EventTargetGroupOrigin, Image, Location, + PublicStatus, ) @@ -270,7 +271,8 @@ class CreateEventForm(BaseEventForm): ) new_organizer = FormField(OrganizerForm, default=lambda: EventOrganizer()) - submit = SubmitField(lazy_gettext("Create event")) + submit_draft = SubmitField(lazy_gettext("Save as draft")) + submit = SubmitField(lazy_gettext("Publish event")) def populate_obj(self, obj): for name, field in self._fields.items(): @@ -290,6 +292,10 @@ class CreateEventForm(BaseEventForm): obj.photo = Image() field.populate_obj(obj, name) + obj.public_status = ( + PublicStatus.published if self.submit.data else PublicStatus.draft + ) + def validate(self): if not super(BaseEventForm, self).validate(): return False @@ -341,6 +347,16 @@ class UpdateEventForm(BaseEventForm): description=lazy_gettext("Select the status of the event."), ) + public_status = SelectField( + lazy_gettext("Public status"), + coerce=int, + choices=[ + (int(PublicStatus.published), lazy_gettext("PublicStatus.published")), + (int(PublicStatus.draft), lazy_gettext("PublicStatus.draft")), + ], + description=lazy_gettext("Select the public status of the event."), + ) + submit = SubmitField(lazy_gettext("Update event")) def populate_obj(self, obj): diff --git a/project/models.py b/project/models.py index 91284e9..a13b1c4 100644 --- a/project/models.py +++ b/project/models.py @@ -469,6 +469,11 @@ class EventReferenceRequestRejectionReason(IntEnum): irrelevant = 4 +class PublicStatus(IntEnum): + draft = 1 + published = 2 + + class EventOrganizer(db.Model, TrackableMixin): __tablename__ = "eventorganizer" __table_args__ = (UniqueConstraint("name", "admin_unit_id"),) @@ -643,6 +648,12 @@ class Event(db.Model, TrackableMixin, EventMixin): categories = relationship("EventCategory", secondary="event_eventcategories") + public_status = Column( + IntegerEnum(PublicStatus), + nullable=False, + default=PublicStatus.published.value, + server_default=str(PublicStatus.published.value), + ) status = Column(IntegerEnum(EventStatus)) previous_start_date = db.Column(db.DateTime(timezone=True), nullable=True) rating = Column(Integer()) diff --git a/project/services/event.py b/project/services/event.py index 27fc4b2..4b2849a 100644 --- a/project/services/event.py +++ b/project/services/event.py @@ -28,6 +28,7 @@ from project.models import ( EventStatus, Image, Location, + PublicStatus, ) from project.utils import get_pending_changes, get_place_str from project.views.utils import truncate @@ -101,6 +102,13 @@ def get_event_dates_query(params): ), ) + if not params.can_read_private_events: + event_filter = and_( + event_filter, Event.public_status == PublicStatus.published + ) + else: + event_filter = and_(event_filter, Event.public_status == PublicStatus.published) + if params.date_from: date_filter = EventDate.start >= params.date_from @@ -251,6 +259,13 @@ def get_events_query(params): if params.admin_unit_id: event_filter = and_(event_filter, Event.admin_unit_id == params.admin_unit_id) + if not params.can_read_private_events: + event_filter = and_( + event_filter, Event.public_status == PublicStatus.published + ) + else: + event_filter = and_(event_filter, Event.public_status == PublicStatus.published) + if params.date_from: date_filter = EventDate.start >= params.date_from @@ -325,6 +340,10 @@ def update_event_dates_with_recurrence_rule(event): def insert_event(event): if not event.status: event.status = EventStatus.scheduled + + if not event.public_status: + event.public_status = PublicStatus.published + update_event_dates_with_recurrence_rule(event) db.session.add(event) diff --git a/project/services/event_search.py b/project/services/event_search.py index 9bdad69..2d4e5d0 100644 --- a/project/services/event_search.py +++ b/project/services/event_search.py @@ -17,6 +17,7 @@ class EventSearchParams(object): self._date_to_str = None self._coordinate = None self.admin_unit_id = None + self.can_read_private_events = None self.keyword = None self.latitude = None self.longitude = None diff --git a/project/templates/_macros.html b/project/templates/_macros.html index 76bc355..5ef583e 100644 --- a/project/templates/_macros.html +++ b/project/templates/_macros.html @@ -277,6 +277,12 @@ {% endif %} {% endmacro %} +{% macro render_public_status_pill(event) %} +{% if event.public_status and event.public_status == 1 %} + {{ _('PublicStatus.draft') }} +{% endif %} +{% endmacro %} + {% macro render_attendance_mode_pill(event) %} {% if event.attendance_mode and event.attendance_mode.value != 1 %} {{ event.attendance_mode | loc_enum }} @@ -284,7 +290,7 @@ {% endmacro %} {% macro render_event_warning_pills(event) %} -{{ render_event_status_pill(event) }} {{ render_booked_up_pill(event) }} {{ render_attendance_mode_pill(event) }} +{{ render_public_status_pill(event) }} {{ render_event_status_pill(event) }} {{ render_booked_up_pill(event) }} {{ render_attendance_mode_pill(event) }} {% endmacro %} {% macro render_event_review_status_pill(event) %} diff --git a/project/templates/event/create.html b/project/templates/event/create.html index ec5ca32..2b8b440 100644 --- a/project/templates/event/create.html +++ b/project/templates/event/create.html @@ -363,7 +363,10 @@ $( function() { {% endif %} - {{ render_field(form.submit) }} +
+ {{ form.submit(class="btn btn-primary m-1")|safe }} + {{ form.submit_draft(class="btn btn-secondary m-1")|safe }} +
diff --git a/project/templates/event/update.html b/project/templates/event/update.html index 96bbd82..ee29be8 100644 --- a/project/templates/event/update.html +++ b/project/templates/event/update.html @@ -145,6 +145,7 @@ {{ _('Status') }}
+ {{ render_field_with_errors(form.public_status, class="autocomplete w-100") }} {{ render_field_with_errors(form.status, class="autocomplete w-100") }} {{ render_field_with_errors(form.previous_start_date) }}
diff --git a/project/translations/de/LC_MESSAGES/messages.mo b/project/translations/de/LC_MESSAGES/messages.mo index 7edab459c37631e31afed457003c48636aa687f6..73157e86d53a6115ecb9f47ba043d98061d4a38c 100644 GIT binary patch delta 7197 zcmY+|3w+P@9>?+DY<4%sX0F@cE^Kn2g{fS!A(t^^q%qrnOvCIV?ci5YA(SSH3gzgg zRO_MJ(Szbtil~r?Bf1bpQlXsldi#Akr{mGX^ZWh&e&5^Y`}zL=e;qs;u7C0uSO)9lK!@yus?DQ4{532$o|sR@?K%=%ZeP_3>3~jN4HQI)w3f46p8u zU8+3_+d8h}#84PRLoaNDkD_+84Yl$;7>S4RMm&k(*uJGVVRvjmeE^2x7}Q1zQSVK` zP^`ifoQs-gJx*qR=OYT*Q3lIwh5d0fmf$GdhJ!JVFePIVDwGQ`4VR)1Uq|&nX!Xm; z&`t{;Y9pDbooAyWIT&3{Jd%P|UX0p#8OETC?Ql6N0^5+yJG(IszegQSAhRk0aj5rF zQT;NIV|ON^7CZ+v@!hBhEow#lHPJE})Nuo9LA9u}+JPGQQ+s~G>gP}kt&`{t9F5vx zW7I|xQ6X=K%B2izABxJ6Jk)|FC%WDlO{GC+H48QHJXEM2LhbMo48)B%3|~U+Fd&IM zzz#Sc$D!UohMMStSvT2B%2>>!y&Y!ZJuU?e@FD6fFJcEwB2!vpF1E!xtiB!<(hspN zeuLWiX;j31Lv19O&WdO>Y9aB+1#mi``rm{)O4m<8NpiP6Sc?kzTgZRTNBq?k&!YyY z*Tx$l4YkmIs7O>`M_h~A&>rl9SCIdl&Z*u;#+dVwymp;U6s{%}Y9Zev(RIQIhmx!v zYQ_D`@u&}?YJ2{m)t|BY+g9I?TJUM)A~>OhkqMnt495N#ru#pXLO2b1sE`$+B2b13 z>0PK0KVZ*S+w*6v{st;%{)u{jpLyJ#pF{P(VuoMi9Z6%X$NWxf3VNZdJ?M=Za2RSq z<1qqDQ4`FxYyW%cXveqGCbR?n3#c+~45Pw~l0W=K6 zamevI8&C`R7`4;S(1%A&Wtw){3Y9y3Faq;Y8<}GD8K}>bIj9IdfRVToJLCF}#9ssL zr$IaY#a{R~Y5|d*yahy~p0_|vl!Dr6XEV>9yQqE(PzzatVYuAtPnds4MPj2msPH~& zg(vKV)2M;Yo4;WL>VKfJKZ@n+c{0|+G}Nu>W{x%IU=;0Zkq=F06YBlFsQ&Iz3L5wX zDl`{RFV^Am%4AfBY@CfFQ4!dS+S!+=YxS)e%)zUkf;zf>s0HMpHkyx(uo_7l*I7zI z$?=xC&3q4a?{}HsnSo@KLK}~YL<;Krz9%YzxyY-|SnP#MQAf4g>K9NO$RLA5bpQKM z(Af^eMwp9Qc`<6|Gf)e3Q4`!_F0tniV?)}XLM>#oweLbL^pN=#)~9~bo?ld*`JIq! zy`9FP2I_(eVU}5B&O`b*PolonK1VI|97f~s7>iNeyid+#)O**Vj(C*Si&5{p=qfbJ zC``oHQP-(?cW(jRF^>9Z)EQ1kMPx2&p^H%wS%cc?)2Il(XzlNyBDWJ2;XSCNJBS+R zNO$6|flt$*om~hbedz6|uU#ya+_0 zHWZIqPzoy9u0-)i+;m`wW-RLBE+d!cTG zO{piKLfixOUN2O{icm*bf_|*TtKa`$P|yxepjLhcmDN8ZH_G`Pweobr&;|RVLRy7w zalN&Fj0x21^yM8)5PkiPg(c zk(!A?IM3P_m`hO$TaHS;cTu7K7&Xpu)NMG0+OU3sx>|7<1x=WSx;7nA6HUNoI2E<9 z1(<>>QAe`{HPCKUzXMo+q1j%pOhNTqh5AAAEC%5VI09eE=KQtN;Qrp1Nki1YEl_9G z-rBocy|2}Wpe7uRMBQ0{b8shWhXV$9XP=L^Q=fb{scmOrvS=5>8AArrFBi6-17>dKqv8euqW;H6OmZ6euJt{JrF%myQ<%WBZ zfre}R4K?8wR1WOL zLf!xU6!@%hGKYHqB$|brsK1Tc@w6OoCyP)6K8{MtS}eldcr&IC_?re}$UxJ8S>R z>KCmZILbTwaMb(tN7?<4r9l(5LMRrrC)WZ6rl4l5NfLt>V)h{2lfJs)LVOFEw zpNCrTLezW@jw1f*_y`U4aUH7uGAf(jM1697it2a(bMrX2=TVV)34Qn`>N>lJtZ*4MVDqt-9H>ZSV?)frrZ^Eb&}@vsdodGN zqZYCs6`3oj_rh=S77&A~H${z`ghax1+ELJT>49Bvg1u0KTKQwBj_XhZKaUFeYp8+V zK`s14Y=x)ndE_|n$l_4r#G6T|Bu>RR-T!O~I@^3y*84FLD=-;XpceQR>RNtpsJ&2#x;D3= zcKSDKUxmtrC$TwhL><}ts7UNbMeYY|gwYedEKfln^(?a(wXypqy59Hx4jQzRAFwfA zHXCxObp&as(C45QHUZmW8ET@{sB60k@4{oK>sMIheOWz#3DloM_1|fJ;Zo25r%)lf zVuty>9mSy9+o2-W4Hd#0P?5++MQ)hsMe?}_NAHpid_EJsD?4y(^cMd*IB2DPEps9bs(b;NrxT=)Om zs|CmT30aZz2kJ-?rg))C$295%$ZrYfe$2S%96%-0kEm=7n(i$i8Fi-Zt)7bt;Vn2H%dP!a)CQa~?`R@W zN6`?wVl#}w9PEwxW&D$}Erm5Sw8Nd)4Sz)~pyLcO9CI)bSInplZ}yLnxblMHN?%1) zVWGdGqPVKG^bTJ|!AyTq?e-9HHkzWQom&6hoz z)b8tXE+izw*STwEMyJ|ceMW{SWKFBQy{f#}=PxgwUOK7VUs5>PH_2a7rh>n`veq{^ zuWrri;mMIR{pIg&E-q${(vsSB!|#k5^zI6)>P?@wRL911ZvM;bg_A2)FPO&ON-L|T wP4fM9FnUj`^-Xv!Fs4swh40Vx{JDbK{e{cxMErN=!pSw0id)u>FRl*z4_}mf`~Uy| delta 6820 zcmYM%2~^fq8prXg?8xEOhKh+OxnLG3q-X@;R-)pHXj(=`%kVvtQ%#K?i7cg& z>X@2krcsuqok~eca{rP{+84rigz4!mW_dfTz_r5RIoo?~f zsTRKP+WN0_{Cl~Da~-jLxN86Z7Z&GSFRI}fh1tlft{B^42}WQ!2H*k=#44*V#a7gx zL4SO~+F$bYxmPK4;lTz}$2}N>2d&}eVlmf-*7Y*5&lTrfXR3jmC9JsmWG`%0q;Wf zpJnxDks;hB)Iz>MW#kwtli#9G6Q7}=$eU3s*J$k_5_@7YDg#BxV%$XRfQwLDQ;W*L z2Gn~Wp!zi;yXJmG1sqOvnz$`0Lve}ZUlS$LppIFnfO1iLH5xVWRC``&^(Cl4pF<7& zDr$x6Q44tomGT`{Z$xd?A=LY)P+M~*(dQK|(VzjZp;8o**OZN8gLF`3C9j4+w?2ebM9-rc+G6xl4 zDQd-2QJI>DT2U1$lTV{oyb?LrZXIeXJ~h8ZoekeF))2+4N_B5k0C(~$7RylsRHFu{ zM+Leam5FnBD@JjowW49z2Oma$+2R7#ss zDfTCPJ#USA-pT5{P-kWk>irSsID0+=)&F7BhuV^7QSZN`cII~*?ZJDf0UJ>h9@Pu@ zPgI8s7>d_XD+%o3U8iu=N~6#Z`=LJ$z*cy>Il|h<;7Ho3q6j4hG-?)Rt5s2j8tm-Ikr{RL@O7nyaa%xy;nup71FBd9&Ugd7v+$3fw2_*`$V z;IhnY)Vy}u2Eb^kx6 z(2j;ZsK~!Tt^6$N^j<}ExMsHG3Mi0JvkgX4k3sdj#p+q8h2&vdEJJ0i(yW!t@7|%n zk2}mS{pAys)IXq`MdO-fYw!F17kf)cc!JEB^$iU=!-LjJVAUU?ysu zC()-ps;8jH-$F(D5o*N;Q7b)$%Fsz`zkZbxU(}%r?(gk+IOE#{sR^GS@VK<71i%L z#$n_j@6dKf&3C7df>M=-dhuS=p3X!*OWZ=#{eB(!Fmr!Ht>_x+8pULL4#N!U^D!4+ z!=ZQ%b*<9}GZ_}5#;w5)==+pH3Wcxm=3b&Q5PZA0q8L;_T~J%q8+B%KPyrWVdz_A1 z$YZFje9E4$MD^cj&p)*K9!%E#KS4ng{*Fp@_z-XJV^Jy2L|$|QP$`>;x~5ZcI?hFX zARR?5;5*b-G@%ahMdSjwW>nzmcX)rGWMePg|9KR;^Pt`y?87e9Z(t5~ByTNo5-w}O zl|l`8nTN_qH}Xxh8-O|+gHRLQjaon{Dxj%WuRvw$LG)*SS7i^X&8Ja&y&RR1ov2jr zLk)Bibqmg*R(uT=upb+)3A>_hOB!mT`%s5(CMvLMOu-uTX>Z=Apn>+HIv&O{Y&pz3 zEYnaOpGQAji~hI)@5N21KwX}<6=A4xqfuMc&D#4|J=^N}dE{Rc7STXfT{TwWZqy2M z^1ZzuhYP4zq5cs08H;h!U0%TNpw7T)yag{{Dn<|Y{<&S6YBchhv_&U_52l##t$(D52MCAkJ{2}7>{WM-c}9s zQ3$4?z$`%xP-<494%M@$!&Z;V%ofz%evUdDM^GtmLXG#UJ#R76TVMogfw9;M6Hx*C z((Q$ORK&%oh-afFT7&^ugPQ0?)ZV{|Q*jIOk>T2p^8RO2jBit4g<9!dcY6z%h8k}H z>M$vsZmHsbH`EJeNdGHSrDFdQ$TR`@$AQvpTZZRvp8 zs?HdSS=bTp#3bGSi4?lhu*6)4Iz0PO9WP@#26N&PFbg&DSPaAmP${oOrM3zq@Xx3T zS78XQwfb9D{{V0P{r?#S4RBBmcpTO7G^*o8tN&_sKkl5~3rF>f#Wt9P>em;Qks+vz zj6$t=GUZ&Dy~8^OHO?yRjB9)px>4AH9qi( zyofi?#&|m$*p~JrjKzMaaSE|L`o>dGgmY1WY(x!k81>>wRK!hI{{gjC&8STL7gI6p zKJRNa6ZL!ss^2`+IF+bz7o*O?Gst^Bw~~S)ug65(X)l~Y?b&(MKv&FW)G5A>%2@3E z-g_CSQ{NwxFb|V)7AnBysB8Hi>bmd7Fx~%i6!iW6GwK@sdh-EMPVfTifGM;OKn*Yn z|B7=_8E94N8G~9t3MznnRKE&)z5-iQUxQlkX6(TH?f`{8_&w_I#Z2^8oPavLDHwxk z7>haB5htKB^C)UB7h@FGqQ=>XgK;bJDeW#{Pt2a=)n}nkE7(Rsd$tSJaX)IHqo|0_ zqxS5&JrA7h?PUaNi{eoI5>b1dhVht*+LA)lR+XYM^9Z)XRg=ko7YdtbNWlH(1ytk_ zW#0GsNK~MYU^G^nt5GT5f(rB)>bf>zcl-r4QPLFeT4v!A>gA~0b$*J^`!xdOGKm#p4^%EZU0Of;f0aR9Y7$5ChN2h?@^1JkjMZ<;sI5LCot zQ7NiMbzFxU_(Rl|e2QK1I2Pb_jKlot-U_E6i+0arIW}W5PMYCu#ZpYA{u~CPZ#xC; z{U?}+`*0}!$J%?(^sd_g)af6KI*c<+pScPHY2S*<)CX4Ig+bK6Fuz1Cwlc<$kv3k%PuRR`h`foK0Pz#)i+N#Co zYHY*&?p+E>>F1b*r%;D0`T_3@^gNThd>ToG;wf3yJ-U5c8wq^td zVG;Jl@pyX#h2<3Pz%|$%zr&swGSB-K%R&V(7xQpA`r+T_H9Qu#BdDP;DZ;<@k3PY* z(^K2kmZrw9U6~r$@J+v9zlJOQ_qS*`Gw@tcP@jZ8nFIUwYdDfq655bIYHUF5vI!xz lUlzyJ))yz&R!s?QXf7TX(NI^m&97nl^xBpUJ<8{W{14A?4~75$ diff --git a/project/translations/de/LC_MESSAGES/messages.po b/project/translations/de/LC_MESSAGES/messages.po index 66947fe..757ccf0 100644 --- a/project/translations/de/LC_MESSAGES/messages.po +++ b/project/translations/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-12 23:45+0200\n" +"POT-Creation-Date: 2021-08-15 14:50+0200\n" "PO-Revision-Date: 2020-06-07 18:51+0200\n" "Last-Translator: FULL NAME \n" "Language: de\n" @@ -176,7 +176,7 @@ msgstr "Nutzungsbedingungen" msgid "Legal notice" msgstr "Impressum" -#: project/forms/admin.py:12 project/templates/_macros.html:1322 +#: project/forms/admin.py:12 project/templates/_macros.html:1328 #: project/templates/layout.html:339 #: project/templates/widget/event_suggestion/create.html:199 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -249,8 +249,8 @@ msgstr "Breitengrad" msgid "Longitude" msgstr "Längengrad" -#: project/forms/admin_unit.py:28 project/forms/event.py:35 -#: project/forms/event.py:64 project/forms/event.py:359 +#: project/forms/admin_unit.py:28 project/forms/event.py:36 +#: project/forms/event.py:65 project/forms/event.py:375 #: project/forms/event_place.py:25 project/forms/event_place.py:50 #: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66 #: project/forms/organizer.py:25 project/forms/organizer.py:52 @@ -274,32 +274,32 @@ msgstr "" "eindeutig zu identifizieren. Der Kurzname darf nur Buchstaben, Nummern " "und Unterstriche enthalten." -#: project/forms/admin_unit.py:40 project/templates/_macros.html:1452 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1458 msgid "Short name must contain only letters numbers or underscore" msgstr "Der Kurzname darf nur Buchstaben, Nummern und Unterstriche enthalten" -#: project/forms/admin_unit.py:46 project/forms/event.py:56 -#: project/forms/event.py:90 project/forms/event_place.py:26 +#: project/forms/admin_unit.py:46 project/forms/event.py:57 +#: project/forms/event.py:91 project/forms/event_place.py:26 #: project/forms/organizer.py:26 msgid "Link URL" msgstr "Link URL" #: project/forms/admin_unit.py:47 project/forms/admin_unit_member.py:11 #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 -#: project/forms/event.py:57 project/forms/event_suggestion.py:38 +#: project/forms/event.py:58 project/forms/event_suggestion.py:38 #: project/forms/organizer.py:27 project/templates/_macros.html:262 -#: project/templates/_macros.html:1412 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1418 project/templates/admin/users.html:19 msgid "Email" msgstr "Email" -#: project/forms/admin_unit.py:48 project/forms/event.py:58 +#: project/forms/admin_unit.py:48 project/forms/event.py:59 #: project/forms/event_suggestion.py:31 project/forms/organizer.py:28 -#: project/templates/_macros.html:305 +#: project/templates/_macros.html:311 msgid "Phone" msgstr "Telefon" -#: project/forms/admin_unit.py:49 project/forms/event.py:59 -#: project/forms/organizer.py:29 project/templates/_macros.html:313 +#: project/forms/admin_unit.py:49 project/forms/event.py:60 +#: project/forms/organizer.py:29 project/templates/_macros.html:319 msgid "Fax" msgstr "Fax" @@ -441,47 +441,47 @@ msgstr "50 km" msgid "100 km" msgstr "100 km" -#: project/forms/event.py:53 +#: project/forms/event.py:54 msgid "Organizator" msgstr "Veranstalter" -#: project/forms/event.py:66 +#: project/forms/event.py:67 msgid "Enter a short, meaningful name for the event." msgstr "Gib einen kurzen, aussagekräftigen Namen für die Veranstaltung ein." -#: project/forms/event.py:69 +#: project/forms/event.py:70 msgid "Start" msgstr "Beginn" -#: project/forms/event.py:71 +#: project/forms/event.py:72 msgid "Indicate when the event will take place." msgstr "Gib an, wann die Veranstaltung stattfindet." -#: project/forms/event.py:74 +#: project/forms/event.py:75 msgid "End" msgstr "Ende" -#: project/forms/event.py:76 +#: project/forms/event.py:77 msgid "Indicate when the event will end. An event can last a maximum of 14 days." msgstr "" "Gib an, wann die Veranstaltung endet. Eine Veranstaltung darf maximal 14 " "Tage dauern." -#: project/forms/event.py:81 project/templates/event/create.html:244 +#: project/forms/event.py:82 project/templates/event/create.html:244 #: project/templates/event/update.html:135 #: project/templates/widget/event_suggestion/create.html:234 msgid "Recurring event" msgstr "Regelmäßige Veranstaltung" -#: project/forms/event.py:85 project/forms/event_place.py:28 +#: project/forms/event.py:86 project/forms/event_place.py:28 msgid "Description" msgstr "Beschreibung" -#: project/forms/event.py:87 +#: project/forms/event.py:88 msgid "Add an description of the event." msgstr "Füge der Veranstaltung eine Beschreibung hinzu." -#: project/forms/event.py:92 +#: project/forms/event.py:93 msgid "" "Enter a link to an external website containing more information about the" " event." @@ -489,19 +489,19 @@ msgstr "" "Gib einen Link zu einer externen Website ein, die weitere Informationen " "zur Veranstaltung enthält." -#: project/forms/event.py:97 +#: project/forms/event.py:98 msgid "Ticket Link URL" msgstr "Ticket Link" -#: project/forms/event.py:99 +#: project/forms/event.py:100 msgid "Enter a link where tickets can be purchased." msgstr "Gib einen Link ein, über den Tickets gekauft werden können." -#: project/forms/event.py:102 project/templates/_macros.html:244 +#: project/forms/event.py:103 project/templates/_macros.html:244 msgid "Tags" msgstr "Stichworte" -#: project/forms/event.py:104 +#: project/forms/event.py:105 msgid "" "Enter keywords with which the event should be found. Words do not need to" " be entered if they are already in the name or description." @@ -510,68 +510,68 @@ msgstr "" "Worte müssen nicht eingegeben werden, wenn sie bereits im Namen oder in " "der Beschreibung enthalten sind." -#: project/forms/event.py:109 +#: project/forms/event.py:110 msgid "Kid friendly" msgstr "Für Kinder geeignet" -#: project/forms/event.py:111 +#: project/forms/event.py:112 msgid "If the event is particularly suitable for children." msgstr "Wenn die Veranstaltung besonders für Kinder geeignet ist." -#: project/forms/event.py:114 +#: project/forms/event.py:115 msgid "Accessible for free" msgstr "Kostenlos zugänglich" -#: project/forms/event.py:116 +#: project/forms/event.py:117 msgid "If the event is accessible for free." msgstr "Wenn die Veranstaltung kostenlos zugänglich ist." -#: project/forms/event.py:119 +#: project/forms/event.py:120 msgid "Typical Age from" msgstr "Typisches Alter von" -#: project/forms/event.py:121 +#: project/forms/event.py:122 msgid "The minimum age that participants should be." msgstr "Das Mindestalter, das die Teilnehmer haben sollten." -#: project/forms/event.py:124 +#: project/forms/event.py:125 msgid "Typical Age to" msgstr "Typisches Alter bis" -#: project/forms/event.py:126 +#: project/forms/event.py:127 msgid "The maximum age that participants should be." msgstr "Das maximale Alter, das die Teilnehmer haben sollten." -#: project/forms/event.py:129 +#: project/forms/event.py:130 msgid "Registration required" msgstr "Anmeldung erforderlich" -#: project/forms/event.py:131 +#: project/forms/event.py:132 msgid "If the participants needs to register for the event." msgstr "Wenn sich die Teilnehmer für die Veranstaltung anmelden müssen." -#: project/forms/event.py:136 project/templates/_macros.html:276 +#: project/forms/event.py:137 project/templates/_macros.html:276 #: project/templates/layout.html:159 msgid "Booked up" msgstr "Ausgebucht" -#: project/forms/event.py:138 +#: project/forms/event.py:139 msgid "If the event is booked up or sold out." msgstr "Wenn die Veranstaltung ausgebucht oder ausverkauft ist." -#: project/forms/event.py:141 +#: project/forms/event.py:142 msgid "Expected number of participants" msgstr "Erwartete Teilnehmerzahl" -#: project/forms/event.py:143 +#: project/forms/event.py:144 msgid "The estimated expected attendance." msgstr "Die geschätzte erwartete Teilnehmerzahl." -#: project/forms/event.py:146 +#: project/forms/event.py:147 msgid "Price info" msgstr "Preisinformation" -#: project/forms/event.py:148 +#: project/forms/event.py:149 msgid "" "Enter price information in textual form. E.g., different prices for " "adults and children." @@ -579,23 +579,23 @@ msgstr "" "Gib die Preisinformationen in Textform ein. Z.B. unterschiedliche Preise " "für Erwachsene und Kinder." -#: project/forms/event.py:153 +#: project/forms/event.py:154 msgid "Target group origin" msgstr "Für Touristen/Einwohner geeignet" -#: project/forms/event.py:158 +#: project/forms/event.py:159 msgid "EventTargetGroupOrigin.both" msgstr "Für Touristen und Einwohner" -#: project/forms/event.py:162 +#: project/forms/event.py:163 msgid "EventTargetGroupOrigin.tourist" msgstr "Hauptsächlich für Touristen" -#: project/forms/event.py:166 +#: project/forms/event.py:167 msgid "EventTargetGroupOrigin.resident" msgstr "Hauptsächlich für Einwohner" -#: project/forms/event.py:169 +#: project/forms/event.py:170 msgid "" "Choose whether the event is particularly suitable for tourists or " "residents." @@ -603,32 +603,32 @@ msgstr "" "Wähle, ob die Veranstaltung besonders für Touristen oder Einwohner " "geeignet ist." -#: project/forms/event.py:174 +#: project/forms/event.py:175 msgid "Attendance mode" msgstr "Teilnahme" -#: project/forms/event.py:179 +#: project/forms/event.py:180 msgid "EventAttendanceMode.offline" msgstr "Präsenzveranstaltung" -#: project/forms/event.py:183 project/templates/layout.html:147 +#: project/forms/event.py:184 project/templates/layout.html:147 msgid "EventAttendanceMode.online" msgstr "Online" -#: project/forms/event.py:185 project/templates/layout.html:150 +#: project/forms/event.py:186 project/templates/layout.html:150 msgid "EventAttendanceMode.mixed" msgstr "Präsenzveranstaltung und online" -#: project/forms/event.py:187 +#: project/forms/event.py:188 msgid "Choose how people can attend the event." msgstr "Wähle aus, wie Personen an der Veranstaltung teilnehmen können." -#: project/forms/event.py:191 project/forms/event_place.py:27 +#: project/forms/event.py:192 project/forms/event_place.py:27 #: project/templates/widget/event_suggestion/create.html:252 msgid "Photo" msgstr "Foto" -#: project/forms/event.py:193 +#: project/forms/event.py:194 msgid "" "We recommend uploading a photo for the event. It looks a lot more, but of" " course it works without it." @@ -636,41 +636,41 @@ msgstr "" "Wir empfehlen dir, ein Foto für die Veranstaltung hochzuladen. Es macht " "schon deutlich mehr her, aber es geht natürlich auch ohne." -#: project/forms/event.py:203 project/templates/_macros.html:1193 +#: project/forms/event.py:204 project/templates/_macros.html:1199 msgid "The start must be before the end." msgstr "Der Start muss vor dem Ende sein." -#: project/forms/event.py:209 project/templates/_macros.html:1210 +#: project/forms/event.py:210 project/templates/_macros.html:1216 msgid "An event can last a maximum of 14 days." msgstr "Eine Veranstaltung darf maximal 14 Tage dauern." -#: project/forms/event.py:217 project/templates/_macros.html:423 -#: project/templates/_macros.html:582 +#: project/forms/event.py:218 project/templates/_macros.html:429 +#: project/templates/_macros.html:588 msgid "Previous start date" msgstr "Vorheriges Startdatum" -#: project/forms/event.py:219 +#: project/forms/event.py:220 msgid "Enter when the event should have taken place before it was postponed." msgstr "" "Gib ein, wann die Veranstaltung hätte stattfinden sollen, bevor sie " "verschoben wurde." -#: project/forms/event.py:224 project/forms/event_suggestion.py:71 +#: project/forms/event.py:225 project/forms/event_suggestion.py:71 msgid "Categories" msgstr "Kategorien" -#: project/forms/event.py:227 project/forms/event_suggestion.py:74 +#: project/forms/event.py:228 project/forms/event_suggestion.py:74 msgid "Choose categories that fit the event." msgstr "Wähle Kategorien, die zur Veranstaltung passen." -#: project/forms/event.py:230 project/forms/reference.py:14 +#: project/forms/event.py:231 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:75 #: project/templates/event/create.html:358 #: project/templates/event/update.html:214 msgid "Rating" msgstr "Bewertung" -#: project/forms/event.py:234 project/forms/reference.py:18 +#: project/forms/event.py:235 project/forms/reference.py:18 #: project/forms/reference.py:31 project/forms/reference_request.py:79 msgid "" "Choose how relevant the event is to your organization. The value is not " @@ -679,9 +679,9 @@ msgstr "" "Wähle aus, wie relevant die Veranstaltung für deine Organisation ist. Der" " Wert ist nicht sichtbar und dient der Sortierung." -#: project/forms/event.py:242 project/forms/event.py:251 -#: project/forms/event.py:315 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:462 project/templates/_macros.html:618 +#: project/forms/event.py:243 project/forms/event.py:252 +#: project/forms/event.py:321 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:468 project/templates/_macros.html:624 #: project/templates/event/create.html:283 #: project/templates/event/update.html:164 #: project/templates/event_place/create.html:21 @@ -690,18 +690,18 @@ msgstr "" msgid "Place" msgstr "Ort" -#: project/forms/event.py:244 +#: project/forms/event.py:245 msgid "Select existing place" msgstr "Vorhandenen Ort auswählen" -#: project/forms/event.py:245 +#: project/forms/event.py:246 msgid "Enter new place" msgstr "Neuen Ort eingeben" -#: project/forms/event.py:258 project/forms/event.py:267 -#: project/forms/event.py:323 project/forms/event.py:373 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:500 -#: project/templates/_macros.html:655 project/templates/event/create.html:254 +#: project/forms/event.py:259 project/forms/event.py:268 +#: project/forms/event.py:329 project/forms/event.py:389 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:506 +#: project/templates/_macros.html:661 project/templates/event/create.html:254 #: project/templates/event/update.html:155 #: project/templates/organizer/create.html:17 #: project/templates/organizer/delete.html:13 @@ -709,30 +709,31 @@ msgstr "Neuen Ort eingeben" msgid "Organizer" msgstr "Veranstalter" -#: project/forms/event.py:260 +#: project/forms/event.py:261 msgid "Select existing organizer" msgstr "Vorhandenen Veranstalter auswählen" -#: project/forms/event.py:261 +#: project/forms/event.py:262 msgid "Enter new organizer" msgstr "Neuen Veranstalter eingeben" -#: project/forms/event.py:273 project/templates/event/create.html:4 -#: project/templates/event/create.html:221 project/templates/layout.html:256 -#: project/templates/manage/events.html:12 -#: project/templates/manage/organizers.html:21 -msgid "Create event" -msgstr "Veranstaltung erstellen" +#: project/forms/event.py:274 +msgid "Save as draft" +msgstr "Als Entwurf speicher" -#: project/forms/event.py:299 +#: project/forms/event.py:275 +msgid "Publish event" +msgstr "Veranstaltung veröffentlichen" + +#: project/forms/event.py:305 msgid "Select existing place or enter new place" msgstr "Existierenden Ort wählen oder neuen Ort eingeben" -#: project/forms/event.py:306 +#: project/forms/event.py:312 msgid "Select existing organizer or enter new organizer" msgstr "Wähle einen vorhandenen Veranstalter oder gib einen neuen Veranstalter ein" -#: project/forms/event.py:318 +#: project/forms/event.py:324 msgid "" "Choose where the event takes place. You can add and modify places at " "Manage > Places." @@ -740,7 +741,7 @@ msgstr "" "Wähle, wo die Veranstaltung stattfindet. Du kannst Orte unter Verwaltung " "> Orte hinzufügen und ändern." -#: project/forms/event.py:326 +#: project/forms/event.py:332 msgid "" "Select the organizer. You can add and modify organizers at Manage > " "Organizers." @@ -748,75 +749,91 @@ msgstr "" "Wähle den Veranstalter. Du kannst Veranstalter unter Verwaltung > " "Veranstalter hinzufügen und ändern." -#: project/forms/event.py:332 project/templates/event/update.html:145 +#: project/forms/event.py:338 project/templates/event/update.html:145 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "Status" -#: project/forms/event.py:335 +#: project/forms/event.py:341 msgid "EventStatus.scheduled" msgstr "Geplant" -#: project/forms/event.py:336 project/templates/layout.html:113 +#: project/forms/event.py:342 project/templates/layout.html:113 #: project/templates/layout.html:128 msgid "EventStatus.cancelled" msgstr "Abgesagt" -#: project/forms/event.py:337 project/templates/layout.html:116 +#: project/forms/event.py:343 project/templates/layout.html:116 #: project/templates/layout.html:131 msgid "EventStatus.movedOnline" msgstr "Online verschoben" -#: project/forms/event.py:338 project/templates/layout.html:119 +#: project/forms/event.py:344 project/templates/layout.html:119 #: project/templates/layout.html:134 msgid "EventStatus.postponed" msgstr "Verschoben" -#: project/forms/event.py:339 project/templates/layout.html:122 +#: project/forms/event.py:345 project/templates/layout.html:122 #: project/templates/layout.html:137 msgid "EventStatus.rescheduled" msgstr "Neu angesetzt" -#: project/forms/event.py:341 +#: project/forms/event.py:347 msgid "Select the status of the event." msgstr "Wähle den Status der Veranstaltung." -#: project/forms/event.py:344 project/templates/event/update.html:4 +#: project/forms/event.py:351 +msgid "Public status" +msgstr "Öffentlicher Status" + +#: project/forms/event.py:354 +msgid "PublicStatus.published" +msgstr "Veröffentlicht" + +#: project/forms/event.py:355 project/templates/_macros.html:282 +msgid "PublicStatus.draft" +msgstr "Entwurf" + +#: project/forms/event.py:357 +msgid "Select the public status of the event." +msgstr "Wähle den öffentlichen Status der Veranstaltung." + +#: project/forms/event.py:360 project/templates/event/update.html:4 #: project/templates/event/update.html:112 msgid "Update event" msgstr "Veranstaltung aktualisieren" -#: project/forms/event.py:358 project/templates/_macros.html:1165 +#: project/forms/event.py:374 project/templates/_macros.html:1171 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "Veranstaltung löschen" -#: project/forms/event.py:366 project/forms/event_date.py:15 +#: project/forms/event.py:382 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "Von" -#: project/forms/event.py:367 project/forms/event_date.py:16 +#: project/forms/event.py:383 project/forms/event_date.py:16 #: project/forms/planing.py:15 msgid "to" msgstr "bis" -#: project/forms/event.py:368 project/forms/event_date.py:17 +#: project/forms/event.py:384 project/forms/event_date.py:17 msgid "Keyword" msgstr "Stichwort" -#: project/forms/event.py:370 project/forms/event_date.py:19 -#: project/forms/planing.py:17 project/templates/_macros.html:386 +#: project/forms/event.py:386 project/forms/event_date.py:19 +#: project/forms/planing.py:17 project/templates/_macros.html:392 msgid "Category" msgstr "Kategorie" -#: project/forms/event.py:376 +#: project/forms/event.py:392 msgid "Find events" msgstr "Veranstaltungen finden" #: project/forms/event_date.py:22 project/forms/planing.py:20 -#: project/templates/_macros.html:137 project/templates/_macros.html:320 +#: project/templates/_macros.html:137 project/templates/_macros.html:326 #: project/templates/admin_unit/create.html:29 #: project/templates/admin_unit/update.html:30 #: project/templates/event_place/create.html:30 @@ -960,7 +977,7 @@ msgid "Weekdays" msgstr "Wochentage" #: project/forms/reference.py:11 project/forms/reference_request.py:15 -#: project/templates/_macros.html:521 project/templates/_macros.html:681 +#: project/templates/_macros.html:527 project/templates/_macros.html:687 #: project/templates/admin_unit/create.html:19 #: project/templates/admin_unit/update.html:20 #: project/templates/layout.html:286 @@ -988,7 +1005,7 @@ msgstr "Anfrage speichern" msgid "Delete request" msgstr "Anfrage löschen" -#: project/forms/reference_request.py:27 project/templates/_macros.html:1334 +#: project/forms/reference_request.py:27 project/templates/_macros.html:1340 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1050,8 +1067,8 @@ msgstr "Ablehnen" msgid "This field is required." msgstr "Dieses Feld ist erforderlich." -#: project/templates/_macros.html:134 project/templates/_macros.html:409 -#: project/templates/_macros.html:416 project/templates/_macros.html:861 +#: project/templates/_macros.html:134 project/templates/_macros.html:415 +#: project/templates/_macros.html:422 project/templates/_macros.html:867 msgid "Date" msgstr "Datum" @@ -1071,27 +1088,27 @@ msgstr "Auf Google Maps anzeigen" msgid "Link" msgstr "Link" -#: project/templates/_macros.html:363 +#: project/templates/_macros.html:369 #, python-format msgid "Created at %(created_at)s by %(created_by)s." msgstr "Erstellt am %(created_at)s von %(created_by)s." -#: project/templates/_macros.html:365 +#: project/templates/_macros.html:371 #, python-format msgid "Created at %(created_at)s." msgstr "Erstellt am %(created_at)s." -#: project/templates/_macros.html:370 +#: project/templates/_macros.html:376 #, python-format msgid "Last updated at %(updated_at)s by %(updated_by)s." msgstr "Zuletzt aktualisiert am %(updated_at)s von %(updated_by)s." -#: project/templates/_macros.html:372 +#: project/templates/_macros.html:378 #, python-format msgid "Last updated at %(updated_at)s." msgstr "Zuletzt aktualisiert am %(updated_at)s." -#: project/templates/_macros.html:402 project/templates/_macros.html:578 +#: project/templates/_macros.html:408 project/templates/_macros.html:584 #: project/templates/event/actions.html:12 #: project/templates/event/create.html:228 #: project/templates/event/delete.html:13 @@ -1101,47 +1118,47 @@ msgstr "Zuletzt aktualisiert am %(updated_at)s." msgid "Event" msgstr "Veranstaltung" -#: project/templates/_macros.html:412 project/templates/_macros.html:564 +#: project/templates/_macros.html:418 project/templates/_macros.html:570 #, python-format msgid "%(count)d event dates" msgstr "%(count)d Termine" -#: project/templates/_macros.html:445 project/templates/_macros.html:600 -#: project/templates/_macros.html:1397 project/templates/event/actions.html:32 +#: project/templates/_macros.html:451 project/templates/_macros.html:606 +#: project/templates/_macros.html:1403 project/templates/event/actions.html:32 msgid "Share" msgstr "Teilen" -#: project/templates/_macros.html:449 project/templates/_macros.html:604 -#: project/templates/_macros.html:1427 +#: project/templates/_macros.html:455 project/templates/_macros.html:610 +#: project/templates/_macros.html:1433 msgid "Add to calendar" msgstr "Zum Kalender" -#: project/templates/_macros.html:483 project/templates/_macros.html:637 +#: project/templates/_macros.html:489 project/templates/_macros.html:643 msgid "Show directions" msgstr "Anreise planen" -#: project/templates/_macros.html:488 project/templates/_macros.html:642 +#: project/templates/_macros.html:494 project/templates/_macros.html:648 msgid "The event takes place online." msgstr "Die Veranstaltung findet online statt." -#: project/templates/_macros.html:490 project/templates/_macros.html:644 +#: project/templates/_macros.html:496 project/templates/_macros.html:650 msgid "The event takes place both offline and online." msgstr "" "Die Veranstaltung findet sowohl als Präsenzveranstaltung als auch online " "statt." -#: project/templates/_macros.html:705 project/templates/event_date/list.html:4 +#: project/templates/_macros.html:711 project/templates/event_date/list.html:4 #: project/templates/event_date/list.html:258 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "Termine" -#: project/templates/_macros.html:778 +#: project/templates/_macros.html:784 msgid "Search location on Google" msgstr "Ort bei Google suchen" -#: project/templates/_macros.html:811 project/templates/_macros.html:813 +#: project/templates/_macros.html:817 project/templates/_macros.html:819 #: project/templates/event_date/list.html:279 #: project/templates/widget/event_suggestion/create.html:188 #: project/templates/widget/event_suggestion/create.html:213 @@ -1152,12 +1169,12 @@ msgstr "Ort bei Google suchen" msgid "Previous" msgstr "Zurück" -#: project/templates/_macros.html:815 +#: project/templates/_macros.html:821 #, python-format msgid "Page %(page)d of %(pages)d (%(total)d total)" msgstr "Seite %(page)d von %(pages)d (%(total)d insgesamt)" -#: project/templates/_macros.html:817 project/templates/_macros.html:819 +#: project/templates/_macros.html:823 project/templates/_macros.html:825 #: project/templates/event_date/list.html:281 #: project/templates/widget/event_suggestion/create.html:189 #: project/templates/widget/event_suggestion/create.html:214 @@ -1167,68 +1184,68 @@ msgstr "Seite %(page)d von %(pages)d (%(total)d insgesamt)" msgid "Next" msgstr "Weiter" -#: project/templates/_macros.html:884 +#: project/templates/_macros.html:890 msgid "Radius" msgstr "Umkreis" -#: project/templates/_macros.html:1094 +#: project/templates/_macros.html:1100 msgid "Edit image" msgstr "Bild bearbeiten" -#: project/templates/_macros.html:1115 +#: project/templates/_macros.html:1121 msgid "Close" msgstr "Schließen" -#: project/templates/_macros.html:1116 +#: project/templates/_macros.html:1122 msgid "Okay" msgstr "OK" -#: project/templates/_macros.html:1128 +#: project/templates/_macros.html:1134 msgid "Choose image file" msgstr "Bild-Datei auswählen" -#: project/templates/_macros.html:1164 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1170 project/templates/event/actions.html:46 msgid "Edit event" msgstr "Veranstaltung bearbeiten" -#: project/templates/_macros.html:1167 project/templates/manage/events.html:30 +#: project/templates/_macros.html:1173 project/templates/manage/events.html:30 msgid "More" msgstr "Mehr" -#: project/templates/_macros.html:1214 +#: project/templates/_macros.html:1220 msgid "Please enter a valid time, between 00:00 and 23:59." msgstr "Bitte gib eine gültige Uhrzeit zwischen 00:00 und 23:59 ein." -#: project/templates/_macros.html:1242 +#: project/templates/_macros.html:1248 #, python-format msgid "Just use %(term)s" msgstr "Verwende einfach %(term)s" -#: project/templates/_macros.html:1294 +#: project/templates/_macros.html:1300 msgid "Event suggestion" msgstr "Veranstaltungsvorschlag" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Link copied" msgstr "Link kopiert" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Copy link" msgstr "Link kopieren" -#: project/templates/_macros.html:1435 +#: project/templates/_macros.html:1441 msgid "Google calendar" msgstr "Google Kalender" -#: project/templates/_macros.html:1436 +#: project/templates/_macros.html:1442 msgid "Apple calendar" msgstr "Apple Kalender" -#: project/templates/_macros.html:1437 +#: project/templates/_macros.html:1443 msgid "Yahoo calendar" msgstr "Yahoo Kalender" -#: project/templates/_macros.html:1438 +#: project/templates/_macros.html:1444 msgid "Other calendar" msgstr "Anderer Kalender" @@ -1237,7 +1254,7 @@ msgid "Manage" msgstr "Verwaltung" #: project/templates/home.html:29 project/templates/security/login_user.html:35 -#: project/views/widget.py:179 +#: project/views/widget.py:180 msgid "Register for free" msgstr "Kostenlos registrieren" @@ -1287,6 +1304,13 @@ msgstr "Ausloggen" msgid "Show events" msgstr "Veranstaltungen anzeigen" +#: project/templates/event/create.html:4 +#: project/templates/event/create.html:221 project/templates/layout.html:256 +#: project/templates/manage/events.html:12 +#: project/templates/manage/organizers.html:21 +msgid "Create event" +msgstr "Veranstaltung erstellen" + #: project/templates/layout.html:258 msgid "Review suggestions" msgstr "Vorschläge prüfen" @@ -1763,7 +1787,7 @@ msgstr "Vorschau" msgid "Organization successfully updated" msgstr "Organisation erfolgreich aktualisiert" -#: project/views/admin.py:68 project/views/manage.py:259 +#: project/views/admin.py:68 project/views/manage.py:260 msgid "Settings successfully updated" msgstr "Einstellungen erfolgreich aktualisiert" @@ -1824,23 +1848,27 @@ msgstr "Die eingegebene Email passt nicht zur Email der Einladung" msgid "Invitation successfully deleted" msgstr "Einladung erfolgreich gelöscht" -#: project/views/event.py:167 -msgid "Event successfully created" -msgstr "Veranstaltung erfolgreich erstellt" +#: project/views/event.py:171 +msgid "Event successfully published" +msgstr "Veranstaltung erfolgreich veröffentlicht" -#: project/views/event.py:207 +#: project/views/event.py:173 +msgid "Draft successfully saved" +msgstr "Entwurf erfolgreich gespeichert" + +#: project/views/event.py:216 msgid "Event successfully updated" msgstr "Veranstaltung erfolgreich aktualisiert" -#: project/views/event.py:230 project/views/reference.py:162 +#: project/views/event.py:239 project/views/reference.py:162 msgid "Entered name does not match event name" msgstr "Der eingegebene Name entspricht nicht dem Namen der Veranstaltung" -#: project/views/event.py:236 +#: project/views/event.py:245 msgid "Event successfully deleted" msgstr "Veranstaltung erfolgreich gelöscht" -#: project/views/event.py:383 +#: project/views/event.py:392 msgid "Referenced event changed" msgstr "Empfohlene Veranstaltung wurde geändert" @@ -1978,11 +2006,11 @@ msgstr "Anzeigen" msgid "You do not have permission for this action" msgstr "Du hast keine Berechtigung für diese Aktion" -#: project/views/widget.py:171 +#: project/views/widget.py:172 msgid "Thank you so much! The event is being verified." msgstr "Vielen Dank! Die Veranstaltung wird geprüft." -#: project/views/widget.py:175 +#: project/views/widget.py:176 msgid "" "For more options and your own calendar of events, you can register for " "free." @@ -1990,7 +2018,7 @@ msgstr "" "Für mehr Optionen und einen eigenen Veranstaltungskalender, kannst du " "dich kostenlos registrieren." -#: project/views/widget.py:238 +#: project/views/widget.py:239 msgid "New event review" msgstr "Neue Veranstaltung zu prüfen" @@ -2019,3 +2047,9 @@ msgstr "Neue Veranstaltung zu prüfen" #~ msgid "Enter if the event takes place regularly." #~ msgstr "Gib an, ob die Veranstaltung regelmäßig stattfindet." +#~ msgid "Event successfully created" +#~ msgstr "Veranstaltung erfolgreich erstellt" + +#~ msgid "Draft" +#~ msgstr "Entwurf" + diff --git a/project/translations/en/LC_MESSAGES/messages.mo b/project/translations/en/LC_MESSAGES/messages.mo index e4ac24f95f0471ac88f5e6083ab97b2318822ddd..5f8283b595282fa9bf6c595f58e5a485b5cf96eb 100644 GIT binary patch delta 20 ccmbO!Ia6}OV-9vx1w#`nQ-jT~IMy=*07wG{w*UYD delta 20 ccmbO!Ia6}OV-9vB1tViC6VuJFIMy=*07v%*xBvhE diff --git a/project/translations/en/LC_MESSAGES/messages.po b/project/translations/en/LC_MESSAGES/messages.po index d9330d7..59eb1aa 100644 --- a/project/translations/en/LC_MESSAGES/messages.po +++ b/project/translations/en/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-12 23:45+0200\n" +"POT-Creation-Date: 2021-08-15 14:50+0200\n" "PO-Revision-Date: 2021-04-30 15:04+0200\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -176,7 +176,7 @@ msgstr "" msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1322 +#: project/forms/admin.py:12 project/templates/_macros.html:1328 #: project/templates/layout.html:339 #: project/templates/widget/event_suggestion/create.html:199 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -247,8 +247,8 @@ msgstr "" msgid "Longitude" msgstr "" -#: project/forms/admin_unit.py:28 project/forms/event.py:35 -#: project/forms/event.py:64 project/forms/event.py:359 +#: project/forms/admin_unit.py:28 project/forms/event.py:36 +#: project/forms/event.py:65 project/forms/event.py:375 #: project/forms/event_place.py:25 project/forms/event_place.py:50 #: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66 #: project/forms/organizer.py:25 project/forms/organizer.py:52 @@ -269,32 +269,32 @@ msgstr "" msgid "The short name is used to create a unique identifier for your events" msgstr "" -#: project/forms/admin_unit.py:40 project/templates/_macros.html:1452 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1458 msgid "Short name must contain only letters numbers or underscore" msgstr "" -#: project/forms/admin_unit.py:46 project/forms/event.py:56 -#: project/forms/event.py:90 project/forms/event_place.py:26 +#: project/forms/admin_unit.py:46 project/forms/event.py:57 +#: project/forms/event.py:91 project/forms/event_place.py:26 #: project/forms/organizer.py:26 msgid "Link URL" msgstr "" #: project/forms/admin_unit.py:47 project/forms/admin_unit_member.py:11 #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 -#: project/forms/event.py:57 project/forms/event_suggestion.py:38 +#: project/forms/event.py:58 project/forms/event_suggestion.py:38 #: project/forms/organizer.py:27 project/templates/_macros.html:262 -#: project/templates/_macros.html:1412 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1418 project/templates/admin/users.html:19 msgid "Email" msgstr "" -#: project/forms/admin_unit.py:48 project/forms/event.py:58 +#: project/forms/admin_unit.py:48 project/forms/event.py:59 #: project/forms/event_suggestion.py:31 project/forms/organizer.py:28 -#: project/templates/_macros.html:305 +#: project/templates/_macros.html:311 msgid "Phone" msgstr "" -#: project/forms/admin_unit.py:49 project/forms/event.py:59 -#: project/forms/organizer.py:29 project/templates/_macros.html:313 +#: project/forms/admin_unit.py:49 project/forms/event.py:60 +#: project/forms/organizer.py:29 project/templates/_macros.html:319 msgid "Fax" msgstr "" @@ -433,230 +433,230 @@ msgstr "" msgid "100 km" msgstr "" -#: project/forms/event.py:53 +#: project/forms/event.py:54 msgid "Organizator" msgstr "" -#: project/forms/event.py:66 +#: project/forms/event.py:67 msgid "Enter a short, meaningful name for the event." msgstr "" -#: project/forms/event.py:69 +#: project/forms/event.py:70 msgid "Start" msgstr "" -#: project/forms/event.py:71 +#: project/forms/event.py:72 msgid "Indicate when the event will take place." msgstr "" -#: project/forms/event.py:74 +#: project/forms/event.py:75 msgid "End" msgstr "" -#: project/forms/event.py:76 +#: project/forms/event.py:77 msgid "Indicate when the event will end. An event can last a maximum of 14 days." msgstr "" -#: project/forms/event.py:81 project/templates/event/create.html:244 +#: project/forms/event.py:82 project/templates/event/create.html:244 #: project/templates/event/update.html:135 #: project/templates/widget/event_suggestion/create.html:234 msgid "Recurring event" msgstr "" -#: project/forms/event.py:85 project/forms/event_place.py:28 +#: project/forms/event.py:86 project/forms/event_place.py:28 msgid "Description" msgstr "" -#: project/forms/event.py:87 +#: project/forms/event.py:88 msgid "Add an description of the event." msgstr "" -#: project/forms/event.py:92 +#: project/forms/event.py:93 msgid "" "Enter a link to an external website containing more information about the" " event." msgstr "" -#: project/forms/event.py:97 +#: project/forms/event.py:98 msgid "Ticket Link URL" msgstr "" -#: project/forms/event.py:99 +#: project/forms/event.py:100 msgid "Enter a link where tickets can be purchased." msgstr "" -#: project/forms/event.py:102 project/templates/_macros.html:244 +#: project/forms/event.py:103 project/templates/_macros.html:244 msgid "Tags" msgstr "" -#: project/forms/event.py:104 +#: project/forms/event.py:105 msgid "" "Enter keywords with which the event should be found. Words do not need to" " be entered if they are already in the name or description." msgstr "" -#: project/forms/event.py:109 +#: project/forms/event.py:110 msgid "Kid friendly" msgstr "" -#: project/forms/event.py:111 +#: project/forms/event.py:112 msgid "If the event is particularly suitable for children." msgstr "" -#: project/forms/event.py:114 +#: project/forms/event.py:115 msgid "Accessible for free" msgstr "" -#: project/forms/event.py:116 +#: project/forms/event.py:117 msgid "If the event is accessible for free." msgstr "" -#: project/forms/event.py:119 +#: project/forms/event.py:120 msgid "Typical Age from" msgstr "" -#: project/forms/event.py:121 +#: project/forms/event.py:122 msgid "The minimum age that participants should be." msgstr "" -#: project/forms/event.py:124 +#: project/forms/event.py:125 msgid "Typical Age to" msgstr "" -#: project/forms/event.py:126 +#: project/forms/event.py:127 msgid "The maximum age that participants should be." msgstr "" -#: project/forms/event.py:129 +#: project/forms/event.py:130 msgid "Registration required" msgstr "" -#: project/forms/event.py:131 +#: project/forms/event.py:132 msgid "If the participants needs to register for the event." msgstr "" -#: project/forms/event.py:136 project/templates/_macros.html:276 +#: project/forms/event.py:137 project/templates/_macros.html:276 #: project/templates/layout.html:159 msgid "Booked up" msgstr "" -#: project/forms/event.py:138 +#: project/forms/event.py:139 msgid "If the event is booked up or sold out." msgstr "" -#: project/forms/event.py:141 +#: project/forms/event.py:142 msgid "Expected number of participants" msgstr "" -#: project/forms/event.py:143 +#: project/forms/event.py:144 msgid "The estimated expected attendance." msgstr "" -#: project/forms/event.py:146 +#: project/forms/event.py:147 msgid "Price info" msgstr "" -#: project/forms/event.py:148 +#: project/forms/event.py:149 msgid "" "Enter price information in textual form. E.g., different prices for " "adults and children." msgstr "" -#: project/forms/event.py:153 +#: project/forms/event.py:154 msgid "Target group origin" msgstr "Suitable for tourists / residents" -#: project/forms/event.py:158 +#: project/forms/event.py:159 msgid "EventTargetGroupOrigin.both" msgstr "For tourists and residents" -#: project/forms/event.py:162 +#: project/forms/event.py:163 msgid "EventTargetGroupOrigin.tourist" msgstr "Mainly for tourists" -#: project/forms/event.py:166 +#: project/forms/event.py:167 msgid "EventTargetGroupOrigin.resident" msgstr "Mainly for residents" -#: project/forms/event.py:169 +#: project/forms/event.py:170 msgid "" "Choose whether the event is particularly suitable for tourists or " "residents." msgstr "" -#: project/forms/event.py:174 +#: project/forms/event.py:175 msgid "Attendance mode" msgstr "" -#: project/forms/event.py:179 +#: project/forms/event.py:180 msgid "EventAttendanceMode.offline" msgstr "Normal (Offline)" -#: project/forms/event.py:183 project/templates/layout.html:147 +#: project/forms/event.py:184 project/templates/layout.html:147 msgid "EventAttendanceMode.online" msgstr "Online" -#: project/forms/event.py:185 project/templates/layout.html:150 +#: project/forms/event.py:186 project/templates/layout.html:150 msgid "EventAttendanceMode.mixed" msgstr "Online and offline" -#: project/forms/event.py:187 +#: project/forms/event.py:188 msgid "Choose how people can attend the event." msgstr "" -#: project/forms/event.py:191 project/forms/event_place.py:27 +#: project/forms/event.py:192 project/forms/event_place.py:27 #: project/templates/widget/event_suggestion/create.html:252 msgid "Photo" msgstr "" -#: project/forms/event.py:193 +#: project/forms/event.py:194 msgid "" "We recommend uploading a photo for the event. It looks a lot more, but of" " course it works without it." msgstr "" -#: project/forms/event.py:203 project/templates/_macros.html:1193 +#: project/forms/event.py:204 project/templates/_macros.html:1199 msgid "The start must be before the end." msgstr "" -#: project/forms/event.py:209 project/templates/_macros.html:1210 +#: project/forms/event.py:210 project/templates/_macros.html:1216 msgid "An event can last a maximum of 14 days." msgstr "" -#: project/forms/event.py:217 project/templates/_macros.html:423 -#: project/templates/_macros.html:582 +#: project/forms/event.py:218 project/templates/_macros.html:429 +#: project/templates/_macros.html:588 msgid "Previous start date" msgstr "" -#: project/forms/event.py:219 +#: project/forms/event.py:220 msgid "Enter when the event should have taken place before it was postponed." msgstr "" -#: project/forms/event.py:224 project/forms/event_suggestion.py:71 +#: project/forms/event.py:225 project/forms/event_suggestion.py:71 msgid "Categories" msgstr "" -#: project/forms/event.py:227 project/forms/event_suggestion.py:74 +#: project/forms/event.py:228 project/forms/event_suggestion.py:74 msgid "Choose categories that fit the event." msgstr "" -#: project/forms/event.py:230 project/forms/reference.py:14 +#: project/forms/event.py:231 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:75 #: project/templates/event/create.html:358 #: project/templates/event/update.html:214 msgid "Rating" msgstr "" -#: project/forms/event.py:234 project/forms/reference.py:18 +#: project/forms/event.py:235 project/forms/reference.py:18 #: project/forms/reference.py:31 project/forms/reference_request.py:79 msgid "" "Choose how relevant the event is to your organization. The value is not " "visible and is used for sorting." msgstr "" -#: project/forms/event.py:242 project/forms/event.py:251 -#: project/forms/event.py:315 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:462 project/templates/_macros.html:618 +#: project/forms/event.py:243 project/forms/event.py:252 +#: project/forms/event.py:321 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:468 project/templates/_macros.html:624 #: project/templates/event/create.html:283 #: project/templates/event/update.html:164 #: project/templates/event_place/create.html:21 @@ -665,18 +665,18 @@ msgstr "" msgid "Place" msgstr "" -#: project/forms/event.py:244 +#: project/forms/event.py:245 msgid "Select existing place" msgstr "" -#: project/forms/event.py:245 +#: project/forms/event.py:246 msgid "Enter new place" msgstr "" -#: project/forms/event.py:258 project/forms/event.py:267 -#: project/forms/event.py:323 project/forms/event.py:373 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:500 -#: project/templates/_macros.html:655 project/templates/event/create.html:254 +#: project/forms/event.py:259 project/forms/event.py:268 +#: project/forms/event.py:329 project/forms/event.py:389 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:506 +#: project/templates/_macros.html:661 project/templates/event/create.html:254 #: project/templates/event/update.html:155 #: project/templates/organizer/create.html:17 #: project/templates/organizer/delete.html:13 @@ -684,110 +684,127 @@ msgstr "" msgid "Organizer" msgstr "" -#: project/forms/event.py:260 +#: project/forms/event.py:261 msgid "Select existing organizer" msgstr "" -#: project/forms/event.py:261 +#: project/forms/event.py:262 msgid "Enter new organizer" msgstr "" -#: project/forms/event.py:273 project/templates/event/create.html:4 -#: project/templates/event/create.html:221 project/templates/layout.html:256 -#: project/templates/manage/events.html:12 -#: project/templates/manage/organizers.html:21 -msgid "Create event" +#: project/forms/event.py:274 +msgid "Save as draft" msgstr "" -#: project/forms/event.py:299 +#: project/forms/event.py:275 +msgid "Publish event" +msgstr "" + +#: project/forms/event.py:305 msgid "Select existing place or enter new place" msgstr "" -#: project/forms/event.py:306 +#: project/forms/event.py:312 msgid "Select existing organizer or enter new organizer" msgstr "" -#: project/forms/event.py:318 +#: project/forms/event.py:324 msgid "" "Choose where the event takes place. You can add and modify places at " "Manage > Places." msgstr "" -#: project/forms/event.py:326 +#: project/forms/event.py:332 msgid "" "Select the organizer. You can add and modify organizers at Manage > " "Organizers." msgstr "" -#: project/forms/event.py:332 project/templates/event/update.html:145 +#: project/forms/event.py:338 project/templates/event/update.html:145 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "" -#: project/forms/event.py:335 +#: project/forms/event.py:341 msgid "EventStatus.scheduled" msgstr "Scheduled" -#: project/forms/event.py:336 project/templates/layout.html:113 +#: project/forms/event.py:342 project/templates/layout.html:113 #: project/templates/layout.html:128 msgid "EventStatus.cancelled" msgstr "Cancelled" -#: project/forms/event.py:337 project/templates/layout.html:116 +#: project/forms/event.py:343 project/templates/layout.html:116 #: project/templates/layout.html:131 msgid "EventStatus.movedOnline" msgstr "Moved online" -#: project/forms/event.py:338 project/templates/layout.html:119 +#: project/forms/event.py:344 project/templates/layout.html:119 #: project/templates/layout.html:134 msgid "EventStatus.postponed" msgstr "Postponed" -#: project/forms/event.py:339 project/templates/layout.html:122 +#: project/forms/event.py:345 project/templates/layout.html:122 #: project/templates/layout.html:137 msgid "EventStatus.rescheduled" msgstr "Rescheduled" -#: project/forms/event.py:341 +#: project/forms/event.py:347 msgid "Select the status of the event." msgstr "" -#: project/forms/event.py:344 project/templates/event/update.html:4 +#: project/forms/event.py:351 +msgid "Public status" +msgstr "" + +#: project/forms/event.py:354 +msgid "PublicStatus.published" +msgstr "" + +#: project/forms/event.py:355 project/templates/_macros.html:282 +msgid "PublicStatus.draft" +msgstr "" + +#: project/forms/event.py:357 +msgid "Select the public status of the event." +msgstr "" + +#: project/forms/event.py:360 project/templates/event/update.html:4 #: project/templates/event/update.html:112 msgid "Update event" msgstr "" -#: project/forms/event.py:358 project/templates/_macros.html:1165 +#: project/forms/event.py:374 project/templates/_macros.html:1171 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "" -#: project/forms/event.py:366 project/forms/event_date.py:15 +#: project/forms/event.py:382 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "" -#: project/forms/event.py:367 project/forms/event_date.py:16 +#: project/forms/event.py:383 project/forms/event_date.py:16 #: project/forms/planing.py:15 msgid "to" msgstr "" -#: project/forms/event.py:368 project/forms/event_date.py:17 +#: project/forms/event.py:384 project/forms/event_date.py:17 msgid "Keyword" msgstr "" -#: project/forms/event.py:370 project/forms/event_date.py:19 -#: project/forms/planing.py:17 project/templates/_macros.html:386 +#: project/forms/event.py:386 project/forms/event_date.py:19 +#: project/forms/planing.py:17 project/templates/_macros.html:392 msgid "Category" msgstr "" -#: project/forms/event.py:376 +#: project/forms/event.py:392 msgid "Find events" msgstr "" #: project/forms/event_date.py:22 project/forms/planing.py:20 -#: project/templates/_macros.html:137 project/templates/_macros.html:320 +#: project/templates/_macros.html:137 project/templates/_macros.html:326 #: project/templates/admin_unit/create.html:29 #: project/templates/admin_unit/update.html:30 #: project/templates/event_place/create.html:30 @@ -927,7 +944,7 @@ msgid "Weekdays" msgstr "" #: project/forms/reference.py:11 project/forms/reference_request.py:15 -#: project/templates/_macros.html:521 project/templates/_macros.html:681 +#: project/templates/_macros.html:527 project/templates/_macros.html:687 #: project/templates/admin_unit/create.html:19 #: project/templates/admin_unit/update.html:20 #: project/templates/layout.html:286 @@ -955,7 +972,7 @@ msgstr "" msgid "Delete request" msgstr "" -#: project/forms/reference_request.py:27 project/templates/_macros.html:1334 +#: project/forms/reference_request.py:27 project/templates/_macros.html:1340 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1017,8 +1034,8 @@ msgstr "" msgid "This field is required." msgstr "" -#: project/templates/_macros.html:134 project/templates/_macros.html:409 -#: project/templates/_macros.html:416 project/templates/_macros.html:861 +#: project/templates/_macros.html:134 project/templates/_macros.html:415 +#: project/templates/_macros.html:422 project/templates/_macros.html:867 msgid "Date" msgstr "" @@ -1038,27 +1055,27 @@ msgstr "" msgid "Link" msgstr "" -#: project/templates/_macros.html:363 +#: project/templates/_macros.html:369 #, python-format msgid "Created at %(created_at)s by %(created_by)s." msgstr "" -#: project/templates/_macros.html:365 +#: project/templates/_macros.html:371 #, python-format msgid "Created at %(created_at)s." msgstr "" -#: project/templates/_macros.html:370 +#: project/templates/_macros.html:376 #, python-format msgid "Last updated at %(updated_at)s by %(updated_by)s." msgstr "" -#: project/templates/_macros.html:372 +#: project/templates/_macros.html:378 #, python-format msgid "Last updated at %(updated_at)s." msgstr "" -#: project/templates/_macros.html:402 project/templates/_macros.html:578 +#: project/templates/_macros.html:408 project/templates/_macros.html:584 #: project/templates/event/actions.html:12 #: project/templates/event/create.html:228 #: project/templates/event/delete.html:13 @@ -1068,45 +1085,45 @@ msgstr "" msgid "Event" msgstr "" -#: project/templates/_macros.html:412 project/templates/_macros.html:564 +#: project/templates/_macros.html:418 project/templates/_macros.html:570 #, python-format msgid "%(count)d event dates" msgstr "" -#: project/templates/_macros.html:445 project/templates/_macros.html:600 -#: project/templates/_macros.html:1397 project/templates/event/actions.html:32 +#: project/templates/_macros.html:451 project/templates/_macros.html:606 +#: project/templates/_macros.html:1403 project/templates/event/actions.html:32 msgid "Share" msgstr "" -#: project/templates/_macros.html:449 project/templates/_macros.html:604 -#: project/templates/_macros.html:1427 +#: project/templates/_macros.html:455 project/templates/_macros.html:610 +#: project/templates/_macros.html:1433 msgid "Add to calendar" msgstr "" -#: project/templates/_macros.html:483 project/templates/_macros.html:637 +#: project/templates/_macros.html:489 project/templates/_macros.html:643 msgid "Show directions" msgstr "" -#: project/templates/_macros.html:488 project/templates/_macros.html:642 +#: project/templates/_macros.html:494 project/templates/_macros.html:648 msgid "The event takes place online." msgstr "" -#: project/templates/_macros.html:490 project/templates/_macros.html:644 +#: project/templates/_macros.html:496 project/templates/_macros.html:650 msgid "The event takes place both offline and online." msgstr "" -#: project/templates/_macros.html:705 project/templates/event_date/list.html:4 +#: project/templates/_macros.html:711 project/templates/event_date/list.html:4 #: project/templates/event_date/list.html:258 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "" -#: project/templates/_macros.html:778 +#: project/templates/_macros.html:784 msgid "Search location on Google" msgstr "" -#: project/templates/_macros.html:811 project/templates/_macros.html:813 +#: project/templates/_macros.html:817 project/templates/_macros.html:819 #: project/templates/event_date/list.html:279 #: project/templates/widget/event_suggestion/create.html:188 #: project/templates/widget/event_suggestion/create.html:213 @@ -1117,12 +1134,12 @@ msgstr "" msgid "Previous" msgstr "" -#: project/templates/_macros.html:815 +#: project/templates/_macros.html:821 #, python-format msgid "Page %(page)d of %(pages)d (%(total)d total)" msgstr "" -#: project/templates/_macros.html:817 project/templates/_macros.html:819 +#: project/templates/_macros.html:823 project/templates/_macros.html:825 #: project/templates/event_date/list.html:281 #: project/templates/widget/event_suggestion/create.html:189 #: project/templates/widget/event_suggestion/create.html:214 @@ -1132,68 +1149,68 @@ msgstr "" msgid "Next" msgstr "" -#: project/templates/_macros.html:884 +#: project/templates/_macros.html:890 msgid "Radius" msgstr "" -#: project/templates/_macros.html:1094 +#: project/templates/_macros.html:1100 msgid "Edit image" msgstr "" -#: project/templates/_macros.html:1115 +#: project/templates/_macros.html:1121 msgid "Close" msgstr "" -#: project/templates/_macros.html:1116 +#: project/templates/_macros.html:1122 msgid "Okay" msgstr "" -#: project/templates/_macros.html:1128 +#: project/templates/_macros.html:1134 msgid "Choose image file" msgstr "" -#: project/templates/_macros.html:1164 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1170 project/templates/event/actions.html:46 msgid "Edit event" msgstr "" -#: project/templates/_macros.html:1167 project/templates/manage/events.html:30 +#: project/templates/_macros.html:1173 project/templates/manage/events.html:30 msgid "More" msgstr "" -#: project/templates/_macros.html:1214 +#: project/templates/_macros.html:1220 msgid "Please enter a valid time, between 00:00 and 23:59." msgstr "" -#: project/templates/_macros.html:1242 +#: project/templates/_macros.html:1248 #, python-format msgid "Just use %(term)s" msgstr "" -#: project/templates/_macros.html:1294 +#: project/templates/_macros.html:1300 msgid "Event suggestion" msgstr "" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Link copied" msgstr "" -#: project/templates/_macros.html:1406 +#: project/templates/_macros.html:1412 msgid "Copy link" msgstr "" -#: project/templates/_macros.html:1435 +#: project/templates/_macros.html:1441 msgid "Google calendar" msgstr "" -#: project/templates/_macros.html:1436 +#: project/templates/_macros.html:1442 msgid "Apple calendar" msgstr "" -#: project/templates/_macros.html:1437 +#: project/templates/_macros.html:1443 msgid "Yahoo calendar" msgstr "" -#: project/templates/_macros.html:1438 +#: project/templates/_macros.html:1444 msgid "Other calendar" msgstr "" @@ -1202,7 +1219,7 @@ msgid "Manage" msgstr "" #: project/templates/home.html:29 project/templates/security/login_user.html:35 -#: project/views/widget.py:179 +#: project/views/widget.py:180 msgid "Register for free" msgstr "" @@ -1252,6 +1269,13 @@ msgstr "" msgid "Show events" msgstr "" +#: project/templates/event/create.html:4 +#: project/templates/event/create.html:221 project/templates/layout.html:256 +#: project/templates/manage/events.html:12 +#: project/templates/manage/organizers.html:21 +msgid "Create event" +msgstr "" + #: project/templates/layout.html:258 msgid "Review suggestions" msgstr "" @@ -1726,7 +1750,7 @@ msgstr "" msgid "Organization successfully updated" msgstr "" -#: project/views/admin.py:68 project/views/manage.py:259 +#: project/views/admin.py:68 project/views/manage.py:260 msgid "Settings successfully updated" msgstr "" @@ -1784,23 +1808,27 @@ msgstr "" msgid "Invitation successfully deleted" msgstr "" -#: project/views/event.py:167 -msgid "Event successfully created" +#: project/views/event.py:171 +msgid "Event successfully published" msgstr "" -#: project/views/event.py:207 +#: project/views/event.py:173 +msgid "Draft successfully saved" +msgstr "" + +#: project/views/event.py:216 msgid "Event successfully updated" msgstr "" -#: project/views/event.py:230 project/views/reference.py:162 +#: project/views/event.py:239 project/views/reference.py:162 msgid "Entered name does not match event name" msgstr "" -#: project/views/event.py:236 +#: project/views/event.py:245 msgid "Event successfully deleted" msgstr "" -#: project/views/event.py:383 +#: project/views/event.py:392 msgid "Referenced event changed" msgstr "" @@ -1934,17 +1962,17 @@ msgstr "" msgid "You do not have permission for this action" msgstr "" -#: project/views/widget.py:171 +#: project/views/widget.py:172 msgid "Thank you so much! The event is being verified." msgstr "" -#: project/views/widget.py:175 +#: project/views/widget.py:176 msgid "" "For more options and your own calendar of events, you can register for " "free." msgstr "" -#: project/views/widget.py:238 +#: project/views/widget.py:239 msgid "New event review" msgstr "" @@ -1968,3 +1996,9 @@ msgstr "" #~ msgid "Enter if the event takes place regularly." #~ msgstr "" +#~ msgid "Event successfully created" +#~ msgstr "" + +#~ msgid "Draft" +#~ msgstr "" + diff --git a/project/views/api.py b/project/views/api.py deleted file mode 100644 index 8428dc9..0000000 --- a/project/views/api.py +++ /dev/null @@ -1,44 +0,0 @@ -from flask import jsonify - -from project import app -from project.dateutils import get_today -from project.jsonld import get_sd_for_event_date -from project.models import Event, EventDate -from project.services.event import get_event_dates_query -from project.services.event_search import EventSearchParams - - -@app.route("/api/events") -def api_events(): - today = today = get_today() - dates = ( - EventDate.query.join(Event) - .filter(EventDate.start >= today) - .order_by(EventDate.start) - .all() - ) - return json_from_event_dates(dates) - - -@app.route("/api/event_dates") -def api_event_dates(): - params = EventSearchParams() - params.load_from_request() - - dates = get_event_dates_query(params).paginate() - return json_from_event_dates(dates.items) - - -def json_from_event_dates(dates): - structured_events = list() - for event_date in dates: - structured_event = get_sd_for_event_date(event_date) - structured_event.pop("@context", None) - structured_events.append(structured_event) - - result = {} - result["@context"] = "https://schema.org" - result["@type"] = "Project" - result["name"] = "Prototyp" - result["event"] = structured_events - return jsonify(result) diff --git a/project/views/event.py b/project/views/event.py index 1d0cd88..4cdd4a4 100644 --- a/project/views/event.py +++ b/project/views/event.py @@ -9,6 +9,7 @@ from sqlalchemy.exc import SQLAlchemyError from project import app, db from project.access import ( access_or_401, + can_read_event_or_401, can_reference_event, can_request_event_reference, has_access, @@ -27,6 +28,7 @@ from project.models import ( EventReference, EventReviewStatus, EventSuggestion, + PublicStatus, User, ) from project.services.event import ( @@ -53,6 +55,7 @@ from project.views.utils import ( @app.route("/event/") def event(event_id): event = get_event_with_details_or_404(event_id) + can_read_event_or_401(event) user_rights = get_menu_user_rights(event) dates = get_upcoming_event_dates(event.id) url = url_for("event", event_id=event_id, _external=True) @@ -80,6 +83,7 @@ def event(event_id): @app.route("/event//actions") def event_actions(event_id): event = Event.query.get_or_404(event_id) + can_read_event_or_401(event) user_rights = get_user_rights(event) url = url_for("event", event_id=event_id, _external=True) share_links = get_share_links(url, event.name) @@ -163,8 +167,13 @@ def event_create_for_admin_unit_id(id): if event_suggestion: send_event_suggestion_review_status_mail(event_suggestion) + success_msg = ( + gettext("Event successfully published") + if event.public_status == PublicStatus.published + else gettext("Draft successfully saved") + ) flash_message( - gettext("Event successfully created"), + success_msg, url_for("event", event_id=event.id), ) return redirect(url_for("event_actions", event_id=event.id)) diff --git a/project/views/event_date.py b/project/views/event_date.py index 18de5c2..4f8c31f 100644 --- a/project/views/event_date.py +++ b/project/views/event_date.py @@ -4,6 +4,7 @@ from flask import redirect, render_template, request, url_for from flask.wrappers import Response from project import app +from project.access import can_read_event_or_401 from project.dateutils import create_icalendar from project.forms.event_date import FindEventDateForm from project.jsonld import DateTimeEncoder, get_sd_for_event_date @@ -52,6 +53,7 @@ def event_date_search(): @app.route("/eventdate/") def event_date(id): event_date = get_event_date_with_details_or_404(id) + can_read_event_or_401(event_date.event) if "src" in request.args: track_analytics("event_date", str(id), request.args["src"]) @@ -81,6 +83,7 @@ def event_date(id): @app.route("/eventdate//ical") def event_date_ical(id): event_date = get_event_date_with_details_or_404(id) + can_read_event_or_401(event_date.event) event = create_ical_event_for_date(event_date) cal = create_icalendar() diff --git a/project/views/manage.py b/project/views/manage.py index fd19ad7..a493c42 100644 --- a/project/views/manage.py +++ b/project/views/manage.py @@ -140,6 +140,7 @@ def manage_admin_unit_events(id): form.populate_obj(params) params.admin_unit_id = admin_unit.id + params.can_read_private_events = True events = get_events_query(params).paginate() return render_template( "manage/events.html", diff --git a/project/views/widget.py b/project/views/widget.py index 83fcee1..db53176 100644 --- a/project/views/widget.py +++ b/project/views/widget.py @@ -7,7 +7,7 @@ from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.sql import func from project import app, db -from project.access import has_admin_unit_member_permission +from project.access import can_read_event_or_401, has_admin_unit_member_permission from project.dateutils import get_next_full_hour from project.forms.event_date import FindEventDateForm from project.forms.event_suggestion import CreateEventSuggestionForm @@ -75,6 +75,7 @@ def widget_event_date(au_short_name, id): AdminUnit.short_name == au_short_name ).first_or_404() event_date = get_event_date_with_details_or_404(id) + can_read_event_or_401(event_date.event) structured_data = json.dumps( get_sd_for_event_date(event_date), indent=2, cls=DateTimeEncoder ) diff --git a/tests/api/test_event.py b/tests/api/test_event.py index 7a013f1..baa6d88 100644 --- a/tests/api/test_event.py +++ b/tests/api/test_event.py @@ -1,5 +1,7 @@ import base64 +from project.models import PublicStatus + def test_read(client, app, db, seeder, utils): user_id, admin_unit_id = seeder.setup_base() @@ -20,12 +22,34 @@ def test_read(client, app, db, seeder, utils): assert response.json["status"] == "scheduled" +def test_read_otherDraft(client, app, db, seeder, utils): + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id = seeder.create_event(admin_unit_id, draft=True) + + url = utils.get_url("api_v1_event", id=event_id) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + +def test_read_myDraft(client, app, db, seeder, utils): + user_id, admin_unit_id = seeder.setup_api_access() + event_id = seeder.create_event(admin_unit_id, draft=True) + + url = utils.get_url("api_v1_event", id=event_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + assert response.json["public_status"] == "draft" + + def test_list(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) + event_id = seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_event_list") - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["id"] == event_id def test_search(client, seeder, utils): @@ -33,18 +57,34 @@ def test_search(client, seeder, utils): event_id = seeder.create_event(admin_unit_id) image_id = seeder.upsert_default_image() seeder.assign_image_to_event(event_id, image_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_event_search") - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["id"] == event_id def test_dates(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) event_id = seeder.create_event(admin_unit_id) - url = utils.get_url("api_v1_event_dates", id=event_id) utils.get_ok(url) + event_id = seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("api_v1_event_dates", id=event_id) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + +def test_dates_myDraft(client, seeder, utils): + user_id, admin_unit_id = seeder.setup_api_access() + event_id = seeder.create_event(admin_unit_id, draft=True) + + url = utils.get_url("api_v1_event_dates", id=event_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + def create_put( place_id, organizer_id, name="Neuer Name", start="2021-02-07T11:00:00.000Z" @@ -84,6 +124,7 @@ def test_put(client, seeder, utils, app, mocker): put["expected_participants"] = 500 put["price_info"] = "Erwachsene 5€, Kinder 2€." put["recurrence_rule"] = "RRULE:FREQ=DAILY;COUNT=7" + put["public_status"] = "draft" url = utils.get_url("api_v1_event", id=event_id) response = utils.put_json(url, put) @@ -120,6 +161,7 @@ def test_put(client, seeder, utils, app, mocker): assert event.expected_participants == put["expected_participants"] assert event.price_info == put["price_info"] assert event.recurrence_rule == put["recurrence_rule"] + assert event.public_status == PublicStatus.draft len_dates = len(event.dates) assert len_dates == 7 diff --git a/tests/api/test_event_date.py b/tests/api/test_event_date.py index 261c513..98c3ffb 100644 --- a/tests/api/test_event_date.py +++ b/tests/api/test_event_date.py @@ -1,23 +1,37 @@ def test_read(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) seeder.create_event(admin_unit_id) - url = utils.get_url("api_v1_event_date", id=1) utils.get_ok(url) + seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("api_v1_event_date", id=2) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + seeder.authorize_api_access(user_id, admin_unit_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + def test_list(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_event_date_list") - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["id"] == 1 def test_search(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) + event_id = seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_event_date_search", sort="-rating") response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["event"]["id"] == event_id assert response.json["items"][0]["start"].endswith("+02:00") diff --git a/tests/api/test_organization.py b/tests/api/test_organization.py index aad9cc5..efcc655 100644 --- a/tests/api/test_organization.py +++ b/tests/api/test_organization.py @@ -13,21 +13,39 @@ def test_list(client, seeder, utils): def test_event_date_search(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id = seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url( "api_v1_organization_event_date_search", id=admin_unit_id, sort="-rating" ) - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["event"]["id"] == event_id + + seeder.authorize_api_access(user_id, admin_unit_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + assert len(response.json["items"]) == 2 + assert response.json["items"][1]["event"]["public_status"] == "draft" def test_event_search(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id = seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_organization_event_search", id=admin_unit_id) - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["id"] == event_id + + seeder.authorize_api_access(user_id, admin_unit_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + assert len(response.json["items"]) == 2 + assert response.json["items"][1]["public_status"] == "draft" def test_organizers(client, seeder, utils): @@ -60,11 +78,19 @@ def test_organizers_post(client, seeder, utils, app): def test_events(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id = seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) url = utils.get_url("api_v1_organization_event_list", id=admin_unit_id) - utils.get_ok(url) + response = utils.get_ok(url) + assert len(response.json["items"]) == 1 + assert response.json["items"][0]["id"] == event_id + + seeder.authorize_api_access(user_id, admin_unit_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + assert len(response.json["items"]) == 2 def prepare_events_post_data(seeder, utils): @@ -92,7 +118,7 @@ def test_events_post(client, seeder, utils, app): assert "id" in response.json with app.app_context(): - from project.models import Event + from project.models import Event, PublicStatus event = ( Event.query.filter(Event.admin_unit_id == admin_unit_id) @@ -104,6 +130,7 @@ def test_events_post(client, seeder, utils, app): assert event.organizer_id == organizer_id assert event.photo is not None assert event.photo.encoding_format == "image/png" + assert event.public_status == PublicStatus.published def test_events_post_photo_no_data(client, seeder, utils, app): diff --git a/tests/seeder.py b/tests/seeder.py index 1eb87da..4c8339a 100644 --- a/tests/seeder.py +++ b/tests/seeder.py @@ -156,7 +156,10 @@ class Seeder(object): return client_id def setup_api_access(self): - user_id, admin_unit_id = self.setup_base(admin=True) + user_id, admin_unit_id = self.setup_base(admin=True, log_in=False) + return self.authorize_api_access(user_id, admin_unit_id) + + def authorize_api_access(self, user_id, admin_unit_id): oauth2_client_id = self.insert_default_oauth2_client(user_id) with self._app.app_context(): @@ -167,7 +170,9 @@ class Seeder(object): client_secret = oauth2_client.client_secret scope = oauth2_client.scope + self._utils.login() self._utils.authorize(client_id, client_secret, scope) + self._utils.logout() return (user_id, admin_unit_id) def get_event_category_id(self, category_name): @@ -177,16 +182,22 @@ class Seeder(object): return category.id def create_event( - self, admin_unit_id, recurrence_rule="", external_link="", end=None + self, + admin_unit_id, + recurrence_rule="", + external_link="", + end=None, + draft=False, + name="Name", ): - from project.models import Event, EventAttendanceMode + from project.models import Event, EventAttendanceMode, PublicStatus from project.services.event import insert_event, upsert_event_category with self._app.app_context(): event = Event() event.admin_unit_id = admin_unit_id event.categories = [upsert_event_category("Other")] - event.name = "Name" + event.name = name event.description = "Beschreibung" event.start = self.get_now_by_minute() event.end = end @@ -198,6 +209,10 @@ class Seeder(object): event.tags = "" event.price_info = "" event.attendance_mode = EventAttendanceMode.offline + + if draft: + event.public_status = PublicStatus.draft + insert_event(event) self._db.session.commit() event_id = event.id diff --git a/tests/test___init__.py b/tests/test___init__.py index 41b4202..76706bd 100644 --- a/tests/test___init__.py +++ b/tests/test___init__.py @@ -1,3 +1,6 @@ +import sqlalchemy + + def test_mail_server(): import os @@ -29,3 +32,38 @@ def test_migrations(app, seeder): seeder.create_any_reference(admin_unit_id) seeder.create_reference_request(event_id, admin_unit_id) downgrade() + + +def test_migration_public_status(app, seeder): + from flask_migrate import upgrade + + from project import db + from project.models import Event, PublicStatus + + with app.app_context(): + db.drop_all() + db.engine.execute("DROP TABLE IF EXISTS alembic_version;") + upgrade(revision="1fb9f679defb") + + sql = """ +DO $$ +DECLARE + admin_unit_id adminunit.id%TYPE; + event_place_id eventplace.id%TYPE; + organizer_id eventorganizer.id%TYPE; + event_id event.id%TYPE; +BEGIN + INSERT INTO adminunit (name) VALUES ('Org') RETURNING id INTO admin_unit_id; + INSERT INTO eventplace (name, admin_unit_id) VALUES ('Place', admin_unit_id) RETURNING id INTO event_place_id; + INSERT INTO eventorganizer (name, admin_unit_id) VALUES ('Organizer', admin_unit_id) RETURNING id INTO organizer_id; + INSERT INTO event (name, admin_unit_id, event_place_id, organizer_id, start) VALUES ('Event', admin_unit_id, event_place_id, organizer_id, current_timestamp) RETURNING id INTO event_id; +END $$; + """ + db.engine.execute(sqlalchemy.text(sql).execution_options(autocommit=True)) + upgrade() + + events = Event.query.all() + assert len(events) > 0 + + for event in events: + assert event.public_status == PublicStatus.published diff --git a/tests/utils.py b/tests/utils.py index 9115ccc..1a00116 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -246,6 +246,10 @@ class UtilActions(object): def assert_response_unauthorized(self, response): assert response.status_code == 401 + return response + + def assert_response_forbidden(self, response): + assert response.status_code == 403 def assert_response_notFound(self, response): assert response.status_code == 404 @@ -277,6 +281,12 @@ class UtilActions(object): def assert_response_permission_missing(self, response, endpoint, **values): self.assert_response_redirect(response, endpoint, **values) + def assert_response_contains(self, response, needle): + assert needle.encode("UTF-8") in response.data + + def assert_response_contains_not(self, response, needle): + assert needle.encode("UTF-8") not in response.data + def parse_query_parameters(self, url): query = urlsplit(url).query params = parse_qs(query) diff --git a/tests/views/test_api.py b/tests/views/test_api.py deleted file mode 100644 index db96fe1..0000000 --- a/tests/views/test_api.py +++ /dev/null @@ -1,38 +0,0 @@ -def test_events(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) - - url = utils.get_url("api_events") - utils.get_ok(url) - - -def test_event_dates(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() - seeder.create_event(admin_unit_id) - - url = utils.get_url("api_event_dates") - utils.get_ok(url) - - url = utils.get_url("api_event_dates", keyword="name") - utils.get_ok(url) - - url = utils.get_url("api_event_dates", category_id=2000) - utils.get_ok(url) - - url = utils.get_url("api_event_dates", category_id=0) - utils.get_ok(url) - - url = utils.get_url("api_event_dates", weekday=1) - utils.get_ok(url) - - url = utils.get_url( - "api_event_dates", coordinate="51.9077888,10.4333312", distance=500 - ) - utils.get_ok(url) - - url = utils.get_url("api_event_dates", date_from="2020-10-03", date_to="2021-10-03") - utils.get_ok(url) - - organizer_id = seeder.upsert_default_event_organizer(admin_unit_id) - url = utils.get_url("api_event_dates", organizer_id=organizer_id) - utils.get_ok(url) diff --git a/tests/views/test_event.py b/tests/views/test_event.py index 18611b9..1dbd057 100644 --- a/tests/views/test_event.py +++ b/tests/views/test_event.py @@ -6,12 +6,20 @@ from psycopg2.errors import UniqueViolation "external_link", [None, "https://example.com", "www.example.com"] ) def test_read(client, seeder, utils, external_link): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) event_id = seeder.create_event(admin_unit_id, external_link=external_link) url = utils.get_url("event", event_id=event_id) utils.get_ok(url) + event_id = seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("event", event_id=event_id) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + utils.login() + utils.get_ok(url) + def test_read_containsActionLink(seeder, utils): user_id, admin_unit_id = seeder.setup_base() @@ -305,7 +313,7 @@ def test_create_verifiedSuggestionRedirectsToReviewStatus( def test_actions(seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) event_id = seeder.create_event(admin_unit_id) url = utils.get_url("event_actions", event_id=event_id) @@ -315,6 +323,14 @@ def test_actions(seeder, utils): assert b"Empfehlung anfragen" not in response.data assert b"Veranstaltung empfehlen" not in response.data + event_id = seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("event_actions", event_id=event_id) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + utils.login() + utils.get_ok(url) + def test_actions_withReferenceRequestLink(seeder, utils): user_id, admin_unit_id = seeder.setup_base() diff --git a/tests/views/test_event_date.py b/tests/views/test_event_date.py index bdfffa7..0d49403 100644 --- a/tests/views/test_event_date.py +++ b/tests/views/test_event_date.py @@ -1,5 +1,5 @@ def test_read(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) seeder.create_event(admin_unit_id, end=seeder.get_now_by_minute()) url = utils.get_url("event_date", id=1) @@ -9,14 +9,30 @@ def test_read(client, seeder, utils): response = client.get(url) utils.assert_response_redirect(response, "event_date", id=1) + seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("event_date", id=2) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + utils.login() + utils.get_ok(url) + def test_ical(client, seeder, utils): - user_id, admin_unit_id = seeder.setup_base() + user_id, admin_unit_id = seeder.setup_base(log_in=False) seeder.create_event(admin_unit_id, end=seeder.get_now_by_minute()) url = utils.get_url("event_date_ical", id=1) utils.get_ok(url) + seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("event_date_ical", id=2) + response = utils.get(url) + utils.assert_response_unauthorized(response) + + utils.login() + utils.get_ok(url) + def test_list(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() diff --git a/tests/views/test_manage.py b/tests/views/test_manage.py index 879ec97..27a5265 100644 --- a/tests/views/test_manage.py +++ b/tests/views/test_manage.py @@ -78,6 +78,12 @@ def test_admin_unit_events(client, seeder, utils): date_to="2021-10-03", ) + event_id = seeder.create_event(admin_unit_id, draft=True) + response = utils.get_endpoint_ok("manage_admin_unit_events", id=admin_unit_id) + + event_url = utils.get_url("event", event_id=event_id) + utils.assert_response_contains(response, event_url) + def test_admin_unit_events_invalidDateFormat(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() diff --git a/tests/views/test_oauth2_token.py b/tests/views/test_oauth2_token.py index e319c80..1432935 100644 --- a/tests/views/test_oauth2_token.py +++ b/tests/views/test_oauth2_token.py @@ -3,6 +3,7 @@ import pytest def test_list(client, seeder, utils): user_id, admin_unit_id = seeder.setup_api_access() + utils.login() url = utils.get_url("oauth2_tokens") utils.get_ok(url) @@ -11,6 +12,7 @@ def test_list(client, seeder, utils): @pytest.mark.parametrize("db_error", [True, False]) def test_revoke(client, seeder, utils, app, mocker, db_error): user_id, admin_unit_id = seeder.setup_api_access() + utils.login() with app.app_context(): from project.models import OAuth2Token diff --git a/tests/views/test_widget.py b/tests/views/test_widget.py index c91997c..0eafabd 100644 --- a/tests/views/test_widget.py +++ b/tests/views/test_widget.py @@ -4,10 +4,17 @@ import pytest def test_event_dates(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() seeder.create_event(admin_unit_id) + seeder.create_event(admin_unit_id, draft=True) au_short_name = "meinecrew" url = utils.get_url("widget_event_dates", au_short_name=au_short_name) - utils.get_ok(url) + response = utils.get_ok(url) + + event_url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=1) + utils.assert_response_contains(response, event_url) + + draft_url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=2) + utils.assert_response_contains_not(response, draft_url) url = utils.get_url( "widget_event_dates", au_short_name=au_short_name, keyword="name" @@ -37,8 +44,8 @@ def test_event_dates(client, seeder, utils): def test_event_date(client, seeder, utils, app, db): - user_id, admin_unit_id = seeder.setup_base() - event_id = seeder.create_event(admin_unit_id) + user_id, admin_unit_id = seeder.setup_base(log_in=False) + seeder.create_event(admin_unit_id) au_short_name = "meinecrew" with app.app_context(): @@ -53,9 +60,14 @@ def test_event_date(client, seeder, utils, app, db): admin_unit.widget_link_color = Color("#FF0000") db.session.commit() - url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=event_id) + url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=1) utils.get_ok(url) + seeder.create_event(admin_unit_id, draft=True) + url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=2) + response = utils.get(url) + utils.assert_response_unauthorized(response) + def test_infoscreen(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base()