From f9faf45297ce9975717961f684d101f67c1e6ec3 Mon Sep 17 00:00:00 2001 From: Daniel Grams Date: Sat, 17 Jun 2023 15:06:32 +0200 Subject: [PATCH] Adjust organization choice when creating reference request #497 --- project/access.py | 22 +++---- project/api/organization/resources.py | 15 ++++- project/services/admin_unit.py | 58 +++++++++++++++++++ .../templates/event/reference_request.html | 51 +++++++++++++++- project/views/event.py | 53 ++--------------- project/views/reference_request.py | 32 +++++++--- tests/api/test_organization.py | 12 ++++ 7 files changed, 172 insertions(+), 71 deletions(-) diff --git a/project/access.py b/project/access.py index 6e7fb67..62d5d13 100644 --- a/project/access.py +++ b/project/access.py @@ -4,9 +4,9 @@ from flask_login import login_user from flask_principal import Permission, RoleNeed from flask_security import current_user from flask_security.utils import FsPermNeed -from sqlalchemy import and_ +from sqlalchemy import and_, exists -from project import app +from project import app, db 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 @@ -145,16 +145,16 @@ def can_request_event_reference(event): if event.public_status != PublicStatus.published: return False - return len(get_admin_units_for_event_reference_request(event)) > 0 - - -def get_admin_units_for_event_reference_request(event): - return AdminUnit.query.filter( - and_( - AdminUnit.id != event.admin_unit_id, - AdminUnit.incoming_reference_requests_allowed, + return db.session.scalar( + exists() + .where( + and_( + AdminUnit.id != event.admin_unit_id, + AdminUnit.incoming_reference_requests_allowed, + ) ) - ).all() + .select() + ) def admin_units_the_current_user_is_member_of(): diff --git a/project/api/organization/resources.py b/project/api/organization/resources.py index ef94690..83ce142 100644 --- a/project/api/organization/resources.py +++ b/project/api/organization/resources.py @@ -93,7 +93,7 @@ from project.services.reference import ( get_reference_outgoing_query, get_relation_outgoing_query, ) -from project.views.utils import send_mail +from project.views.utils import get_current_admin_unit_for_api, send_mail class OrganizationResource(BaseResource): @@ -224,8 +224,19 @@ class OrganizationListResource(BaseResource): login_api_user() include_unverified = can_verify_admin_unit() + reference_request_for_admin_unit_id = None - pagination = get_admin_unit_query(keyword, include_unverified).paginate() + if "for_reference_request" in request.args: + admin_unit = get_current_admin_unit_for_api() + + if admin_unit: + reference_request_for_admin_unit_id = admin_unit.id + + pagination = get_admin_unit_query( + keyword, + include_unverified, + reference_request_for_admin_unit_id=reference_request_for_admin_unit_id, + ).paginate() return pagination diff --git a/project/services/admin_unit.py b/project/services/admin_unit.py index a506ea4..4079778 100644 --- a/project/services/admin_unit.py +++ b/project/services/admin_unit.py @@ -20,6 +20,10 @@ from project.models import ( ) from project.services.image import upsert_image_with_data from project.services.location import assign_location_values +from project.services.reference import ( + get_newest_reference_requests, + get_newest_references, +) def insert_admin_unit_for_user(admin_unit, user, invitation=None): @@ -175,6 +179,7 @@ def get_admin_unit_query( keyword=None, include_unverified=False, only_verifier=False, + reference_request_for_admin_unit_id=None, ): query = AdminUnit.query @@ -187,6 +192,13 @@ def get_admin_unit_query( ) query = query.filter(only_verifier_filter) + if reference_request_for_admin_unit_id: + request_filter = and_( + AdminUnit.id != reference_request_for_admin_unit_id, + AdminUnit.incoming_reference_requests_allowed, + ) + query = query.filter(request_filter) + if keyword: like_keyword = "%" + keyword + "%" order_keyword = keyword + "%" @@ -384,3 +396,49 @@ def get_admin_units_with_due_delete_request(): def delete_admin_unit(admin_unit: AdminUnit): db.session.delete(admin_unit) db.session.commit() + + +def get_admin_unit_suggestions_for_reference_requests(admin_unit, max_choices=5): + admin_unit_ids = [] + admin_unit_choices = [] + selected_ids = [] + + def add_admin_units(admin_units, selected=True): + for admin_unit in admin_units: + if admin_unit.id in admin_unit_ids: + continue + + admin_unit_ids.append(admin_unit.id) + admin_unit_choices.append(admin_unit) + + if selected: + selected_ids.append(admin_unit.id) + + # Neuste ausgehende Empfehlungsanfragen + limit = max_choices - len(admin_unit_ids) + reference_requests = get_newest_reference_requests(admin_unit.id, limit) + add_admin_units([r.admin_unit for r in reference_requests]) + + # Neuste ausgehende Empfehlungen + limit = max_choices - len(admin_unit_ids) + if limit > 0: + references = get_newest_references(admin_unit.id, limit) + add_admin_units([r.admin_unit for r in references]) + + # Eingehende Beziehungen, die Organisation oder Events automatisch verifizieren + limit = max_choices - len(admin_unit_ids) + if limit > 0: + relations = get_admin_unit_relations_for_reference_requests( + admin_unit.id, limit + ) + add_admin_units([r.source_admin_unit for r in relations]) + + # Organisationen, die eingehende Empfehlungsanfragen erlauben + limit = max_choices - len(admin_unit_ids) + if limit > 0: + admin_units_for_reference = get_admin_units_for_reference_requests( + admin_unit.id, limit + ) + add_admin_units(admin_units_for_reference, False) + + return (admin_unit_choices, selected_ids) diff --git a/project/templates/event/reference_request.html b/project/templates/event/reference_request.html index 75c000d..ce5bd0a 100644 --- a/project/templates/event/reference_request.html +++ b/project/templates/event/reference_request.html @@ -1,8 +1,57 @@ {% extends "layout.html" %} -{% from "_macros.html" import render_field_with_errors, render_field %} +{% from "_macros.html" import render_field_with_errors, render_field, render_form_styles, render_form_scripts %} + {%- block title -%} {{ event.name }} {%- endblock -%} + +{% block styles %} +{{ render_form_styles() }} +{% endblock %} + +{% block header_before_site_js %} +{{ render_form_scripts() }} +{%- endblock -%} + +{% block header %} + +{% endblock %} + {% block content %}

{{ _('Request reference for event "%(name)s"', name=event.name) }}

diff --git a/project/views/event.py b/project/views/event.py index 0a26143..7efecba 100644 --- a/project/views/event.py +++ b/project/views/event.py @@ -31,8 +31,7 @@ from project.models import ( ) from project.models.event_reference_request import EventReferenceRequest from project.services.admin_unit import ( - get_admin_unit_relations_for_reference_requests, - get_admin_units_for_reference_requests, + get_admin_unit_suggestions_for_reference_requests, ) from project.services.event import ( create_ical_events_for_event, @@ -44,10 +43,6 @@ from project.services.event import ( update_event, upsert_event_category, ) -from project.services.reference import ( - get_newest_reference_requests, - get_newest_references, -) from project.utils import get_event_category_name, get_place_str from project.views.event_suggestion import send_event_suggestion_review_status_mail from project.views.reference_request import handle_request_according_to_relation @@ -119,48 +114,10 @@ def prepare_form_reference_requests(form, admin_unit): form.reference_request_admin_unit_id.choices = [] return - max_choices = 5 - admin_unit_ids = [] - admin_unit_choices = [] - selected_ids = [] - - def add_admin_units(admin_units, selected=True): - for admin_unit in admin_units: - if admin_unit.id in admin_unit_ids: - continue - - admin_unit_ids.append(admin_unit.id) - admin_unit_choices.append(admin_unit) - - if selected: - selected_ids.append(admin_unit.id) - - # Neuste ausgehende Empfehlungsanfragen - limit = max_choices - len(admin_unit_ids) - reference_requests = get_newest_reference_requests(admin_unit.id, limit) - add_admin_units([r.admin_unit for r in reference_requests]) - - # Neuste ausgehende Empfehlungen - limit = max_choices - len(admin_unit_ids) - if limit > 0: - references = get_newest_references(admin_unit.id, limit) - add_admin_units([r.admin_unit for r in references]) - - # Eingehende Beziehungen, die Organisation oder Events automatisch verifizieren - limit = max_choices - len(admin_unit_ids) - if limit > 0: - relations = get_admin_unit_relations_for_reference_requests( - admin_unit.id, limit - ) - add_admin_units([r.source_admin_unit for r in relations]) - - # Organisationen, die eingehende Empfehlungsanfragen erlauben - limit = max_choices - len(admin_unit_ids) - if limit > 0: - admin_units_for_reference = get_admin_units_for_reference_requests( - admin_unit.id, limit - ) - add_admin_units(admin_units_for_reference, False) + ( + admin_unit_choices, + selected_ids, + ) = get_admin_unit_suggestions_for_reference_requests(admin_unit) form.reference_request_admin_unit_id.choices = sorted( [(a.id, a.name) for a in admin_unit_choices], diff --git a/project/views/reference_request.py b/project/views/reference_request.py index 0fd7c05..892c940 100644 --- a/project/views/reference_request.py +++ b/project/views/reference_request.py @@ -9,7 +9,6 @@ from project.access import ( can_request_event_reference, get_admin_unit_for_manage_or_404, get_admin_unit_members_with_permission, - get_admin_units_for_event_reference_request, ) from project.forms.reference_request import CreateEventReferenceRequestForm from project.models import ( @@ -17,7 +16,11 @@ from project.models import ( EventReferenceRequest, EventReferenceRequestReviewStatus, ) -from project.services.admin_unit import get_admin_unit_by_id, get_admin_unit_relation +from project.services.admin_unit import ( + get_admin_unit_by_id, + get_admin_unit_relation, + get_admin_unit_suggestions_for_reference_requests, +) from project.services.reference import ( create_event_reference_for_request, get_reference_requests_incoming_query, @@ -76,13 +79,24 @@ def event_reference_request_create(event_id): abort(401) form = CreateEventReferenceRequestForm() - form.admin_unit_id.choices = sorted( - [ - (admin_unit.id, admin_unit.name) - for admin_unit in get_admin_units_for_event_reference_request(event) - ], - key=lambda admin_unit: admin_unit[1], - ) + + if form.admin_unit_id.data and form.admin_unit_id.data > 0: + admin_unit = get_admin_unit_by_id(form.admin_unit_id.data) + + if admin_unit: + form.admin_unit_id.choices = [(admin_unit.id, admin_unit.name)] + + if not form.admin_unit_id.choices: + ( + admin_unit_choices, + selected_ids, + ) = get_admin_unit_suggestions_for_reference_requests( + event.admin_unit, max_choices=1 + ) + form.admin_unit_id.choices = [(a.id, a.name) for a in admin_unit_choices] + form.admin_unit_id.data = ( + admin_unit_choices[0].id if len(admin_unit_choices) > 0 else None + ) if form.validate_on_submit(): request = EventReferenceRequest() diff --git a/tests/api/test_organization.py b/tests/api/test_organization.py index 10aa1ee..f478655 100644 --- a/tests/api/test_organization.py +++ b/tests/api/test_organization.py @@ -23,6 +23,18 @@ def test_list(client, seeder: Seeder, utils: UtilActions): utils.get_json_ok(url) +def test_list_for_reference_request(client, seeder: Seeder, utils: UtilActions): + user_id, admin_unit_id = seeder.setup_api_access() + other_user_id = seeder.create_user("other@test.de") + other_admin_unit_id = seeder.create_admin_unit(other_user_id, "Other Crew") + + url = utils.get_url("api_v1_organization_list", for_reference_request="1") + response = utils.get_json_ok(url, headers={"X-OrganizationId": str(admin_unit_id)}) + + assert len(response.json["items"]) == 2 + assert response.json["items"][1]["id"] == other_admin_unit_id + + def test_list_unverified(client, app, seeder: Seeder, utils: UtilActions): user_id, verified_admin_unit_id = seeder.setup_base( email="verified@test.de",