Delete organization #454

This commit is contained in:
Daniel Grams 2023-04-27 15:37:59 +02:00
parent 52f43286c4
commit 5fd75d9c1f
34 changed files with 1106 additions and 177 deletions

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-04-21 12:29+0200\n"
"POT-Creation-Date: 2023-04-27 15:10+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -211,7 +211,7 @@ msgstr ""
#: project/forms/admin.py:13 project/templates/_macros.html:1473
#: project/templates/layout.html:311
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:71
#: project/views/admin_unit.py:82 project/views/root.py:71
msgid "Contact"
msgstr ""
@ -302,10 +302,13 @@ msgid "Update organization"
msgstr ""
#: project/forms/admin.py:68 project/templates/admin/delete_admin_unit.html:6
#: project/templates/admin_unit/request_deletion.html:6
#: project/templates/admin_unit/update.html:93
msgid "Delete organization"
msgstr ""
#: project/forms/admin.py:69 project/forms/admin_unit.py:28
#: project/forms/admin_unit.py:134 project/forms/admin_unit.py:139
#: project/forms/event.py:85 project/forms/event.py:114
#: project/forms/event_place.py:25 project/forms/event_place.py:50
#: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66
@ -471,6 +474,17 @@ msgstr ""
msgid "Link Color"
msgstr ""
#: project/forms/admin_unit.py:133
msgid "Request deletion"
msgstr ""
#: project/forms/admin_unit.py:138
#: project/templates/admin_unit/cancel_deletion.html:6
#: project/templates/admin_unit/update.html:26
#: project/templates/manage/events.html:49
msgid "Cancel deletion"
msgstr ""
#: project/forms/admin_unit_member.py:13
msgid "Invite"
msgstr ""
@ -577,7 +591,7 @@ msgstr ""
msgid "100 km"
msgstr ""
#: project/forms/event.py:38 project/templates/manage/events.html:94
#: project/forms/event.py:38 project/templates/manage/events.html:100
msgid "Start"
msgstr ""
@ -762,8 +776,8 @@ msgid "Choose how people can attend the event."
msgstr ""
#: project/forms/event.py:225 project/forms/event_place.py:27
#: project/templates/manage/events.html:98
#: project/templates/manage/events.html:133
#: project/templates/manage/events.html:104
#: project/templates/manage/events.html:139
#: project/templates/manage/places.html:21
#: project/templates/manage/places.html:39
#: project/templates/widget/event_suggestion/create.html:258
@ -829,7 +843,7 @@ msgstr ""
#: project/templates/event_place/create.html:31
#: project/templates/event_place/delete.html:13
#: project/templates/event_place/update.html:31
#: project/templates/manage/events.html:97
#: project/templates/manage/events.html:103
msgid "Place"
msgstr ""
@ -846,7 +860,7 @@ msgstr ""
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:647 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/manage/events.html:96
#: project/templates/manage/events.html:102
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
#: project/templates/organizer/update.html:27
@ -971,7 +985,7 @@ msgstr ""
#: project/forms/event.py:446 project/forms/event_date.py:24
#: project/forms/planing.py:22 project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/admin_unit/update.html:46
#: project/templates/event_place/create.html:40
#: project/templates/event_place/update.html:40
#: project/templates/manage/organizers.html:19
@ -1121,8 +1135,10 @@ msgstr ""
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:491 project/templates/_macros.html:664
#: project/templates/admin/delete_admin_unit.html:13
#: project/templates/admin_unit/cancel_deletion.html:13
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/admin_unit/request_deletion.html:15
#: project/templates/admin_unit/update.html:36
#: project/templates/layout.html:247
msgid "Organization"
msgstr ""
@ -1264,7 +1280,7 @@ msgstr ""
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
#: project/templates/manage/events.html:95
#: project/templates/manage/events.html:101
#: project/templates/widget/event_suggestion/create.html:229
msgid "Event"
msgstr ""
@ -1307,9 +1323,9 @@ msgstr ""
#: project/templates/_macros.html:590 project/templates/_macros.html:633
#: project/templates/_macros.html:765
#: project/templates/admin/admin_units.html:34
#: project/templates/admin/admin_units.html:36
#: project/templates/admin/users.html:32
#: project/templates/manage/events.html:110
#: project/templates/manage/events.html:116
#: project/templates/manage/members.html:35
#: project/templates/manage/organizers.html:33
#: project/templates/manage/places.html:31
@ -1325,7 +1341,7 @@ msgstr ""
#: project/templates/_macros.html:703 project/templates/_macros.html:1297
#: project/templates/event/actions.html:38
#: project/templates/manage/events.html:117
#: project/templates/manage/events.html:123
#: project/templates/manage/references_incoming.html:10
msgid "Reference event"
msgstr ""
@ -1338,7 +1354,7 @@ msgstr ""
#: project/templates/_macros.html:723 project/templates/_macros.html:1294
#: project/templates/event/actions.html:32
#: project/templates/manage/events.html:115
#: project/templates/manage/events.html:121
msgid "Request reference"
msgstr ""
@ -1423,11 +1439,11 @@ msgid "Duplicate event"
msgstr ""
#: project/templates/_macros.html:1301 project/templates/event/actions.html:44
#: project/templates/manage/events.html:121
#: project/templates/manage/events.html:127
msgid "Add to list"
msgstr ""
#: project/templates/_macros.html:1304 project/templates/manage/events.html:124
#: project/templates/_macros.html:1304 project/templates/manage/events.html:130
msgid "More"
msgstr ""
@ -1482,7 +1498,7 @@ msgstr ""
msgid "Enter list name"
msgstr ""
#: project/templates/admin/admin_units.html:32 project/templates/home.html:25
#: project/templates/admin/admin_units.html:34 project/templates/home.html:25
msgid "Manage"
msgstr ""
@ -1500,7 +1516,7 @@ msgstr ""
#: project/templates/layout.html:157 project/templates/layout.html:205
#: project/templates/manage/events.html:6
#: project/templates/manage/events.html:48
#: project/templates/manage/events.html:54
#: project/templates/manage/events_vue.html:4
msgid "Events"
msgstr ""
@ -1546,7 +1562,7 @@ msgstr ""
#: project/templates/event/create.html:5
#: project/templates/event/create.html:221 project/templates/layout.html:212
#: project/templates/manage/events.html:49
#: project/templates/manage/events.html:55
#: project/templates/manage/organizers.html:38
msgid "Create event"
msgstr ""
@ -1623,7 +1639,7 @@ msgstr ""
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
#: project/templates/admin_unit/update.html:23
#: project/templates/admin_unit/update.html:30
#: project/templates/layout.html:259 project/templates/manage/widgets.html:11
#: project/templates/manage/widgets.html:15 project/templates/profile.html:19
msgid "Settings"
@ -1677,17 +1693,17 @@ msgstr ""
msgid "Users"
msgstr ""
#: project/templates/admin/admin_units.html:33
#: project/templates/manage/events.html:109
#: project/templates/admin/admin_units.html:35
#: project/templates/manage/events.html:115
#: project/templates/manage/organizers.html:32
#: project/templates/manage/references_incoming.html:19
#: project/templates/manage/references_outgoing.html:19
msgid "View"
msgstr ""
#: project/templates/admin/admin_units.html:35
#: project/templates/admin/admin_units.html:37
#: project/templates/admin/users.html:33
#: project/templates/manage/events.html:111
#: project/templates/manage/events.html:117
#: project/templates/manage/members.html:21
#: project/templates/manage/members.html:36
#: project/templates/manage/organizers.html:34
@ -1701,7 +1717,7 @@ msgstr ""
msgid "User"
msgstr ""
#: project/templates/admin/email.html:47 project/views/admin.py:155
#: project/templates/admin/email.html:47 project/views/admin.py:144
msgid "Mail sent successfully"
msgstr ""
@ -1718,7 +1734,7 @@ msgid "Mails sent successfully"
msgstr ""
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/admin_unit/update.html:66
#: project/templates/event/create.html:347
#: project/templates/event/update.html:204
#: project/templates/event_place/create.html:57
@ -1738,7 +1754,18 @@ msgstr ""
msgid "Invite user"
msgstr ""
#: project/templates/admin_unit/update.html:72
#: project/templates/admin_unit/request_deletion.html:8
msgid ""
"The organization is not deleted immediately. After a period of time, the "
"organization will be deleted. Until then, the deletion can be canceled."
msgstr ""
#: project/templates/admin_unit/update.html:25
#: project/templates/manage/events.html:48
msgid "The organization is scheduled for deletion."
msgstr ""
#: project/templates/admin_unit/update.html:79
#: project/templates/manage/verification_requests_outgoing.html:6
#: project/templates/manage/verification_requests_outgoing.html:11
msgid "Verification requests"
@ -1773,6 +1800,7 @@ msgid "You have been invited to join %(admin_unit_name)s."
msgstr ""
#: project/templates/email/invitation_notice.html:5
#: project/templates/email/organization_deletion_requested_notice.html:5
#: project/templates/email/organization_invitation_notice.html:5
msgid "Click here to view the invitation"
msgstr ""
@ -1790,6 +1818,11 @@ msgstr ""
msgid "Notification settings"
msgstr ""
#: project/templates/email/organization_deletion_requested_notice.html:4
#, python-format
msgid "%(admin_unit_name)s is scheduled for deletion."
msgstr ""
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -1887,7 +1920,7 @@ msgstr ""
#: project/templates/event/actions.html:74 project/templates/event/read.html:32
#: project/templates/event_date/read.html:34
#: project/templates/manage/events.html:145
#: project/templates/manage/events.html:151
msgid "Add event to list"
msgstr ""
@ -2008,21 +2041,21 @@ msgstr ""
msgid "Verify organization"
msgstr ""
#: project/templates/manage/events.html:85
#: project/templates/manage/events.html:91
msgid "More filters"
msgstr ""
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of references"
msgstr ""
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of reference requests."
msgstr ""
#: project/templates/manage/events.html:112
#: project/templates/manage/events.html:118
msgid "Duplicate"
msgstr ""
@ -2192,63 +2225,68 @@ msgstr ""
msgid "Preview"
msgstr ""
#: project/views/admin.py:60
#: project/views/admin.py:63
msgid "Organization successfully updated"
msgstr ""
#: project/views/admin.py:82
#: project/views/admin.py:85 project/views/admin_unit.py:182
#: project/views/admin_unit.py:215
msgid "Entered name does not match organization name"
msgstr ""
#: project/views/admin.py:87
#: project/views/admin.py:89
msgid "Organization successfully deleted"
msgstr ""
#: project/views/admin.py:111 project/views/manage.py:443
#: project/views/admin.py:113 project/views/manage.py:432
#: project/views/user.py:28
msgid "Settings successfully updated"
msgstr ""
#: project/views/admin.py:144
#: project/views/admin.py:133
#, python-format
msgid "Test mail from %(site_name)s"
msgstr ""
#: project/views/admin.py:187
#: project/views/admin.py:162
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr ""
#: project/views/admin.py:237
#: project/views/admin.py:212
msgid "User successfully updated"
msgstr ""
#: project/views/admin.py:257
#: project/views/admin.py:232
msgid "Entered email does not match user email"
msgstr ""
#: project/views/admin.py:262
#: project/views/admin.py:237
msgid "User successfully deleted"
msgstr ""
#: project/views/admin_unit.py:69
#: project/views/admin_unit.py:78
msgid ""
"Organizations cannot currently be created. The project is in a closed "
"test phase. If you are interested, you can contact us."
msgstr ""
#: project/views/admin_unit.py:119
#: project/views/admin_unit.py:128
msgid "Organization successfully created"
msgstr ""
#: project/views/admin_unit.py:149
#: project/views/admin_unit.py:158
msgid "AdminUnit successfully updated"
msgstr ""
#: project/views/admin_unit.py:171
#: project/views/admin_unit.py:245
msgid "Organization invitation accepted"
msgstr ""
#: project/views/admin_unit.py:259
msgid "Organization deletion requested"
msgstr ""
#: project/views/admin_unit_member.py:43
msgid "Member successfully updated"
msgstr ""
@ -2432,26 +2470,26 @@ msgid ""
"verified automatically."
msgstr ""
#: project/views/utils.py:65
#: project/views/utils.py:71
msgid ""
"An entry with the entered values already exists. Duplicate entries are "
"not allowed."
msgstr ""
#: project/views/utils.py:116
#: project/views/utils.py:122
#, python-format
msgid "Error in the %s field - %s"
msgstr ""
#: project/views/utils.py:123
#: project/views/utils.py:129
msgid "Show"
msgstr ""
#: project/views/utils.py:131
#: project/views/utils.py:137
msgid "You do not have permission for this action"
msgstr ""
#: project/views/utils.py:252
#: project/views/utils.py:258
msgid ""
"The invitation was issued to another user. Sign in with the email address"
" the invitation was sent to."

View File

@ -21,9 +21,15 @@ depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
# op.drop_table('spatial_ref_sys')
op.drop_constraint(
"eventsuggestion_event_id_fkey", "eventsuggestion", type_="foreignkey"
op.execute(
"ALTER TABLE eventsuggestion DROP CONSTRAINT IF EXISTS eventsuggestion_event_id_fkey;"
)
op.execute(
"ALTER TABLE eventsuggestion DROP CONSTRAINT IF EXISTS fk_eventsuggestion_event_id_event;"
)
# op.drop_constraint(
# "eventsuggestion_event_id_fkey", "eventsuggestion", type_="foreignkey"
# )
op.create_foreign_key(
None, "eventsuggestion", "event", ["event_id"], ["id"], ondelete="SET NULL"
)

View File

@ -68,7 +68,9 @@ def upgrade():
sa.PrimaryKeyConstraint("id"),
)
# op.drop_table('spatial_ref_sys')
op.drop_constraint("event_contact_id_fkey", "event", type_="foreignkey")
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS event_contact_id_fkey;")
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS fk_event_event_contact_id;")
# op.drop_constraint("event_contact_id_fkey", "event", type_="foreignkey")
op.drop_column("event", "review_status")
op.drop_column("event", "rejection_resaon")
op.drop_column("event", "contact_id")

View File

@ -67,8 +67,12 @@ def upgrade():
upgrade_category_to_categories()
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS event_category_id_fkey;")
op.execute(
"ALTER TABLE event DROP CONSTRAINT IF EXISTS fk_event_event_category_id;"
)
# op.drop_table('spatial_ref_sys')
op.drop_constraint("event_category_id_fkey", "event", type_="foreignkey")
# op.drop_constraint("event_category_id_fkey", "event", type_="foreignkey")
op.drop_column("event", "category_id")
# ### end Alembic commands ###

View File

@ -20,7 +20,8 @@ depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint("event_event_place_id_fkey", "event", type_="foreignkey")
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS event_event_place_id_fkey;")
# op.drop_constraint("event_event_place_id_fkey", "event", type_="foreignkey")
op.create_foreign_key(None, "event", "eventplace", ["event_place_id"], ["id"])
# ### end Alembic commands ###

View File

@ -33,7 +33,9 @@ def upgrade():
sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.Column("updated_by_id", sa.Integer(), nullable=True),
sa.CheckConstraint("source_admin_unit_id != target_admin_unit_id"),
sa.CheckConstraint(
"source_admin_unit_id != target_admin_unit_id", name="source_neq_target"
),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],

View File

@ -21,8 +21,16 @@ depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint("event_place_id_fkey", "event", type_="foreignkey")
op.drop_constraint("event_host_id_fkey", "event", type_="foreignkey")
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS event_place_id_fkey;")
op.execute(
"ALTER TABLE event DROP CONSTRAINT IF EXISTS fk_event_event_place_id_place;"
)
op.execute("ALTER TABLE event DROP CONSTRAINT IF EXISTS event_host_id_fkey;")
op.execute(
"ALTER TABLE event DROP CONSTRAINT IF EXISTS fk_event_event_host_id_place;"
)
# op.drop_constraint("event_place_id_fkey", "event", type_="foreignkey")
# op.drop_constraint("event_host_id_fkey", "event", type_="foreignkey")
op.drop_column("event", "host_id")
op.drop_column("event", "place_id")
op.drop_table("eventsuggestiondate")

View File

@ -18,10 +18,19 @@ depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
# op.drop_table('spatial_ref_sys')
op.drop_constraint(
"eventplace_name_organizer_id_admin_unit_id_key", "eventplace", type_="unique"
op.execute(
"ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS eventplace_name_organizer_id_admin_unit_id_key;"
)
op.drop_constraint("eventplace_organizer_id_fkey", "eventplace", type_="foreignkey")
# op.drop_constraint(
# "eventplace_name_organizer_id_admin_unit_id_key", "eventplace", type_="unique"
# )
op.execute(
"ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS eventplace_organizer_id_fkey;"
)
op.execute(
"ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS fk_eventplace_organizer_id;"
)
# op.drop_constraint("eventplace_organizer_id_fkey", "eventplace", type_="foreignkey")
op.drop_column("eventplace", "public")
op.drop_column("eventplace", "organizer_id")
# ### end Alembic commands ###

View File

@ -40,7 +40,7 @@ def upgrade():
op.alter_column("event", "host_id", existing_type=sa.INTEGER(), nullable=True)
op.alter_column("event", "place_id", existing_type=sa.INTEGER(), nullable=True)
op.create_foreign_key(None, "event", "eventorganizer", ["organizer_id"], ["id"])
op.drop_constraint("place_name_key", "place", type_="unique")
op.execute("ALTER TABLE place DROP CONSTRAINT IF EXISTS place_name_key;")
# ### end Alembic commands ###

View File

@ -294,7 +294,10 @@ def upgrade():
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("organization_id", sa.Integer(), nullable=True),
sa.Column("admin_unit_id", sa.Integer(), nullable=True),
sa.CheckConstraint("NOT(organization_id IS NULL AND admin_unit_id IS NULL)"),
sa.CheckConstraint(
"NOT(organization_id IS NULL AND admin_unit_id IS NULL)",
name="org_or_adminunit_check",
),
sa.ForeignKeyConstraint(
["admin_unit_id"],
["adminunit.id"],

View File

@ -0,0 +1,348 @@
"""empty message
Revision ID: cbac4166f9c0
Revises: 30650020b4b7
Create Date: 2023-04-27 11:02:04.294121
"""
import sqlalchemy as sa
import sqlalchemy_utils
from alembic import op
from project import dbtypes
# revision identifiers, used by Alembic.
revision = "cbac4166f9c0"
down_revision = "30650020b4b7"
branch_labels = None
depends_on = None
def upgrade():
op.execute("ALTER TABLE adminunit DROP CONSTRAINT IF EXISTS adminunit_name_key;")
op.execute("ALTER TABLE adminunit DROP CONSTRAINT IF EXISTS uq_adminunit_name;")
op.execute(
"ALTER TABLE adminunit DROP CONSTRAINT IF EXISTS adminunit_short_name_key;"
)
op.execute(
"ALTER TABLE adminunit DROP CONSTRAINT IF EXISTS uq_adminunit_short_name;"
)
with op.batch_alter_table("adminunit", schema=None) as batch_op:
batch_op.add_column(
sa.Column("deletion_requested_at", sa.DateTime(), nullable=True)
)
batch_op.add_column(
sa.Column("deletion_requested_by_id", sa.Integer(), nullable=True)
)
batch_op.create_unique_constraint(batch_op.f("uq_adminunit_name"), ["name"])
batch_op.create_unique_constraint(
batch_op.f("uq_adminunit_short_name"), ["short_name"]
)
batch_op.create_foreign_key(
batch_op.f("fk_adminunit_deletion_requested_by_id_user"),
"user",
["deletion_requested_by_id"],
["id"],
)
op.execute(
"ALTER TABLE adminunitmemberinvitation DROP CONSTRAINT IF EXISTS adminunitmemberinvitation_email_admin_unit_id_key;"
)
op.execute(
"ALTER TABLE adminunitmemberinvitation DROP CONSTRAINT IF EXISTS uq_adminunitmemberinvitation_email;"
)
with op.batch_alter_table("adminunitmemberinvitation", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_adminunitmemberinvitation_email"), ["email", "admin_unit_id"]
)
op.execute(
"ALTER TABLE adminunitmemberrole DROP CONSTRAINT IF EXISTS adminunitmemberrole_name_key;"
)
op.execute(
"ALTER TABLE adminunitmemberrole DROP CONSTRAINT IF EXISTS uq_adminunitmemberrole_name;"
)
with op.batch_alter_table("adminunitmemberrole", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_adminunitmemberrole_name"), ["name"]
)
op.execute(
"ALTER TABLE adminunitrelation DROP CONSTRAINT IF EXISTS adminunitrelation_source_admin_unit_id_target_admin_unit_id_key;"
)
op.execute(
"ALTER TABLE adminunitrelation DROP CONSTRAINT IF EXISTS uq_adminunitrelation_source_admin_unit_id;"
)
with op.batch_alter_table("adminunitrelation", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_adminunitrelation_source_admin_unit_id"),
["source_admin_unit_id", "target_admin_unit_id"],
)
op.execute(
"ALTER TABLE event_coorganizers DROP CONSTRAINT IF EXISTS event_coorganizers_event_id_organizer_id_key;"
)
op.execute(
"ALTER TABLE event_coorganizers DROP CONSTRAINT IF EXISTS uq_event_coorganizers_event_id;"
)
with op.batch_alter_table("event_coorganizers", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_event_coorganizers_event_id"), ["event_id", "organizer_id"]
)
op.execute(
"ALTER TABLE event_eventcategories DROP CONSTRAINT IF EXISTS event_eventcategories_event_id_category_id;"
)
op.execute(
"ALTER TABLE event_eventcategories DROP CONSTRAINT IF EXISTS event_eventcategories_event_id_category_id_key;"
)
op.execute(
"ALTER TABLE event_eventcategories DROP CONSTRAINT IF EXISTS uq_event_eventcategories_event_id;"
)
with op.batch_alter_table("event_eventcategories", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_event_eventcategories_event_id"), ["event_id", "category_id"]
)
op.execute(
"ALTER TABLE event_eventlists DROP CONSTRAINT IF EXISTS event_eventlists_event_id_list_id_key;"
)
op.execute(
"ALTER TABLE event_eventlists DROP CONSTRAINT IF EXISTS uq_event_eventlists_event_id;"
)
with op.batch_alter_table("event_eventlists", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_event_eventlists_event_id"), ["event_id", "list_id"]
)
op.execute(
"ALTER TABLE eventcategory DROP CONSTRAINT IF EXISTS eventcategory_name_key;"
)
op.execute(
"ALTER TABLE eventcategory DROP CONSTRAINT IF EXISTS uq_eventcategory_name;"
)
with op.batch_alter_table("eventcategory", schema=None) as batch_op:
batch_op.create_unique_constraint(batch_op.f("uq_eventcategory_name"), ["name"])
op.execute(
"ALTER TABLE eventorganizer DROP CONSTRAINT IF EXISTS eventorganizer_name_admin_unit_id_key;"
)
op.execute(
"ALTER TABLE eventorganizer DROP CONSTRAINT IF EXISTS uq_eventorganizer_name;"
)
with op.batch_alter_table("eventorganizer", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_eventorganizer_name"), ["name", "admin_unit_id"]
)
op.execute(
"ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS eventplace_name_admin_unit_id;"
)
op.execute(
"ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS eventplace_name_admin_unit_id_key;"
)
op.execute("ALTER TABLE eventplace DROP CONSTRAINT IF EXISTS uq_eventplace_name;")
with op.batch_alter_table("eventplace", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_eventplace_name"), ["name", "admin_unit_id"]
)
op.execute(
"ALTER TABLE eventsuggestion_eventcategories DROP CONSTRAINT IF EXISTS eventsuggestion_eventcategori_event_suggestion_id_category__key;"
)
op.execute(
"ALTER TABLE eventsuggestion_eventcategories DROP CONSTRAINT IF EXISTS eventsuggestion_eventcategories_event_suggestion_id_category_id;"
)
op.execute(
"ALTER TABLE eventsuggestion_eventcategories DROP CONSTRAINT IF EXISTS uq_eventsuggestion_eventcategories_event_suggestion_id;"
)
with op.batch_alter_table(
"eventsuggestion_eventcategories", schema=None
) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_eventsuggestion_eventcategories_event_suggestion_id"),
["event_suggestion_id", "category_id"],
)
op.execute(
"ALTER TABLE flask_dance_oauth DROP CONSTRAINT IF EXISTS flask_dance_oauth_provider_user_id_key;"
)
op.execute(
"ALTER TABLE flask_dance_oauth DROP CONSTRAINT IF EXISTS uq_flask_dance_oauth_provider_user_id;"
)
with op.batch_alter_table("flask_dance_oauth", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_flask_dance_oauth_provider_user_id"), ["provider_user_id"]
)
op.execute(
"ALTER TABLE oauth2_code DROP CONSTRAINT IF EXISTS oauth2_code_code_key;"
)
op.execute("ALTER TABLE oauth2_code DROP CONSTRAINT IF EXISTS uq_oauth2_code_code;")
with op.batch_alter_table("oauth2_code", schema=None) as batch_op:
batch_op.create_unique_constraint(batch_op.f("uq_oauth2_code_code"), ["code"])
op.execute(
"ALTER TABLE oauth2_token DROP CONSTRAINT IF EXISTS oauth2_token_access_token_key;"
)
op.execute(
"ALTER TABLE oauth2_token DROP CONSTRAINT IF EXISTS uq_oauth2_token_access_token;"
)
with op.batch_alter_table("oauth2_token", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_oauth2_token_access_token"), ["access_token"]
)
op.execute("ALTER TABLE role DROP CONSTRAINT IF EXISTS role_name_key;")
op.execute("ALTER TABLE role DROP CONSTRAINT IF EXISTS uq_role_name;")
with op.batch_alter_table("role", schema=None) as batch_op:
batch_op.create_unique_constraint(batch_op.f("uq_role_name"), ["name"])
op.execute("ALTER TABLE public.user DROP CONSTRAINT IF EXISTS user_email_key;")
op.execute("ALTER TABLE public.user DROP CONSTRAINT IF EXISTS uq_user_email;")
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.create_unique_constraint(batch_op.f("uq_user_email"), ["email"])
op.execute(
"ALTER TABLE user_favoriteevents DROP CONSTRAINT IF EXISTS user_favoriteevents_user_id_event_id_key;"
)
op.execute(
"ALTER TABLE user_favoriteevents DROP CONSTRAINT IF EXISTS uq_user_favoriteevents_user_id;"
)
with op.batch_alter_table("user_favoriteevents", schema=None) as batch_op:
batch_op.create_unique_constraint(
batch_op.f("uq_user_favoriteevents_user_id"), ["user_id", "event_id"]
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("user_favoriteevents", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_user_favoriteevents_user_id"), type_="unique"
)
batch_op.create_unique_constraint(
"user_favoriteevents_user_id_event_id_key", ["user_id", "event_id"]
)
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_user_email"), type_="unique")
batch_op.create_unique_constraint("user_email_key", ["email"])
with op.batch_alter_table("role", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_role_name"), type_="unique")
batch_op.create_unique_constraint("role_name_key", ["name"])
with op.batch_alter_table("oauth2_token", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_oauth2_token_access_token"), type_="unique"
)
batch_op.create_unique_constraint(
"oauth2_token_access_token_key", ["access_token"]
)
with op.batch_alter_table("oauth2_code", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_oauth2_code_code"), type_="unique")
batch_op.create_unique_constraint("oauth2_code_code_key", ["code"])
with op.batch_alter_table("flask_dance_oauth", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_flask_dance_oauth_provider_user_id"), type_="unique"
)
batch_op.create_unique_constraint(
"flask_dance_oauth_provider_user_id_key", ["provider_user_id"]
)
with op.batch_alter_table(
"eventsuggestion_eventcategories", schema=None
) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_eventsuggestion_eventcategories_event_suggestion_id"),
type_="unique",
)
batch_op.create_unique_constraint(
"eventsuggestion_eventcategori_event_suggestion_id_category__key",
["event_suggestion_id", "category_id"],
)
with op.batch_alter_table("eventplace", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_eventplace_name"), type_="unique")
batch_op.create_unique_constraint(
"eventplace_name_admin_unit_id_key", ["name", "admin_unit_id"]
)
with op.batch_alter_table("eventorganizer", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_eventorganizer_name"), type_="unique")
batch_op.create_unique_constraint(
"eventorganizer_name_admin_unit_id_key", ["name", "admin_unit_id"]
)
with op.batch_alter_table("eventcategory", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_eventcategory_name"), type_="unique")
batch_op.create_unique_constraint("eventcategory_name_key", ["name"])
with op.batch_alter_table("event_eventlists", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_event_eventlists_event_id"), type_="unique"
)
batch_op.create_unique_constraint(
"event_eventlists_event_id_list_id_key", ["event_id", "list_id"]
)
with op.batch_alter_table("event_eventcategories", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_event_eventcategories_event_id"), type_="unique"
)
batch_op.create_unique_constraint(
"event_eventcategories_event_id_category_id_key",
["event_id", "category_id"],
)
with op.batch_alter_table("event_coorganizers", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_event_coorganizers_event_id"), type_="unique"
)
batch_op.create_unique_constraint(
"event_coorganizers_event_id_organizer_id_key", ["event_id", "organizer_id"]
)
with op.batch_alter_table("adminunitrelation", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_adminunitrelation_source_admin_unit_id"), type_="unique"
)
batch_op.create_unique_constraint(
"adminunitrelation_source_admin_unit_id_target_admin_unit_id_key",
["source_admin_unit_id", "target_admin_unit_id"],
)
with op.batch_alter_table("adminunitmemberrole", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_adminunitmemberrole_name"), type_="unique"
)
batch_op.create_unique_constraint("adminunitmemberrole_name_key", ["name"])
with op.batch_alter_table("adminunitmemberinvitation", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("uq_adminunitmemberinvitation_email"), type_="unique"
)
batch_op.create_unique_constraint(
"adminunitmemberinvitation_email_admin_unit_id_key",
["email", "admin_unit_id"],
)
with op.batch_alter_table("adminunit", schema=None) as batch_op:
batch_op.drop_constraint(
batch_op.f("fk_adminunit_deletion_requested_by_id_user"), type_="foreignkey"
)
batch_op.drop_constraint(batch_op.f("uq_adminunit_short_name"), type_="unique")
batch_op.drop_constraint(batch_op.f("uq_adminunit_name"), type_="unique")
batch_op.create_unique_constraint("adminunit_short_name_key", ["short_name"])
batch_op.create_unique_constraint("adminunit_name_key", ["name"])
batch_op.drop_column("deletion_requested_by_id")
batch_op.drop_column("deletion_requested_at")
# ### end Alembic commands ###

View File

@ -12,6 +12,7 @@ from flask_qrcode import QRcode
from flask_security import Security, SQLAlchemySessionUserDatastore
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from sqlalchemy import MetaData
from project.custom_session_interface import CustomSessionInterface
@ -183,7 +184,15 @@ if app.config["MAIL_SUPPRESS_SEND"]:
email_dispatched.connect(log_message)
# Create db
db = SQLAlchemy(app)
convention = {
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(constraint_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
metadata = MetaData(naming_convention=convention)
db = SQLAlchemy(app, metadata=metadata)
migrate = Migrate(app, db)
# Celery tasks

View File

@ -1,3 +1,4 @@
from celery import group
from celery.schedules import crontab
from project import celery
@ -7,6 +8,9 @@ from project import celery
def setup_periodic_tasks(sender, **kwargs):
sender.add_periodic_task(crontab(hour=0, minute=0), clear_images_task)
sender.add_periodic_task(crontab(hour=0, minute=5), clear_admin_unit_dumps_task)
sender.add_periodic_task(
crontab(hour=0, minute=30), delete_admin_units_with_due_request_task
)
sender.add_periodic_task(crontab(hour=1, minute=0), update_recurring_dates_task)
sender.add_periodic_task(crontab(hour=2, minute=0), dump_all_task)
sender.add_periodic_task(crontab(hour=3, minute=0), seo_generate_sitemap_task)
@ -63,6 +67,36 @@ def clear_admin_unit_dumps_task():
clear_admin_unit_dumps()
@celery.task(
acks_late=True,
reject_on_worker_lost=True,
)
def delete_admin_units_with_due_request_task():
from project.services.admin_unit import get_admin_units_with_due_delete_request
admin_units = get_admin_units_with_due_delete_request()
if not admin_units:
return
group(delete_admin_unit_task.s(admin_unit.id) for admin_unit in admin_units).delay()
@celery.task(
acks_late=True,
reject_on_worker_lost=True,
)
def delete_admin_unit_task(admin_unit_id):
from project.services.admin_unit import delete_admin_unit, get_admin_unit_by_id
admin_unit = get_admin_unit_by_id(admin_unit_id)
if not admin_unit:
return
delete_admin_unit(admin_unit)
@celery.task(
acks_late=True,
reject_on_worker_lost=True,

View File

@ -127,3 +127,13 @@ class UpdateAdminUnitWidgetForm(FlaskForm):
validators=[Optional()],
)
submit = SubmitField(lazy_gettext("Update settings"))
class RequestAdminUnitDeletionForm(FlaskForm):
submit = SubmitField(lazy_gettext("Request deletion"))
name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
class CancelAdminUnitDeletionForm(FlaskForm):
submit = SubmitField(lazy_gettext("Cancel deletion"))
name = StringField(lazy_gettext("Name"), validators=[DataRequired()])

View File

@ -2,6 +2,7 @@ from flask_security import AsaList, RoleMixin
from sqlalchemy import (
Boolean,
Column,
DateTime,
ForeignKey,
Integer,
String,
@ -88,7 +89,9 @@ class AdminUnitRelation(db.Model, TrackableMixin):
__tablename__ = "adminunitrelation"
__table_args__ = (
UniqueConstraint("source_admin_unit_id", "target_admin_unit_id"),
CheckConstraint("source_admin_unit_id != target_admin_unit_id"),
CheckConstraint(
"source_admin_unit_id != target_admin_unit_id", name="source_neq_target"
),
)
id = Column(Integer(), primary_key=True)
source_admin_unit_id = db.Column(
@ -148,6 +151,15 @@ class AdminUnit(db.Model, TrackableMixin):
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), unique=True)
short_name = Column(Unicode(100), unique=True)
deletion_requested_at = deferred(Column(DateTime, nullable=True), group="deletion")
deletion_requested_by_id = deferred(
Column(ForeignKey("user.id"), nullable=True), group="deletion"
)
deletion_requested_by = relationship(
"User",
primaryjoin="User.id == AdminUnit.deletion_requested_by_id",
remote_side="User.id",
)
members = relationship(
"AdminUnitMember",
cascade="all, delete-orphan",

View File

@ -30,8 +30,12 @@ class EventSuggestion(db.Model, TrackableMixin, EventMixin):
__table_args__ = (
CheckConstraint(
"NOT(event_place_id IS NULL AND event_place_text IS NULL)",
name="place_not_null",
),
CheckConstraint(
"NOT(organizer_id IS NULL AND organizer_text IS NULL)",
name="organizer_not_null",
),
CheckConstraint("NOT(organizer_id IS NULL AND organizer_text IS NULL)"),
)
id = Column(Integer(), primary_key=True)

View File

@ -1,3 +1,5 @@
import datetime
from sqlalchemy import and_, func, or_
from project import db
@ -312,3 +314,13 @@ def create_ical_events_for_admin_unit(
params.can_read_private_events = False
return create_ical_events_for_search(params)
def get_admin_units_with_due_delete_request():
due = datetime.datetime.utcnow() - datetime.timedelta(days=3)
return AdminUnit.query.filter(AdminUnit.deletion_requested_at < due).all()
def delete_admin_unit(admin_unit: AdminUnit):
db.session.delete(admin_unit)
db.session.commit()

View File

@ -19,6 +19,7 @@
<th>{{ _('Name') }}</th>
<th></th>
<th>created_at</th>
<th>deletion_requested_at</th>
<th></th>
</tr>
</thead>
@ -28,6 +29,7 @@
<td>{{ admin_unit.name }}</td>
<td>{{ render_admin_unit_badges(admin_unit) }}</td>
<td>{% if admin_unit.created_at %}{{ admin_unit.created_at | dateformat }}{% endif %}</td>
<td>{% if admin_unit.deletion_requested_at %}{{ admin_unit.deletion_requested_at | dateformat }}{% endif %}</td>
<td>
<a href="{{ url_for('manage_admin_unit', id=admin_unit.id) }}">{{ _('Manage') }}</a>
<a href="{{ url_for('organizations', path=admin_unit.id) }}">{{ _('View') }}</a>

View File

@ -0,0 +1,24 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field_with_errors, render_field %}
{% block content %}
<h1>{{ _('Cancel deletion') }} &quot;{{ admin_unit.name }}&quot;</h1>
<form action="" method="POST">
{{ form.hidden_tag() }}
<div class="card mb-4">
<div class="card-header">
{{ _('Organization') }}
</div>
<div class="card-body">
{{ render_field_with_errors(form.name) }}
</div>
</div>
{{ render_field(form.submit) }}
</form>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field_with_errors, render_field %}
{% block content %}
<h1>{{ _('Delete organization') }} &quot;{{ admin_unit.name }}&quot;</h1>
<p>{{ _('The organization is not deleted immediately. After a period of time, the organization will be deleted. Until then, the deletion can be canceled.') }}</p>
<form action="" method="POST">
{{ form.hidden_tag() }}
<div class="card mb-4">
<div class="card-header">
{{ _('Organization') }}
</div>
<div class="card-body">
{{ render_field_with_errors(form.name) }}
</div>
</div>
{{ render_field(form.submit) }}
</form>
{% endblock %}

View File

@ -20,6 +20,13 @@
{% block content %}
{% if admin_unit.deletion_requested_at %}
<div class="alert alert-danger" role="alert">
{{ _('The organization is scheduled for deletion.') }}
<a class="alert-link" href="{{ url_for('admin_unit_cancel_deletion', id=admin_unit.id) }}" role="button">{{ _('Cancel deletion') }}</a>
</div>
{% endif %}
<h1>{{ _('Settings') }}</h1>
<form id="main-form" action="" method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
@ -81,4 +88,10 @@
{{ render_field(form.submit) }}
</form>
{% if not admin_unit.deletion_requested_at %}
<div class="my-4">
<a class="btn btn-danger" href="{{ url_for('admin_unit_request_deletion', id=admin_unit.id) }}" role="button">{{ _('Delete organization') }}&hellip;</a>
</div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,6 @@
{% extends "email/layout.html" %}
{% from "_macros.html" import render_email_button %}
{% block content %}
<p>{{ _('%(admin_unit_name)s is scheduled for deletion.', admin_unit_name=admin_unit.name) }}</p>
{{ render_email_button(url_for('admin_unit_cancel_deletion', id=admin_unit.id, _external=True), _('Click here to view the invitation')) }}
{% endblock %}

View File

@ -0,0 +1,3 @@
{{ _('%(admin_unit_name)s is scheduled for deletion.', admin_unit_name=admin_unit.name) }}
{{ _('Click the link below to cancel the deletion') }}
{{ url_for('admin_unit_cancel_deletion', id=admin_unit.id, _external=True) }}

View File

@ -43,6 +43,12 @@ var vue_app_data = { eventId: 0 };
<a class="alert-link" href="{{ url_for('manage_admin_unit_verification_requests_outgoing', id=admin_unit.id) }}" role="button">{{ _('Verify organization') }}</a>
</div>
{% endif %}
{% if admin_unit.deletion_requested_at %}
<div class="alert alert-danger" role="alert">
{{ _('The organization is scheduled for deletion.') }}
<a class="alert-link" href="{{ url_for('admin_unit_cancel_deletion', id=admin_unit.id) }}" role="button">{{ _('Cancel deletion') }}</a>
</div>
{% endif %}
<h1 class="mb-0">
{{ _('Events') }}

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-04-21 12:29+0200\n"
"POT-Creation-Date: 2023-04-27 15:10+0200\n"
"PO-Revision-Date: 2020-06-07 18:51+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
@ -212,7 +212,7 @@ msgstr "Impressum"
#: project/forms/admin.py:13 project/templates/_macros.html:1473
#: project/templates/layout.html:311
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:71
#: project/views/admin_unit.py:82 project/views/root.py:71
msgid "Contact"
msgstr "Kontakt"
@ -311,10 +311,13 @@ msgid "Update organization"
msgstr "Organisation aktualisieren"
#: project/forms/admin.py:68 project/templates/admin/delete_admin_unit.html:6
#: project/templates/admin_unit/request_deletion.html:6
#: project/templates/admin_unit/update.html:93
msgid "Delete organization"
msgstr "Organisation löschen"
#: project/forms/admin.py:69 project/forms/admin_unit.py:28
#: project/forms/admin_unit.py:134 project/forms/admin_unit.py:139
#: project/forms/event.py:85 project/forms/event.py:114
#: project/forms/event_place.py:25 project/forms/event_place.py:50
#: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66
@ -491,6 +494,17 @@ msgstr "Hauptfarbe"
msgid "Link Color"
msgstr "Linkfarbe"
#: project/forms/admin_unit.py:133
msgid "Request deletion"
msgstr "Löschung beantragen"
#: project/forms/admin_unit.py:138
#: project/templates/admin_unit/cancel_deletion.html:6
#: project/templates/admin_unit/update.html:26
#: project/templates/manage/events.html:49
msgid "Cancel deletion"
msgstr "Löschen abbrechen"
#: project/forms/admin_unit_member.py:13
msgid "Invite"
msgstr "Einladen"
@ -600,7 +614,7 @@ msgstr "50 km"
msgid "100 km"
msgstr "100 km"
#: project/forms/event.py:38 project/templates/manage/events.html:94
#: project/forms/event.py:38 project/templates/manage/events.html:100
msgid "Start"
msgstr "Beginn"
@ -794,8 +808,8 @@ msgid "Choose how people can attend the event."
msgstr "Wähle aus, wie Personen an der Veranstaltung teilnehmen können."
#: project/forms/event.py:225 project/forms/event_place.py:27
#: project/templates/manage/events.html:98
#: project/templates/manage/events.html:133
#: project/templates/manage/events.html:104
#: project/templates/manage/events.html:139
#: project/templates/manage/places.html:21
#: project/templates/manage/places.html:39
#: project/templates/widget/event_suggestion/create.html:258
@ -869,7 +883,7 @@ msgstr "Ungültiger Mitveranstalter."
#: project/templates/event_place/create.html:31
#: project/templates/event_place/delete.html:13
#: project/templates/event_place/update.html:31
#: project/templates/manage/events.html:97
#: project/templates/manage/events.html:103
msgid "Place"
msgstr "Ort"
@ -886,7 +900,7 @@ msgstr "Neuen Ort eingeben"
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:647 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/manage/events.html:96
#: project/templates/manage/events.html:102
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
#: project/templates/organizer/update.html:27
@ -1015,7 +1029,7 @@ msgstr "Kategorie"
#: project/forms/event.py:446 project/forms/event_date.py:24
#: project/forms/planing.py:22 project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/admin_unit/update.html:46
#: project/templates/event_place/create.html:40
#: project/templates/event_place/update.html:40
#: project/templates/manage/organizers.html:19
@ -1169,8 +1183,10 @@ msgstr "Wochentage"
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:491 project/templates/_macros.html:664
#: project/templates/admin/delete_admin_unit.html:13
#: project/templates/admin_unit/cancel_deletion.html:13
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/admin_unit/request_deletion.html:15
#: project/templates/admin_unit/update.html:36
#: project/templates/layout.html:247
msgid "Organization"
msgstr "Organisation"
@ -1319,7 +1335,7 @@ msgstr "Zuletzt aktualisiert am %(updated_at)s."
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
#: project/templates/manage/events.html:95
#: project/templates/manage/events.html:101
#: project/templates/widget/event_suggestion/create.html:229
msgid "Event"
msgstr "Veranstaltung"
@ -1364,9 +1380,9 @@ msgstr "Merkzettel"
#: project/templates/_macros.html:590 project/templates/_macros.html:633
#: project/templates/_macros.html:765
#: project/templates/admin/admin_units.html:34
#: project/templates/admin/admin_units.html:36
#: project/templates/admin/users.html:32
#: project/templates/manage/events.html:110
#: project/templates/manage/events.html:116
#: project/templates/manage/members.html:35
#: project/templates/manage/organizers.html:33
#: project/templates/manage/places.html:31
@ -1382,7 +1398,7 @@ msgstr "Empfohlen von"
#: project/templates/_macros.html:703 project/templates/_macros.html:1297
#: project/templates/event/actions.html:38
#: project/templates/manage/events.html:117
#: project/templates/manage/events.html:123
#: project/templates/manage/references_incoming.html:10
msgid "Reference event"
msgstr "Veranstaltung empfehlen"
@ -1395,7 +1411,7 @@ msgstr "Empfehlungsanfragen"
#: project/templates/_macros.html:723 project/templates/_macros.html:1294
#: project/templates/event/actions.html:32
#: project/templates/manage/events.html:115
#: project/templates/manage/events.html:121
msgid "Request reference"
msgstr "Empfehlung anfragen"
@ -1480,11 +1496,11 @@ msgid "Duplicate event"
msgstr "Veranstaltung duplizieren"
#: project/templates/_macros.html:1301 project/templates/event/actions.html:44
#: project/templates/manage/events.html:121
#: project/templates/manage/events.html:127
msgid "Add to list"
msgstr "Zu Liste hinzufügen"
#: project/templates/_macros.html:1304 project/templates/manage/events.html:124
#: project/templates/_macros.html:1304 project/templates/manage/events.html:130
msgid "More"
msgstr "Mehr"
@ -1539,7 +1555,7 @@ msgstr "Veranstalter eingeben"
msgid "Enter list name"
msgstr "Listenname eingeben"
#: project/templates/admin/admin_units.html:32 project/templates/home.html:25
#: project/templates/admin/admin_units.html:34 project/templates/home.html:25
msgid "Manage"
msgstr "Verwaltung"
@ -1557,7 +1573,7 @@ msgstr "Features"
#: project/templates/layout.html:157 project/templates/layout.html:205
#: project/templates/manage/events.html:6
#: project/templates/manage/events.html:48
#: project/templates/manage/events.html:54
#: project/templates/manage/events_vue.html:4
msgid "Events"
msgstr "Veranstaltungen"
@ -1603,7 +1619,7 @@ msgstr "Veranstaltungen anzeigen"
#: project/templates/event/create.html:5
#: project/templates/event/create.html:221 project/templates/layout.html:212
#: project/templates/manage/events.html:49
#: project/templates/manage/events.html:55
#: project/templates/manage/organizers.html:38
msgid "Create event"
msgstr "Veranstaltung erstellen"
@ -1680,7 +1696,7 @@ msgstr "Organisationseinladungen"
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
#: project/templates/admin_unit/update.html:23
#: project/templates/admin_unit/update.html:30
#: project/templates/layout.html:259 project/templates/manage/widgets.html:11
#: project/templates/manage/widgets.html:15 project/templates/profile.html:19
msgid "Settings"
@ -1734,17 +1750,17 @@ msgstr "OAuth2 Clients"
msgid "Users"
msgstr "Nutzer"
#: project/templates/admin/admin_units.html:33
#: project/templates/manage/events.html:109
#: project/templates/admin/admin_units.html:35
#: project/templates/manage/events.html:115
#: project/templates/manage/organizers.html:32
#: project/templates/manage/references_incoming.html:19
#: project/templates/manage/references_outgoing.html:19
msgid "View"
msgstr "Anzeigen"
#: project/templates/admin/admin_units.html:35
#: project/templates/admin/admin_units.html:37
#: project/templates/admin/users.html:33
#: project/templates/manage/events.html:111
#: project/templates/manage/events.html:117
#: project/templates/manage/members.html:21
#: project/templates/manage/members.html:36
#: project/templates/manage/organizers.html:34
@ -1758,7 +1774,7 @@ msgstr "Löschen"
msgid "User"
msgstr "Nutzer"
#: project/templates/admin/email.html:47 project/views/admin.py:155
#: project/templates/admin/email.html:47 project/views/admin.py:144
msgid "Mail sent successfully"
msgstr "Mail erfolgreich gesendet"
@ -1775,7 +1791,7 @@ msgid "Mails sent successfully"
msgstr "Mails erfolgreich gesendet"
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/admin_unit/update.html:66
#: project/templates/event/create.html:347
#: project/templates/event/update.html:204
#: project/templates/event_place/create.html:57
@ -1795,7 +1811,18 @@ msgstr "Beziehung zu %(admin_unit_name)s"
msgid "Invite user"
msgstr "Nutzer:in einladen"
#: project/templates/admin_unit/update.html:72
#: project/templates/admin_unit/request_deletion.html:8
msgid ""
"The organization is not deleted immediately. After a period of time, the "
"organization will be deleted. Until then, the deletion can be canceled."
msgstr "Die Organisation wird nicht sofort gelöscht. Nach einer Frist wird die Organisation gelöscht. Bis dahin kann die Löschung abgebrochen werden."
#: project/templates/admin_unit/update.html:25
#: project/templates/manage/events.html:48
msgid "The organization is scheduled for deletion."
msgstr "Die Organisation ist zur Löschung vorgesehen."
#: project/templates/admin_unit/update.html:79
#: project/templates/manage/verification_requests_outgoing.html:6
#: project/templates/manage/verification_requests_outgoing.html:11
msgid "Verification requests"
@ -1830,6 +1857,7 @@ msgid "You have been invited to join %(admin_unit_name)s."
msgstr "Du wurdest eingeladen, %(admin_unit_name)s beizutreten."
#: project/templates/email/invitation_notice.html:5
#: project/templates/email/organization_deletion_requested_notice.html:5
#: project/templates/email/organization_invitation_notice.html:5
msgid "Click here to view the invitation"
msgstr "Klicke hier, um die Einladung anzunehmen."
@ -1847,6 +1875,11 @@ msgstr "das ist eine Nachricht von %(site_name)s."
msgid "Notification settings"
msgstr "Benachrichtigungseinstellungen"
#: project/templates/email/organization_deletion_requested_notice.html:4
#, python-format
msgid "%(admin_unit_name)s is scheduled for deletion."
msgstr "%(admin_unit_name)s ist zur Löschung vorgesehen."
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -1948,7 +1981,7 @@ msgstr "Zeige alle Veranstaltungen von %(admin_unit_name)s"
#: project/templates/event/actions.html:74 project/templates/event/read.html:32
#: project/templates/event_date/read.html:34
#: project/templates/manage/events.html:145
#: project/templates/manage/events.html:151
msgid "Add event to list"
msgstr "Veranstaltung zu Liste hinzufügen"
@ -2074,21 +2107,21 @@ msgstr ""
msgid "Verify organization"
msgstr "Organisation verifizieren"
#: project/templates/manage/events.html:85
#: project/templates/manage/events.html:91
msgid "More filters"
msgstr "Mehr Filter"
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of references"
msgstr "Anzahl an Empfehlungen"
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of reference requests."
msgstr "Anzahl an Empfehlungsanfragen"
#: project/templates/manage/events.html:112
#: project/templates/manage/events.html:118
msgid "Duplicate"
msgstr "Duplizieren"
@ -2260,46 +2293,47 @@ msgstr "Optionale Details"
msgid "Preview"
msgstr "Vorschau"
#: project/views/admin.py:60
#: project/views/admin.py:63
msgid "Organization successfully updated"
msgstr "Organisation erfolgreich aktualisiert"
#: project/views/admin.py:82
#: project/views/admin.py:85 project/views/admin_unit.py:182
#: project/views/admin_unit.py:215
msgid "Entered name does not match organization name"
msgstr "Der eingegebene Name entspricht nicht dem Namen der Organisation"
#: project/views/admin.py:87
#: project/views/admin.py:89
msgid "Organization successfully deleted"
msgstr "Organisation erfolgreich gelöscht"
#: project/views/admin.py:111 project/views/manage.py:443
#: project/views/admin.py:113 project/views/manage.py:432
#: project/views/user.py:28
msgid "Settings successfully updated"
msgstr "Einstellungen erfolgreich aktualisiert"
#: project/views/admin.py:144
#: project/views/admin.py:133
#, python-format
msgid "Test mail from %(site_name)s"
msgstr "Test-Mail von %(site_name)s"
#: project/views/admin.py:187
#: project/views/admin.py:162
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr "Newsletter von %(site_name)s"
#: project/views/admin.py:237
#: project/views/admin.py:212
msgid "User successfully updated"
msgstr "Nutzer erfolgreich aktualisiert"
#: project/views/admin.py:257
#: project/views/admin.py:232
msgid "Entered email does not match user email"
msgstr "Die eingegebene Email passt nicht zur Email des Nutzers"
#: project/views/admin.py:262
#: project/views/admin.py:237
msgid "User successfully deleted"
msgstr "Nutzer erfolgreich gelöscht"
#: project/views/admin_unit.py:69
#: project/views/admin_unit.py:78
msgid ""
"Organizations cannot currently be created. The project is in a closed "
"test phase. If you are interested, you can contact us."
@ -2308,18 +2342,22 @@ msgstr ""
" sich in einer geschlossenen Test-Phase. Bei Interesse kannst du uns "
"kontaktieren."
#: project/views/admin_unit.py:119
#: project/views/admin_unit.py:128
msgid "Organization successfully created"
msgstr "Organisation erfolgreich erstellt"
#: project/views/admin_unit.py:149
#: project/views/admin_unit.py:158
msgid "AdminUnit successfully updated"
msgstr "Organisation erfolgreich aktualisiert"
#: project/views/admin_unit.py:171
#: project/views/admin_unit.py:245
msgid "Organization invitation accepted"
msgstr "Organisationseinladung akzeptiert"
#: project/views/admin_unit.py:259
msgid "Organization deletion requested"
msgstr "Löschung der Organisation beantragt"
#: project/views/admin_unit_member.py:43
msgid "Member successfully updated"
msgstr "Mitglied erfolgreich aktualisiert"
@ -2507,7 +2545,7 @@ msgstr ""
"Ob alle zukünftigen Empfehlungsanfragen von %(admin_unit_name)s "
"automatisch verifiziert werden sollen."
#: project/views/utils.py:65
#: project/views/utils.py:71
msgid ""
"An entry with the entered values already exists. Duplicate entries are "
"not allowed."
@ -2515,20 +2553,20 @@ msgstr ""
"Ein Eintrag mit den eingegebenen Werten existiert bereits. Doppelte "
"Einträge sind nicht erlaubt."
#: project/views/utils.py:116
#: project/views/utils.py:122
#, python-format
msgid "Error in the %s field - %s"
msgstr "Fehler im Feld %s: %s"
#: project/views/utils.py:123
#: project/views/utils.py:129
msgid "Show"
msgstr "Anzeigen"
#: project/views/utils.py:131
#: project/views/utils.py:137
msgid "You do not have permission for this action"
msgstr "Du hast keine Berechtigung für diese Aktion"
#: project/views/utils.py:252
#: project/views/utils.py:258
msgid ""
"The invitation was issued to another user. Sign in with the email address"
" the invitation was sent to."

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2023-04-21 12:29+0200\n"
"POT-Creation-Date: 2023-04-27 15:10+0200\n"
"PO-Revision-Date: 2021-04-30 15:04+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
@ -212,7 +212,7 @@ msgstr ""
#: project/forms/admin.py:13 project/templates/_macros.html:1473
#: project/templates/layout.html:311
#: project/templates/widget/event_suggestion/create.html:204
#: project/views/admin_unit.py:73 project/views/root.py:71
#: project/views/admin_unit.py:82 project/views/root.py:71
msgid "Contact"
msgstr ""
@ -303,10 +303,13 @@ msgid "Update organization"
msgstr ""
#: project/forms/admin.py:68 project/templates/admin/delete_admin_unit.html:6
#: project/templates/admin_unit/request_deletion.html:6
#: project/templates/admin_unit/update.html:93
msgid "Delete organization"
msgstr ""
#: project/forms/admin.py:69 project/forms/admin_unit.py:28
#: project/forms/admin_unit.py:134 project/forms/admin_unit.py:139
#: project/forms/event.py:85 project/forms/event.py:114
#: project/forms/event_place.py:25 project/forms/event_place.py:50
#: project/forms/event_suggestion.py:26 project/forms/oauth2_client.py:66
@ -472,6 +475,17 @@ msgstr ""
msgid "Link Color"
msgstr ""
#: project/forms/admin_unit.py:133
msgid "Request deletion"
msgstr ""
#: project/forms/admin_unit.py:138
#: project/templates/admin_unit/cancel_deletion.html:6
#: project/templates/admin_unit/update.html:26
#: project/templates/manage/events.html:49
msgid "Cancel deletion"
msgstr ""
#: project/forms/admin_unit_member.py:13
msgid "Invite"
msgstr ""
@ -578,7 +592,7 @@ msgstr ""
msgid "100 km"
msgstr ""
#: project/forms/event.py:38 project/templates/manage/events.html:94
#: project/forms/event.py:38 project/templates/manage/events.html:100
msgid "Start"
msgstr ""
@ -763,8 +777,8 @@ msgid "Choose how people can attend the event."
msgstr ""
#: project/forms/event.py:225 project/forms/event_place.py:27
#: project/templates/manage/events.html:98
#: project/templates/manage/events.html:133
#: project/templates/manage/events.html:104
#: project/templates/manage/events.html:139
#: project/templates/manage/places.html:21
#: project/templates/manage/places.html:39
#: project/templates/widget/event_suggestion/create.html:258
@ -830,7 +844,7 @@ msgstr ""
#: project/templates/event_place/create.html:31
#: project/templates/event_place/delete.html:13
#: project/templates/event_place/update.html:31
#: project/templates/manage/events.html:97
#: project/templates/manage/events.html:103
msgid "Place"
msgstr ""
@ -847,7 +861,7 @@ msgstr ""
#: project/forms/event_suggestion.py:60 project/templates/_macros.html:475
#: project/templates/_macros.html:647 project/templates/event/create.html:253
#: project/templates/event/update.html:156
#: project/templates/manage/events.html:96
#: project/templates/manage/events.html:102
#: project/templates/organizer/create.html:27
#: project/templates/organizer/delete.html:13
#: project/templates/organizer/update.html:27
@ -972,7 +986,7 @@ msgstr ""
#: project/forms/event.py:446 project/forms/event_date.py:24
#: project/forms/planing.py:22 project/templates/_macros.html:305
#: project/templates/admin_unit/create.html:38
#: project/templates/admin_unit/update.html:39
#: project/templates/admin_unit/update.html:46
#: project/templates/event_place/create.html:40
#: project/templates/event_place/update.html:40
#: project/templates/manage/organizers.html:19
@ -1122,8 +1136,10 @@ msgstr ""
#: project/forms/reference.py:11 project/forms/reference_request.py:16
#: project/templates/_macros.html:491 project/templates/_macros.html:664
#: project/templates/admin/delete_admin_unit.html:13
#: project/templates/admin_unit/cancel_deletion.html:13
#: project/templates/admin_unit/create.html:28
#: project/templates/admin_unit/update.html:29
#: project/templates/admin_unit/request_deletion.html:15
#: project/templates/admin_unit/update.html:36
#: project/templates/layout.html:247
msgid "Organization"
msgstr ""
@ -1272,7 +1288,7 @@ msgstr ""
#: project/templates/event/actions.html:25
#: project/templates/event/create.html:230
#: project/templates/event/update.html:122
#: project/templates/manage/events.html:95
#: project/templates/manage/events.html:101
#: project/templates/widget/event_suggestion/create.html:229
msgid "Event"
msgstr ""
@ -1315,9 +1331,9 @@ msgstr ""
#: project/templates/_macros.html:590 project/templates/_macros.html:633
#: project/templates/_macros.html:765
#: project/templates/admin/admin_units.html:34
#: project/templates/admin/admin_units.html:36
#: project/templates/admin/users.html:32
#: project/templates/manage/events.html:110
#: project/templates/manage/events.html:116
#: project/templates/manage/members.html:35
#: project/templates/manage/organizers.html:33
#: project/templates/manage/places.html:31
@ -1333,7 +1349,7 @@ msgstr ""
#: project/templates/_macros.html:703 project/templates/_macros.html:1297
#: project/templates/event/actions.html:38
#: project/templates/manage/events.html:117
#: project/templates/manage/events.html:123
#: project/templates/manage/references_incoming.html:10
msgid "Reference event"
msgstr ""
@ -1346,7 +1362,7 @@ msgstr ""
#: project/templates/_macros.html:723 project/templates/_macros.html:1294
#: project/templates/event/actions.html:32
#: project/templates/manage/events.html:115
#: project/templates/manage/events.html:121
msgid "Request reference"
msgstr ""
@ -1431,11 +1447,11 @@ msgid "Duplicate event"
msgstr ""
#: project/templates/_macros.html:1301 project/templates/event/actions.html:44
#: project/templates/manage/events.html:121
#: project/templates/manage/events.html:127
msgid "Add to list"
msgstr ""
#: project/templates/_macros.html:1304 project/templates/manage/events.html:124
#: project/templates/_macros.html:1304 project/templates/manage/events.html:130
msgid "More"
msgstr ""
@ -1490,7 +1506,7 @@ msgstr ""
msgid "Enter list name"
msgstr ""
#: project/templates/admin/admin_units.html:32 project/templates/home.html:25
#: project/templates/admin/admin_units.html:34 project/templates/home.html:25
msgid "Manage"
msgstr ""
@ -1508,7 +1524,7 @@ msgstr ""
#: project/templates/layout.html:157 project/templates/layout.html:205
#: project/templates/manage/events.html:6
#: project/templates/manage/events.html:48
#: project/templates/manage/events.html:54
#: project/templates/manage/events_vue.html:4
msgid "Events"
msgstr ""
@ -1554,7 +1570,7 @@ msgstr ""
#: project/templates/event/create.html:5
#: project/templates/event/create.html:221 project/templates/layout.html:212
#: project/templates/manage/events.html:49
#: project/templates/manage/events.html:55
#: project/templates/manage/organizers.html:38
msgid "Create event"
msgstr ""
@ -1631,7 +1647,7 @@ msgstr ""
#: project/templates/admin/settings.html:4
#: project/templates/admin/settings.html:11
#: project/templates/admin_unit/update.html:6
#: project/templates/admin_unit/update.html:23
#: project/templates/admin_unit/update.html:30
#: project/templates/layout.html:259 project/templates/manage/widgets.html:11
#: project/templates/manage/widgets.html:15 project/templates/profile.html:19
msgid "Settings"
@ -1685,17 +1701,17 @@ msgstr ""
msgid "Users"
msgstr ""
#: project/templates/admin/admin_units.html:33
#: project/templates/manage/events.html:109
#: project/templates/admin/admin_units.html:35
#: project/templates/manage/events.html:115
#: project/templates/manage/organizers.html:32
#: project/templates/manage/references_incoming.html:19
#: project/templates/manage/references_outgoing.html:19
msgid "View"
msgstr ""
#: project/templates/admin/admin_units.html:35
#: project/templates/admin/admin_units.html:37
#: project/templates/admin/users.html:33
#: project/templates/manage/events.html:111
#: project/templates/manage/events.html:117
#: project/templates/manage/members.html:21
#: project/templates/manage/members.html:36
#: project/templates/manage/organizers.html:34
@ -1709,7 +1725,7 @@ msgstr ""
msgid "User"
msgstr ""
#: project/templates/admin/email.html:47 project/views/admin.py:155
#: project/templates/admin/email.html:47 project/views/admin.py:144
msgid "Mail sent successfully"
msgstr ""
@ -1726,7 +1742,7 @@ msgid "Mails sent successfully"
msgstr ""
#: project/templates/admin_unit/create.html:58
#: project/templates/admin_unit/update.html:59
#: project/templates/admin_unit/update.html:66
#: project/templates/event/create.html:347
#: project/templates/event/update.html:204
#: project/templates/event_place/create.html:57
@ -1746,7 +1762,18 @@ msgstr ""
msgid "Invite user"
msgstr ""
#: project/templates/admin_unit/update.html:72
#: project/templates/admin_unit/request_deletion.html:8
msgid ""
"The organization is not deleted immediately. After a period of time, the "
"organization will be deleted. Until then, the deletion can be canceled."
msgstr ""
#: project/templates/admin_unit/update.html:25
#: project/templates/manage/events.html:48
msgid "The organization is scheduled for deletion."
msgstr ""
#: project/templates/admin_unit/update.html:79
#: project/templates/manage/verification_requests_outgoing.html:6
#: project/templates/manage/verification_requests_outgoing.html:11
msgid "Verification requests"
@ -1781,6 +1808,7 @@ msgid "You have been invited to join %(admin_unit_name)s."
msgstr ""
#: project/templates/email/invitation_notice.html:5
#: project/templates/email/organization_deletion_requested_notice.html:5
#: project/templates/email/organization_invitation_notice.html:5
msgid "Click here to view the invitation"
msgstr ""
@ -1798,6 +1826,11 @@ msgstr ""
msgid "Notification settings"
msgstr ""
#: project/templates/email/organization_deletion_requested_notice.html:4
#, python-format
msgid "%(admin_unit_name)s is scheduled for deletion."
msgstr ""
#: project/templates/email/organization_invitation_accepted_notice.html:4
#, python-format
msgid ""
@ -1895,7 +1928,7 @@ msgstr ""
#: project/templates/event/actions.html:74 project/templates/event/read.html:32
#: project/templates/event_date/read.html:34
#: project/templates/manage/events.html:145
#: project/templates/manage/events.html:151
msgid "Add event to list"
msgstr ""
@ -2016,21 +2049,21 @@ msgstr ""
msgid "Verify organization"
msgstr ""
#: project/templates/manage/events.html:85
#: project/templates/manage/events.html:91
msgid "More filters"
msgstr ""
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of references"
msgstr ""
#: project/templates/manage/events.html:99
#: project/templates/manage/events.html:134
#: project/templates/manage/events.html:105
#: project/templates/manage/events.html:140
msgid "Number of reference requests."
msgstr ""
#: project/templates/manage/events.html:112
#: project/templates/manage/events.html:118
msgid "Duplicate"
msgstr ""
@ -2200,63 +2233,68 @@ msgstr ""
msgid "Preview"
msgstr ""
#: project/views/admin.py:60
#: project/views/admin.py:63
msgid "Organization successfully updated"
msgstr ""
#: project/views/admin.py:82
#: project/views/admin.py:85 project/views/admin_unit.py:182
#: project/views/admin_unit.py:215
msgid "Entered name does not match organization name"
msgstr ""
#: project/views/admin.py:87
#: project/views/admin.py:89
msgid "Organization successfully deleted"
msgstr ""
#: project/views/admin.py:111 project/views/manage.py:443
#: project/views/admin.py:113 project/views/manage.py:432
#: project/views/user.py:28
msgid "Settings successfully updated"
msgstr ""
#: project/views/admin.py:144
#: project/views/admin.py:133
#, python-format
msgid "Test mail from %(site_name)s"
msgstr ""
#: project/views/admin.py:187
#: project/views/admin.py:162
#, python-format
msgid "Newsletter from %(site_name)s"
msgstr ""
#: project/views/admin.py:237
#: project/views/admin.py:212
msgid "User successfully updated"
msgstr ""
#: project/views/admin.py:257
#: project/views/admin.py:232
msgid "Entered email does not match user email"
msgstr ""
#: project/views/admin.py:262
#: project/views/admin.py:237
msgid "User successfully deleted"
msgstr ""
#: project/views/admin_unit.py:69
#: project/views/admin_unit.py:78
msgid ""
"Organizations cannot currently be created. The project is in a closed "
"test phase. If you are interested, you can contact us."
msgstr ""
#: project/views/admin_unit.py:119
#: project/views/admin_unit.py:128
msgid "Organization successfully created"
msgstr ""
#: project/views/admin_unit.py:149
#: project/views/admin_unit.py:158
msgid "AdminUnit successfully updated"
msgstr ""
#: project/views/admin_unit.py:171
#: project/views/admin_unit.py:245
msgid "Organization invitation accepted"
msgstr ""
#: project/views/admin_unit.py:259
msgid "Organization deletion requested"
msgstr ""
#: project/views/admin_unit_member.py:43
msgid "Member successfully updated"
msgstr ""
@ -2440,26 +2478,26 @@ msgid ""
"verified automatically."
msgstr ""
#: project/views/utils.py:65
#: project/views/utils.py:71
msgid ""
"An entry with the entered values already exists. Duplicate entries are "
"not allowed."
msgstr ""
#: project/views/utils.py:116
#: project/views/utils.py:122
#, python-format
msgid "Error in the %s field - %s"
msgstr ""
#: project/views/utils.py:123
#: project/views/utils.py:129
msgid "Show"
msgstr ""
#: project/views/utils.py:131
#: project/views/utils.py:137
msgid "You do not have permission for this action"
msgstr ""
#: project/views/utils.py:252
#: project/views/utils.py:258
msgid ""
"The invitation was issued to another user. Sign in with the email address"
" the invitation was sent to."

View File

@ -18,6 +18,7 @@ from project.forms.admin import (
)
from project.models import AdminUnit, Role, User
from project.services.admin import upsert_settings
from project.services.admin_unit import delete_admin_unit
from project.services.user import set_roles_for_user
from project.views.utils import (
flash_errors,
@ -84,8 +85,7 @@ def admin_admin_unit_delete(id):
flash(gettext("Entered name does not match organization name"), "danger")
else:
try:
db.session.delete(admin_unit)
db.session.commit()
delete_admin_unit(admin_unit)
flash(gettext("Organization successfully deleted"), "success")
return redirect(url_for("admin_admin_units"))
except SQLAlchemyError as e:

View File

@ -1,4 +1,6 @@
from flask import flash, redirect, render_template, request, url_for
import datetime
from flask import flash, g, redirect, render_template, request, url_for
from flask_babel import gettext
from flask_security import auth_required, current_user
from sqlalchemy.exc import SQLAlchemyError
@ -10,7 +12,12 @@ from project.access import (
get_admin_unit_members_with_permission,
has_access,
)
from project.forms.admin_unit import CreateAdminUnitForm, UpdateAdminUnitForm
from project.forms.admin_unit import (
CancelAdminUnitDeletionForm,
CreateAdminUnitForm,
RequestAdminUnitDeletionForm,
UpdateAdminUnitForm,
)
from project.models import AdminUnit, AdminUnitInvitation, AdminUnitRelation, Location
from project.services.admin_unit import (
insert_admin_unit_for_user,
@ -22,6 +29,8 @@ from project.views.utils import (
flash_message,
get_current_admin_unit,
handleSqlError,
manage_required,
non_match_for_deletion,
permission_missing,
send_mails,
)
@ -157,6 +166,71 @@ def admin_unit_update(id):
return render_template("admin_unit/update.html", form=form, admin_unit=admin_unit)
@app.route("/admin_unit/<int:id>/request-deletion", methods=("GET", "POST"))
@auth_required()
@manage_required("admin_unit:update")
def admin_unit_request_deletion(id):
admin_unit = g.admin_unit
if admin_unit.deletion_requested_at: # pragma: no cover
return redirect(url_for("admin_unit_cancel_deletion", id=admin_unit.id))
form = RequestAdminUnitDeletionForm()
if form.validate_on_submit():
if non_match_for_deletion(form.name.data, admin_unit.name):
flash(gettext("Entered name does not match organization name"), "danger")
else:
admin_unit.deletion_requested_at = datetime.datetime.utcnow()
admin_unit.deletion_requested_by_id = current_user.id
try:
db.session.commit()
send_admin_unit_deletion_requested_mails(admin_unit)
return redirect(url_for("manage_admin_unit", id=admin_unit.id))
except SQLAlchemyError as e:
db.session.rollback()
flash(handleSqlError(e), "danger")
else:
flash_errors(form)
return render_template(
"admin_unit/request_deletion.html", form=form, admin_unit=admin_unit
)
@app.route("/admin_unit/<int:id>/cancel-deletion", methods=("GET", "POST"))
@auth_required()
@manage_required("admin_unit:update")
def admin_unit_cancel_deletion(id):
admin_unit = g.admin_unit
if not admin_unit.deletion_requested_at: # pragma: no cover
return redirect(url_for("admin_unit_request_deletion", id=admin_unit.id))
form = CancelAdminUnitDeletionForm()
if form.validate_on_submit():
if non_match_for_deletion(form.name.data, admin_unit.name):
flash(gettext("Entered name does not match organization name"), "danger")
else:
admin_unit.deletion_requested_at = None
admin_unit.deletion_requested_by_id = None
try:
db.session.commit()
return redirect(url_for("manage_admin_unit", id=admin_unit.id))
except SQLAlchemyError as e:
db.session.rollback()
flash(handleSqlError(e), "danger")
else:
flash_errors(form)
return render_template(
"admin_unit/cancel_deletion.html", form=form, admin_unit=admin_unit
)
def send_admin_unit_invitation_accepted_mails(
invitation: AdminUnitInvitation, relation: AdminUnitRelation, admin_unit: AdminUnit
):
@ -174,3 +248,15 @@ def send_admin_unit_invitation_accepted_mails(
relation=relation,
admin_unit=admin_unit,
)
def send_admin_unit_deletion_requested_mails(admin_unit: AdminUnit):
members = get_admin_unit_members_with_permission(admin_unit.id, "admin_unit:update")
emails = list(map(lambda member: member.user.email, members))
send_mails(
emails,
gettext("Organization deletion requested"),
"organization_deletion_requested_notice",
admin_unit=admin_unit,
)

View File

@ -1,3 +1,4 @@
from functools import wraps
from urllib.parse import quote_plus
from flask import Markup, flash, g, redirect, render_template, request, url_for
@ -10,7 +11,12 @@ from sqlalchemy.exc import SQLAlchemyError
from wtforms import FormField
from project import app, celery, mail
from project.access import get_admin_unit_for_manage, get_admin_units_for_manage
from project.access import (
get_admin_unit_for_manage,
get_admin_unit_for_manage_or_404,
get_admin_units_for_manage,
has_access,
)
from project.dateutils import berlin_tz, round_to_next_day
from project.models import Event, EventAttendanceMode, EventDate
from project.utils import get_place_str, strings_are_equal_ignoring_case
@ -298,3 +304,23 @@ def get_celery_poll_group_result(): # pragma: no cover
"successful": False,
"error": getattr(e, "message", "Unknown error"),
}
def manage_required(permission=None):
def decorator(f):
@wraps(f)
def decorated_function(id, *args, **kwargs):
admin_unit = get_admin_unit_for_manage_or_404(id)
if permission and not has_access(admin_unit, permission):
return permission_missing(
url_for("manage_admin_unit", id=admin_unit.id)
)
g.admin_unit = admin_unit
return f(id, *args, **kwargs)
return decorated_function
return decorator

View File

@ -0,0 +1,17 @@
def test_get_admin_units_with_due_delete_request(client, seeder, db, utils, app):
user_id, admin_unit_id = seeder.setup_base()
with app.app_context():
import datetime
from project.models import AdminUnit
from project.services.admin_unit import get_admin_units_with_due_delete_request
admin_unit = db.session.get(AdminUnit, admin_unit_id)
admin_unit.deletion_requested_at = (
datetime.datetime.utcnow() - datetime.timedelta(days=4)
)
db.session.commit()
due_admin_units = get_admin_units_with_due_delete_request()
assert len(due_admin_units) == 1

View File

@ -537,3 +537,34 @@ def test_purge_eventorganizer(client, app, db, seeder):
location = db.session.get(Location, location_id)
assert location is None
def test_delete_admin_unit(client, app, db, seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
instance_id = seeder.upsert_default_event_organizer(admin_unit_id)
image_id = seeder.upsert_default_image()
location_id = seeder.create_location(street="Street")
with app.app_context():
from project.models import AdminUnit, EventOrganizer, Image, Location
from project.services.admin_unit import delete_admin_unit
instance = db.session.get(EventOrganizer, instance_id)
instance.logo = db.session.get(Image, image_id)
instance.location = db.session.get(Location, location_id)
db.session.commit()
assert instance.logo is not None
assert instance.location is not None
admin_unit = db.session.get(AdminUnit, admin_unit_id)
delete_admin_unit(admin_unit)
admin_unit = db.session.get(AdminUnit, admin_unit_id)
assert admin_unit is None
image = db.session.get(Image, image_id)
assert image is None
location = db.session.get(Location, location_id)
assert admin_unit is location

View File

@ -1,3 +1,6 @@
import pytest
def create_form_data(response, utils):
return {
"csrf_token": utils.get_csrf(response),
@ -297,3 +300,111 @@ def test_list(client, app, utils, seeder):
seeder.create_admin_unit(user_id, "Meine Crew")
response = client.get("/manage/admin_units")
assert b"Meine Crew" in response.data
@pytest.mark.parametrize("db_error", [True, False])
@pytest.mark.parametrize("non_match", [True, False])
def test_admin_unit_request_deletion(
client, seeder, utils, app, db, mocker, db_error, non_match
):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("admin_unit_request_deletion", id=admin_unit_id)
response = utils.get_ok(url)
if db_error:
utils.mock_db_commit(mocker)
form_name = "Meine Crew"
if non_match:
form_name = "wrong"
response = utils.post_form(
url,
response,
{
"name": form_name,
},
)
if non_match:
utils.assert_response_error_message(
response, "Der eingegebene Name entspricht nicht dem Namen der Organisation"
)
return
if db_error:
utils.assert_response_db_error(response)
return
utils.assert_response_redirect(response, "manage_admin_unit", id=admin_unit_id)
with app.app_context():
from project.models import AdminUnit
admin_unit = db.session.get(AdminUnit, admin_unit_id)
assert admin_unit.deletion_requested_at is not None
@pytest.mark.parametrize("db_error", [True, False])
@pytest.mark.parametrize("non_match", [True, False])
def test_admin_unit_cancel_deletion(
client, seeder, utils, app, db, mocker, db_error, non_match
):
user_id, admin_unit_id = seeder.setup_base()
with app.app_context():
import datetime
from project.models import AdminUnit
admin_unit = db.session.get(AdminUnit, admin_unit_id)
admin_unit.deletion_requested_at = datetime.datetime.utcnow()
db.session.commit()
url = utils.get_url("admin_unit_cancel_deletion", id=admin_unit_id)
response = utils.get_ok(url)
if db_error:
utils.mock_db_commit(mocker)
form_name = "Meine Crew"
if non_match:
form_name = "wrong"
response = utils.post_form(
url,
response,
{
"name": form_name,
},
)
if non_match:
utils.assert_response_error_message(
response, "Der eingegebene Name entspricht nicht dem Namen der Organisation"
)
return
if db_error:
utils.assert_response_db_error(response)
return
utils.assert_response_redirect(response, "manage_admin_unit", id=admin_unit_id)
with app.app_context():
from project.models import AdminUnit
admin_unit = db.session.get(AdminUnit, admin_unit_id)
assert admin_unit.deletion_requested_at is None
def test_admin_unit_cancel_deletion_permission_missing(client, seeder, utils, mocker):
owner_id, admin_unit_id, member_id = seeder.setup_base_event_verifier()
response = utils.get_endpoint("admin_unit_cancel_deletion", id=admin_unit_id)
utils.assert_response_permission_missing(
response, "manage_admin_unit", id=admin_unit_id
)