Integrated verification requests #484

This commit is contained in:
Daniel Grams 2023-06-02 12:32:08 +02:00
parent b57a286ef9
commit 26870f996e
45 changed files with 2618 additions and 578 deletions

View File

@ -0,0 +1,33 @@
describe("Verification request", () => {
it("lists", () => {
cy.login();
cy.createAdminUnit().then(function (adminUnitId) {
cy.createIncomingVerificationRequest(adminUnitId).then(function (
requestId
) {
cy.visit(
"/manage/admin_unit/" + adminUnitId + "/verification_requests/incoming"
);
cy.screenshot("incoming");
});
});
});
it("creates", () => {
cy.login();
cy.createAdminUnit().then(function (adminUnitId) {
cy.createAdminUnit("test@test.de", "Other Crew", false).then(function (otherAdminUnitId) {
cy.visit("/manage/admin_unit/" + otherAdminUnitId + "/verification_requests/outgoing/create/select");
cy.screenshot("create-select");
cy.get(".btn-primary:first").click();
cy.url().should("include", "/verification_requests/outgoing/create/target");
cy.screenshot("create");
cy.get("#submit").click();
cy.url().should("include", "/verification_requests/outgoing");
cy.screenshot("outgoing");
});
});
});
});

View File

@ -0,0 +1,42 @@
describe("Verification request review", () => {
it("reviews", () => {
cy.login();
cy.createAdminUnit().then(function (adminUnitId) {
cy.createIncomingVerificationRequest(adminUnitId).then(function (
requestId
) {
// Status
cy.visit("/verification_request/" + requestId + "/review_status");
cy.screenshot("status");
// Reject
cy.visit("/verification_request/" + requestId + "/review");
cy.screenshot("review");
cy.get(".decision-container .btn-danger").click();
cy.get("#rejectFormModal select[name=rejection_reason]")
.select("Nicht relevant")
.should("have.value", "6");
cy.get("#rejectFormModal").screenshot("reject");
cy.get("#rejectFormModal .btn-danger").click();
cy.url().should("include", "/verification_requests/incoming");
cy.get("div.alert").should(
"contain",
"Verifizierungsanfrage erfolgreich aktualisiert"
);
cy.get("main .badge-pill").should("contain", "Abgelehnt");
// Accept
cy.visit("/verification_request/" + requestId + "/review");
cy.get(".decision-container .btn-success").click();
cy.get("#auto_verify").parent().click();
cy.get("#acceptFormModal").screenshot("accept");
cy.get("#acceptFormModal .btn-success").click();
cy.url().should("include", "/verification_requests/incoming");
cy.get("div.alert").should(
"contain",
"Organisation erfolgreich verifiziert"
);
});
});
});
});

View File

@ -32,9 +32,11 @@ Cypress.Commands.add(
Cypress.Commands.add(
"createAdminUnit",
(userEmail = "test@test.de", name = "Meine Crew") => {
(userEmail = "test@test.de", name = "Meine Crew", verified = true) => {
let cmd = "flask test admin-unit-create " + userEmail + ' "' + name + '"';
cmd += (verified) ? " --verified" : " --no-verified";
return cy
.logexec("flask test admin-unit-create " + userEmail + ' "' + name + '"')
.logexec(cmd)
.then(function (result) {
let json = JSON.parse(result.stdout);
return json.admin_unit_id;
@ -114,6 +116,15 @@ Cypress.Commands.add("createOauth2Client", (userId) => {
});
});
Cypress.Commands.add("createIncomingVerificationRequest", (adminUnitId) => {
return cy
.logexec("flask test verification-request-create-incoming " + adminUnitId)
.then(function (result) {
let json = JSON.parse(result.stdout);
return json.verification_request_id;
});
});
Cypress.Commands.add("createIncomingReferenceRequest", (adminUnitId) => {
return cy
.logexec("flask test reference-request-create-incoming " + adminUnitId)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
"""empty message
Revision ID: 6634c8f0b7fc
Revises: becc71f97606
Create Date: 2023-05-31 22:37:22.719433
"""
import sqlalchemy as sa
import sqlalchemy_utils
from alembic import op
from project import dbtypes
from project.models import (
AdminUnitVerificationRequestRejectionReason,
AdminUnitVerificationRequestReviewStatus,
)
# revision identifiers, used by Alembic.
revision = "6634c8f0b7fc"
down_revision = "becc71f97606"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"adminunitverificationrequest",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("source_admin_unit_id", sa.Integer(), nullable=False),
sa.Column("target_admin_unit_id", sa.Integer(), nullable=False),
sa.Column(
"review_status",
dbtypes.IntegerEnum(AdminUnitVerificationRequestReviewStatus),
nullable=True,
),
sa.Column(
"rejection_reason",
dbtypes.IntegerEnum(AdminUnitVerificationRequestRejectionReason),
nullable=True,
),
sa.Column("created_at", sa.DateTime(), nullable=True),
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",
name=op.f("ck_adminunitverificationrequest_auvr_source_neq_target"),
),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
name=op.f("fk_adminunitverificationrequest_created_by_id_user"),
ondelete="SET NULL",
),
sa.ForeignKeyConstraint(
["source_admin_unit_id"],
["adminunit.id"],
name=op.f("fk_adminunitverificationrequest_source_admin_unit_id_adminunit"),
ondelete="CASCADE",
),
sa.ForeignKeyConstraint(
["target_admin_unit_id"],
["adminunit.id"],
name=op.f("fk_adminunitverificationrequest_target_admin_unit_id_adminunit"),
ondelete="CASCADE",
),
sa.ForeignKeyConstraint(
["updated_by_id"],
["user.id"],
name=op.f("fk_adminunitverificationrequest_updated_by_id_user"),
ondelete="SET NULL",
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_adminunitverificationrequest")),
sa.UniqueConstraint(
"source_admin_unit_id",
"target_admin_unit_id",
name=op.f("uq_adminunitverificationrequest_source_admin_unit_id"),
),
)
op.add_column(
"adminunit", sa.Column("description", sa.UnicodeText(), nullable=True)
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("adminunit", "description")
op.drop_table("adminunitverificationrequest")
# ### end Alembic commands ###

View File

@ -290,7 +290,7 @@ from project.views import (
root,
)
from project.views import user as user_view
from project.views import widget
from project.views import verification_request, verification_request_review, widget
if __name__ == "__main__": # pragma: no cover
app.run()

View File

@ -37,6 +37,7 @@ class OrganizationBaseSchema(OrganizationIdSchema):
email = marshmallow.auto_field()
phone = marshmallow.auto_field()
fax = marshmallow.auto_field()
description = marshmallow.auto_field()
is_verified = fields.Boolean()

View File

@ -12,6 +12,8 @@ from project.init_data import create_initial_data
from project.models import (
AdminUnit,
AdminUnitInvitation,
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
Event,
EventAttendanceMode,
EventDateDefinition,
@ -152,6 +154,7 @@ def _create_admin_unit(user_id, name, verified=False):
admin_unit.name = name
admin_unit.short_name = name.lower().replace(" ", "")
admin_unit.incoming_reference_requests_allowed = True
admin_unit.incoming_verification_requests_allowed = True
admin_unit.suggestions_enabled = True
admin_unit.can_create_other = True
admin_unit.can_verify_other = True
@ -171,9 +174,10 @@ def _create_admin_unit(user_id, name, verified=False):
@test_cli.command("admin-unit-create")
@click.argument("user_email")
@click.argument("name", default="Meine Crew")
def create_admin_unit(user_email, name):
@click.option("--verified/--no-verified", default=True)
def create_admin_unit(user_email, name, verified):
user = find_user_by_email(user_email)
admin_unit_id = _create_admin_unit(user.id, name, verified=True)
admin_unit_id = _create_admin_unit(user.id, name, verified=verified)
result = {"admin_unit_id": admin_unit_id}
click.echo(json.dumps(result))
@ -325,6 +329,48 @@ def create_incoming_reference_request(admin_unit_id):
click.echo(json.dumps(result))
def _create_admin_unit_verification_request(source_admin_unit_id, target_admin_unit_id):
target_admin_unit = get_admin_unit_by_id(target_admin_unit_id)
target_admin_unit.can_verify_other = True
target_admin_unit.incoming_verification_requests_allowed = True
request = AdminUnitVerificationRequest()
request.source_admin_unit_id = source_admin_unit_id
request.target_admin_unit_id = target_admin_unit_id
request.review_status = AdminUnitVerificationRequestReviewStatus.inbox
db.session.add(request)
db.session.commit()
request_id = request.id
return request_id
def _create_incoming_admin_unit_verification_request(admin_unit_id):
other_user_id = _create_user("other@test.de")
other_admin_unit_id = _create_admin_unit(
other_user_id, "Other Crew", verified=False
)
request_id = _create_admin_unit_verification_request(
other_admin_unit_id, admin_unit_id
)
return (other_user_id, other_admin_unit_id, request_id)
@test_cli.command("verification-request-create-incoming")
@click.argument("admin_unit_id")
def create_incoming_admin_unit_verification_request(admin_unit_id):
(
other_user_id,
other_admin_unit_id,
verification_request_id,
) = _create_incoming_admin_unit_verification_request(admin_unit_id)
result = {
"other_user_id": other_user_id,
"other_admin_unit_id": other_admin_unit_id,
"verification_request_id": verification_request_id,
}
click.echo(json.dumps(result))
def _create_reference(event_id, admin_unit_id):
reference = EventReference()
reference.event_id = event_id

View File

@ -31,10 +31,12 @@ class AdminUnitLocationForm(FlaskForm):
class BaseAdminUnitForm(FlaskForm):
name = HTML5StringField(
lazy_gettext("Name"), validators=[DataRequired(), Length(min=5, max=255)]
lazy_gettext("Name of organization"),
description=lazy_gettext("The full name of the organization"),
validators=[DataRequired(), Length(min=5, max=255)],
)
short_name = HTML5StringField(
lazy_gettext("Short name"),
lazy_gettext("Short name for organization"),
description=lazy_gettext(
"The short name is used to create a unique identifier for your events"
),
@ -49,6 +51,11 @@ class BaseAdminUnitForm(FlaskForm):
),
],
)
description = TextAreaField(
lazy_gettext("Description"),
description=lazy_gettext("Describe the organization in a few words"),
validators=[Optional()],
)
url = URLField(lazy_gettext("Link URL"), validators=[Optional(), Length(max=255)])
email = EmailField(lazy_gettext("Email"), validators=[Optional(), Length(max=255)])
phone = TelField(lazy_gettext("Phone"), validators=[Optional(), Length(max=255)])

View File

@ -0,0 +1,90 @@
from flask_babel import lazy_gettext
from flask_wtf import FlaskForm
from wtforms import SelectField, StringField, SubmitField
from wtforms.fields import BooleanField
from wtforms.validators import DataRequired, Optional
from project.models import (
AdminUnitVerificationRequestRejectionReason,
AdminUnitVerificationRequestReviewStatus,
)
class CreateAdminUnitVerificationRequestForm(FlaskForm):
submit = SubmitField(lazy_gettext("Request verification"))
class DeleteVerificationRequestForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete request"))
name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
class VerificationRequestReviewForm(FlaskForm):
review_status = SelectField(
lazy_gettext("Review status"),
coerce=int,
choices=[
(
int(AdminUnitVerificationRequestReviewStatus.inbox),
lazy_gettext("AdminUnitVerificationRequestReviewStatus.inbox"),
),
(
int(AdminUnitVerificationRequestReviewStatus.verified),
lazy_gettext("AdminUnitVerificationRequestReviewStatus.verified"),
),
(
int(AdminUnitVerificationRequestReviewStatus.rejected),
lazy_gettext("AdminUnitVerificationRequestReviewStatus.rejected"),
),
],
description=lazy_gettext("Choose the result of your review."),
)
rejection_reason = SelectField(
lazy_gettext("Rejection reason"),
coerce=int,
choices=[
(
0,
lazy_gettext("AdminUnitVerificationRequestRejectionReason.noreason"),
),
(
int(AdminUnitVerificationRequestRejectionReason.notresponsible),
lazy_gettext(
"AdminUnitVerificationRequestRejectionReason.notresponsible"
),
),
(
int(AdminUnitVerificationRequestRejectionReason.missinginformation),
lazy_gettext(
"AdminUnitVerificationRequestRejectionReason.missinginformation"
),
),
(
int(AdminUnitVerificationRequestRejectionReason.unknown),
lazy_gettext("AdminUnitVerificationRequestRejectionReason.unknown"),
),
(
int(AdminUnitVerificationRequestRejectionReason.untrustworthy),
lazy_gettext(
"AdminUnitVerificationRequestRejectionReason.untrustworthy"
),
),
(
int(AdminUnitVerificationRequestRejectionReason.illegal),
lazy_gettext("AdminUnitVerificationRequestRejectionReason.illegal"),
),
(
int(AdminUnitVerificationRequestRejectionReason.irrelevant),
lazy_gettext("AdminUnitVerificationRequestRejectionReason.irrelevant"),
),
],
description=lazy_gettext("Choose why you rejected the request."),
)
auto_verify = BooleanField(
lazy_gettext("Verify reference requests automatically"),
validators=[Optional()],
)
submit = SubmitField(lazy_gettext("Save review"))

View File

@ -23,6 +23,11 @@ def create_initial_data():
"admin_unit.members:read",
"admin_unit.members:update",
"admin_unit.members:delete",
"verification_request:create",
"verification_request:read",
"verification_request:update",
"verification_request:delete",
"verification_request:verify",
]
event_permissions = [
"event:verify",

View File

@ -83,11 +83,17 @@ def get_context_processors():
from project.services.reference import (
get_reference_requests_incoming_badge_query,
)
from project.services.verification import (
get_verification_requests_incoming_badge_query,
)
reviews_badge = 0
reference_requests_incoming_badge = get_reference_requests_incoming_badge_query(
admin_unit
).count()
verification_requests_incoming_badge = (
get_verification_requests_incoming_badge_query(admin_unit).count()
)
if has_access(admin_unit, "event:verify"):
reviews_badge = get_event_reviews_badge_query(admin_unit).count()
@ -95,6 +101,7 @@ def get_context_processors():
return {
"reviews_badge": reviews_badge,
"reference_requests_incoming_badge": reference_requests_incoming_badge,
"verification_requests_incoming_badge": verification_requests_incoming_badge,
}
def has_tos():

View File

@ -6,6 +6,11 @@ from project.models.admin_unit import (
AdminUnitMemberRole,
AdminUnitRelation,
)
from project.models.admin_unit_verification_request import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestRejectionReason,
AdminUnitVerificationRequestReviewStatus,
)
from project.models.custom_widget import CustomWidget
from project.models.event import Event, EventStatus, PublicStatus
from project.models.event_category import EventCategory

View File

@ -22,6 +22,7 @@ from sqlalchemy.schema import CheckConstraint
from sqlalchemy_utils import ColorType
from project import db
from project.models.admin_unit_verification_request import AdminUnitVerificationRequest
from project.models.trackable_mixin import TrackableMixin
from project.utils import make_check_violation
@ -239,6 +240,7 @@ class AdminUnit(db.Model, TrackableMixin):
email = deferred(Column(Unicode(255)), group="detail")
phone = deferred(Column(Unicode(255)), group="detail")
fax = deferred(Column(Unicode(255)), group="detail")
description = deferred(Column(UnicodeText(), nullable=True), group="detail")
widget_font = deferred(Column(Unicode(255)), group="widget")
widget_background_color = deferred(Column(ColorType), group="widget")
widget_primary_color = deferred(Column(ColorType), group="widget")
@ -306,6 +308,27 @@ class AdminUnit(db.Model, TrackableMixin):
lazy=True,
),
)
outgoing_verification_requests = relationship(
"AdminUnitVerificationRequest",
primaryjoin=remote(AdminUnitVerificationRequest.source_admin_unit_id) == id,
single_parent=True,
cascade="all, delete-orphan",
passive_deletes=True,
backref=backref(
"source_admin_unit",
lazy=True,
),
)
incoming_verification_requests = relationship(
"AdminUnitVerificationRequest",
primaryjoin=remote(AdminUnitVerificationRequest.target_admin_unit_id) == id,
cascade="all, delete-orphan",
passive_deletes=True,
backref=backref(
"target_admin_unit",
lazy=True,
),
)
@hybrid_property
def is_verified(self):

View File

@ -0,0 +1,69 @@
from enum import IntEnum
from sqlalchemy import CheckConstraint, Column, Integer, UniqueConstraint
from sqlalchemy.event import listens_for
from sqlalchemy.ext.hybrid import hybrid_property
from project import db
from project.dbtypes import IntegerEnum
from project.models.trackable_mixin import TrackableMixin
from project.utils import make_check_violation
class AdminUnitVerificationRequestReviewStatus(IntEnum):
inbox = 1
verified = 2
rejected = 3
class AdminUnitVerificationRequestRejectionReason(IntEnum):
notresponsible = 1
missinginformation = 2
unknown = 3
untrustworthy = 4
illegal = 5
irrelevant = 6
class AdminUnitVerificationRequest(db.Model, TrackableMixin):
__tablename__ = "adminunitverificationrequest"
__table_args__ = (
UniqueConstraint("source_admin_unit_id", "target_admin_unit_id"),
CheckConstraint(
"source_admin_unit_id != target_admin_unit_id",
name="auvr_source_neq_target",
),
)
id = Column(Integer(), primary_key=True)
source_admin_unit_id = db.Column(
db.Integer, db.ForeignKey("adminunit.id", ondelete="CASCADE"), nullable=False
)
target_admin_unit_id = db.Column(
db.Integer, db.ForeignKey("adminunit.id", ondelete="CASCADE"), nullable=False
)
review_status = Column(IntegerEnum(AdminUnitVerificationRequestReviewStatus))
rejection_reason = Column(IntegerEnum(AdminUnitVerificationRequestRejectionReason))
@hybrid_property
def verified(self):
return self.review_status == AdminUnitVerificationRequestReviewStatus.verified
def validate(self):
source_id = (
self.source_admin_unit.id
if self.source_admin_unit
else self.source_admin_unit_id
)
target_id = (
self.target_admin_unit.id
if self.target_admin_unit
else self.target_admin_unit_id
)
if source_id == target_id: # pragma: no cover
raise make_check_violation("There must be no self-reference.")
@listens_for(AdminUnitVerificationRequest, "before_insert")
@listens_for(AdminUnitVerificationRequest, "before_update")
def before_saving_admin_unit_verification_request(mapper, connect, self):
self.validate()

View File

@ -0,0 +1,29 @@
from sqlalchemy import and_
from sqlalchemy.orm import load_only
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
def get_verification_requests_incoming_query(admin_unit):
return AdminUnitVerificationRequest.query.filter(
and_(
AdminUnitVerificationRequest.review_status
!= AdminUnitVerificationRequestReviewStatus.verified,
AdminUnitVerificationRequest.target_admin_unit_id == admin_unit.id,
)
)
def get_verification_requests_incoming_badge_query(admin_unit):
return AdminUnitVerificationRequest.query.options(
load_only(AdminUnitVerificationRequest.id)
).filter(
and_(
AdminUnitVerificationRequest.review_status
== AdminUnitVerificationRequestReviewStatus.inbox,
AdminUnitVerificationRequest.target_admin_unit_id == admin_unit.id,
)
)

View File

@ -39,6 +39,10 @@ const OrganizationRead = {
{{ organization.location.postalCode }} {{ organization.location.city }}
</div>
<div v-if="organization.description" class="mt-3">
<span style="white-space: pre;">{{ organization.description }}</span>
</div>
<b-list-group class="mt-4">
<b-list-group-item :href="'/eventdates?admin_unit_id=' + organization.id">
<i class="fa fa-fw fa-list"></i>

View File

@ -177,6 +177,15 @@
{% endif %}
{% endmacro %}
{% macro render_text_prop(prop, icon = None, label_key = None) %}
{% if prop %}
<div>
{% if icon %}<i class="fa fa-fw {{ icon }}" data-toggle="tooltip" title="{{ _(label_key) }}"></i>{% endif %}
<span style="white-space:pre-wrap;">{{ prop }}</span>
</div>
{% endif %}
{% endmacro %}
{% macro render_int_prop(prop, icon = None, label_key = None) %}
{% if prop %}
<div>
@ -280,6 +289,12 @@
{% endif %}
{% endmacro %}
{% macro render_verification_request_review_status_pill(reference_request) %}
{% if reference_request.review_status %}
<span class="badge badge-pill {% if reference_request.review_status == 1 %}badge-info{% elif reference_request.review_status == 2 %}badge-success{% else %}badge-danger{% endif %}">{{ reference_request.review_status | loc_enum }}</span>
{% endif %}
{% endmacro %}
{% macro render_admin_unit_badges(admin_unit) %}
{% if admin_unit.is_verified %}<i class="fa fa-check-circle text-primary" data-toggle="tooltip" title="{{ _('Verified') }}"></i>{% endif %}
{% endmacro %}
@ -340,6 +355,11 @@
{{ render_enum_prop(reference_request.rejection_reason, 'fa-search-minus', 'Rejection reason') }}
{% endmacro %}
{% macro render_verification_request_review_status(verification_request) %}
{{ render_enum_prop(verification_request.review_status, 'fa-certificate', 'Review status') }}
{{ render_enum_prop(verification_request.rejection_reason, 'fa-search-minus', 'Rejection reason') }}
{% endmacro %}
{% macro render_audit(tracking_mixing, show_user=False) %}
{% set created_at = tracking_mixing.created_at | datetimeformat('short') %}
{% set updated_at = tracking_mixing.updated_at | datetimeformat('short') %}

View File

@ -30,6 +30,7 @@
<div class="card-body">
{{ render_field_with_errors(form.name) }}
{{ render_field_with_errors(form.short_name) }}
{{ render_field_with_errors(form.description) }}
</div>
</div>

View File

@ -38,6 +38,7 @@
<div class="card-body">
{{ render_field_with_errors(form.name) }}
{{ render_field_with_errors(form.short_name) }}
{{ render_field_with_errors(form.description) }}
</div>
</div>

View File

@ -0,0 +1,6 @@
{% extends "email/layout.html" %}
{% from "_macros.html" import render_email_button %}
{% block content %}
<p>{{ _('There is a new verification request that needs to be reviewed.') }}</p>
{{ render_email_button(url_for('admin_unit_verification_request_review', id=request.id, _external=True), _('Click here to review the request')) }}
{% endblock %}

View File

@ -0,0 +1,3 @@
{{ _('There is a new verification request that needs to be reviewed.') }}
{{ _('Click the link below to review the request') }}
{{ url_for('admin_unit_verification_request_review', id=request.id, _external=True) }}

View File

@ -0,0 +1,6 @@
{% extends "email/layout.html" %}
{% from "_macros.html" import render_email_button %}
{% block content %}
<p>{{ _('The review status of your verification request has been updated.') }}</p>
{{ render_email_button(url_for('admin_unit_verification_request_review_status', id=request.id, _external=True), _('Click here to view the status')) }}
{% endblock %}

View File

@ -0,0 +1,3 @@
{{ _('The review status of your verification request has been updated.') }}
{{ _('Click the link below to view the status') }}
{{ url_for('admin_unit_verification_request_review_status', id=request.id, _external=True) }}

View File

@ -1,5 +1,5 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_radio_buttons, render_phone_prop, render_email_prop, render_string_prop, render_field_with_errors, render_field, render_event_props, render_image_with_link, render_place, render_link_prop %}
{% from "_macros.html" import render_field_with_errors, render_field %}
{%- block title -%}
{{ event.name }}
{%- endblock -%}

View File

@ -255,16 +255,35 @@
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle text-truncate" href="#" id="navbarAdminUnitOrganizationDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ _('Organization') }}
{% if menu_options['verification_requests_incoming_badge'] > 0 %}
<span class="badge badge-secondary badge-pill">{{ menu_options['verification_requests_incoming_badge'] }}</span>
{% endif %}
</a>
<div class="dropdown-menu" aria-labelledby="navbarAdminUnitOrganizationDropdown">
{% if not current_admin_unit.is_verified %}
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_verification_requests_outgoing', id=current_admin_unit.id) }}">{{ _('Outgoing verification requests') }}</a>
<div class="dropdown-divider"></div>
{% endif %}
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_organizers', id=current_admin_unit.id) }}">{{ _('Organizers') }}</a>
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_event_places', id=current_admin_unit.id) }}">{{ _('Places') }}</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_members', id=current_admin_unit.id) }}">{{ _('Members') }}</a>
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_relations', id=current_admin_unit.id) }}">{{ _('Relations') }}</a>
{% if current_admin_unit.can_verify_other %}
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_verification_requests_incoming', id=current_admin_unit.id) }}">{{ _('Incoming verification requests') }}
{% if menu_options['verification_requests_incoming_badge'] > 0 %}
<span class="badge badge-secondary badge-pill">{{ menu_options['verification_requests_incoming_badge'] }}</span>
{% endif %}
</a>
{% endif %}
{% if current_admin_unit.can_invite_other %}
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_organization_invitations', id=current_admin_unit.id) }}">{{ _('Organization invitations') }}</a>
{% endif %}
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{{ url_for('admin_unit_update', id=current_admin_unit.id) }}">{{ _('Settings') }}</a>
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_export', id=current_admin_unit.id) }}">{{ _('Export') }}</a>

View File

@ -0,0 +1,28 @@
{% extends "layout.html" %}
{% set active_id = "verification_requests_incoming" %}
{% from "_macros.html" import render_verification_request_review_status_pill, render_pagination %}
{%- block title -%}
{{ _('Incoming verification requests') }}
{%- endblock -%}
{% block content %}
<h1 class="mb-1">{{ _('Incoming verification requests') }}</h1>
<ul class="list-group mt-4">
{% for request in requests %}
<li class="list-group-item">
<div class="dropdown d-inline-block">
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ request.source_admin_unit.name }}</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="{{ url_for('admin_unit_verification_request_review_status', id=request.id) }}">{{ _('Show review status') }}</a>
<a class="dropdown-item" href="{{ url_for('admin_unit_verification_request_review', id=request.id) }}">{{ _('Review request') }}&hellip;</a>
</div>
</div>
{{ render_verification_request_review_status_pill(request) }}
</li>
{% endfor %}
</ul>
<div class="my-4">{{ render_pagination(pagination) }}</div>
{% endblock %}

View File

@ -1,45 +1,33 @@
{% extends "layout.html" %}
{% set active_id = "verification_requests_outgoing" %}
{% from "_macros.html" import render_logo, render_location_prop, render_fax_prop, render_phone_prop, render_email_prop,
render_link_prop, render_admin_unit_badges, render_pagination %}
{% from "_macros.html" import render_verification_request_review_status_pill, render_pagination %}
{%- block title -%}
{{ _('Verification requests') }}
{{ _('Outgoing verification requests') }}
{%- endblock -%}
{% block content %}
<h1 class="mb-1">
{{ _('Verification requests') }}
{{ _('Outgoing verification requests') }}
<a class="btn btn-outline-secondary btn-sm m-1" href="{{ url_for('manage_admin_unit_verification_requests_outgoing_create_select', id=admin_unit.id) }}" role="button"><i class="fa fa-plus"></i> {{ _('Request verification') }}</a>
{% if config["DOCS_URL"] %}
<a class="btn btn-outline-info btn-sm m-1 my-auto float-right" href="{{ config["DOCS_URL"] }}/goto/organization-verify" target="_blank" rel="noopener noreferrer" role="button"><i class="fa fa-fw fa-info-circle"></i> {{ _('Docs') }}</a>
{% endif %}
</h1>
<p class="text-muted">{{ _('Here you can find organizations that can verify other organizations.') }}</p>
{% for other_admin_unit in admin_units %}
<div class="card mb-3">
<div class="card-body p-3">
<h2 class="mt-0">
<a href="{{ url_for('organizations', path=other_admin_unit.id) }}" class="text-body">{{
other_admin_unit.name }}</a>
{{ render_admin_unit_badges(other_admin_unit) }}
</h2>
<p>{{ other_admin_unit.incoming_verification_requests_text }}</p>
<div class="row">
{% if other_admin_unit.logo_id %}
<div class="col-12 col-sm-auto order-sm-last">{{ render_logo(other_admin_unit.logo) }}</div>
{% endif %}
<div class="col-12 col-sm">
{{ render_link_prop(other_admin_unit.url) }}
{{ render_email_prop(other_admin_unit.email) }}
{{ render_phone_prop(other_admin_unit.phone) }}
{{ render_fax_prop(other_admin_unit.fax) }}
{{ render_location_prop(other_admin_unit.location) }}
</div>
</div>
<ul class="list-group mt-4">
{% for request in requests %}
<li class="list-group-item">
<div class="dropdown d-inline-block">
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ request.target_admin_unit.name }}</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="{{ url_for('admin_unit_verification_request_review_status', id=request.id) }}">{{ _('Show review status') }}</a>
<a class="dropdown-item" href="{{ url_for('admin_unit_verification_request_delete', id=request.id) }}">{{ _('Delete request') }}&hellip;</a>
</div>
</div>
{{ render_verification_request_review_status_pill(request) }}
</li>
{% endfor %}
</ul>
<div class="my-4">{{ render_pagination(pagination) }}</div>

View File

@ -0,0 +1,42 @@
{% extends "layout.html" %}
{% set active_id = "verification_requests_outgoing" %}
{% from "_macros.html" import render_admin_unit_badges, render_logo, render_location_prop, render_text_prop, render_field_with_errors, render_field %}
{%- block title -%}
{{ _('Request verification for organization "%(name)s"', name=admin_unit.name) }}
{%- endblock -%}
{% block content %}
<h1>{{ _('Request verification for organization "%(name)s"', name=admin_unit.name) }}</h1>
<div class="w-normal">
<p>{{ _('Ask "%(name)s" to verify your organization.', name=target_admin_unit.name) }}</p>
<div class="card mb-3">
<div class="card-body p-3">
<h2 class="mt-0">
<a href="{{ url_for('organizations', path=target_admin_unit.id) }}" class="text-body">{{
target_admin_unit.name }}</a>
{{ render_admin_unit_badges(target_admin_unit) }}
</h2>
<div class="row">
{% if target_admin_unit.logo_id %}
<div class="col-12 col-sm-auto order-sm-last">{{ render_logo(target_admin_unit.logo) }}</div>
{% endif %}
<div class="col-12 col-sm">
{{ render_location_prop(target_admin_unit.location) }}
<p>{{ render_text_prop(target_admin_unit.description) }}</p>
<p>{{ render_text_prop(target_admin_unit.incoming_verification_requests_text) }}</p>
</div>
</div>
</div>
</div>
<form action="" method="POST">
{{ form.hidden_tag() }}
{{ render_field(form.submit) }}
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,47 @@
{% extends "layout.html" %}
{% set active_id = "verification_requests_outgoing" %}
{% from "_macros.html" import render_text_prop, render_logo, render_location_prop, render_fax_prop, render_phone_prop, render_email_prop,
render_link_prop, render_admin_unit_badges, render_pagination %}
{%- block title -%}
{{ _('Verification requests') }}
{%- endblock -%}
{% block content %}
<h1 class="mb-1">
{{ _('Verification requests') }}
{% if config["DOCS_URL"] %}
<a class="btn btn-outline-info btn-sm m-1 my-auto float-right" href="{{ config["DOCS_URL"] }}/goto/organization-verify" target="_blank" rel="noopener noreferrer" role="button"><i class="fa fa-fw fa-info-circle"></i> {{ _('Docs') }}</a>
{% endif %}
</h1>
<div class="w-normal">
<p class="text-muted">{{ _('Here you can find organizations that can verify other organizations.') }}</p>
{% for other_admin_unit in admin_units %}
<div class="card mb-3">
<div class="card-body p-3">
<h2 class="mt-0">
<a href="{{ url_for('organizations', path=other_admin_unit.id) }}" class="text-body">{{
other_admin_unit.name }}</a>
{{ render_admin_unit_badges(other_admin_unit) }}
</h2>
<div class="row">
{% if other_admin_unit.logo_id %}
<div class="col-12 col-sm-auto order-sm-last">{{ render_logo(other_admin_unit.logo) }}</div>
{% endif %}
<div class="col-12 col-sm">
{{ render_location_prop(other_admin_unit.location) }}
<p>{{ render_text_prop(other_admin_unit.description) }}</p>
<p>{{ render_text_prop(other_admin_unit.incoming_verification_requests_text) }}</p>
<a class="btn btn-primary btn-sm" href="{{ url_for('manage_admin_unit_verification_requests_outgoing_create', id=admin_unit.id, target_id=other_admin_unit.id) }}" role="button"><i class="fa fa-plus"></i> {{ _('Request verification') }}&hellip;</a>
</div>
</div>
</div>
</div>
{% endfor %}
<div class="my-4">{{ render_pagination(pagination) }}</div>
</div>
{% endblock %}

View File

@ -0,0 +1,24 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_field_with_errors, render_field %}
{% block content %}
<h1>{{ _('Delete verification request') }} &quot;{{ verification_request.target_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,124 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_roles, render_text_prop, render_location_prop, render_admin_unit_badges, render_fax_prop, render_logo, render_jquery_steps_header, render_phone_prop, render_email_prop, render_string_prop, render_field_with_errors, render_field, render_image_with_link, render_place, render_link_prop %}
{%- block title -%}
{{ request.source_admin_unit.name }}
{%- endblock -%}
{% block header_before_site_js %}
{{ render_jquery_steps_header() }}
<script>
$( function() {
$('#acceptFormModal .btn-success').click(function() {
$('#acceptFormModal form').submit();
});
$('#rejectFormModal .btn-danger').click(function() {
$('#rejectFormModal form').submit();
});
});
</script>
{% endblock %}
{% block content %}
<h1>{{ _('Review verification request') }}</h1>
<div class="mt-3 w-normal">
<div class="card mb-3">
<div class="card-header">
{{ _('Organization') }}
</div>
<div class="card-body">
<h5 class="card-title">{{ request.source_admin_unit.name }}{{ render_admin_unit_badges(request.source_admin_unit) }}</h5>
{% if request.source_admin_unit.logo_id %}
<div class="my-4">{{ render_logo(request.source_admin_unit.logo) }}</div>
{% endif %}
<div class="my-4">
{{ render_link_prop(request.source_admin_unit.url) }}
{{ render_email_prop(request.source_admin_unit.email) }}
{{ render_phone_prop(request.source_admin_unit.phone) }}
{{ render_fax_prop(request.source_admin_unit.fax) }}
{{ render_location_prop(request.source_admin_unit.location) }}
{% if request.source_admin_unit.description %}
<div class="my-2">
{{ render_text_prop(request.source_admin_unit.description) }}
</div>
{% endif %}
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
{{ _('Members') }}
</div>
<ul class="list-group list-group-flush">
{% for member in request.source_admin_unit.members %}
<li class="list-group-item">
<span>{{ member.user.email }}</span>
<small class="text-secondary">{{ render_roles(member.roles)}}</small>
</li>
{% endfor %}
</ul>
</div>
<div class="d-flex justify-content-between my-4 decision-container">
<button type="button" class="btn btn-success m-1" data-toggle="modal" data-target="#acceptFormModal"><i class="fa fa-check"></i> {{ _('Accept verification request') }}&hellip;</button>
<button type="button" class="btn btn-danger m-1" data-toggle="modal" data-target="#rejectFormModal"><i class="fa fa-ban"></i> {{ _('Reject verification request') }}&hellip;</button>
</div>
<div class="modal fade" id="acceptFormModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ _('Accept verification request') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="" method="POST">
{{ form.hidden_tag() }}
<input type="hidden" name="{{ form.review_status.name }}" value="2" />
<input type="hidden" name="{{ form.rejection_reason.name }}" value="0" />
{{ render_field_with_errors(form.auto_verify, ri="switch") }}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ _('Cancel') }}</button>
<button type="button" class="btn btn-success">{{ _('Accept verification request') }}</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="rejectFormModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ _('Reject verification request') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="" method="POST">
{{ form.hidden_tag() }}
<input type="hidden" name="{{ form.review_status.name }}" value="3" />
{{ render_field_with_errors(form.rejection_reason) }}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ _('Cancel') }}</button>
<button type="button" class="btn btn-danger">{{ _('Reject verification request') }}</button>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,19 @@
{% extends "layout.html" %}
{% from "_macros.html" import render_verification_request_review_status %}
{%- block title -%}
{{ _('Review status') }}
{%- endblock -%}
{% block content %}
<h1>{{ verification_request.source_admin_unit.name }} - {{ verification_request.target_admin_unit.name }}</h1>
<div class="card mb-3">
<div class="card-header">
{{ _('Review status') }}
</div>
<div class="card-body">
{{ render_verification_request_review_status(verification_request) }}
</div>
</div>
{% endblock %}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,6 @@ from project.models import (
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
@ -492,17 +491,3 @@ def manage_admin_unit_widgets(id):
flash_errors(form)
return render_template("manage/widgets.html", form=form, admin_unit=admin_unit)
@app.route("/manage/admin_unit/<int:id>/verification_requests/outgoing")
@auth_required()
def manage_admin_unit_verification_requests_outgoing(id):
admin_unit = get_admin_unit_for_manage_or_404(id)
admin_units = get_admin_unit_query(only_verifier=True).paginate()
return render_template(
"manage/verification_requests_outgoing.html",
admin_unit=admin_unit,
admin_units=admin_units.items,
pagination=get_pagination_urls(admin_units, id=id),
)

View File

@ -0,0 +1,204 @@
from flask import flash, g, redirect, render_template, url_for
from flask_babel import gettext
from flask_security import auth_required
from sqlalchemy.exc import SQLAlchemyError
from project import app, db
from project.access import access_or_401, get_admin_unit_members_with_permission
from project.forms.verification_request import (
CreateAdminUnitVerificationRequestForm,
DeleteVerificationRequestForm,
)
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
from project.models.admin_unit import AdminUnit
from project.services.admin_unit import get_admin_unit_query
from project.services.verification import get_verification_requests_incoming_query
from project.views.utils import (
flash_errors,
get_pagination_urls,
handleSqlError,
manage_required,
non_match_for_deletion,
send_mails,
)
@app.route("/manage/admin_unit/<int:id>/verification_requests/incoming")
@auth_required()
@manage_required("verification_request:read")
def manage_admin_unit_verification_requests_incoming(id):
admin_unit = g.manage_admin_unit
requests = (
get_verification_requests_incoming_query(admin_unit)
.order_by(AdminUnitVerificationRequest.created_at.desc())
.paginate()
)
return render_template(
"manage/verification_requests_incoming.html",
admin_unit=admin_unit,
requests=requests.items,
pagination=get_pagination_urls(requests, id=id),
)
@app.route("/manage/admin_unit/<int:id>/verification_requests/outgoing")
@auth_required()
@manage_required("verification_request:read")
def manage_admin_unit_verification_requests_outgoing(id):
admin_unit = g.manage_admin_unit
requests = (
AdminUnitVerificationRequest.query.filter(
AdminUnitVerificationRequest.source_admin_unit_id == admin_unit.id
)
.order_by(AdminUnitVerificationRequest.created_at.desc())
.paginate()
)
if not admin_unit.is_verified and requests.total == 0:
return redirect(
url_for(
"manage_admin_unit_verification_requests_outgoing_create_select",
id=admin_unit.id,
)
)
return render_template(
"manage/verification_requests_outgoing.html",
admin_unit=admin_unit,
requests=requests.items,
pagination=get_pagination_urls(requests, id=id),
)
@app.route("/manage/admin_unit/<int:id>/verification_requests/outgoing/create/select")
@auth_required()
@manage_required("verification_request:create")
def manage_admin_unit_verification_requests_outgoing_create_select(id):
admin_unit = g.manage_admin_unit
admin_units = get_admin_unit_query(only_verifier=True).paginate()
return render_template(
"manage/verification_requests_outgoing_create_select.html",
admin_unit=admin_unit,
admin_units=admin_units.items,
pagination=get_pagination_urls(admin_units, id=id),
)
@app.route(
"/manage/admin_unit/<int:id>/verification_requests/outgoing/create/target/<int:target_id>",
methods=("GET", "POST"),
)
@auth_required()
@manage_required("verification_request:create")
def manage_admin_unit_verification_requests_outgoing_create(id, target_id):
admin_unit = g.manage_admin_unit
target_admin_unit = AdminUnit.query.get_or_404(target_id)
if (
target_admin_unit.id == admin_unit.id
or not target_admin_unit.can_verify_other
or not target_admin_unit.incoming_verification_requests_allowed
): # pragma: no cover
return redirect(
url_for(
"manage_admin_unit_verification_requests_outgoing_create_select",
id=admin_unit.id,
)
)
form = CreateAdminUnitVerificationRequestForm()
if form.validate_on_submit():
request = AdminUnitVerificationRequest()
form.populate_obj(request)
request.source_admin_unit = admin_unit
request.target_admin_unit = target_admin_unit
try:
db.session.add(request)
request.review_status = AdminUnitVerificationRequestReviewStatus.inbox
send_verification_request_inbox_mails(request)
msg = gettext(
"Request successfully created. You will be notified after the other organization reviewed the request."
)
db.session.commit()
flash(msg, "success")
return redirect(
url_for(
"manage_admin_unit_verification_requests_outgoing",
id=admin_unit.id,
)
)
except SQLAlchemyError as e:
db.session.rollback()
flash(handleSqlError(e), "danger")
else:
flash_errors(form)
return render_template(
"manage/verification_requests_outgoing_create.html",
form=form,
admin_unit=admin_unit,
target_admin_unit=target_admin_unit,
)
@app.route("/verification_request/<int:id>/delete", methods=("GET", "POST"))
@auth_required()
def admin_unit_verification_request_delete(id):
request = AdminUnitVerificationRequest.query.get_or_404(id)
access_or_401(request.source_admin_unit, "verification_request:delete")
form = DeleteVerificationRequestForm()
if form.validate_on_submit():
if non_match_for_deletion(form.name.data, request.target_admin_unit.name):
flash(gettext("Entered name does not match organization name"), "danger")
else:
try:
db.session.delete(request)
db.session.commit()
flash(gettext("Verification request successfully deleted"), "success")
return redirect(
url_for(
"manage_admin_unit_verification_requests_outgoing",
id=request.source_admin_unit.id,
)
)
except SQLAlchemyError as e:
db.session.rollback()
flash(handleSqlError(e), "danger")
else:
flash_errors(form)
return render_template(
"verification_request/delete.html", form=form, verification_request=request
)
def send_member_verification_request_verify_mails(
admin_unit_id, subject, template, **context
):
# Benachrichtige alle Mitglieder der AdminUnit, die Requests verifizieren können
members = get_admin_unit_members_with_permission(
admin_unit_id, "verification_request:verify"
)
emails = list(map(lambda member: member.user.email, members))
send_mails(emails, subject, template, **context)
def send_verification_request_inbox_mails(request):
send_member_verification_request_verify_mails(
request.target_admin_unit_id or request.target_admin_unit.id,
gettext("New verification request"),
"verification_request_notice",
request=request,
)

View File

@ -0,0 +1,118 @@
from flask import abort, flash, redirect, render_template, url_for
from flask_babel import gettext
from flask_security import auth_required
from sqlalchemy.exc import SQLAlchemyError
from project import app, db
from project.access import (
access_or_401,
get_admin_unit_members_with_permission,
has_access,
)
from project.forms.verification_request import VerificationRequestReviewForm
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
from project.services.admin_unit import upsert_admin_unit_relation
from project.views.utils import flash_errors, handleSqlError, send_mails
@app.route("/verification_request/<int:id>/review", methods=("GET", "POST"))
@auth_required()
def admin_unit_verification_request_review(id):
request = AdminUnitVerificationRequest.query.get_or_404(id)
access_or_401(request.target_admin_unit, "verification_request:verify")
if request.review_status == AdminUnitVerificationRequestReviewStatus.verified:
flash(gettext("Request already verified"), "danger")
return redirect(
url_for(
"manage_admin_unit_verification_requests_incoming",
id=request.target_admin_unit_id,
)
)
form = VerificationRequestReviewForm(obj=request)
if form.validate_on_submit():
form.populate_obj(request)
if request.review_status != AdminUnitVerificationRequestReviewStatus.rejected:
request.rejection_reason = None
if request.rejection_reason == 0:
request.rejection_reason = None
try:
if (
request.review_status
== AdminUnitVerificationRequestReviewStatus.verified
):
relation = upsert_admin_unit_relation(
request.target_admin_unit_id, request.source_admin_unit_id
)
relation.verify = True
if form.auto_verify.data:
relation.auto_verify_event_reference_requests = True
msg = gettext("Organization successfully verified")
else:
msg = gettext("Verification request successfully updated")
db.session.commit()
send_verification_request_review_status_mails(request)
flash(msg, "success")
return redirect(
url_for(
"manage_admin_unit_verification_requests_incoming",
id=request.target_admin_unit_id,
)
)
except SQLAlchemyError as e:
db.session.rollback()
flash(handleSqlError(e), "danger")
else:
flash_errors(form)
form.auto_verify.description = gettext(
"If all upcoming reference requests of %(admin_unit_name)s should be verified automatically.",
admin_unit_name=request.source_admin_unit.name,
)
return render_template(
"verification_request/review.html",
form=form,
request=request,
)
@app.route("/verification_request/<int:id>/review_status")
def admin_unit_verification_request_review_status(id):
request = AdminUnitVerificationRequest.query.get_or_404(id)
if not has_access(
request.target_admin_unit, "verification_request:verify"
) and not has_access(request.source_admin_unit, "verification_request:create"):
abort(401)
return render_template(
"verification_request/review_status.html",
verification_request=request,
)
def send_verification_request_review_status_mails(request):
# Benachrichtige alle Mitglieder der AdminUnit, die diesen Request erstellt hatte
members = get_admin_unit_members_with_permission(
request.source_admin_unit_id, "verification_request:create"
)
emails = list(map(lambda member: member.user.email, members))
send_mails(
emails,
gettext("Verification request review status updated"),
"verification_request_review_status_notice",
request=request,
)

View File

@ -677,6 +677,68 @@ class Seeder(object):
)
return (other_user_id, other_admin_unit_id, relation_id)
def setup_admin_unit_missing_verification_scenario(self, log_in_verifier=False):
verifier_user_id = self.create_user()
verifier_admin_unit_id = self.create_admin_unit(
verifier_user_id,
"Stadtmarketing",
verified=True,
can_verify_other=True,
incoming_verification_requests_allowed=True,
incoming_verification_requests_text="Please give us a call",
)
unverified_user_id, unverified_admin_unit_id = self.setup_base(
log_in=not log_in_verifier,
admin_unit_verified=False,
email="mitglied@verein.de",
name="Verein",
)
if log_in_verifier:
self._utils.login()
return (
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
)
def create_admin_unit_verification_request(
self, source_admin_unit_id, target_admin_unit_id
):
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
with self._app.app_context():
from project.services.admin_unit import get_admin_unit_by_id
target_admin_unit = get_admin_unit_by_id(target_admin_unit_id)
target_admin_unit.can_verify_other = True
target_admin_unit.incoming_verification_requests_allowed = True
request = AdminUnitVerificationRequest()
request.source_admin_unit_id = source_admin_unit_id
request.target_admin_unit_id = target_admin_unit_id
request.review_status = AdminUnitVerificationRequestReviewStatus.inbox
self._db.session.add(request)
self._db.session.commit()
request_id = request.id
return request_id
def create_incoming_admin_unit_verification_request(self, admin_unit_id):
other_user_id = self.create_user("other@test.de")
other_admin_unit_id = self.create_admin_unit(
other_user_id, "Other Crew", verified=False
)
request_id = self.create_admin_unit_verification_request(
other_admin_unit_id, admin_unit_id
)
return (other_user_id, other_admin_unit_id, request_id)
def create_reference_request(self, event_id, admin_unit_id):
from project.models import (
EventReferenceRequest,

View File

@ -14,7 +14,7 @@ def test_location_update_coordinate(client, app, db):
assert location.coordinate is not None
def test_event_category(client, app, db, seeder):
def test_event_category(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base()
event_id = seeder.create_event(admin_unit_id)
@ -28,7 +28,7 @@ def test_event_category(client, app, db, seeder):
assert event.category is None
def test_event_properties(client, app, db, seeder):
def test_event_properties(client, app, db, seeder: Seeder):
with app.app_context():
from sqlalchemy.exc import IntegrityError
@ -51,7 +51,7 @@ def test_event_properties(client, app, db, seeder):
assert event.min_start == start
def test_event_allday(client, app, db, seeder):
def test_event_allday(client, app, db, seeder: Seeder):
from project.dateutils import create_berlin_date
user_id, admin_unit_id = seeder.setup_base()
@ -93,7 +93,7 @@ def test_event_allday(client, app, db, seeder):
assert event_date.end == create_berlin_date(2031, 1, 1, 23, 59, 59)
def test_event_has_multiple_dates(client, app, db, seeder):
def test_event_has_multiple_dates(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base()
event_with_recc_id = seeder.create_event(
admin_unit_id, recurrence_rule="RRULE:FREQ=DAILY;COUNT=7"
@ -110,7 +110,7 @@ def test_event_has_multiple_dates(client, app, db, seeder):
assert event_without_recc.has_multiple_dates() is False
def test_oauth2_token(client, app, seeder):
def test_oauth2_token(client, app, seeder: Seeder):
import time
from project.models import OAuth2Token
@ -124,7 +124,7 @@ def test_oauth2_token(client, app, seeder):
assert not token.is_refresh_token_active()
def test_admin_unit_relations(client, app, db, seeder):
def test_admin_unit_relations(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base(log_in=False)
(
other_user_id,
@ -145,7 +145,34 @@ def test_admin_unit_relations(client, app, db, seeder):
assert len(admin_unit.outgoing_relations) == 0
def test_event_date_defintion_deletion(client, app, db, seeder):
def test_admin_unit_verification_requests(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base(log_in=False)
(
other_user_id,
other_admin_unit_id,
request_id,
) = seeder.create_incoming_admin_unit_verification_request(admin_unit_id)
with app.app_context():
from project.services.admin_unit import get_admin_unit_by_id
admin_unit = get_admin_unit_by_id(admin_unit_id)
assert len(admin_unit.incoming_verification_requests) == 1
request = admin_unit.incoming_verification_requests[0]
assert request.id == request_id
other_admin_unit = get_admin_unit_by_id(other_admin_unit_id)
assert len(other_admin_unit.outgoing_verification_requests) == 1
request = other_admin_unit.outgoing_verification_requests[0]
assert request.id == request_id
db.session.delete(request)
db.session.commit()
assert len(admin_unit.incoming_verification_requests) == 0
assert len(other_admin_unit.outgoing_verification_requests) == 0
def test_event_date_defintion_deletion(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
event_id = seeder.create_event(admin_unit_id)
@ -180,7 +207,7 @@ def test_event_date_defintion_deletion(client, app, db, seeder):
assert event.date_definitions[0].id == date_definition2_id
def test_admin_unit_deletion(client, app, db, seeder):
def test_admin_unit_deletion(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base(log_in=False)
my_event_id = seeder.create_event(admin_unit_id)
suggestion_id = seeder.create_event_suggestion(admin_unit_id)
@ -206,12 +233,19 @@ def test_admin_unit_deletion(client, app, db, seeder):
)
incoming_reference_id = seeder.create_reference(other_event_id, admin_unit_id)
outgoing_reference_id = seeder.create_reference(my_event_id, other_admin_unit_id)
incoming_verification_request_id = seeder.create_admin_unit_verification_request(
other_admin_unit_id, admin_unit_id
)
outgoing_verification_request_id = seeder.create_admin_unit_verification_request(
admin_unit_id, other_admin_unit_id
)
with app.app_context():
from project.models import (
AdminUnit,
AdminUnitMemberInvitation,
AdminUnitRelation,
AdminUnitVerificationRequest,
Event,
EventDate,
EventDateDefinition,
@ -247,6 +281,18 @@ def test_admin_unit_deletion(client, app, db, seeder):
assert (
db.session.get(EventReferenceRequest, outgoing_reference_request_id) is None
)
assert (
db.session.get(
AdminUnitVerificationRequest, incoming_verification_request_id
)
is None
)
assert (
db.session.get(
AdminUnitVerificationRequest, outgoing_verification_request_id
)
is None
)
assert db.session.get(EventSuggestion, suggestion_id) is None
assert db.session.get(EventPlace, event_place_id) is None
assert db.session.get(EventOrganizer, organizer_id) is None
@ -257,7 +303,7 @@ def test_admin_unit_deletion(client, app, db, seeder):
assert db.session.get(Event, other_event_id) is not None
def test_event_co_organizers_deletion(client, app, db, seeder):
def test_event_co_organizers_deletion(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base(log_in=False)
event_id, organizer_a_id, organizer_b_id = seeder.create_event_with_co_organizers(
admin_unit_id
@ -282,7 +328,7 @@ def test_event_co_organizers_deletion(client, app, db, seeder):
assert db.session.get(EventOrganizer, organizer_b_id).id is not None
def test_admin_unit_verification(client, app, db, seeder):
def test_admin_unit_verification(client, app, db, seeder: Seeder):
user_id, admin_unit_id = seeder.setup_base(log_in=False, admin_unit_verified=False)
other_user_id = seeder.create_user("other@test.de")
other_admin_unit_id = seeder.create_admin_unit(other_user_id, "Other Crew")
@ -323,7 +369,7 @@ def test_admin_unit_verification(client, app, db, seeder):
assert len(all_verified) == 0
def test_admin_unit_invitations(client, app, db, seeder):
def test_admin_unit_invitations(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
invitation_id = seeder.create_admin_unit_invitation(admin_unit_id)
@ -342,7 +388,7 @@ def test_admin_unit_invitations(client, app, db, seeder):
assert invitation is None
def test_event_list_deletion(client, app, db, seeder):
def test_event_list_deletion(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
event_id = seeder.create_event(admin_unit_id)
event_list_a_id = seeder.create_event_list(admin_unit_id, event_id, "List A")
@ -381,7 +427,7 @@ def test_event_list_deletion(client, app, db, seeder):
assert len(event_list_b.events) == 0
def test_event_is_favored_by_current_user(client, app, db, seeder):
def test_event_is_favored_by_current_user(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
event_id = seeder.create_event(admin_unit_id)
@ -392,7 +438,7 @@ def test_event_is_favored_by_current_user(client, app, db, seeder):
assert event.is_favored_by_current_user() is False
def test_purge_event_photo(client, app, db, seeder):
def test_purge_event_photo(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
event_id = seeder.create_event(admin_unit_id)
first_image_id = seeder.upsert_default_image()
@ -414,7 +460,7 @@ def test_purge_event_photo(client, app, db, seeder):
assert image is None
def test_purge_event_place_photo(client, app, db, seeder):
def test_purge_event_place_photo(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
place_id = seeder.upsert_default_event_place(admin_unit_id)
first_image_id = seeder.upsert_default_image()
@ -451,7 +497,7 @@ def test_purge_event_place_photo(client, app, db, seeder):
assert image is None
def test_purge_eventsuggestion_photo(client, app, db, seeder):
def test_purge_eventsuggestion_photo(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
suggestion_id = seeder.create_event_suggestion(admin_unit_id)
image_id = seeder.upsert_default_image()
@ -475,7 +521,7 @@ def test_purge_eventsuggestion_photo(client, app, db, seeder):
assert image is None
def test_purge_adminunit(client, app, db, seeder):
def test_purge_adminunit(client, app, db, seeder: Seeder):
_, admin_unit_id = seeder.setup_base(log_in=False)
instance_id = admin_unit_id
image_id = seeder.upsert_default_image()
@ -507,7 +553,7 @@ def test_purge_adminunit(client, app, db, seeder):
assert location is None
def test_purge_eventorganizer(client, app, db, seeder):
def test_purge_eventorganizer(client, app, db, seeder: 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()
@ -539,7 +585,7 @@ def test_purge_eventorganizer(client, app, db, seeder):
assert location is None
def test_delete_admin_unit(client, app, db, seeder):
def test_delete_admin_unit(client, app, db, seeder: 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()

View File

@ -24,7 +24,7 @@ def test_index_withValidCookie(client, seeder, app, utils):
utils.assert_response_redirect(response, "manage_admin_unit", id=admin_unit_id)
def test_index_withInvalidCookie(client, seeder, utils):
def test_index_withInvalidCookie(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
client.set_cookie("localhost", "manage_admin_unit_id", "invalid")
@ -70,7 +70,7 @@ def test_index_after_login_organization_invitation(client, app, db, utils, seede
)
def test_admin_unit(client, seeder, utils):
def test_admin_unit(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
response = utils.get_endpoint("manage_admin_unit", id=admin_unit_id)
@ -79,7 +79,7 @@ def test_admin_unit(client, seeder, utils):
)
def test_admin_unit_404(client, seeder, utils):
def test_admin_unit_404(client, seeder: Seeder, utils: UtilActions):
owner_id = seeder.create_user("owner@owner")
admin_unit_id = seeder.create_admin_unit(owner_id, "Other crew")
seeder.create_user()
@ -89,13 +89,13 @@ def test_admin_unit_404(client, seeder, utils):
utils.assert_response_notFound(response)
def test_admin_unit_event_reviews(client, seeder, utils):
def test_admin_unit_event_reviews(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
utils.get_endpoint_ok("manage_admin_unit_event_reviews", id=admin_unit_id)
def test_admin_unit_events(client, seeder, utils):
def test_admin_unit_events(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base(admin_unit_verified=False)
utils.get_endpoint_ok(
@ -112,7 +112,9 @@ def test_admin_unit_events(client, seeder, utils):
utils.assert_response_contains(response, event_url)
def test_admin_unit_events_invalidDateFormat(client, seeder, utils):
def test_admin_unit_events_invalidDateFormat(
client, seeder: Seeder, utils: UtilActions
):
user_id, admin_unit_id = seeder.setup_base()
utils.get_endpoint_ok(
@ -126,7 +128,7 @@ def test_admin_unit_events_invalidDateFormat(client, seeder, utils):
)
def test_admin_unit_events_place(client, seeder, utils):
def test_admin_unit_events_place(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base(admin_unit_verified=False)
seeder.create_event(admin_unit_id, draft=True)
event_place_id = seeder.upsert_default_event_place(admin_unit_id)
@ -136,25 +138,27 @@ def test_admin_unit_events_place(client, seeder, utils):
)
def test_admin_unit_organizers(client, seeder, utils):
def test_admin_unit_organizers(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
utils.get_endpoint_ok("manage_admin_unit_organizers", id=admin_unit_id)
def test_admin_unit_event_places(client, seeder, utils):
def test_admin_unit_event_places(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
utils.get_endpoint_ok("manage_admin_unit_event_places", id=admin_unit_id)
def test_admin_unit_members(client, seeder, utils):
def test_admin_unit_members(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
utils.get_endpoint_ok("manage_admin_unit_members", id=admin_unit_id)
def test_admin_unit_members_permission_missing(client, seeder, utils):
def test_admin_unit_members_permission_missing(
client, seeder: Seeder, utils: UtilActions
):
owner_id, admin_unit_id, member_id = seeder.setup_base_event_verifier()
response = utils.get_endpoint("manage_admin_unit_members", id=admin_unit_id)
@ -164,7 +168,9 @@ def test_admin_unit_members_permission_missing(client, seeder, utils):
@pytest.mark.parametrize("db_error", [True, False])
def test_admin_unit_widgets(client, seeder, utils, mocker, db_error):
def test_admin_unit_widgets(
client, seeder: Seeder, utils: UtilActions, mocker, db_error
):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_widgets", id=admin_unit_id)
@ -184,7 +190,9 @@ def test_admin_unit_widgets(client, seeder, utils, mocker, db_error):
)
def test_admin_unit_widgets_permission_missing(client, seeder, utils, mocker):
def test_admin_unit_widgets_permission_missing(
client, seeder: Seeder, utils: UtilActions, mocker
):
owner_id, admin_unit_id, member_id = seeder.setup_base_event_verifier()
url = utils.get_url("manage_admin_unit_widgets", id=admin_unit_id)
@ -196,63 +204,43 @@ def test_admin_unit_widgets_permission_missing(client, seeder, utils, mocker):
)
def test_admin_unit_relations(client, seeder, utils):
def test_admin_unit_relations(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_relations", id=admin_unit_id)
utils.get_ok(url)
def test_admin_unit_organization_invitations(client, seeder, utils):
def test_admin_unit_organization_invitations(
client, seeder: Seeder, utils: UtilActions
):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_organization_invitations", id=admin_unit_id)
utils.get_ok(url)
def test_admin_unit_event_lists(client, seeder, utils):
def test_admin_unit_event_lists(client, seeder: Seeder, utils: UtilActions):
user_id, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_event_lists", id=admin_unit_id)
utils.get_ok(url)
def test_admin_unit_custom_widgets(client, seeder, utils):
def test_admin_unit_custom_widgets(client, seeder: Seeder, utils: UtilActions):
_, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_custom_widgets", id=admin_unit_id)
utils.get_ok(url)
def test_admin_unit_events_import(client, seeder, utils):
def test_admin_unit_events_import(client, seeder: Seeder, utils: UtilActions):
_, admin_unit_id = seeder.setup_base()
url = utils.get_url("manage_admin_unit_events_import", id=admin_unit_id)
utils.get_ok(url)
def test_verification_requests_outgoing(client, seeder, utils):
user_id = seeder.create_user()
seeder.create_admin_unit(
user_id,
"Stadtmarketing",
verified=True,
can_verify_other=True,
incoming_verification_requests_allowed=True,
incoming_verification_requests_text="Please give us a call",
)
_, other_admin_unit_id = seeder.setup_base(
admin_unit_verified=False, email="mitglied@verein.de", name="Verein"
)
response = utils.get_endpoint_ok(
"manage_admin_unit_verification_requests_outgoing", id=other_admin_unit_id
)
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

View File

@ -0,0 +1,166 @@
import pytest
from tests.seeder import Seeder
from tests.utils import UtilActions
@pytest.mark.parametrize("db_error", [True, False])
def test_create(client, app, utils: UtilActions, seeder: Seeder, mocker, db_error):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario()
url = utils.get_url(
"manage_admin_unit_verification_requests_outgoing_create",
id=unverified_admin_unit_id,
target_id=verifier_admin_unit_id,
)
response = utils.get_ok(url)
if db_error:
utils.mock_db_commit(mocker)
mail_mock = utils.mock_send_mails(mocker)
response = utils.post_form(
url,
response,
{},
)
if db_error:
utils.assert_response_db_error(response)
return
utils.assert_response_redirect(
response,
"manage_admin_unit_verification_requests_outgoing",
id=unverified_admin_unit_id,
)
utils.assert_send_mail_called(mail_mock, "test@test.de")
with app.app_context():
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
verification_request = (
AdminUnitVerificationRequest.query.filter(
AdminUnitVerificationRequest.source_admin_unit_id
== unverified_admin_unit_id
)
.filter(
AdminUnitVerificationRequest.target_admin_unit_id
== verifier_admin_unit_id
)
.first()
)
assert verification_request is not None
assert (
verification_request.review_status
== AdminUnitVerificationRequestReviewStatus.inbox
)
def test_admin_unit_verification_requests_incoming(
client, utils: UtilActions, seeder: Seeder
):
user_id, admin_unit_id = seeder.setup_base()
seeder.create_incoming_admin_unit_verification_request(admin_unit_id)
utils.get_endpoint_ok(
"manage_admin_unit_verification_requests_incoming", id=admin_unit_id
)
def test_verification_requests_outgoing(client, seeder: Seeder, utils: UtilActions):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario()
response = utils.get_endpoint(
"manage_admin_unit_verification_requests_outgoing", id=unverified_admin_unit_id
)
utils.assert_response_redirect(
response,
"manage_admin_unit_verification_requests_outgoing_create_select",
id=unverified_admin_unit_id,
)
response = utils.get_endpoint_ok(
"manage_admin_unit_verification_requests_outgoing_create_select",
id=unverified_admin_unit_id,
)
utils.assert_response_contains(response, "Stadtmarketing")
utils.assert_response_contains(response, "Please give us a call")
seeder.create_admin_unit_verification_request(
unverified_admin_unit_id, verifier_admin_unit_id
)
response = utils.get_endpoint_ok(
"manage_admin_unit_verification_requests_outgoing",
id=unverified_admin_unit_id,
)
@pytest.mark.parametrize("db_error", [True, False])
@pytest.mark.parametrize("non_match", [True, False])
def test_delete(
client, seeder: Seeder, utils: UtilActions, app, db, mocker, db_error, non_match
):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario()
request_id = seeder.create_admin_unit_verification_request(
unverified_admin_unit_id, verifier_admin_unit_id
)
url = utils.get_url("admin_unit_verification_request_delete", id=request_id)
response = utils.get_ok(url)
if db_error:
utils.mock_db_commit(mocker)
form_name = "Stadtmarketing"
if non_match:
form_name = "Falscher Name"
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_verification_requests_outgoing",
id=unverified_admin_unit_id,
)
with app.app_context():
from project.models import AdminUnitVerificationRequest
request = db.session.get(AdminUnitVerificationRequest, request_id)
assert request is None

View File

@ -0,0 +1,174 @@
import pytest
from tests.seeder import Seeder
from tests.utils import UtilActions
@pytest.mark.parametrize("db_error", [True, False])
@pytest.mark.parametrize("is_verified", [True, False])
def test_review_verify(
client, seeder: Seeder, utils: UtilActions, app, mocker, db, db_error, is_verified
):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario(log_in_verifier=True)
verification_request_id = seeder.create_admin_unit_verification_request(
unverified_admin_unit_id, verifier_admin_unit_id
)
url = utils.get_url(
"admin_unit_verification_request_review", id=verification_request_id
)
if is_verified:
with app.app_context():
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
verification_request = db.session.get(
AdminUnitVerificationRequest, verification_request_id
)
verification_request.review_status = (
AdminUnitVerificationRequestReviewStatus.verified
)
db.session.commit()
response = client.get(url)
utils.assert_response_redirect(
response,
"manage_admin_unit_verification_requests_incoming",
id=verifier_admin_unit_id,
)
return
response = utils.get_ok(url)
if db_error:
utils.mock_db_commit(mocker)
mail_mock = utils.mock_send_mails(mocker)
response = utils.post_form(
url,
response,
{
"review_status": 2,
"auto_verify": 1,
},
)
if db_error:
utils.assert_response_db_error(response)
return
utils.assert_response_redirect(
response,
"manage_admin_unit_verification_requests_incoming",
id=verifier_admin_unit_id,
)
utils.assert_send_mail_called(mail_mock, "mitglied@verein.de")
with app.app_context():
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
from project.services.admin_unit import get_admin_unit_relation
verification_request = db.session.get(
AdminUnitVerificationRequest, verification_request_id
)
assert verification_request.verified
relation = get_admin_unit_relation(
verifier_admin_unit_id, unverified_admin_unit_id
)
assert relation is not None
assert relation.verify
assert relation.auto_verify_event_reference_requests
def test_review_reject(client, seeder: Seeder, utils: UtilActions, app, db, mocker):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario(log_in_verifier=True)
verification_request_id = seeder.create_admin_unit_verification_request(
unverified_admin_unit_id, verifier_admin_unit_id
)
url = utils.get_url(
"admin_unit_verification_request_review", id=verification_request_id
)
response = utils.get_ok(url)
response = utils.post_form(
url,
response,
{
"review_status": 3,
"rejection_reason": 0,
},
)
utils.assert_response_redirect(
response,
"manage_admin_unit_verification_requests_incoming",
id=verifier_admin_unit_id,
)
with app.app_context():
from project.models import (
AdminUnitVerificationRequest,
AdminUnitVerificationRequestReviewStatus,
)
verification_request = db.session.get(
AdminUnitVerificationRequest, verification_request_id
)
assert (
verification_request.review_status
== AdminUnitVerificationRequestReviewStatus.rejected
)
assert verification_request.rejection_reason is None
def test_review_status(client, seeder: Seeder, utils: UtilActions):
(
verifier_user_id,
verifier_admin_unit_id,
unverified_user_id,
unverified_admin_unit_id,
) = seeder.setup_admin_unit_missing_verification_scenario(log_in_verifier=True)
verification_request_id = seeder.create_admin_unit_verification_request(
unverified_admin_unit_id, verifier_admin_unit_id
)
url = utils.get_url(
"admin_unit_verification_request_review_status", id=verification_request_id
)
utils.get_ok(url)
def test_review_status_401_unauthorized(client, seeder: Seeder, utils: UtilActions):
seeder.create_user()
third_user_id = seeder.create_user("third@third.de")
third_admin_unit_id = seeder.create_admin_unit(third_user_id, "Third Crew")
(
other_user_id,
other_admin_unit_id,
verification_request_id,
) = seeder.create_incoming_admin_unit_verification_request(third_admin_unit_id)
url = utils.get_url(
"admin_unit_verification_request_review_status", id=verification_request_id
)
response = client.get(url)
assert response.status_code == 401