Passed
Push — main ( 8b4e52...828e64 )
by Jochen
04:53
created

byceps.blueprints.admin.webhook.views   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 206
Duplicated Lines 0 %

Test Coverage

Coverage 39.38%

Importance

Changes 0
Metric Value
eloc 130
dl 0
loc 206
ccs 39
cts 99
cp 0.3938
rs 10
c 0
b 0
f 0
wmc 20

7 Functions

Rating   Name   Duplication   Size   Complexity  
A update_form() 0 26 3
B update() 0 41 5
A _get_webhook_or_404() 0 7 2
A create_form() 0 13 2
A test() 0 19 2
A create() 0 29 4
A index() 0 11 2
1
"""
2
byceps.blueprints.admin.webhook.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2021 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
import json
10
11 1
from flask import abort, request
12 1
from flask_babel import gettext
13
14 1
from ....announce.events import EVENT_TYPES_TO_NAMES
15 1
from ....announce.helpers import call_webhook
16 1
from ....services.webhooks import service as webhook_service
17 1
from ....services.webhooks.transfer.models import OutgoingWebhook, WebhookID
18 1
from ....util.authorization import register_permission_enum
19 1
from ....util.framework.blueprint import create_blueprint
20 1
from ....util.framework.flash import flash_error, flash_success
21 1
from ....util.framework.templating import templated
22 1
from ....util.views import permission_required, redirect_to, respond_no_content
23
24 1
from .authorization import WebhookPermission
25 1
from .forms import (
26
    assemble_create_form,
27
    assemble_update_form,
28
    _create_event_field_name,
29
)
30
31
32 1
blueprint = create_blueprint('webhook_admin', __name__)
33
34
35 1
register_permission_enum(WebhookPermission)
36
37
38 1
WEBHOOK_EVENT_NAMES = frozenset(EVENT_TYPES_TO_NAMES.values())
39
40
41 1
@blueprint.get('/')
42 1
@permission_required(WebhookPermission.view)
43 1
@templated
44
def index():
45
    """Show webhooks."""
46 1
    webhooks = webhook_service.get_all_webhooks()
47
48 1
    webhooks.sort(key=lambda w: (w.description is None, w.description or ''))
49
50 1
    return {
51
        'webhooks': webhooks,
52
    }
53
54
55 1
@blueprint.get('/create')
56 1
@permission_required(WebhookPermission.administrate)
57 1
@templated
58 1
def create_form(erroneous_form=None):
59
    """Show form to create a webhook."""
60
    event_names = WEBHOOK_EVENT_NAMES
61
    CreateForm = assemble_create_form(event_names)
62
63
    form = erroneous_form if erroneous_form else CreateForm()
64
65
    return {
66
        'form': form,
67
        'event_names': event_names,
68
    }
69
70
71 1
@blueprint.post('/')
72 1
@permission_required(WebhookPermission.administrate)
73
def create():
74
    """Create a webhook."""
75
    event_names = WEBHOOK_EVENT_NAMES
76
    CreateForm = assemble_create_form(event_names)
77
78
    form = CreateForm(request.form)
79
80
    if not form.validate():
81
        return create_form(form)
82
83
    event_selectors = {}
84
    for event_name in event_names:
85
        if form.get_field_for_event_name(event_name).data:
86
            event_selectors[event_name] = None
87
88
    format = form.format.data.strip()
89
    url = form.url.data.strip()
90
    description = form.description.data.strip()
91
    enabled = False
92
93
    webhook = webhook_service.create_outgoing_webhook(
94
        event_selectors, format, url, enabled, description=description
95
    )
96
97
    flash_success(gettext('Webhook has been created.'))
98
99
    return redirect_to('.index')
100
101
102 1
@blueprint.get('/webhooks/<uuid:webhook_id>/update')
103 1
@permission_required(WebhookPermission.administrate)
104 1
@templated
105 1
def update_form(webhook_id, erroneous_form=None):
106
    """Show form to update a webhook."""
107
    webhook = _get_webhook_or_404(webhook_id)
108
109
    event_names = WEBHOOK_EVENT_NAMES
110
    UpdateForm = assemble_update_form(event_names)
111
112
    # Pre-fill event type checkboxes.
113
    event_type_fields = {}
114
    for event_type_name in webhook.event_selectors:
115
        field_name = _create_event_field_name(event_type_name)
116
        event_type_fields[field_name] = True
117
118
    form = (
119
        erroneous_form
120
        if erroneous_form
121
        else UpdateForm(obj=webhook, **event_type_fields)
122
    )
123
124
    return {
125
        'webhook': webhook,
126
        'form': form,
127
        'event_names': event_names,
128
    }
129
130
131 1
@blueprint.post('/webhooks/<uuid:webhook_id>')
132 1
@permission_required(WebhookPermission.administrate)
133
def update(webhook_id):
134
    """Update the webhook."""
135
    webhook = _get_webhook_or_404(webhook_id)
136
137
    event_names = WEBHOOK_EVENT_NAMES
138
    UpdateForm = assemble_update_form(event_names)
139
140
    form = UpdateForm(request.form)
141
142
    if not form.validate():
143
        return update_form(webhook.id, form)
144
145
    event_selectors = {}
146
    for event_name in event_names:
147
        if form.get_field_for_event_name(event_name).data:
148
            event_selectors[event_name] = None
149
150
    format = form.format.data.strip()
151
    url = form.url.data.strip()
152
    text_prefix = form.text_prefix.data.lstrip()  # Allow trailing whitespace.
153
    extra_fields_str = form.extra_fields.data.strip()
154
    extra_fields = json.loads(extra_fields_str) if extra_fields_str else None
155
    description = form.description.data.strip()
156
    enabled = form.enabled.data
157
158
    webhook = webhook_service.update_outgoing_webhook(
159
        webhook.id,
160
        event_selectors,
161
        format,
162
        text_prefix,
163
        extra_fields,
164
        url,
165
        description,
166
        enabled,
167
    )
168
169
    flash_success(gettext('Webhook has been updated.'))
170
171
    return redirect_to('.index')
172
173
174 1
@blueprint.post('/webhooks/<uuid:webhook_id>/test')
175 1
@permission_required(WebhookPermission.administrate)
176 1
@respond_no_content
177
def test(webhook_id):
178
    """Call the webhook (synchronously)."""
179
    webhook = _get_webhook_or_404(webhook_id)
180
181
    text = 'Test, test … is this thing on?!'
182
    try:
183
        call_webhook(webhook, text)
184
        flash_success(
185
            gettext('Webhook call has been successful.'), icon='success'
186
        )
187
    except Exception as e:
188
        flash_error(
189
            gettext('Webhook call failed:')
190
            + f'<br><pre style="white-space: pre-wrap;">{e}</pre>',
191
            icon='warning',
192
            text_is_safe=True,
193
        )
194
195
196
# helpers
197
198
199 1
def _get_webhook_or_404(webhook_id: WebhookID) -> OutgoingWebhook:
200
    webhook = webhook_service.find_webhook(webhook_id)
201
202
    if webhook is None:
203
        abort(404)
204
205
    return webhook
206