diff --git a/messages.pot b/messages.pot index a4fc61d..7e14675 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-09-10 09:01+0200\n" +"POT-Creation-Date: 2021-09-19 16:31+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -191,7 +191,7 @@ msgstr "" msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1389 +#: project/forms/admin.py:12 project/templates/_macros.html:1405 #: project/templates/layout.html:313 #: project/templates/widget/event_suggestion/create.html:204 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -279,7 +279,7 @@ msgid "Longitude" msgstr "" #: project/forms/admin_unit.py:28 project/forms/event.py:36 -#: project/forms/event.py:65 project/forms/event.py:379 +#: project/forms/event.py:65 project/forms/event.py:399 #: 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 @@ -299,7 +299,7 @@ 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:1525 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1541 msgid "Short name must contain only letters numbers or underscore" msgstr "" @@ -313,7 +313,7 @@ msgstr "" #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 #: 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:1485 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1501 project/templates/admin/users.html:19 msgid "Email" msgstr "" @@ -492,8 +492,8 @@ msgstr "" msgid "All-day" msgstr "" -#: project/forms/event.py:86 project/templates/event/create.html:252 -#: project/templates/event/update.html:143 +#: project/forms/event.py:86 project/templates/event/create.html:274 +#: project/templates/event/update.html:165 #: project/templates/widget/event_suggestion/create.html:240 msgid "Recurring event" msgstr "" @@ -650,16 +650,16 @@ msgid "" " course it works without it." msgstr "" -#: project/forms/event.py:208 project/templates/_macros.html:1246 +#: project/forms/event.py:208 project/templates/_macros.html:1262 msgid "The start must be before the end." msgstr "" -#: project/forms/event.py:214 project/templates/_macros.html:1263 +#: project/forms/event.py:214 project/templates/_macros.html:1279 msgid "An event can last a maximum of 14 days." msgstr "" #: project/forms/event.py:222 project/templates/_macros.html:419 -#: project/templates/_macros.html:575 +#: project/templates/_macros.html:582 msgid "Previous start date" msgstr "" @@ -677,8 +677,8 @@ msgstr "" #: project/forms/event.py:235 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:76 -#: project/templates/event/create.html:366 -#: project/templates/event/update.html:223 +#: project/templates/event/create.html:390 +#: project/templates/event/update.html:246 msgid "Rating" msgstr "" @@ -689,152 +689,166 @@ msgid "" "visible and is used for sorting." msgstr "" -#: project/forms/event.py:247 project/forms/event.py:256 -#: project/forms/event.py:325 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:459 project/templates/_macros.html:612 -#: project/templates/event/create.html:291 -#: project/templates/event/update.html:173 +#: project/forms/event.py:244 +msgid "Co-organizers" +msgstr "" + +#: project/forms/event.py:247 +msgid "" +"Select optional co-organizers. You can add and modify organizers at " +"Organization > Organizers." +msgstr "" + +#: project/forms/event.py:258 +msgid "Invalid co-organizer." +msgstr "" + +#: project/forms/event.py:267 project/forms/event.py:276 +#: project/forms/event.py:345 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:459 project/templates/_macros.html:619 +#: project/templates/event/create.html:315 +#: project/templates/event/update.html:196 #: project/templates/event_place/create.html:31 #: project/templates/event_place/delete.html:13 #: project/templates/event_place/update.html:31 msgid "Place" msgstr "" -#: project/forms/event.py:249 +#: project/forms/event.py:269 msgid "Select existing place" msgstr "" -#: project/forms/event.py:250 +#: project/forms/event.py:270 msgid "Enter new place" msgstr "" -#: project/forms/event.py:263 project/forms/event.py:272 -#: project/forms/event.py:333 project/forms/event.py:395 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:497 -#: project/templates/_macros.html:649 project/templates/event/create.html:262 -#: project/templates/event/update.html:164 +#: project/forms/event.py:283 project/forms/event.py:292 +#: project/forms/event.py:353 project/forms/event.py:415 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:496 +#: project/templates/_macros.html:656 project/templates/event/create.html:284 +#: project/templates/event/update.html:186 #: project/templates/organizer/create.html:27 #: project/templates/organizer/delete.html:13 #: project/templates/organizer/update.html:27 msgid "Organizer" msgstr "" -#: project/forms/event.py:265 +#: project/forms/event.py:285 msgid "Select existing organizer" msgstr "" -#: project/forms/event.py:266 +#: project/forms/event.py:286 msgid "Enter new organizer" msgstr "" -#: project/forms/event.py:278 +#: project/forms/event.py:298 msgid "Save as draft" msgstr "" -#: project/forms/event.py:279 +#: project/forms/event.py:299 msgid "Publish event" msgstr "" -#: project/forms/event.py:309 +#: project/forms/event.py:329 msgid "Select existing place or enter new place" msgstr "" -#: project/forms/event.py:316 +#: project/forms/event.py:336 msgid "Select existing organizer or enter new organizer" msgstr "" -#: project/forms/event.py:328 +#: project/forms/event.py:348 msgid "" "Choose where the event takes place. You can add and modify places at " -"Manage > Places." +"Organization > Places." msgstr "" -#: project/forms/event.py:336 +#: project/forms/event.py:356 msgid "" -"Select the organizer. You can add and modify organizers at Manage > " -"Organizers." +"Select the organizer. You can add and modify organizers at Organization >" +" Organizers." msgstr "" -#: project/forms/event.py:342 project/templates/event/update.html:153 +#: project/forms/event.py:362 project/templates/event/update.html:175 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "" -#: project/forms/event.py:345 +#: project/forms/event.py:365 msgid "EventStatus.scheduled" msgstr "" -#: project/forms/event.py:346 project/templates/layout.html:82 +#: project/forms/event.py:366 project/templates/layout.html:82 #: project/templates/layout.html:97 msgid "EventStatus.cancelled" msgstr "" -#: project/forms/event.py:347 project/templates/layout.html:85 +#: project/forms/event.py:367 project/templates/layout.html:85 #: project/templates/layout.html:100 msgid "EventStatus.movedOnline" msgstr "" -#: project/forms/event.py:348 project/templates/layout.html:88 +#: project/forms/event.py:368 project/templates/layout.html:88 #: project/templates/layout.html:103 msgid "EventStatus.postponed" msgstr "" -#: project/forms/event.py:349 project/templates/layout.html:91 +#: project/forms/event.py:369 project/templates/layout.html:91 #: project/templates/layout.html:106 msgid "EventStatus.rescheduled" msgstr "" -#: project/forms/event.py:351 +#: project/forms/event.py:371 msgid "Select the status of the event." msgstr "" -#: project/forms/event.py:355 +#: project/forms/event.py:375 msgid "Public status" msgstr "" -#: project/forms/event.py:358 +#: project/forms/event.py:378 msgid "PublicStatus.published" msgstr "" -#: project/forms/event.py:359 project/templates/_macros.html:282 +#: project/forms/event.py:379 project/templates/_macros.html:282 msgid "PublicStatus.draft" msgstr "" -#: project/forms/event.py:361 +#: project/forms/event.py:381 msgid "Select the public status of the event." msgstr "" -#: project/forms/event.py:364 project/templates/event/update.html:5 -#: project/templates/event/update.html:119 +#: project/forms/event.py:384 project/templates/event/update.html:5 +#: project/templates/event/update.html:141 msgid "Update event" msgstr "" -#: project/forms/event.py:378 project/templates/_macros.html:1218 +#: project/forms/event.py:398 project/templates/_macros.html:1234 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "" -#: project/forms/event.py:386 project/forms/event_date.py:15 +#: project/forms/event.py:406 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "" -#: project/forms/event.py:388 project/forms/event_date.py:17 +#: project/forms/event.py:408 project/forms/event_date.py:17 #: project/forms/planing.py:16 msgid "to" msgstr "" -#: project/forms/event.py:390 project/forms/event_date.py:19 +#: project/forms/event.py:410 project/forms/event_date.py:19 msgid "Keyword" msgstr "" -#: project/forms/event.py:392 project/forms/event_date.py:21 +#: project/forms/event.py:412 project/forms/event_date.py:21 #: project/forms/planing.py:19 project/templates/_macros.html:392 msgid "Category" msgstr "" -#: project/forms/event.py:398 +#: project/forms/event.py:418 msgid "Find events" msgstr "" @@ -895,13 +909,13 @@ msgstr "" msgid "I would like to be notified by email after the review" msgstr "" -#: project/forms/event_suggestion.py:52 project/templates/event/create.html:296 +#: project/forms/event_suggestion.py:52 project/templates/event/create.html:320 msgid "" "Choose where the event takes place. If the venue is not yet in the list, " "just enter it." msgstr "" -#: project/forms/event_suggestion.py:62 project/templates/event/create.html:266 +#: project/forms/event_suggestion.py:62 project/templates/event/create.html:288 msgid "" "Select the organizer. If the organizer is not yet on the list, just enter" " it." @@ -983,7 +997,7 @@ msgid "Weekdays" msgstr "" #: project/forms/reference.py:11 project/forms/reference_request.py:16 -#: project/templates/_macros.html:518 project/templates/_macros.html:675 +#: project/templates/_macros.html:512 project/templates/_macros.html:672 #: project/templates/admin_unit/create.html:28 #: project/templates/admin_unit/update.html:29 #: project/templates/layout.html:258 @@ -1011,7 +1025,7 @@ msgstr "" msgid "Delete request" msgstr "" -#: project/forms/reference_request.py:28 project/templates/_macros.html:1401 +#: project/forms/reference_request.py:28 project/templates/_macros.html:1417 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1078,7 +1092,7 @@ msgid "This field is required." msgstr "" #: project/templates/_macros.html:134 project/templates/_macros.html:414 -#: project/templates/_macros.html:914 +#: project/templates/_macros.html:930 msgid "Date" msgstr "" @@ -1118,64 +1132,64 @@ msgstr "" msgid "Last updated at %(updated_at)s." msgstr "" -#: project/templates/_macros.html:408 project/templates/_macros.html:571 +#: project/templates/_macros.html:408 project/templates/_macros.html:578 #: project/templates/event/actions.html:12 -#: project/templates/event/create.html:235 +#: project/templates/event/create.html:257 #: project/templates/event/delete.html:13 -#: project/templates/event/update.html:126 +#: project/templates/event/update.html:148 #: project/templates/widget/event_suggestion/create.html:229 msgid "Event" msgstr "" -#: project/templates/_macros.html:441 project/templates/_macros.html:593 -#: project/templates/_macros.html:1470 project/templates/event/actions.html:32 +#: project/templates/_macros.html:441 project/templates/_macros.html:600 +#: project/templates/_macros.html:1486 project/templates/event/actions.html:32 msgid "Share" msgstr "" -#: project/templates/_macros.html:445 project/templates/_macros.html:597 -#: project/templates/_macros.html:1500 +#: project/templates/_macros.html:445 project/templates/_macros.html:604 +#: project/templates/_macros.html:1516 msgid "Add to calendar" msgstr "" -#: project/templates/_macros.html:453 project/templates/_macros.html:605 +#: project/templates/_macros.html:453 project/templates/_macros.html:612 #: project/templates/event/report.html:4 msgid "Report event" msgstr "" -#: project/templates/_macros.html:480 project/templates/_macros.html:631 +#: project/templates/_macros.html:480 project/templates/_macros.html:638 msgid "Show directions" msgstr "" -#: project/templates/_macros.html:485 project/templates/_macros.html:636 +#: project/templates/_macros.html:485 project/templates/_macros.html:643 msgid "The event takes place online." msgstr "" -#: project/templates/_macros.html:487 project/templates/_macros.html:638 +#: project/templates/_macros.html:487 project/templates/_macros.html:645 msgid "The event takes place both offline and online." msgstr "" -#: project/templates/_macros.html:699 project/templates/event_date/list.html:5 +#: project/templates/_macros.html:696 project/templates/event_date/list.html:5 #: project/templates/event_date/list.html:300 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "" -#: project/templates/_macros.html:772 +#: project/templates/_macros.html:788 msgid "Search location on Google" msgstr "" -#: project/templates/_macros.html:838 +#: project/templates/_macros.html:854 #, python-format msgid "%(count)d event dates" msgstr "" -#: project/templates/_macros.html:854 project/templates/_macros.html:856 +#: project/templates/_macros.html:870 project/templates/_macros.html:872 #: project/templates/event_date/list.html:321 msgid "First" msgstr "" -#: project/templates/_macros.html:859 project/templates/_macros.html:861 +#: project/templates/_macros.html:875 project/templates/_macros.html:877 #: project/templates/event_date/list.html:322 #: project/templates/widget/event_suggestion/create.html:193 #: project/templates/widget/event_suggestion/create.html:218 @@ -1186,12 +1200,12 @@ msgstr "" msgid "Previous" msgstr "" -#: project/templates/_macros.html:863 +#: project/templates/_macros.html:879 #, python-format msgid "Page %(page)d of %(pages)d (%(total)d total)" msgstr "" -#: project/templates/_macros.html:865 project/templates/_macros.html:867 +#: project/templates/_macros.html:881 project/templates/_macros.html:883 #: project/templates/event_date/list.html:324 #: project/templates/widget/event_suggestion/create.html:194 #: project/templates/widget/event_suggestion/create.html:219 @@ -1201,73 +1215,73 @@ msgstr "" msgid "Next" msgstr "" -#: project/templates/_macros.html:870 project/templates/_macros.html:872 +#: project/templates/_macros.html:886 project/templates/_macros.html:888 #: project/templates/event_date/list.html:325 msgid "Last" msgstr "" -#: project/templates/_macros.html:937 +#: project/templates/_macros.html:953 msgid "Radius" msgstr "" -#: project/templates/_macros.html:1147 +#: project/templates/_macros.html:1163 msgid "Edit image" msgstr "" -#: project/templates/_macros.html:1168 +#: project/templates/_macros.html:1184 msgid "Close" msgstr "" -#: project/templates/_macros.html:1169 +#: project/templates/_macros.html:1185 msgid "Okay" msgstr "" -#: project/templates/_macros.html:1181 +#: project/templates/_macros.html:1197 msgid "Choose image file" msgstr "" -#: project/templates/_macros.html:1217 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1233 project/templates/event/actions.html:46 msgid "Edit event" msgstr "" -#: project/templates/_macros.html:1220 project/templates/manage/events.html:40 +#: project/templates/_macros.html:1236 project/templates/manage/events.html:40 msgid "More" msgstr "" -#: project/templates/_macros.html:1267 +#: project/templates/_macros.html:1283 msgid "Please enter a valid time, between 00:00 and 23:59." msgstr "" -#: project/templates/_macros.html:1295 +#: project/templates/_macros.html:1311 #, python-format msgid "Just use %(term)s" msgstr "" -#: project/templates/_macros.html:1361 +#: project/templates/_macros.html:1377 msgid "Event suggestion" msgstr "" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Link copied" msgstr "" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Copy link" msgstr "" -#: project/templates/_macros.html:1508 +#: project/templates/_macros.html:1524 msgid "Google calendar" msgstr "" -#: project/templates/_macros.html:1509 +#: project/templates/_macros.html:1525 msgid "Apple calendar" msgstr "" -#: project/templates/_macros.html:1510 +#: project/templates/_macros.html:1526 msgid "Yahoo calendar" msgstr "" -#: project/templates/_macros.html:1511 +#: project/templates/_macros.html:1527 msgid "Other calendar" msgstr "" @@ -1327,7 +1341,7 @@ msgid "Show events" msgstr "" #: project/templates/event/create.html:5 -#: project/templates/event/create.html:228 project/templates/layout.html:226 +#: project/templates/event/create.html:250 project/templates/layout.html:226 #: project/templates/manage/events.html:22 #: project/templates/manage/organizers.html:21 msgid "Create event" @@ -1444,8 +1458,8 @@ msgstr "" #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 -#: project/templates/event/create.html:354 -#: project/templates/event/update.html:211 +#: project/templates/event/create.html:378 +#: project/templates/event/update.html:234 #: project/templates/event_place/create.html:57 #: project/templates/event_place/update.html:57 #: project/templates/organizer/create.html:56 @@ -1570,31 +1584,33 @@ msgid "Enter place or address" msgstr "" #: project/templates/event/create.html:183 +#: project/templates/event/create.html:240 #: project/templates/event/update.html:106 +#: project/templates/event/update.html:132 #: project/templates/widget/event_suggestion/create.html:129 msgid "Enter organizer" msgstr "" -#: project/templates/event/create.html:245 -#: project/templates/event/update.html:136 +#: project/templates/event/create.html:267 +#: project/templates/event/update.html:158 msgid "Event date" msgstr "" -#: project/templates/event/create.html:283 +#: project/templates/event/create.html:305 msgid "Switch to organizer search" msgstr "" -#: project/templates/event/create.html:316 +#: project/templates/event/create.html:340 msgid "Switch to place search" msgstr "" -#: project/templates/event/create.html:327 -#: project/templates/event/update.html:184 +#: project/templates/event/create.html:351 +#: project/templates/event/update.html:207 msgid "Access" msgstr "" -#: project/templates/event/create.html:341 -#: project/templates/event/update.html:198 +#: project/templates/event/create.html:365 +#: project/templates/event/update.html:221 msgid "Target group" msgstr "" @@ -1900,11 +1916,11 @@ msgstr "" msgid "Event successfully deleted" msgstr "" -#: project/views/event.py:397 +#: project/views/event.py:404 msgid "Referenced event changed" msgstr "" -#: project/views/event.py:420 +#: project/views/event.py:427 msgid "New event report" msgstr "" diff --git a/migrations/versions/811e16ed3bf0_.py b/migrations/versions/811e16ed3bf0_.py new file mode 100644 index 0000000..9181899 --- /dev/null +++ b/migrations/versions/811e16ed3bf0_.py @@ -0,0 +1,61 @@ +"""empty message + +Revision ID: 811e16ed3bf0 +Revises: 12ca023b94f8 +Create Date: 2021-09-18 16:21:08.415884 + +""" +import sqlalchemy as sa +import sqlalchemy_utils +from alembic import op + +from project import dbtypes + +# revision identifiers, used by Alembic. +revision = "811e16ed3bf0" +down_revision = "12ca023b94f8" +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_table( + "event_coorganizers", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("event_id", sa.Integer(), nullable=False), + sa.Column("organizer_id", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint( + ["event_id"], + ["event.id"], + ), + sa.ForeignKeyConstraint( + ["organizer_id"], + ["eventorganizer.id"], + ), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("event_id", "organizer_id"), + ) + op.create_unique_constraint( + "event_eventcategories_event_id_category_id", + "event_eventcategories", + ["event_id", "category_id"], + ) + op.create_unique_constraint( + "eventsuggestion_eventcategories_event_suggestion_id_category_id", + "eventsuggestion_eventcategories", + ["event_suggestion_id", "category_id"], + ) + + +def downgrade(): + op.drop_constraint( + "eventsuggestion_eventcategories_event_suggestion_id_category_id", + "eventsuggestion_eventcategories", + type_="unique", + ) + op.drop_constraint( + "event_eventcategories_event_id_category_id", + "event_eventcategories", + type_="unique", + ) + op.drop_table("event_coorganizers") diff --git a/project/api/event/schemas.py b/project/api/event/schemas.py index a011346..415144f 100644 --- a/project/api/event/schemas.py +++ b/project/api/event/schemas.py @@ -16,7 +16,11 @@ from project.api.image.schemas import ( ImageSchema, ) from project.api.organization.schemas import OrganizationRefSchema -from project.api.organizer.schemas import OrganizerRefSchema, OrganizerWriteIdSchema +from project.api.organizer.schemas import ( + OrganizerDumpIdSchema, + OrganizerRefSchema, + OrganizerWriteIdSchema, +) from project.api.place.schemas import ( PlaceRefSchema, PlaceSearchItemSchema, @@ -167,6 +171,7 @@ class EventSchema(EventIdSchema, EventBaseSchemaMixin): place = fields.Nested(PlaceRefSchema, attribute="event_place") photo = fields.Nested(ImageSchema) categories = fields.List(fields.Nested(EventCategoryRefSchema)) + co_organizers = fields.List(fields.Nested(OrganizerRefSchema)) class EventDumpSchema(EventIdSchema, EventBaseSchemaMixin): @@ -177,6 +182,9 @@ class EventDumpSchema(EventIdSchema, EventBaseSchemaMixin): category_ids = fields.Pluck( EventCategoryIdSchema, "id", many=True, attribute="categories" ) + co_organizer_ids = fields.Pluck( + OrganizerDumpIdSchema, "id", many=True, attribute="co_organizers" + ) class EventRefSchema(EventIdSchema): @@ -262,6 +270,10 @@ class EventWriteSchemaMixin(object): required=True, metadata={"description": "Who is organizing the event."}, ) + co_organizers = fields.List( + fields.Nested(OrganizerWriteIdSchema), + metadata={"description": "Optional co-organizers."}, + ) place = fields.Nested( PlaceWriteIdSchema, required=True, diff --git a/project/api/organizer/schemas.py b/project/api/organizer/schemas.py index a4bb1f3..b164e93 100644 --- a/project/api/organizer/schemas.py +++ b/project/api/organizer/schemas.py @@ -31,6 +31,10 @@ class OrganizerIdSchema(OrganizerModelSchema, IdSchemaMixin): pass +class OrganizerDumpIdSchema(OrganizerModelSchema, IdSchemaMixin): + pass + + class OrganizerWriteIdSchema(OrganizerModelSchema, WriteIdSchemaMixin): pass diff --git a/project/cli/test.py b/project/cli/test.py index 4006585..f396e5c 100644 --- a/project/cli/test.py +++ b/project/cli/test.py @@ -2,6 +2,7 @@ import json import click from flask.cli import AppGroup +from flask_migrate import stamp from flask_security.confirmable import confirm_user from sqlalchemy import MetaData @@ -97,6 +98,7 @@ def drop_all(): @test_cli.command("create-all") def create_all(): + stamp() db.create_all() click.echo("Create all done.") diff --git a/project/forms/event.py b/project/forms/event.py index d7e0964..f33ccc5 100644 --- a/project/forms/event.py +++ b/project/forms/event.py @@ -240,6 +240,25 @@ class BaseEventForm(SharedEventForm): "Choose how relevant the event is to your organization. The value is not visible and is used for sorting." ), ) + co_organizer_ids = SelectMultipleField( + lazy_gettext("Co-organizers"), + validators=[Optional()], + coerce=int, + description=lazy_gettext( + "Select optional co-organizers. You can add and modify organizers at Organization > Organizers." + ), + ) + + def validate(self): + result = super().validate() + + if self.co_organizer_ids.data and self.organizer_id.data: + if self.organizer_id.data in self.co_organizer_ids.data: + msg = gettext("Invalid co-organizer.") + self.co_organizer_ids.errors.append(msg) + result = False + + return result class CreateEventForm(BaseEventForm): @@ -301,7 +320,7 @@ class CreateEventForm(BaseEventForm): ) def validate(self): - if not super(BaseEventForm, self).validate(): + if not super().validate(): return False if ( not self.event_place_id.data or self.event_place_id.data == 0 @@ -326,7 +345,7 @@ class UpdateEventForm(BaseEventForm): validators=[DataRequired()], coerce=int, description=lazy_gettext( - "Choose where the event takes place. You can add and modify places at Manage > Places." + "Choose where the event takes place. You can add and modify places at Organization > Places." ), ) organizer_id = SelectField( @@ -334,7 +353,7 @@ class UpdateEventForm(BaseEventForm): validators=[DataRequired()], coerce=int, description=lazy_gettext( - "Select the organizer. You can add and modify organizers at Manage > Organizers." + "Select the organizer. You can add and modify organizers at Organization > Organizers." ), ) diff --git a/project/jsonld.py b/project/jsonld.py index 7d43626..d493e2f 100644 --- a/project/jsonld.py +++ b/project/jsonld.py @@ -133,8 +133,13 @@ def get_sd_for_event_date(event_date): result["location"] = get_sd_for_place(event.event_place) organizer_list = list() + if event.organizer: organizer_list.append(get_sd_for_organizer(event.organizer)) + + for co_organizer in event.co_organizers: + organizer_list.append(get_sd_for_organizer(co_organizer)) + if event.admin_unit: organizer_list.append(get_sd_for_admin_unit(event.admin_unit)) result["organizer"] = organizer_list diff --git a/project/models.py b/project/models.py index 161fb5a..a80f57a 100644 --- a/project/models.py +++ b/project/models.py @@ -331,6 +331,12 @@ class AdminUnitRelation(db.Model, TrackableMixin): raise make_check_violation("There must be no self-reference.") +@listens_for(AdminUnitRelation, "before_insert") +@listens_for(AdminUnitRelation, "before_update") +def before_saving_admin_unit_relation(mapper, connect, self): + self.validate() + + class AdminUnit(db.Model, TrackableMixin): __tablename__ = "adminunit" id = Column(Integer(), primary_key=True) @@ -765,6 +771,11 @@ class Event(db.Model, TrackableMixin, EventMixin): event_place = db.relationship("EventPlace", uselist=False) categories = relationship("EventCategory", secondary="event_eventcategories") + co_organizers = relationship( + "EventOrganizer", + secondary="event_coorganizers", + backref=backref("co_organized_events", lazy=True), + ) public_status = Column( IntegerEnum(PublicStatus), @@ -798,12 +809,30 @@ class Event(db.Model, TrackableMixin, EventMixin): else: return None + @property + def co_organizer_ids(self): + return [c.id for c in self.co_organizers] + + @co_organizer_ids.setter + def co_organizer_ids(self, value): + self.co_organizers = EventOrganizer.query.filter( + EventOrganizer.id.in_(value) + ).all() + def validate(self): if self.organizer and self.organizer.admin_unit_id != self.admin_unit_id: - raise make_check_violation("Invalid organizer") + raise make_check_violation("Invalid organizer.") + + if self.co_organizers: + for co_organizer in self.co_organizers: + if ( + co_organizer.admin_unit_id != self.admin_unit_id + or co_organizer.id == self.organizer_id + ): + raise make_check_violation("Invalid co-organizer.") if self.event_place and self.event_place.admin_unit_id != self.admin_unit_id: - raise make_check_violation("Invalid place") + raise make_check_violation("Invalid place.") if self.start and self.end: if self.start > self.end: @@ -816,7 +845,8 @@ class Event(db.Model, TrackableMixin, EventMixin): @listens_for(Event, "before_insert") @listens_for(Event, "before_update") -def purge_event(mapper, connect, self): +def before_saving_event(mapper, connect, self): + self.validate() self.purge_event_mixin() @@ -842,6 +872,7 @@ def purge_event_date(mapper, connect, self): class EventEventCategories(db.Model): __tablename__ = "event_eventcategories" + __table_args__ = (UniqueConstraint("event_id", "category_id"),) id = Column(Integer(), primary_key=True) event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False) category_id = db.Column( @@ -851,6 +882,7 @@ class EventEventCategories(db.Model): class EventSuggestionEventCategories(db.Model): __tablename__ = "eventsuggestion_eventcategories" + __table_args__ = (UniqueConstraint("event_suggestion_id", "category_id"),) id = Column(Integer(), primary_key=True) event_suggestion_id = db.Column( db.Integer, db.ForeignKey("eventsuggestion.id"), nullable=False @@ -860,6 +892,16 @@ class EventSuggestionEventCategories(db.Model): ) +class EventCoOrganizers(db.Model): + __tablename__ = "event_coorganizers" + __table_args__ = (UniqueConstraint("event_id", "organizer_id"),) + id = Column(Integer(), primary_key=True) + event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False) + organizer_id = db.Column( + db.Integer, db.ForeignKey("eventorganizer.id"), nullable=False + ) + + class Analytics(db.Model): __tablename__ = "analytics" id = Column(Integer(), primary_key=True) diff --git a/project/templates/_macros.html b/project/templates/_macros.html index a673151..cba8592 100644 --- a/project/templates/_macros.html +++ b/project/templates/_macros.html @@ -491,25 +491,19 @@ {% if event.organizer %} -
{{ _('Organizer') }}
-
{{ render_string_prop(event.organizer.name) }}
- - {% if event.organizer.logo_id %} -
{{ render_logo(event.organizer.logo) }}
- {% endif %} - - {{ render_link_prop(event.organizer.url) }} - {{ render_email_prop(event.organizer.email) }} - {{ render_phone_prop(event.organizer.phone) }} - {{ render_fax_prop(event.organizer.fax) }} + {{ render_event_props_organizer(event.organizer) }} + {% for co_organizer in event.co_organizers %} + 0 %} class="mt-4"{% endif %}> + {{ render_event_props_organizer(co_organizer) }} +
+ {% endfor %}
- {% endif %} {% if show_admin_unit %} @@ -539,6 +533,19 @@ {% endmacro %} +{% macro render_event_props_organizer(organizer) %} +
{{ render_string_prop(organizer.name) }}
+ +{% if organizer.logo_id %} +
{{ render_logo(organizer.logo) }}
+{% endif %} + +{{ render_link_prop(organizer.url) }} +{{ render_email_prop(organizer.email) }} +{{ render_phone_prop(organizer.phone) }} +{{ render_fax_prop(organizer.fax) }} +{% endmacro %} + {% macro render_event_props_seo(event, start, end, allday, dates = None, show_rating = False, show_admin_unit = True, user_rights=None, share_links=None, calendar_links=None) %}
@@ -648,22 +655,12 @@

{{ _('Organizer') }}

-
- {% if event.organizer.logo_id %} -
{{ render_logo(event.organizer.logo) }}
- {% endif %} - -
-
- {{ render_string_prop(event.organizer.name) }} -
- - {{ render_link_prop(event.organizer.url) }} - {{ render_email_prop(event.organizer.email) }} - {{ render_phone_prop(event.organizer.phone) }} - {{ render_fax_prop(event.organizer.fax) }} + {{ render_event_props_seo_organizer(event.organizer) }} + {% for co_organizer in event.co_organizers %} + 0 %} class="mt-4"{% endif %}> + {{ render_event_props_seo_organizer(co_organizer) }}
-
+ {% endfor %}
@@ -710,6 +707,25 @@ {% endmacro %} +{% macro render_event_props_seo_organizer(organizer) %} +
+ {% if organizer.logo_id %} +
{{ render_logo(organizer.logo) }}
+ {% endif %} + +
+
+ {{ render_string_prop(organizer.name) }} +
+ + {{ render_link_prop(organizer.url) }} + {{ render_email_prop(organizer.email) }} + {{ render_phone_prop(organizer.phone) }} + {{ render_fax_prop(organizer.fax) }} +
+
+{% endmacro %} + {% macro render_google_place_autocomplete_header() %} @@ -165,6 +187,7 @@
{{ render_field_with_errors(form.organizer_id, class="w-100", label_hidden=True) }} + {{ render_field_with_errors(form.co_organizer_ids, class="w-100") }}
diff --git a/project/translations/de/LC_MESSAGES/messages.mo b/project/translations/de/LC_MESSAGES/messages.mo index dbdbcd5..d583785 100644 Binary files a/project/translations/de/LC_MESSAGES/messages.mo and b/project/translations/de/LC_MESSAGES/messages.mo differ diff --git a/project/translations/de/LC_MESSAGES/messages.po b/project/translations/de/LC_MESSAGES/messages.po index c5aff84..cd5c71d 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-09-10 09:01+0200\n" +"POT-Creation-Date: 2021-09-19 16:31+0200\n" "PO-Revision-Date: 2020-06-07 18:51+0200\n" "Last-Translator: FULL NAME \n" "Language: de\n" @@ -192,7 +192,7 @@ msgstr "Nutzungsbedingungen" msgid "Legal notice" msgstr "Impressum" -#: project/forms/admin.py:12 project/templates/_macros.html:1389 +#: project/forms/admin.py:12 project/templates/_macros.html:1405 #: project/templates/layout.html:313 #: project/templates/widget/event_suggestion/create.html:204 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -284,7 +284,7 @@ msgid "Longitude" msgstr "Längengrad" #: project/forms/admin_unit.py:28 project/forms/event.py:36 -#: project/forms/event.py:65 project/forms/event.py:379 +#: project/forms/event.py:65 project/forms/event.py:399 #: 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 @@ -307,7 +307,7 @@ msgstr "" "eindeutig zu identifizieren. Der Kurzname darf nur Buchstaben, Nummern " "und Unterstriche enthalten." -#: project/forms/admin_unit.py:40 project/templates/_macros.html:1525 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1541 msgid "Short name must contain only letters numbers or underscore" msgstr "Der Kurzname darf nur Buchstaben, Nummern und Unterstriche enthalten" @@ -321,7 +321,7 @@ msgstr "Link URL" #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 #: 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:1485 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1501 project/templates/admin/users.html:19 msgid "Email" msgstr "Email" @@ -505,8 +505,8 @@ msgstr "" msgid "All-day" msgstr "Ganztägig" -#: project/forms/event.py:86 project/templates/event/create.html:252 -#: project/templates/event/update.html:143 +#: project/forms/event.py:86 project/templates/event/create.html:274 +#: project/templates/event/update.html:165 #: project/templates/widget/event_suggestion/create.html:240 msgid "Recurring event" msgstr "Regelmäßige Veranstaltung" @@ -674,16 +674,16 @@ 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:208 project/templates/_macros.html:1246 +#: project/forms/event.py:208 project/templates/_macros.html:1262 msgid "The start must be before the end." msgstr "Der Start muss vor dem Ende sein." -#: project/forms/event.py:214 project/templates/_macros.html:1263 +#: project/forms/event.py:214 project/templates/_macros.html:1279 msgid "An event can last a maximum of 14 days." msgstr "Eine Veranstaltung darf maximal 14 Tage dauern." #: project/forms/event.py:222 project/templates/_macros.html:419 -#: project/templates/_macros.html:575 +#: project/templates/_macros.html:582 msgid "Previous start date" msgstr "Vorheriges Startdatum" @@ -703,8 +703,8 @@ msgstr "Wähle Kategorien, die zur Veranstaltung passen." #: project/forms/event.py:235 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:76 -#: project/templates/event/create.html:366 -#: project/templates/event/update.html:223 +#: project/templates/event/create.html:390 +#: project/templates/event/update.html:246 msgid "Rating" msgstr "Bewertung" @@ -717,156 +717,172 @@ 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:247 project/forms/event.py:256 -#: project/forms/event.py:325 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:459 project/templates/_macros.html:612 -#: project/templates/event/create.html:291 -#: project/templates/event/update.html:173 +#: project/forms/event.py:244 +msgid "Co-organizers" +msgstr "Mitveranstalter" + +#: project/forms/event.py:247 +msgid "" +"Select optional co-organizers. You can add and modify organizers at " +"Organization > Organizers." +msgstr "" +"Wähle optionale Mitveranstalter. Du kannst Veranstalter unter " +"Organisation > Veranstalter hinzufügen und ändern." + +#: project/forms/event.py:258 +msgid "Invalid co-organizer." +msgstr "Ungültiger Mitveranstalter." + +#: project/forms/event.py:267 project/forms/event.py:276 +#: project/forms/event.py:345 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:459 project/templates/_macros.html:619 +#: project/templates/event/create.html:315 +#: project/templates/event/update.html:196 #: project/templates/event_place/create.html:31 #: project/templates/event_place/delete.html:13 #: project/templates/event_place/update.html:31 msgid "Place" msgstr "Ort" -#: project/forms/event.py:249 +#: project/forms/event.py:269 msgid "Select existing place" msgstr "Vorhandenen Ort auswählen" -#: project/forms/event.py:250 +#: project/forms/event.py:270 msgid "Enter new place" msgstr "Neuen Ort eingeben" -#: project/forms/event.py:263 project/forms/event.py:272 -#: project/forms/event.py:333 project/forms/event.py:395 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:497 -#: project/templates/_macros.html:649 project/templates/event/create.html:262 -#: project/templates/event/update.html:164 +#: project/forms/event.py:283 project/forms/event.py:292 +#: project/forms/event.py:353 project/forms/event.py:415 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:496 +#: project/templates/_macros.html:656 project/templates/event/create.html:284 +#: project/templates/event/update.html:186 #: project/templates/organizer/create.html:27 #: project/templates/organizer/delete.html:13 #: project/templates/organizer/update.html:27 msgid "Organizer" msgstr "Veranstalter" -#: project/forms/event.py:265 +#: project/forms/event.py:285 msgid "Select existing organizer" msgstr "Vorhandenen Veranstalter auswählen" -#: project/forms/event.py:266 +#: project/forms/event.py:286 msgid "Enter new organizer" msgstr "Neuen Veranstalter eingeben" -#: project/forms/event.py:278 +#: project/forms/event.py:298 msgid "Save as draft" msgstr "Als Entwurf speichern" -#: project/forms/event.py:279 +#: project/forms/event.py:299 msgid "Publish event" msgstr "Veranstaltung veröffentlichen" -#: project/forms/event.py:309 +#: project/forms/event.py:329 msgid "Select existing place or enter new place" msgstr "Existierenden Ort wählen oder neuen Ort eingeben" -#: project/forms/event.py:316 +#: project/forms/event.py:336 msgid "Select existing organizer or enter new organizer" msgstr "Wähle einen vorhandenen Veranstalter oder gib einen neuen Veranstalter ein" -#: project/forms/event.py:328 +#: project/forms/event.py:348 msgid "" "Choose where the event takes place. You can add and modify places at " -"Manage > Places." +"Organization > Places." msgstr "" -"Wähle, wo die Veranstaltung stattfindet. Du kannst Orte unter Verwaltung " -"> Orte hinzufügen und ändern." +"Wähle, wo die Veranstaltung stattfindet. Du kannst Orte unter " +"Organisation > Orte hinzufügen und ändern." -#: project/forms/event.py:336 +#: project/forms/event.py:356 msgid "" -"Select the organizer. You can add and modify organizers at Manage > " -"Organizers." +"Select the organizer. You can add and modify organizers at Organization >" +" Organizers." msgstr "" -"Wähle den Veranstalter. Du kannst Veranstalter unter Verwaltung > " +"Wähle den Veranstalter. Du kannst Veranstalter unter Organisation > " "Veranstalter hinzufügen und ändern." -#: project/forms/event.py:342 project/templates/event/update.html:153 +#: project/forms/event.py:362 project/templates/event/update.html:175 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "Status" -#: project/forms/event.py:345 +#: project/forms/event.py:365 msgid "EventStatus.scheduled" msgstr "Geplant" -#: project/forms/event.py:346 project/templates/layout.html:82 +#: project/forms/event.py:366 project/templates/layout.html:82 #: project/templates/layout.html:97 msgid "EventStatus.cancelled" msgstr "Abgesagt" -#: project/forms/event.py:347 project/templates/layout.html:85 +#: project/forms/event.py:367 project/templates/layout.html:85 #: project/templates/layout.html:100 msgid "EventStatus.movedOnline" msgstr "Online verschoben" -#: project/forms/event.py:348 project/templates/layout.html:88 +#: project/forms/event.py:368 project/templates/layout.html:88 #: project/templates/layout.html:103 msgid "EventStatus.postponed" msgstr "Verschoben" -#: project/forms/event.py:349 project/templates/layout.html:91 +#: project/forms/event.py:369 project/templates/layout.html:91 #: project/templates/layout.html:106 msgid "EventStatus.rescheduled" msgstr "Neu angesetzt" -#: project/forms/event.py:351 +#: project/forms/event.py:371 msgid "Select the status of the event." msgstr "Wähle den Status der Veranstaltung." -#: project/forms/event.py:355 +#: project/forms/event.py:375 msgid "Public status" msgstr "Öffentlicher Status" -#: project/forms/event.py:358 +#: project/forms/event.py:378 msgid "PublicStatus.published" msgstr "Veröffentlicht" -#: project/forms/event.py:359 project/templates/_macros.html:282 +#: project/forms/event.py:379 project/templates/_macros.html:282 msgid "PublicStatus.draft" msgstr "Entwurf" -#: project/forms/event.py:361 +#: project/forms/event.py:381 msgid "Select the public status of the event." msgstr "Wähle den öffentlichen Status der Veranstaltung." -#: project/forms/event.py:364 project/templates/event/update.html:5 -#: project/templates/event/update.html:119 +#: project/forms/event.py:384 project/templates/event/update.html:5 +#: project/templates/event/update.html:141 msgid "Update event" msgstr "Veranstaltung aktualisieren" -#: project/forms/event.py:378 project/templates/_macros.html:1218 +#: project/forms/event.py:398 project/templates/_macros.html:1234 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "Veranstaltung löschen" -#: project/forms/event.py:386 project/forms/event_date.py:15 +#: project/forms/event.py:406 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "Von" -#: project/forms/event.py:388 project/forms/event_date.py:17 +#: project/forms/event.py:408 project/forms/event_date.py:17 #: project/forms/planing.py:16 msgid "to" msgstr "bis" -#: project/forms/event.py:390 project/forms/event_date.py:19 +#: project/forms/event.py:410 project/forms/event_date.py:19 msgid "Keyword" msgstr "Stichwort" -#: project/forms/event.py:392 project/forms/event_date.py:21 +#: project/forms/event.py:412 project/forms/event_date.py:21 #: project/forms/planing.py:19 project/templates/_macros.html:392 msgid "Category" msgstr "Kategorie" -#: project/forms/event.py:398 +#: project/forms/event.py:418 msgid "Find events" msgstr "Veranstaltungen finden" @@ -927,7 +943,7 @@ msgstr "Bitte gib deine Email-Adresse oder deine Telefonnummer für die Prüfung msgid "I would like to be notified by email after the review" msgstr "Ich möchte per Email benachrichtigt werden nach der Prüfung" -#: project/forms/event_suggestion.py:52 project/templates/event/create.html:296 +#: project/forms/event_suggestion.py:52 project/templates/event/create.html:320 msgid "" "Choose where the event takes place. If the venue is not yet in the list, " "just enter it." @@ -935,7 +951,7 @@ msgstr "" "Wähle aus, wo die Veranstaltung stattfindet. Ist der Veranstaltungsort " "noch nicht in der Liste, trage ihn einfach ein." -#: project/forms/event_suggestion.py:62 project/templates/event/create.html:266 +#: project/forms/event_suggestion.py:62 project/templates/event/create.html:288 msgid "" "Select the organizer. If the organizer is not yet on the list, just enter" " it." @@ -1019,7 +1035,7 @@ msgid "Weekdays" msgstr "Wochentage" #: project/forms/reference.py:11 project/forms/reference_request.py:16 -#: project/templates/_macros.html:518 project/templates/_macros.html:675 +#: project/templates/_macros.html:512 project/templates/_macros.html:672 #: project/templates/admin_unit/create.html:28 #: project/templates/admin_unit/update.html:29 #: project/templates/layout.html:258 @@ -1047,7 +1063,7 @@ msgstr "Anfrage speichern" msgid "Delete request" msgstr "Anfrage löschen" -#: project/forms/reference_request.py:28 project/templates/_macros.html:1401 +#: project/forms/reference_request.py:28 project/templates/_macros.html:1417 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1114,7 +1130,7 @@ msgid "This field is required." msgstr "Dieses Feld ist erforderlich." #: project/templates/_macros.html:134 project/templates/_macros.html:414 -#: project/templates/_macros.html:914 +#: project/templates/_macros.html:930 msgid "Date" msgstr "Datum" @@ -1154,66 +1170,66 @@ msgstr "Zuletzt aktualisiert am %(updated_at)s von %(updated_by)s." msgid "Last updated at %(updated_at)s." msgstr "Zuletzt aktualisiert am %(updated_at)s." -#: project/templates/_macros.html:408 project/templates/_macros.html:571 +#: project/templates/_macros.html:408 project/templates/_macros.html:578 #: project/templates/event/actions.html:12 -#: project/templates/event/create.html:235 +#: project/templates/event/create.html:257 #: project/templates/event/delete.html:13 -#: project/templates/event/update.html:126 +#: project/templates/event/update.html:148 #: project/templates/widget/event_suggestion/create.html:229 msgid "Event" msgstr "Veranstaltung" -#: project/templates/_macros.html:441 project/templates/_macros.html:593 -#: project/templates/_macros.html:1470 project/templates/event/actions.html:32 +#: project/templates/_macros.html:441 project/templates/_macros.html:600 +#: project/templates/_macros.html:1486 project/templates/event/actions.html:32 msgid "Share" msgstr "Teilen" -#: project/templates/_macros.html:445 project/templates/_macros.html:597 -#: project/templates/_macros.html:1500 +#: project/templates/_macros.html:445 project/templates/_macros.html:604 +#: project/templates/_macros.html:1516 msgid "Add to calendar" msgstr "Zum Kalender" -#: project/templates/_macros.html:453 project/templates/_macros.html:605 +#: project/templates/_macros.html:453 project/templates/_macros.html:612 #: project/templates/event/report.html:4 msgid "Report event" msgstr "Veranstaltung melden" -#: project/templates/_macros.html:480 project/templates/_macros.html:631 +#: project/templates/_macros.html:480 project/templates/_macros.html:638 msgid "Show directions" msgstr "Anreise planen" -#: project/templates/_macros.html:485 project/templates/_macros.html:636 +#: project/templates/_macros.html:485 project/templates/_macros.html:643 msgid "The event takes place online." msgstr "Die Veranstaltung findet online statt." -#: project/templates/_macros.html:487 project/templates/_macros.html:638 +#: project/templates/_macros.html:487 project/templates/_macros.html:645 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:699 project/templates/event_date/list.html:5 +#: project/templates/_macros.html:696 project/templates/event_date/list.html:5 #: project/templates/event_date/list.html:300 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "Termine" -#: project/templates/_macros.html:772 +#: project/templates/_macros.html:788 msgid "Search location on Google" msgstr "Ort bei Google suchen" -#: project/templates/_macros.html:838 +#: project/templates/_macros.html:854 #, python-format msgid "%(count)d event dates" msgstr "%(count)d Termine" -#: project/templates/_macros.html:854 project/templates/_macros.html:856 +#: project/templates/_macros.html:870 project/templates/_macros.html:872 #: project/templates/event_date/list.html:321 msgid "First" msgstr "Letzte" -#: project/templates/_macros.html:859 project/templates/_macros.html:861 +#: project/templates/_macros.html:875 project/templates/_macros.html:877 #: project/templates/event_date/list.html:322 #: project/templates/widget/event_suggestion/create.html:193 #: project/templates/widget/event_suggestion/create.html:218 @@ -1224,12 +1240,12 @@ msgstr "Letzte" msgid "Previous" msgstr "Zurück" -#: project/templates/_macros.html:863 +#: project/templates/_macros.html:879 #, 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:865 project/templates/_macros.html:867 +#: project/templates/_macros.html:881 project/templates/_macros.html:883 #: project/templates/event_date/list.html:324 #: project/templates/widget/event_suggestion/create.html:194 #: project/templates/widget/event_suggestion/create.html:219 @@ -1239,73 +1255,73 @@ msgstr "Seite %(page)d von %(pages)d (%(total)d insgesamt)" msgid "Next" msgstr "Weiter" -#: project/templates/_macros.html:870 project/templates/_macros.html:872 +#: project/templates/_macros.html:886 project/templates/_macros.html:888 #: project/templates/event_date/list.html:325 msgid "Last" msgstr "Erste" -#: project/templates/_macros.html:937 +#: project/templates/_macros.html:953 msgid "Radius" msgstr "Umkreis" -#: project/templates/_macros.html:1147 +#: project/templates/_macros.html:1163 msgid "Edit image" msgstr "Bild bearbeiten" -#: project/templates/_macros.html:1168 +#: project/templates/_macros.html:1184 msgid "Close" msgstr "Schließen" -#: project/templates/_macros.html:1169 +#: project/templates/_macros.html:1185 msgid "Okay" msgstr "OK" -#: project/templates/_macros.html:1181 +#: project/templates/_macros.html:1197 msgid "Choose image file" msgstr "Bild-Datei auswählen" -#: project/templates/_macros.html:1217 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1233 project/templates/event/actions.html:46 msgid "Edit event" msgstr "Veranstaltung bearbeiten" -#: project/templates/_macros.html:1220 project/templates/manage/events.html:40 +#: project/templates/_macros.html:1236 project/templates/manage/events.html:40 msgid "More" msgstr "Mehr" -#: project/templates/_macros.html:1267 +#: project/templates/_macros.html:1283 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:1295 +#: project/templates/_macros.html:1311 #, python-format msgid "Just use %(term)s" msgstr "Verwende einfach %(term)s" -#: project/templates/_macros.html:1361 +#: project/templates/_macros.html:1377 msgid "Event suggestion" msgstr "Veranstaltungsvorschlag" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Link copied" msgstr "Link kopiert" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Copy link" msgstr "Link kopieren" -#: project/templates/_macros.html:1508 +#: project/templates/_macros.html:1524 msgid "Google calendar" msgstr "Google Kalender" -#: project/templates/_macros.html:1509 +#: project/templates/_macros.html:1525 msgid "Apple calendar" msgstr "Apple Kalender" -#: project/templates/_macros.html:1510 +#: project/templates/_macros.html:1526 msgid "Yahoo calendar" msgstr "Yahoo Kalender" -#: project/templates/_macros.html:1511 +#: project/templates/_macros.html:1527 msgid "Other calendar" msgstr "Anderer Kalender" @@ -1365,7 +1381,7 @@ msgid "Show events" msgstr "Veranstaltungen anzeigen" #: project/templates/event/create.html:5 -#: project/templates/event/create.html:228 project/templates/layout.html:226 +#: project/templates/event/create.html:250 project/templates/layout.html:226 #: project/templates/manage/events.html:22 #: project/templates/manage/organizers.html:21 msgid "Create event" @@ -1482,8 +1498,8 @@ msgstr "Bearbeiten" #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 -#: project/templates/event/create.html:354 -#: project/templates/event/update.html:211 +#: project/templates/event/create.html:378 +#: project/templates/event/update.html:234 #: project/templates/event_place/create.html:57 #: project/templates/event_place/update.html:57 #: project/templates/organizer/create.html:56 @@ -1610,31 +1626,33 @@ msgid "Enter place or address" msgstr "Orte oder Adresse eingeben" #: project/templates/event/create.html:183 +#: project/templates/event/create.html:240 #: project/templates/event/update.html:106 +#: project/templates/event/update.html:132 #: project/templates/widget/event_suggestion/create.html:129 msgid "Enter organizer" msgstr "Veranstalter eingeben" -#: project/templates/event/create.html:245 -#: project/templates/event/update.html:136 +#: project/templates/event/create.html:267 +#: project/templates/event/update.html:158 msgid "Event date" msgstr "Termin" -#: project/templates/event/create.html:283 +#: project/templates/event/create.html:305 msgid "Switch to organizer search" msgstr "Zur Veranstaltersuche wechseln" -#: project/templates/event/create.html:316 +#: project/templates/event/create.html:340 msgid "Switch to place search" msgstr "Zur Ortssuche wechseln" -#: project/templates/event/create.html:327 -#: project/templates/event/update.html:184 +#: project/templates/event/create.html:351 +#: project/templates/event/update.html:207 msgid "Access" msgstr "Zugang" -#: project/templates/event/create.html:341 -#: project/templates/event/update.html:198 +#: project/templates/event/create.html:365 +#: project/templates/event/update.html:221 msgid "Target group" msgstr "Zielgruppe" @@ -1943,11 +1961,11 @@ msgstr "Der eingegebene Name entspricht nicht dem Namen der Veranstaltung" msgid "Event successfully deleted" msgstr "Veranstaltung erfolgreich gelöscht" -#: project/views/event.py:397 +#: project/views/event.py:404 msgid "Referenced event changed" msgstr "Empfohlene Veranstaltung wurde geändert" -#: project/views/event.py:420 +#: project/views/event.py:427 msgid "New event report" msgstr "Neue Meldung zu einer Veranstaltung" diff --git a/project/translations/en/LC_MESSAGES/messages.mo b/project/translations/en/LC_MESSAGES/messages.mo index 824e6b0..b96d6be 100644 Binary files a/project/translations/en/LC_MESSAGES/messages.mo and b/project/translations/en/LC_MESSAGES/messages.mo differ diff --git a/project/translations/en/LC_MESSAGES/messages.po b/project/translations/en/LC_MESSAGES/messages.po index 555153a..9198fd0 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-09-10 09:01+0200\n" +"POT-Creation-Date: 2021-09-19 16:31+0200\n" "PO-Revision-Date: 2021-04-30 15:04+0200\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -192,7 +192,7 @@ msgstr "" msgid "Legal notice" msgstr "" -#: project/forms/admin.py:12 project/templates/_macros.html:1389 +#: project/forms/admin.py:12 project/templates/_macros.html:1405 #: project/templates/layout.html:313 #: project/templates/widget/event_suggestion/create.html:204 #: project/views/admin_unit.py:36 project/views/root.py:58 @@ -280,7 +280,7 @@ msgid "Longitude" msgstr "" #: project/forms/admin_unit.py:28 project/forms/event.py:36 -#: project/forms/event.py:65 project/forms/event.py:379 +#: project/forms/event.py:65 project/forms/event.py:399 #: 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 @@ -300,7 +300,7 @@ 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:1525 +#: project/forms/admin_unit.py:40 project/templates/_macros.html:1541 msgid "Short name must contain only letters numbers or underscore" msgstr "" @@ -314,7 +314,7 @@ msgstr "" #: project/forms/admin_unit_member.py:23 project/forms/admin_unit_member.py:28 #: 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:1485 project/templates/admin/users.html:19 +#: project/templates/_macros.html:1501 project/templates/admin/users.html:19 msgid "Email" msgstr "" @@ -493,8 +493,8 @@ msgstr "" msgid "All-day" msgstr "" -#: project/forms/event.py:86 project/templates/event/create.html:252 -#: project/templates/event/update.html:143 +#: project/forms/event.py:86 project/templates/event/create.html:274 +#: project/templates/event/update.html:165 #: project/templates/widget/event_suggestion/create.html:240 msgid "Recurring event" msgstr "" @@ -651,16 +651,16 @@ msgid "" " course it works without it." msgstr "" -#: project/forms/event.py:208 project/templates/_macros.html:1246 +#: project/forms/event.py:208 project/templates/_macros.html:1262 msgid "The start must be before the end." msgstr "" -#: project/forms/event.py:214 project/templates/_macros.html:1263 +#: project/forms/event.py:214 project/templates/_macros.html:1279 msgid "An event can last a maximum of 14 days." msgstr "" #: project/forms/event.py:222 project/templates/_macros.html:419 -#: project/templates/_macros.html:575 +#: project/templates/_macros.html:582 msgid "Previous start date" msgstr "" @@ -678,8 +678,8 @@ msgstr "" #: project/forms/event.py:235 project/forms/reference.py:14 #: project/forms/reference.py:27 project/forms/reference_request.py:76 -#: project/templates/event/create.html:366 -#: project/templates/event/update.html:223 +#: project/templates/event/create.html:390 +#: project/templates/event/update.html:246 msgid "Rating" msgstr "" @@ -690,152 +690,166 @@ msgid "" "visible and is used for sorting." msgstr "" -#: project/forms/event.py:247 project/forms/event.py:256 -#: project/forms/event.py:325 project/forms/event_suggestion.py:50 -#: project/templates/_macros.html:459 project/templates/_macros.html:612 -#: project/templates/event/create.html:291 -#: project/templates/event/update.html:173 +#: project/forms/event.py:244 +msgid "Co-organizers" +msgstr "" + +#: project/forms/event.py:247 +msgid "" +"Select optional co-organizers. You can add and modify organizers at " +"Organization > Organizers." +msgstr "" + +#: project/forms/event.py:258 +msgid "Invalid co-organizer." +msgstr "" + +#: project/forms/event.py:267 project/forms/event.py:276 +#: project/forms/event.py:345 project/forms/event_suggestion.py:50 +#: project/templates/_macros.html:459 project/templates/_macros.html:619 +#: project/templates/event/create.html:315 +#: project/templates/event/update.html:196 #: project/templates/event_place/create.html:31 #: project/templates/event_place/delete.html:13 #: project/templates/event_place/update.html:31 msgid "Place" msgstr "" -#: project/forms/event.py:249 +#: project/forms/event.py:269 msgid "Select existing place" msgstr "" -#: project/forms/event.py:250 +#: project/forms/event.py:270 msgid "Enter new place" msgstr "" -#: project/forms/event.py:263 project/forms/event.py:272 -#: project/forms/event.py:333 project/forms/event.py:395 -#: project/forms/event_suggestion.py:60 project/templates/_macros.html:497 -#: project/templates/_macros.html:649 project/templates/event/create.html:262 -#: project/templates/event/update.html:164 +#: project/forms/event.py:283 project/forms/event.py:292 +#: project/forms/event.py:353 project/forms/event.py:415 +#: project/forms/event_suggestion.py:60 project/templates/_macros.html:496 +#: project/templates/_macros.html:656 project/templates/event/create.html:284 +#: project/templates/event/update.html:186 #: project/templates/organizer/create.html:27 #: project/templates/organizer/delete.html:13 #: project/templates/organizer/update.html:27 msgid "Organizer" msgstr "" -#: project/forms/event.py:265 +#: project/forms/event.py:285 msgid "Select existing organizer" msgstr "" -#: project/forms/event.py:266 +#: project/forms/event.py:286 msgid "Enter new organizer" msgstr "" -#: project/forms/event.py:278 +#: project/forms/event.py:298 msgid "Save as draft" msgstr "" -#: project/forms/event.py:279 +#: project/forms/event.py:299 msgid "Publish event" msgstr "" -#: project/forms/event.py:309 +#: project/forms/event.py:329 msgid "Select existing place or enter new place" msgstr "" -#: project/forms/event.py:316 +#: project/forms/event.py:336 msgid "Select existing organizer or enter new organizer" msgstr "" -#: project/forms/event.py:328 +#: project/forms/event.py:348 msgid "" "Choose where the event takes place. You can add and modify places at " -"Manage > Places." +"Organization > Places." msgstr "" -#: project/forms/event.py:336 +#: project/forms/event.py:356 msgid "" -"Select the organizer. You can add and modify organizers at Manage > " -"Organizers." +"Select the organizer. You can add and modify organizers at Organization >" +" Organizers." msgstr "" -#: project/forms/event.py:342 project/templates/event/update.html:153 +#: project/forms/event.py:362 project/templates/event/update.html:175 #: project/templates/oauth2_token/list.html:21 msgid "Status" msgstr "" -#: project/forms/event.py:345 +#: project/forms/event.py:365 msgid "EventStatus.scheduled" msgstr "Scheduled" -#: project/forms/event.py:346 project/templates/layout.html:82 +#: project/forms/event.py:366 project/templates/layout.html:82 #: project/templates/layout.html:97 msgid "EventStatus.cancelled" msgstr "Cancelled" -#: project/forms/event.py:347 project/templates/layout.html:85 +#: project/forms/event.py:367 project/templates/layout.html:85 #: project/templates/layout.html:100 msgid "EventStatus.movedOnline" msgstr "Moved online" -#: project/forms/event.py:348 project/templates/layout.html:88 +#: project/forms/event.py:368 project/templates/layout.html:88 #: project/templates/layout.html:103 msgid "EventStatus.postponed" msgstr "Postponed" -#: project/forms/event.py:349 project/templates/layout.html:91 +#: project/forms/event.py:369 project/templates/layout.html:91 #: project/templates/layout.html:106 msgid "EventStatus.rescheduled" msgstr "Rescheduled" -#: project/forms/event.py:351 +#: project/forms/event.py:371 msgid "Select the status of the event." msgstr "" -#: project/forms/event.py:355 +#: project/forms/event.py:375 msgid "Public status" msgstr "" -#: project/forms/event.py:358 +#: project/forms/event.py:378 msgid "PublicStatus.published" msgstr "" -#: project/forms/event.py:359 project/templates/_macros.html:282 +#: project/forms/event.py:379 project/templates/_macros.html:282 msgid "PublicStatus.draft" msgstr "" -#: project/forms/event.py:361 +#: project/forms/event.py:381 msgid "Select the public status of the event." msgstr "" -#: project/forms/event.py:364 project/templates/event/update.html:5 -#: project/templates/event/update.html:119 +#: project/forms/event.py:384 project/templates/event/update.html:5 +#: project/templates/event/update.html:141 msgid "Update event" msgstr "" -#: project/forms/event.py:378 project/templates/_macros.html:1218 +#: project/forms/event.py:398 project/templates/_macros.html:1234 #: project/templates/event/actions.html:47 #: project/templates/event/delete.html:6 msgid "Delete event" msgstr "" -#: project/forms/event.py:386 project/forms/event_date.py:15 +#: project/forms/event.py:406 project/forms/event_date.py:15 #: project/forms/planing.py:14 msgid "From" msgstr "" -#: project/forms/event.py:388 project/forms/event_date.py:17 +#: project/forms/event.py:408 project/forms/event_date.py:17 #: project/forms/planing.py:16 msgid "to" msgstr "" -#: project/forms/event.py:390 project/forms/event_date.py:19 +#: project/forms/event.py:410 project/forms/event_date.py:19 msgid "Keyword" msgstr "" -#: project/forms/event.py:392 project/forms/event_date.py:21 +#: project/forms/event.py:412 project/forms/event_date.py:21 #: project/forms/planing.py:19 project/templates/_macros.html:392 msgid "Category" msgstr "" -#: project/forms/event.py:398 +#: project/forms/event.py:418 msgid "Find events" msgstr "" @@ -896,13 +910,13 @@ msgstr "" msgid "I would like to be notified by email after the review" msgstr "" -#: project/forms/event_suggestion.py:52 project/templates/event/create.html:296 +#: project/forms/event_suggestion.py:52 project/templates/event/create.html:320 msgid "" "Choose where the event takes place. If the venue is not yet in the list, " "just enter it." msgstr "" -#: project/forms/event_suggestion.py:62 project/templates/event/create.html:266 +#: project/forms/event_suggestion.py:62 project/templates/event/create.html:288 msgid "" "Select the organizer. If the organizer is not yet on the list, just enter" " it." @@ -984,7 +998,7 @@ msgid "Weekdays" msgstr "" #: project/forms/reference.py:11 project/forms/reference_request.py:16 -#: project/templates/_macros.html:518 project/templates/_macros.html:675 +#: project/templates/_macros.html:512 project/templates/_macros.html:672 #: project/templates/admin_unit/create.html:28 #: project/templates/admin_unit/update.html:29 #: project/templates/layout.html:258 @@ -1012,7 +1026,7 @@ msgstr "" msgid "Delete request" msgstr "" -#: project/forms/reference_request.py:28 project/templates/_macros.html:1401 +#: project/forms/reference_request.py:28 project/templates/_macros.html:1417 #: project/templates/event_suggestion/review_status.html:18 #: project/templates/reference_request/review_status.html:12 msgid "Review status" @@ -1079,7 +1093,7 @@ msgid "This field is required." msgstr "" #: project/templates/_macros.html:134 project/templates/_macros.html:414 -#: project/templates/_macros.html:914 +#: project/templates/_macros.html:930 msgid "Date" msgstr "" @@ -1119,64 +1133,64 @@ msgstr "" msgid "Last updated at %(updated_at)s." msgstr "" -#: project/templates/_macros.html:408 project/templates/_macros.html:571 +#: project/templates/_macros.html:408 project/templates/_macros.html:578 #: project/templates/event/actions.html:12 -#: project/templates/event/create.html:235 +#: project/templates/event/create.html:257 #: project/templates/event/delete.html:13 -#: project/templates/event/update.html:126 +#: project/templates/event/update.html:148 #: project/templates/widget/event_suggestion/create.html:229 msgid "Event" msgstr "" -#: project/templates/_macros.html:441 project/templates/_macros.html:593 -#: project/templates/_macros.html:1470 project/templates/event/actions.html:32 +#: project/templates/_macros.html:441 project/templates/_macros.html:600 +#: project/templates/_macros.html:1486 project/templates/event/actions.html:32 msgid "Share" msgstr "" -#: project/templates/_macros.html:445 project/templates/_macros.html:597 -#: project/templates/_macros.html:1500 +#: project/templates/_macros.html:445 project/templates/_macros.html:604 +#: project/templates/_macros.html:1516 msgid "Add to calendar" msgstr "" -#: project/templates/_macros.html:453 project/templates/_macros.html:605 +#: project/templates/_macros.html:453 project/templates/_macros.html:612 #: project/templates/event/report.html:4 msgid "Report event" msgstr "" -#: project/templates/_macros.html:480 project/templates/_macros.html:631 +#: project/templates/_macros.html:480 project/templates/_macros.html:638 msgid "Show directions" msgstr "" -#: project/templates/_macros.html:485 project/templates/_macros.html:636 +#: project/templates/_macros.html:485 project/templates/_macros.html:643 msgid "The event takes place online." msgstr "" -#: project/templates/_macros.html:487 project/templates/_macros.html:638 +#: project/templates/_macros.html:487 project/templates/_macros.html:645 msgid "The event takes place both offline and online." msgstr "" -#: project/templates/_macros.html:699 project/templates/event_date/list.html:5 +#: project/templates/_macros.html:696 project/templates/event_date/list.html:5 #: project/templates/event_date/list.html:300 #: project/templates/event_date/search.html:3 #: project/templates/reference_request/review.html:32 msgid "Event Dates" msgstr "" -#: project/templates/_macros.html:772 +#: project/templates/_macros.html:788 msgid "Search location on Google" msgstr "" -#: project/templates/_macros.html:838 +#: project/templates/_macros.html:854 #, python-format msgid "%(count)d event dates" msgstr "" -#: project/templates/_macros.html:854 project/templates/_macros.html:856 +#: project/templates/_macros.html:870 project/templates/_macros.html:872 #: project/templates/event_date/list.html:321 msgid "First" msgstr "" -#: project/templates/_macros.html:859 project/templates/_macros.html:861 +#: project/templates/_macros.html:875 project/templates/_macros.html:877 #: project/templates/event_date/list.html:322 #: project/templates/widget/event_suggestion/create.html:193 #: project/templates/widget/event_suggestion/create.html:218 @@ -1187,12 +1201,12 @@ msgstr "" msgid "Previous" msgstr "" -#: project/templates/_macros.html:863 +#: project/templates/_macros.html:879 #, python-format msgid "Page %(page)d of %(pages)d (%(total)d total)" msgstr "" -#: project/templates/_macros.html:865 project/templates/_macros.html:867 +#: project/templates/_macros.html:881 project/templates/_macros.html:883 #: project/templates/event_date/list.html:324 #: project/templates/widget/event_suggestion/create.html:194 #: project/templates/widget/event_suggestion/create.html:219 @@ -1202,73 +1216,73 @@ msgstr "" msgid "Next" msgstr "" -#: project/templates/_macros.html:870 project/templates/_macros.html:872 +#: project/templates/_macros.html:886 project/templates/_macros.html:888 #: project/templates/event_date/list.html:325 msgid "Last" msgstr "" -#: project/templates/_macros.html:937 +#: project/templates/_macros.html:953 msgid "Radius" msgstr "" -#: project/templates/_macros.html:1147 +#: project/templates/_macros.html:1163 msgid "Edit image" msgstr "" -#: project/templates/_macros.html:1168 +#: project/templates/_macros.html:1184 msgid "Close" msgstr "" -#: project/templates/_macros.html:1169 +#: project/templates/_macros.html:1185 msgid "Okay" msgstr "" -#: project/templates/_macros.html:1181 +#: project/templates/_macros.html:1197 msgid "Choose image file" msgstr "" -#: project/templates/_macros.html:1217 project/templates/event/actions.html:46 +#: project/templates/_macros.html:1233 project/templates/event/actions.html:46 msgid "Edit event" msgstr "" -#: project/templates/_macros.html:1220 project/templates/manage/events.html:40 +#: project/templates/_macros.html:1236 project/templates/manage/events.html:40 msgid "More" msgstr "" -#: project/templates/_macros.html:1267 +#: project/templates/_macros.html:1283 msgid "Please enter a valid time, between 00:00 and 23:59." msgstr "" -#: project/templates/_macros.html:1295 +#: project/templates/_macros.html:1311 #, python-format msgid "Just use %(term)s" msgstr "" -#: project/templates/_macros.html:1361 +#: project/templates/_macros.html:1377 msgid "Event suggestion" msgstr "" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Link copied" msgstr "" -#: project/templates/_macros.html:1479 +#: project/templates/_macros.html:1495 msgid "Copy link" msgstr "" -#: project/templates/_macros.html:1508 +#: project/templates/_macros.html:1524 msgid "Google calendar" msgstr "" -#: project/templates/_macros.html:1509 +#: project/templates/_macros.html:1525 msgid "Apple calendar" msgstr "" -#: project/templates/_macros.html:1510 +#: project/templates/_macros.html:1526 msgid "Yahoo calendar" msgstr "" -#: project/templates/_macros.html:1511 +#: project/templates/_macros.html:1527 msgid "Other calendar" msgstr "" @@ -1328,7 +1342,7 @@ msgid "Show events" msgstr "" #: project/templates/event/create.html:5 -#: project/templates/event/create.html:228 project/templates/layout.html:226 +#: project/templates/event/create.html:250 project/templates/layout.html:226 #: project/templates/manage/events.html:22 #: project/templates/manage/organizers.html:21 msgid "Create event" @@ -1445,8 +1459,8 @@ msgstr "" #: project/templates/admin_unit/create.html:58 #: project/templates/admin_unit/update.html:59 -#: project/templates/event/create.html:354 -#: project/templates/event/update.html:211 +#: project/templates/event/create.html:378 +#: project/templates/event/update.html:234 #: project/templates/event_place/create.html:57 #: project/templates/event_place/update.html:57 #: project/templates/organizer/create.html:56 @@ -1571,31 +1585,33 @@ msgid "Enter place or address" msgstr "" #: project/templates/event/create.html:183 +#: project/templates/event/create.html:240 #: project/templates/event/update.html:106 +#: project/templates/event/update.html:132 #: project/templates/widget/event_suggestion/create.html:129 msgid "Enter organizer" msgstr "" -#: project/templates/event/create.html:245 -#: project/templates/event/update.html:136 +#: project/templates/event/create.html:267 +#: project/templates/event/update.html:158 msgid "Event date" msgstr "" -#: project/templates/event/create.html:283 +#: project/templates/event/create.html:305 msgid "Switch to organizer search" msgstr "" -#: project/templates/event/create.html:316 +#: project/templates/event/create.html:340 msgid "Switch to place search" msgstr "" -#: project/templates/event/create.html:327 -#: project/templates/event/update.html:184 +#: project/templates/event/create.html:351 +#: project/templates/event/update.html:207 msgid "Access" msgstr "" -#: project/templates/event/create.html:341 -#: project/templates/event/update.html:198 +#: project/templates/event/create.html:365 +#: project/templates/event/update.html:221 msgid "Target group" msgstr "" @@ -1901,11 +1917,11 @@ msgstr "" msgid "Event successfully deleted" msgstr "" -#: project/views/event.py:397 +#: project/views/event.py:404 msgid "Referenced event changed" msgstr "" -#: project/views/event.py:420 +#: project/views/event.py:427 msgid "New event report" msgstr "" diff --git a/project/views/event.py b/project/views/event.py index 21e7976..86109ae 100644 --- a/project/views/event.py +++ b/project/views/event.py @@ -300,9 +300,16 @@ def prepare_organizer(form): if organizer: form.organizer_id.choices = [(organizer.id, organizer.name)] + if form.co_organizer_ids.data and len(form.co_organizer_ids.data) > 0: + co_organizers = EventOrganizer.query.filter( + EventOrganizer.id.in_(form.co_organizer_ids.data) + ).all() + form.co_organizer_ids.choices = [(o.id, o.name) for o in co_organizers] + def prepare_event_form(form): form.category_ids.choices = get_event_category_choices() + form.co_organizer_ids.choices = list() prepare_organizer(form) prepare_event_place(form) diff --git a/project/views/utils.py b/project/views/utils.py index 9d530e8..ab3ff33 100644 --- a/project/views/utils.py +++ b/project/views/utils.py @@ -48,7 +48,7 @@ def handleSqlError(e: SQLAlchemyError) -> str: return str(e) prefix = None - message = str(e.orig) + message = gettext(e.orig.message) if hasattr(e.orig, "message") else str(e.orig) if e.orig.pgcode == UNIQUE_VIOLATION: prefix = gettext( diff --git a/tests/api/test_event.py b/tests/api/test_event.py index 1afb1c7..cbb5254 100644 --- a/tests/api/test_event.py +++ b/tests/api/test_event.py @@ -41,6 +41,19 @@ def test_read_myDraft(client, app, db, seeder, utils): assert response.json["public_status"] == "draft" +def test_read_co_organizers(client, app, db, seeder, utils): + user_id, admin_unit_id = seeder.setup_base() + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + + url = utils.get_url("api_v1_event", id=event_id) + response = utils.get_json(url) + utils.assert_response_ok(response) + assert response.json["co_organizers"][0]["id"] == organizer_a_id + assert response.json["co_organizers"][1]["id"] == organizer_b_id + + def test_list(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base() event_id = seeder.create_event(admin_unit_id) @@ -251,6 +264,53 @@ def test_put_organizerFromAnotherAdminUnit(client, seeder, utils, app): utils.assert_response_api_error(response, "Check Violation") +def test_put_co_organizers(client, seeder, utils, app): + user_id, admin_unit_id = seeder.setup_api_access() + event_id = seeder.create_event(admin_unit_id) + place_id = seeder.upsert_default_event_place(admin_unit_id) + organizer_id = seeder.upsert_default_event_organizer(admin_unit_id) + organizer_a_id = seeder.upsert_event_organizer(admin_unit_id, "Organizer A") + organizer_b_id = seeder.upsert_event_organizer(admin_unit_id, "Organizer B") + + put = create_put(place_id, organizer_id) + put["co_organizers"] = [ + {"id": organizer_a_id}, + {"id": organizer_b_id}, + ] + + url = utils.get_url("api_v1_event", id=event_id) + response = utils.put_json(url, put) + utils.assert_response_no_content(response) + + with app.app_context(): + from project.models import Event + + event = Event.query.get(event_id) + assert len(event.co_organizers) == 2 + assert event.co_organizers[0].id == organizer_a_id + assert event.co_organizers[1].id == organizer_b_id + + +def test_put_co_organizerFromAnotherAdminUnit(client, seeder, utils, app): + user_id, admin_unit_id = seeder.setup_api_access() + event_id = seeder.create_event(admin_unit_id) + place_id = seeder.upsert_default_event_place(admin_unit_id) + organizer_id = seeder.upsert_default_event_organizer(admin_unit_id) + + other_admin_unit_id = seeder.create_admin_unit(user_id, "Other Crew") + organizer_a_id = seeder.upsert_event_organizer(other_admin_unit_id, "Organizer A") + + put = create_put(place_id, organizer_id) + put["co_organizers"] = [ + {"id": organizer_a_id}, + ] + + url = utils.get_url("api_v1_event", id=event_id) + response = utils.put_json(url, put) + utils.assert_response_bad_request(response) + utils.assert_response_api_error(response, "Check Violation") + + def test_put_invalidDateFormat(client, seeder, utils, app): user_id, admin_unit_id = seeder.setup_api_access() event_id = seeder.create_event(admin_unit_id) diff --git a/tests/api/test_organization.py b/tests/api/test_organization.py index 453054b..a1452a5 100644 --- a/tests/api/test_organization.py +++ b/tests/api/test_organization.py @@ -48,7 +48,10 @@ def test_event_search(client, seeder, utils): response = utils.get_json(url) utils.assert_response_ok(response) assert len(response.json["items"]) == 2 - assert response.json["items"][1]["public_status"] == "draft" + assert ( + response.json["items"][0]["public_status"] == "draft" + or response.json["items"][1]["public_status"] == "draft" + ) def test_organizers(client, seeder, utils): @@ -142,6 +145,30 @@ def test_events_post(client, seeder, utils, app, allday): assert event.allday == allday +def test_events_post_co_organizers(client, seeder, utils, app): + url, data, admin_unit_id, place_id, organizer_id = prepare_events_post_data( + seeder, utils + ) + organizer_a_id = seeder.upsert_event_organizer(admin_unit_id, "Organizer A") + organizer_b_id = seeder.upsert_event_organizer(admin_unit_id, "Organizer B") + + data["co_organizers"] = [ + {"id": organizer_a_id}, + {"id": organizer_b_id}, + ] + response = utils.post_json(url, data) + utils.assert_response_created(response) + event_id = int(response.json["id"]) + + with app.app_context(): + from project.models import Event + + event = Event.query.get(event_id) + assert len(event.co_organizers) == 2 + assert event.co_organizers[0].id == organizer_a_id + assert event.co_organizers[1].id == organizer_b_id + + def test_events_post_photo_no_data(client, seeder, utils, app): url, data, admin_unit_id, place_id, organizer_id = prepare_events_post_data( seeder, utils diff --git a/tests/cli/test_dump.py b/tests/cli/test_dump.py index e4a71e1..22c48fc 100644 --- a/tests/cli/test_dump.py +++ b/tests/cli/test_dump.py @@ -1,6 +1,7 @@ def test_all(client, seeder, app, utils): user_id, admin_unit_id = seeder.setup_base() seeder.create_event(admin_unit_id, "RRULE:FREQ=DAILY;COUNT=7") + seeder.create_event_with_co_organizers(admin_unit_id) runner = app.test_cli_runner() result = runner.invoke(args=["dump", "all"]) diff --git a/tests/conftest.py b/tests/conftest.py index ab191d7..24c1d09 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -33,12 +33,15 @@ def app(): @pytest.fixture def db(app): + from flask_migrate import stamp + from project import db from project.init_data import create_initial_data with app.app_context(): db.drop_all() db.create_all() + stamp() create_initial_data() return db diff --git a/tests/form.py b/tests/form.py index 72208c3..7309ebd 100644 --- a/tests/form.py +++ b/tests/form.py @@ -115,7 +115,7 @@ class Form: # Override any form values with our input for key, value in values.items(): if key in filled: - filled.pop(key) + del filled[key] if type(value) is list: filled.setlist(key, value) else: diff --git a/tests/seeder.py b/tests/seeder.py index bac0b88..88b77c4 100644 --- a/tests/seeder.py +++ b/tests/seeder.py @@ -199,8 +199,14 @@ class Seeder(object): name="Name", start=None, allday=False, + co_organizer_ids=None, ): - from project.models import Event, EventAttendanceMode, PublicStatus + from project.models import ( + Event, + EventAttendanceMode, + EventOrganizer, + PublicStatus, + ) from project.services.event import insert_event, upsert_event_category with self._app.app_context(): @@ -224,11 +230,25 @@ class Seeder(object): if draft: event.public_status = PublicStatus.draft + if co_organizer_ids: + co_organizers = EventOrganizer.query.filter( + EventOrganizer.id.in_(co_organizer_ids) + ).all() + event.co_organizers = co_organizers + insert_event(event) self._db.session.commit() event_id = event.id return event_id + def create_event_with_co_organizers(self, admin_unit_id): + organizer_a_id = self.upsert_event_organizer(admin_unit_id, "Organizer A") + organizer_b_id = self.upsert_event_organizer(admin_unit_id, "Organizer B") + event_id = self.create_event( + admin_unit_id, co_organizer_ids=[organizer_a_id, organizer_b_id] + ) + return (event_id, organizer_a_id, organizer_b_id) + def create_event_via_form(self, admin_unit_id: int) -> str: place_id = self.upsert_default_event_place(admin_unit_id) organizer_id = self.upsert_default_event_organizer(admin_unit_id) diff --git a/tests/test_jsonld.py b/tests/test_jsonld.py index e2c8607..2ce6372 100644 --- a/tests/test_jsonld.py +++ b/tests/test_jsonld.py @@ -166,6 +166,25 @@ def test_get_sd_for_event_date_allday(client, app, db, seeder, utils): assert '"endDate": "2030-12-31"' in structured_data +def test_get_sd_for_event_date_with_co_organizer(client, app, db, seeder, utils): + user_id, admin_unit_id = seeder.setup_base() + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + + with app.app_context(): + from project.jsonld import get_sd_for_event_date + from project.models import Event + + event = Event.query.get(event_id) + event_date = event.dates[0] + + with app.test_request_context(): + data = get_sd_for_event_date(event_date) + + assert len(data["organizer"]) == 4 + + @pytest.mark.parametrize( "age_from, age_to, typicalAgeRange", [(18, None, "18-"), (None, 14, "-14"), (9, 99, "9-99")], diff --git a/tests/test_models.py b/tests/test_models.py index 1157164..347de48 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -158,3 +158,28 @@ def test_admin_unit_deletion(client, app, db, seeder): assert AdminUnit.query.get(other_admin_unit_id) is not None assert Event.query.get(other_event_id) is not None + + +def test_event_co_organizers_deletion(client, app, db, seeder): + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + + with app.app_context(): + from project.models import Event, EventOrganizer + + event = Event.query.get(event_id) + assert len(event.co_organizers) == 2 + assert event.co_organizers[0].id == organizer_a_id + assert event.co_organizers[1].id == organizer_b_id + + organizer_a = EventOrganizer.query.get(organizer_a_id) + db.session.delete(organizer_a) + db.session.commit() + assert len(event.co_organizers) == 1 + assert event.co_organizers[0].id == organizer_b_id + + db.session.delete(event) + db.session.commit() + assert EventOrganizer.query.get(organizer_b_id).id is not None diff --git a/tests/views/test_event.py b/tests/views/test_event.py index 37012c9..f098517 100644 --- a/tests/views/test_event.py +++ b/tests/views/test_event.py @@ -34,6 +34,18 @@ def test_read_containsActionLink(seeder, utils): assert action_url in str(response.data) +def test_read_co_organizers(seeder, utils): + user_id, admin_unit_id = seeder.setup_base() + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + + url = utils.get_url("event", event_id=event_id) + response = utils.get_ok(url) + utils.assert_response_contains(response, "Organizer A") + utils.assert_response_contains(response, "Organizer B") + + @pytest.mark.parametrize("db_error", [True, False]) def test_create(client, app, utils, seeder, mocker, db_error): user_id, admin_unit_id = seeder.setup_base() @@ -182,6 +194,27 @@ def test_create_missingPlace(client, app, utils, seeder, mocker): def test_create_missingOrganizer(client, app, utils, seeder, mocker): user_id, admin_unit_id = seeder.setup_base() place_id = seeder.upsert_default_event_place(admin_unit_id) + + url = utils.get_url("event_create_for_admin_unit_id", id=admin_unit_id) + response = utils.get_ok(url) + + response = utils.post_form( + url, + response, + { + "name": "Name", + "description": "Beschreibung", + "start": ["2030-12-31", "23:59"], + "event_place_id": place_id, + }, + ) + + utils.assert_response_error_message(response) + + +def test_create_invalidOrganizer(client, app, utils, seeder, mocker): + user_id, admin_unit_id = seeder.setup_base() + place_id = seeder.upsert_default_event_place(admin_unit_id) organizer_id = seeder.upsert_default_event_organizer(admin_unit_id) url = utils.get_url("event_create_for_admin_unit_id", id=admin_unit_id) @@ -193,13 +226,15 @@ def test_create_missingOrganizer(client, app, utils, seeder, mocker): { "name": "Name", "description": "Beschreibung", - "start": ["31.12.2030", "23:59"], + "start": ["2030-12-31", "23:59"], "event_place_id": place_id, "organizer_id": organizer_id, + "co_organizer_ids": [organizer_id], }, ) utils.assert_response_error_message(response) + utils.assert_response_contains(response, "Ungültiger Mitveranstalter") def test_create_invalidDateFormat(client, app, utils, seeder, mocker): @@ -223,6 +258,27 @@ def test_create_invalidDateFormat(client, app, utils, seeder, mocker): utils.assert_response_error_message(response) +def test_create_startInvalid(client, app, utils, seeder, mocker): + user_id, admin_unit_id = seeder.setup_base() + place_id = seeder.upsert_default_event_place(admin_unit_id) + + url = utils.get_url("event_create_for_admin_unit_id", id=admin_unit_id) + response = utils.get_ok(url) + + response = utils.post_form( + url, + response, + { + "name": "Name", + "start": ["31.12.2030", "23:59"], + "end": ["2030-12-31", "23:58"], + "event_place_id": place_id, + }, + ) + + utils.assert_response_error_message(response) + + def test_create_startAfterEnd(client, app, utils, seeder, mocker): user_id, admin_unit_id = seeder.setup_base() place_id = seeder.upsert_default_event_place(admin_unit_id) @@ -445,6 +501,28 @@ def test_update(client, seeder, utils, app, mocker, db_error): assert event is not None +def test_update_co_organizers(client, seeder, utils, app): + user_id, admin_unit_id = seeder.setup_base() + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + + url = utils.get_url("event_update", event_id=event_id) + response = utils.get_ok(url) + + response = utils.post_form( + url, + response, + { + "name": "Neuer Name", + }, + ) + + utils.assert_response_redirect( + response, "manage_admin_unit_events", id=admin_unit_id + ) + + @pytest.mark.parametrize("db_error", [True, False]) def test_delete(client, seeder, utils, app, mocker, db_error): user_id, admin_unit_id = seeder.setup_base() diff --git a/tests/views/test_widget.py b/tests/views/test_widget.py index 17f7eb7..ef5bc0d 100644 --- a/tests/views/test_widget.py +++ b/tests/views/test_widget.py @@ -90,6 +90,20 @@ def test_event_date(client, seeder, utils, app, db): utils.assert_response_unauthorized(response) +def test_event_date_co_organizers(client, seeder, utils, app, db): + user_id, admin_unit_id = seeder.setup_base(log_in=False) + event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers( + admin_unit_id + ) + au_short_name = "meinecrew" + + url = utils.get_url("widget_event_date", au_short_name=au_short_name, id=event_id) + response = utils.get(url) + response = utils.get_ok(url) + utils.assert_response_contains(response, "Organizer A") + utils.assert_response_contains(response, "Organizer B") + + def get_create_data(): return { "accept_tos": "y",