mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
Leave organization #458
This commit is contained in:
parent
51780c17f7
commit
545d2339e8
25
docker-compose.test.services.yml
Normal file
25
docker-compose.test.services.yml
Normal file
@ -0,0 +1,25 @@
|
||||
version: "3.9"
|
||||
name: "eventcally-test-services"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgis/postgis:12-3.1
|
||||
healthcheck:
|
||||
test: "pg_isready --username=eventcally && psql --username=eventcally --list"
|
||||
start_period: "5s"
|
||||
ports:
|
||||
- 5433:5432
|
||||
environment:
|
||||
- POSTGRES_DB=eventcally
|
||||
- POSTGRES_USER=eventcally
|
||||
- POSTGRES_PASSWORD=pass
|
||||
|
||||
redis:
|
||||
image: bitnami/redis:6.2
|
||||
healthcheck:
|
||||
test: "redis-cli -a 'pass' ping | grep PONG"
|
||||
start_period: "5s"
|
||||
ports:
|
||||
- 6380:6379
|
||||
environment:
|
||||
REDIS_PASSWORD: pass
|
||||
48
messages.pot
48
messages.pot
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-05-02 23:21+0200\n"
|
||||
"POT-Creation-Date: 2023-05-03 20:26+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"
|
||||
@ -198,24 +198,24 @@ msgstr ""
|
||||
msgid "You have received an invitation"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:303
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:304
|
||||
#: project/views/root.py:55
|
||||
msgid "Terms of service"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:307
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:308
|
||||
#: project/views/root.py:63
|
||||
msgid "Legal notice"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:13 project/templates/_macros.html:1473
|
||||
#: project/templates/layout.html:311
|
||||
#: project/templates/layout.html:312
|
||||
#: project/templates/widget/event_suggestion/create.html:204
|
||||
#: project/views/admin_unit.py:83 project/views/root.py:71
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:315
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:316
|
||||
#: project/views/root.py:79
|
||||
msgid "Privacy"
|
||||
msgstr ""
|
||||
@ -310,11 +310,11 @@ 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
|
||||
#: project/forms/organizer.py:25 project/forms/organizer.py:52
|
||||
#: project/forms/reference_request.py:23
|
||||
#: project/forms/admin_unit.py:144 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 project/forms/organizer.py:25
|
||||
#: project/forms/organizer.py:52 project/forms/reference_request.py:23
|
||||
#: project/templates/admin/admin_units.html:19
|
||||
#: project/templates/event_place/list.html:19
|
||||
#: project/templates/manage/organizers.html:18
|
||||
@ -487,6 +487,11 @@ msgstr ""
|
||||
msgid "Cancel deletion"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin_unit.py:143 project/templates/layout.html:276
|
||||
#: project/templates/manage/delete_membership.html:6
|
||||
msgid "Leave organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin_unit_member.py:13
|
||||
msgid "Invite"
|
||||
msgstr ""
|
||||
@ -1142,6 +1147,7 @@ msgstr ""
|
||||
#: project/templates/admin_unit/request_deletion.html:15
|
||||
#: project/templates/admin_unit/update.html:36
|
||||
#: project/templates/layout.html:247
|
||||
#: project/templates/manage/delete_membership.html:13
|
||||
msgid "Organization"
|
||||
msgstr ""
|
||||
|
||||
@ -1668,7 +1674,7 @@ msgid "Switch organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/templates/developer/read.html:4
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:319
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:320
|
||||
#: project/templates/profile.html:46
|
||||
msgid "Developer"
|
||||
msgstr ""
|
||||
@ -2262,7 +2268,7 @@ msgid "Organization successfully updated"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin.py:85 project/views/admin_unit.py:187
|
||||
#: project/views/admin_unit.py:220
|
||||
#: project/views/admin_unit.py:220 project/views/manage.py:316
|
||||
msgid "Entered name does not match organization name"
|
||||
msgstr ""
|
||||
|
||||
@ -2270,7 +2276,7 @@ msgstr ""
|
||||
msgid "Organization successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin.py:113 project/views/manage.py:432
|
||||
#: project/views/admin.py:113 project/views/manage.py:486
|
||||
#: project/views/user.py:41
|
||||
msgid "Settings successfully updated"
|
||||
msgstr ""
|
||||
@ -2323,11 +2329,15 @@ msgstr ""
|
||||
msgid "Member successfully updated"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:69
|
||||
#: project/views/admin_unit_member.py:70 project/views/manage.py:307
|
||||
msgid "Last remaining administrator can not leave the organization."
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:79
|
||||
msgid "Entered email does not match member email"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:74
|
||||
#: project/views/admin_unit_member.py:84
|
||||
msgid "Member successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
@ -2420,6 +2430,14 @@ msgstr ""
|
||||
msgid "Places of Google Maps"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/manage.py:302
|
||||
msgid "You are not a member of this organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/manage.py:321
|
||||
msgid "Organization successfully left"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/oauth2_client.py:37
|
||||
msgid "OAuth2 client successfully created"
|
||||
msgstr ""
|
||||
|
||||
@ -8,6 +8,7 @@ from sqlalchemy import and_
|
||||
|
||||
from project import app
|
||||
from project.models import AdminUnit, AdminUnitMember, Event, PublicStatus, User
|
||||
from project.models.admin_unit import AdminUnitMemberRole
|
||||
from project.services.admin_unit import get_member_for_admin_unit_by_user_id
|
||||
|
||||
|
||||
@ -238,3 +239,18 @@ def get_admin_unit_members_with_permission(admin_unit_id: int, permission: str)
|
||||
lambda member: has_admin_unit_member_permission(member, permission), members
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def can_current_user_delete_member(member: AdminUnitMember) -> bool:
|
||||
if current_user.has_role("admin"):
|
||||
return True
|
||||
|
||||
# Check if there is another admin
|
||||
return (
|
||||
AdminUnitMember.query.filter(
|
||||
AdminUnitMember.user_id != member.user_id,
|
||||
AdminUnitMember.admin_unit_id == member.admin_unit_id,
|
||||
AdminUnitMember.roles.any(AdminUnitMemberRole.name == "admin"),
|
||||
).first()
|
||||
is not None
|
||||
)
|
||||
|
||||
@ -137,3 +137,8 @@ class RequestAdminUnitDeletionForm(FlaskForm):
|
||||
class CancelAdminUnitDeletionForm(FlaskForm):
|
||||
submit = SubmitField(lazy_gettext("Cancel deletion"))
|
||||
name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
|
||||
|
||||
|
||||
class AdminUnitDeleteMembershipForm(FlaskForm):
|
||||
submit = SubmitField(lazy_gettext("Leave organization"))
|
||||
name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
|
||||
|
||||
@ -273,6 +273,7 @@
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarAdminUnitSwitchDropdown">
|
||||
<a class="dropdown-item" href="{{ url_for('manage_admin_units') }}">{{ _('Switch organization') }}</a>
|
||||
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_delete_membership', id=current_admin_unit.id) }}">{{ _('Leave organization') }}…</a>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
24
project/templates/manage/delete_membership.html
Normal file
24
project/templates/manage/delete_membership.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_field_with_errors, render_field %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ _('Leave organization') }} "{{ admin_unit.name }}"</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 %}
|
||||
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-05-02 23:21+0200\n"
|
||||
"POT-Creation-Date: 2023-05-03 20:26+0200\n"
|
||||
"PO-Revision-Date: 2020-06-07 18:51+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: de\n"
|
||||
@ -199,24 +199,24 @@ msgstr "message"
|
||||
msgid "You have received an invitation"
|
||||
msgstr "Du hast eine Einladung erhalten"
|
||||
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:303
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:304
|
||||
#: project/views/root.py:55
|
||||
msgid "Terms of service"
|
||||
msgstr "Nutzungsbedingungen"
|
||||
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:307
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:308
|
||||
#: project/views/root.py:63
|
||||
msgid "Legal notice"
|
||||
msgstr "Impressum"
|
||||
|
||||
#: project/forms/admin.py:13 project/templates/_macros.html:1473
|
||||
#: project/templates/layout.html:311
|
||||
#: project/templates/layout.html:312
|
||||
#: project/templates/widget/event_suggestion/create.html:204
|
||||
#: project/views/admin_unit.py:83 project/views/root.py:71
|
||||
msgid "Contact"
|
||||
msgstr "Kontakt"
|
||||
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:315
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:316
|
||||
#: project/views/root.py:79
|
||||
msgid "Privacy"
|
||||
msgstr "Datenschutz"
|
||||
@ -319,11 +319,11 @@ 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
|
||||
#: project/forms/organizer.py:25 project/forms/organizer.py:52
|
||||
#: project/forms/reference_request.py:23
|
||||
#: project/forms/admin_unit.py:144 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 project/forms/organizer.py:25
|
||||
#: project/forms/organizer.py:52 project/forms/reference_request.py:23
|
||||
#: project/templates/admin/admin_units.html:19
|
||||
#: project/templates/event_place/list.html:19
|
||||
#: project/templates/manage/organizers.html:18
|
||||
@ -507,6 +507,11 @@ msgstr "Löschung beantragen"
|
||||
msgid "Cancel deletion"
|
||||
msgstr "Löschen abbrechen"
|
||||
|
||||
#: project/forms/admin_unit.py:143 project/templates/layout.html:276
|
||||
#: project/templates/manage/delete_membership.html:6
|
||||
msgid "Leave organization"
|
||||
msgstr "Organisation verlassen"
|
||||
|
||||
#: project/forms/admin_unit_member.py:13
|
||||
msgid "Invite"
|
||||
msgstr "Einladen"
|
||||
@ -1190,6 +1195,7 @@ msgstr "Wochentage"
|
||||
#: project/templates/admin_unit/request_deletion.html:15
|
||||
#: project/templates/admin_unit/update.html:36
|
||||
#: project/templates/layout.html:247
|
||||
#: project/templates/manage/delete_membership.html:13
|
||||
msgid "Organization"
|
||||
msgstr "Organisation"
|
||||
|
||||
@ -1725,7 +1731,7 @@ msgid "Switch organization"
|
||||
msgstr "Organisation wechseln"
|
||||
|
||||
#: project/templates/developer/read.html:4
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:319
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:320
|
||||
#: project/templates/profile.html:46
|
||||
msgid "Developer"
|
||||
msgstr "Entwickler"
|
||||
@ -2334,7 +2340,7 @@ msgid "Organization successfully updated"
|
||||
msgstr "Organisation erfolgreich aktualisiert"
|
||||
|
||||
#: project/views/admin.py:85 project/views/admin_unit.py:187
|
||||
#: project/views/admin_unit.py:220
|
||||
#: project/views/admin_unit.py:220 project/views/manage.py:316
|
||||
msgid "Entered name does not match organization name"
|
||||
msgstr "Der eingegebene Name entspricht nicht dem Namen der Organisation"
|
||||
|
||||
@ -2342,7 +2348,7 @@ msgstr "Der eingegebene Name entspricht nicht dem Namen der Organisation"
|
||||
msgid "Organization successfully deleted"
|
||||
msgstr "Organisation erfolgreich gelöscht"
|
||||
|
||||
#: project/views/admin.py:113 project/views/manage.py:432
|
||||
#: project/views/admin.py:113 project/views/manage.py:486
|
||||
#: project/views/user.py:41
|
||||
msgid "Settings successfully updated"
|
||||
msgstr "Einstellungen erfolgreich aktualisiert"
|
||||
@ -2398,11 +2404,15 @@ msgstr "Löschung der Organisation beantragt"
|
||||
msgid "Member successfully updated"
|
||||
msgstr "Mitglied erfolgreich aktualisiert"
|
||||
|
||||
#: project/views/admin_unit_member.py:69
|
||||
#: project/views/admin_unit_member.py:70 project/views/manage.py:307
|
||||
msgid "Last remaining administrator can not leave the organization."
|
||||
msgstr "Der letzte verbleibende Administrator kann die Organisation nicht verlassen."
|
||||
|
||||
#: project/views/admin_unit_member.py:79
|
||||
msgid "Entered email does not match member email"
|
||||
msgstr "Die eingegebene Email passt nicht zur Email des Mitglieds"
|
||||
|
||||
#: project/views/admin_unit_member.py:74
|
||||
#: project/views/admin_unit_member.py:84
|
||||
msgid "Member successfully deleted"
|
||||
msgstr "Mitglied erfolgreich gelöscht"
|
||||
|
||||
@ -2495,6 +2505,14 @@ msgstr "Orte der Organisation"
|
||||
msgid "Places of Google Maps"
|
||||
msgstr "Orte von Google Maps"
|
||||
|
||||
#: project/views/manage.py:302
|
||||
msgid "You are not a member of this organization"
|
||||
msgstr "Du bist kein Mitglied dieser Organisation"
|
||||
|
||||
#: project/views/manage.py:321
|
||||
msgid "Organization successfully left"
|
||||
msgstr "Organisation erfolgreich verlassen"
|
||||
|
||||
#: project/views/oauth2_client.py:37
|
||||
msgid "OAuth2 client successfully created"
|
||||
msgstr "OAuth2 Client erfolgreich erstellt"
|
||||
@ -2585,7 +2603,9 @@ msgstr ""
|
||||
msgid ""
|
||||
"You are administrator of at least one organization. Cancel your "
|
||||
"membership to delete your account."
|
||||
msgstr "Du bist Administrator von mindestens einer Organisation. Beende deine Mitgliedschaft, um deinen Account zu löschen."
|
||||
msgstr ""
|
||||
"Du bist Administrator von mindestens einer Organisation. Beende deine "
|
||||
"Mitgliedschaft, um deinen Account zu löschen."
|
||||
|
||||
#: project/views/user.py:92 project/views/user.py:119
|
||||
msgid "Entered email does not match your email"
|
||||
|
||||
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2023-05-02 23:21+0200\n"
|
||||
"POT-Creation-Date: 2023-05-03 20:26+0200\n"
|
||||
"PO-Revision-Date: 2021-04-30 15:04+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: en\n"
|
||||
@ -199,24 +199,24 @@ msgstr ""
|
||||
msgid "You have received an invitation"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:303
|
||||
#: project/forms/admin.py:11 project/templates/layout.html:304
|
||||
#: project/views/root.py:55
|
||||
msgid "Terms of service"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:307
|
||||
#: project/forms/admin.py:12 project/templates/layout.html:308
|
||||
#: project/views/root.py:63
|
||||
msgid "Legal notice"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:13 project/templates/_macros.html:1473
|
||||
#: project/templates/layout.html:311
|
||||
#: project/templates/layout.html:312
|
||||
#: project/templates/widget/event_suggestion/create.html:204
|
||||
#: project/views/admin_unit.py:83 project/views/root.py:71
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:315
|
||||
#: project/forms/admin.py:14 project/templates/layout.html:316
|
||||
#: project/views/root.py:79
|
||||
msgid "Privacy"
|
||||
msgstr ""
|
||||
@ -311,11 +311,11 @@ 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
|
||||
#: project/forms/organizer.py:25 project/forms/organizer.py:52
|
||||
#: project/forms/reference_request.py:23
|
||||
#: project/forms/admin_unit.py:144 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 project/forms/organizer.py:25
|
||||
#: project/forms/organizer.py:52 project/forms/reference_request.py:23
|
||||
#: project/templates/admin/admin_units.html:19
|
||||
#: project/templates/event_place/list.html:19
|
||||
#: project/templates/manage/organizers.html:18
|
||||
@ -488,6 +488,11 @@ msgstr ""
|
||||
msgid "Cancel deletion"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin_unit.py:143 project/templates/layout.html:276
|
||||
#: project/templates/manage/delete_membership.html:6
|
||||
msgid "Leave organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/forms/admin_unit_member.py:13
|
||||
msgid "Invite"
|
||||
msgstr ""
|
||||
@ -1143,6 +1148,7 @@ msgstr ""
|
||||
#: project/templates/admin_unit/request_deletion.html:15
|
||||
#: project/templates/admin_unit/update.html:36
|
||||
#: project/templates/layout.html:247
|
||||
#: project/templates/manage/delete_membership.html:13
|
||||
msgid "Organization"
|
||||
msgstr ""
|
||||
|
||||
@ -1676,7 +1682,7 @@ msgid "Switch organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/templates/developer/read.html:4
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:319
|
||||
#: project/templates/developer/read.html:8 project/templates/layout.html:320
|
||||
#: project/templates/profile.html:46
|
||||
msgid "Developer"
|
||||
msgstr ""
|
||||
@ -2270,7 +2276,7 @@ msgid "Organization successfully updated"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin.py:85 project/views/admin_unit.py:187
|
||||
#: project/views/admin_unit.py:220
|
||||
#: project/views/admin_unit.py:220 project/views/manage.py:316
|
||||
msgid "Entered name does not match organization name"
|
||||
msgstr ""
|
||||
|
||||
@ -2278,7 +2284,7 @@ msgstr ""
|
||||
msgid "Organization successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin.py:113 project/views/manage.py:432
|
||||
#: project/views/admin.py:113 project/views/manage.py:486
|
||||
#: project/views/user.py:41
|
||||
msgid "Settings successfully updated"
|
||||
msgstr ""
|
||||
@ -2331,11 +2337,15 @@ msgstr ""
|
||||
msgid "Member successfully updated"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:69
|
||||
#: project/views/admin_unit_member.py:70 project/views/manage.py:307
|
||||
msgid "Last remaining administrator can not leave the organization."
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:79
|
||||
msgid "Entered email does not match member email"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/admin_unit_member.py:74
|
||||
#: project/views/admin_unit_member.py:84
|
||||
msgid "Member successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
@ -2428,6 +2438,14 @@ msgstr ""
|
||||
msgid "Places of Google Maps"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/manage.py:302
|
||||
msgid "You are not a member of this organization"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/manage.py:321
|
||||
msgid "Organization successfully left"
|
||||
msgstr ""
|
||||
|
||||
#: project/views/oauth2_client.py:37
|
||||
msgid "OAuth2 client successfully created"
|
||||
msgstr ""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from flask import flash, redirect, render_template, url_for
|
||||
from flask_babel import gettext
|
||||
from flask_security import auth_required
|
||||
from flask_security import auth_required, current_user
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from project import app, db
|
||||
@ -59,6 +59,9 @@ def manage_admin_unit_member_delete(id):
|
||||
member = AdminUnitMember.query.get_or_404(id)
|
||||
admin_unit = member.adminunit
|
||||
|
||||
if member.user_id == current_user.id:
|
||||
return redirect(url_for("manage_admin_unit_delete_membership", id=id))
|
||||
|
||||
if not has_access(admin_unit, "admin_unit.members:delete"):
|
||||
return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
|
||||
|
||||
|
||||
@ -17,12 +17,16 @@ from project import app, db, dump_org_path
|
||||
from project.access import (
|
||||
access_or_401,
|
||||
admin_unit_suggestions_enabled_or_404,
|
||||
can_current_user_delete_member,
|
||||
get_admin_unit_for_manage_or_404,
|
||||
get_admin_units_for_manage,
|
||||
has_access,
|
||||
)
|
||||
from project.celery_tasks import dump_admin_unit_task
|
||||
from project.forms.admin_unit import UpdateAdminUnitWidgetForm
|
||||
from project.forms.admin_unit import (
|
||||
AdminUnitDeleteMembershipForm,
|
||||
UpdateAdminUnitWidgetForm,
|
||||
)
|
||||
from project.forms.event import FindEventForm
|
||||
from project.forms.event_place import FindEventPlaceForm
|
||||
from project.models import (
|
||||
@ -37,6 +41,7 @@ from project.services.admin_unit import (
|
||||
get_admin_unit_member_invitations,
|
||||
get_admin_unit_organization_invitations,
|
||||
get_admin_unit_query,
|
||||
get_member_for_admin_unit_by_user_id,
|
||||
)
|
||||
from project.services.event import get_events_query
|
||||
from project.services.event_search import EventSearchParams
|
||||
@ -49,6 +54,7 @@ from project.views.utils import (
|
||||
get_current_admin_unit,
|
||||
get_pagination_urls,
|
||||
handleSqlError,
|
||||
non_match_for_deletion,
|
||||
permission_missing,
|
||||
set_current_admin_unit,
|
||||
)
|
||||
@ -280,6 +286,54 @@ def manage_admin_unit_members(id):
|
||||
)
|
||||
|
||||
|
||||
@app.route("/manage/admin_unit/<int:id>/membership/delete", methods=("GET", "POST"))
|
||||
@auth_required()
|
||||
def manage_admin_unit_delete_membership(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
set_current_admin_unit(admin_unit)
|
||||
|
||||
member = get_member_for_admin_unit_by_user_id(
|
||||
admin_unit.id,
|
||||
current_user.id,
|
||||
)
|
||||
|
||||
if not member:
|
||||
# E.g. global admin
|
||||
flash(gettext("You are not a member of this organization"), "danger")
|
||||
return redirect(url_for("manage_admin_unit_members", id=id))
|
||||
|
||||
if not can_current_user_delete_member(member):
|
||||
flash(
|
||||
gettext("Last remaining administrator can not leave the organization."),
|
||||
"danger",
|
||||
)
|
||||
return redirect(url_for("manage_admin_unit_members", id=id))
|
||||
|
||||
form = AdminUnitDeleteMembershipForm()
|
||||
|
||||
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:
|
||||
try:
|
||||
db.session.delete(member)
|
||||
db.session.commit()
|
||||
flash(gettext("Organization successfully left"), "success")
|
||||
return redirect(url_for("manage_admin_units"))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), "danger")
|
||||
else:
|
||||
flash_errors(form)
|
||||
|
||||
return render_template(
|
||||
"manage/delete_membership.html",
|
||||
admin_unit=admin_unit,
|
||||
member=member,
|
||||
form=form,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/manage/admin_unit/<int:id>/relations")
|
||||
@app.route("/manage/admin_unit/<int:id>/relations/<path:path>")
|
||||
@auth_required()
|
||||
|
||||
@ -121,7 +121,12 @@ class Seeder(object):
|
||||
verify=True,
|
||||
)
|
||||
|
||||
def create_admin_unit_member(self, admin_unit_id, role_names):
|
||||
def create_admin_unit_member(
|
||||
self,
|
||||
admin_unit_id,
|
||||
role_names,
|
||||
email="test@test.de",
|
||||
):
|
||||
from project.services.admin_unit import (
|
||||
add_user_to_admin_unit_with_roles,
|
||||
get_admin_unit_by_id,
|
||||
@ -129,7 +134,7 @@ class Seeder(object):
|
||||
from project.services.user import get_user
|
||||
|
||||
with self._app.app_context():
|
||||
user_id = self.create_user()
|
||||
user_id = self.create_user(email=email)
|
||||
user = get_user(user_id)
|
||||
admin_unit = get_admin_unit_by_id(admin_unit_id)
|
||||
member = add_user_to_admin_unit_with_roles(user, admin_unit, role_names)
|
||||
@ -188,8 +193,12 @@ class Seeder(object):
|
||||
if remove_favorite_event(user_id, event_id):
|
||||
self._db.session.commit()
|
||||
|
||||
def create_admin_unit_member_event_verifier(self, admin_unit_id):
|
||||
return self.create_admin_unit_member(admin_unit_id, ["event_verifier"])
|
||||
def create_admin_unit_member_event_verifier(
|
||||
self,
|
||||
admin_unit_id,
|
||||
email="test@test.de",
|
||||
):
|
||||
return self.create_admin_unit_member(admin_unit_id, ["event_verifier"], email)
|
||||
|
||||
def upsert_event_place(self, admin_unit_id, name, location=None):
|
||||
from project.services.place import upsert_event_place
|
||||
|
||||
@ -246,8 +246,8 @@ class UtilActions(object):
|
||||
url = self.get_image_url(image, **values)
|
||||
return url
|
||||
|
||||
def get(self, url):
|
||||
response = self._client.get(url)
|
||||
def get(self, url, **kwargs):
|
||||
response = self._client.get(url, **kwargs)
|
||||
|
||||
if response.status_code == 200:
|
||||
self._ajax_csrf = self.get_ajax_csrf(response)
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
import pytest
|
||||
|
||||
from tests.seeder import Seeder
|
||||
from tests.utils import UtilActions
|
||||
|
||||
|
||||
def test_update(client, app, utils, seeder):
|
||||
seeder.create_user()
|
||||
user_id = utils.login()
|
||||
@ -63,14 +69,25 @@ def test_update_permission_missing(client, app, db, utils, seeder):
|
||||
assert response.status_code == 302
|
||||
|
||||
|
||||
def test_delete(client, app, utils, seeder):
|
||||
@pytest.mark.parametrize("scenario", ["default", "current_user"])
|
||||
def test_delete(client, app, db, utils: UtilActions, seeder: Seeder, scenario: str):
|
||||
seeder.create_user()
|
||||
user_id = utils.login()
|
||||
admin_unit_id = seeder.create_admin_unit(user_id, "Meine Crew")
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(admin_unit_id)
|
||||
member_email = "test@test.de" if scenario == "current_user" else "member@test.de"
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(
|
||||
admin_unit_id, email=member_email
|
||||
)
|
||||
|
||||
url = "/manage/member/%d/delete" % member_id
|
||||
response = client.get(url)
|
||||
|
||||
if scenario == "current_user":
|
||||
utils.assert_response_redirect(
|
||||
response, "manage_admin_unit_delete_membership", id=admin_unit_id
|
||||
)
|
||||
return
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
with client:
|
||||
@ -78,7 +95,7 @@ def test_delete(client, app, utils, seeder):
|
||||
url,
|
||||
data={
|
||||
"csrf_token": utils.get_csrf(response),
|
||||
"email": "Test@test.de",
|
||||
"email": "member@test.de",
|
||||
"submit": "Submit",
|
||||
},
|
||||
)
|
||||
@ -95,7 +112,9 @@ def test_delete_db_error(client, app, utils, seeder, mocker):
|
||||
seeder.create_user()
|
||||
user_id = utils.login()
|
||||
admin_unit_id = seeder.create_admin_unit(user_id, "Meine Crew")
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(admin_unit_id)
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(
|
||||
admin_unit_id, email="member@test.de"
|
||||
)
|
||||
|
||||
url = "/manage/member/%d/delete" % member_id
|
||||
response = client.get(url)
|
||||
@ -108,7 +127,7 @@ def test_delete_db_error(client, app, utils, seeder, mocker):
|
||||
url,
|
||||
data={
|
||||
"csrf_token": utils.get_csrf(response),
|
||||
"email": "test@test.de",
|
||||
"email": "member@test.de",
|
||||
"submit": "Submit",
|
||||
},
|
||||
)
|
||||
@ -121,7 +140,9 @@ def test_delete_email_does_not_match(client, app, utils, seeder):
|
||||
seeder.create_user()
|
||||
user_id = utils.login()
|
||||
admin_unit_id = seeder.create_admin_unit(user_id, "Meine Crew")
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(admin_unit_id)
|
||||
member_id = seeder.create_admin_unit_member_event_verifier(
|
||||
admin_unit_id, email="member@test.de"
|
||||
)
|
||||
|
||||
url = "/manage/member/%d/delete" % member_id
|
||||
response = client.get(url)
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import pytest
|
||||
|
||||
from tests.seeder import Seeder
|
||||
from tests.utils import UtilActions
|
||||
|
||||
|
||||
def test_index_noCookie(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
@ -248,3 +251,85 @@ def test_verification_requests_outgoing(client, seeder, utils):
|
||||
)
|
||||
utils.assert_response_contains(response, "Stadtmarketing")
|
||||
utils.assert_response_contains(response, "Please give us a call")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scenario", ["db_error", "default", "last_admin", "non_match"])
|
||||
def test_manage_admin_unit_delete_membership(
|
||||
client, utils: UtilActions, seeder: Seeder, app, db, mocker, scenario: str
|
||||
):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
|
||||
with app.app_context():
|
||||
from project.services.admin_unit import get_member_for_admin_unit_by_user_id
|
||||
|
||||
member = get_member_for_admin_unit_by_user_id(
|
||||
admin_unit_id,
|
||||
user_id,
|
||||
)
|
||||
member_id = member.id
|
||||
|
||||
if not scenario == "last_admin":
|
||||
seeder.create_admin_unit_member(
|
||||
admin_unit_id, ["admin"], "admin.member@test.de"
|
||||
)
|
||||
|
||||
url = utils.get_url("manage_admin_unit_delete_membership", id=admin_unit_id)
|
||||
|
||||
if scenario == "last_admin":
|
||||
response = utils.get(url, follow_redirects=True)
|
||||
utils.assert_response_error_message(
|
||||
response,
|
||||
"Der letzte verbleibende Administrator kann die Organisation nicht verlassen.",
|
||||
)
|
||||
return
|
||||
|
||||
response = utils.get_ok(url)
|
||||
|
||||
if scenario == "db_error":
|
||||
utils.mock_db_commit(mocker)
|
||||
|
||||
form_name = "Meine Crew"
|
||||
|
||||
if scenario == "non_match":
|
||||
form_name = "wrong"
|
||||
|
||||
response = utils.post_form(
|
||||
url,
|
||||
response,
|
||||
{
|
||||
"name": form_name,
|
||||
},
|
||||
)
|
||||
|
||||
if scenario == "non_match":
|
||||
utils.assert_response_error_message(
|
||||
response, "Der eingegebene Name entspricht nicht dem Namen der Organisation"
|
||||
)
|
||||
return
|
||||
|
||||
if scenario == "db_error":
|
||||
utils.assert_response_db_error(response)
|
||||
return
|
||||
|
||||
utils.assert_response_redirect(response, "manage_admin_units")
|
||||
|
||||
with app.app_context():
|
||||
from project.models import AdminUnitMember
|
||||
|
||||
assert db.session.get(AdminUnitMember, member_id) is None
|
||||
|
||||
|
||||
def test_manage_admin_unit_delete_membership_no_member(
|
||||
client, utils: UtilActions, seeder: Seeder, app, db
|
||||
):
|
||||
user_id, admin_unit_id = seeder.setup_base(admin=True)
|
||||
other_user_id, other_admin_unit_id = seeder.setup_base(
|
||||
log_in=False, email="other@test.de", name="Other Crew"
|
||||
)
|
||||
|
||||
url = utils.get_url("manage_admin_unit_delete_membership", id=other_admin_unit_id)
|
||||
response = utils.get(url, follow_redirects=True)
|
||||
utils.assert_response_error_message(
|
||||
response,
|
||||
"Du bist kein Mitglied dieser Organisation",
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user