Completed
Push — main ( 375f7e...98c31b )
by Jochen
03:34
created

byceps.announce.discord.board.send_message()   B

Complexity

Conditions 5

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.2742

Importance

Changes 0
Metric Value
cc 5
eloc 20
nop 2
dl 0
loc 32
ccs 14
cts 18
cp 0.7778
crap 5.2742
rs 8.9332
c 0
b 0
f 0
1
"""
2
byceps.announce.discord.board
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
Announce board events on Discord via its webhooks API.
6
7
:Copyright: 2006-2020 Jochen Kupperschmidt
8
:License: Modified BSD, see LICENSE for details.
9
"""
10
11 1
from typing import Optional
12
13 1
from flask import current_app
14 1
import requests
15
16 1
from ...events.board import BoardPostingCreated, BoardTopicCreated
17 1
from ...services.board import board_service
18 1
from ...services.board.transfer.models import BoardID
19 1
from ...services.brand import settings_service as brand_settings_service
20 1
from ...signals import board as board_signals
21 1
from ...typing import BrandID
22 1
from ...util.jobqueue import enqueue
23
24 1
from ..helpers import get_screen_name_or_fallback
25
26
27
# This is a pretty basic implementation that only supports a single
28
# webhook and that fetches its configuration from a brand's setting.
29
# For now, some customization is necessary to post announcements
30
# (especially for different brands, or even different parties) to
31
# different webhooks (i.e. effectively Discord channels).
32
33
34 1
def send_message(board_id: BoardID, text: str) -> None:
35
    """Send text to the webhook API.
36
37
    The endpoint URL already includes the target channel.
38
    """
39 1
    board = board_service.find_board(board_id)
40 1
    if not board:
41
        current_app.logger.warning(
42
            f'Unknown board ID "{board_id}". Not sending message to Discord.'
43
        )
44
        return
45
46 1
    brand_id = board.brand_id
47
48 1
    if not _is_enabled(brand_id):
49 1
        current_app.logger.warning('Announcements on Discord are disabled.')
50 1
        return
51
52 1
    url = _get_webhook_url(brand_id)
53 1
    if not url:
54
        current_app.logger.warning(
55
            'No webhook URL configured for announcements on Discord.'
56
        )
57
        return
58
59 1
    text_prefix = _get_text_prefix(brand_id)
60 1
    if text_prefix:
61 1
        text = text_prefix + text
62
63 1
    data = {'content': text}
64
65 1
    requests.post(url, json=data)  # Ignore response code for now.
66
67
68 1
def _is_enabled(brand_id: BrandID) -> bool:
69
    """Return `true' if announcements on Discord are enabled."""
70 1
    value = brand_settings_service.find_setting_value(
71
        brand_id, 'announce_discord_enabled'
72
    )
73 1
    return value == 'true'
74
75
76 1
def _get_webhook_url(brand_id: BrandID) -> str:
77
    """Return the configured webhook URL."""
78 1
    return brand_settings_service.find_setting_value(
79
        brand_id, 'announce_discord_webhook_url'
80
    )
81
82
83 1
def _get_text_prefix(brand_id: BrandID) -> Optional[str]:
84
    """Return the configured text prefix."""
85 1
    return brand_settings_service.find_setting_value(
86
        brand_id, 'announce_discord_text_prefix'
87
    )
88
89
90
# board events
91
92
93
# Note: URLs are wrapped in `<…>` because that prevents
94
#       preview embedding on Discord.
95
96
97 1
@board_signals.topic_created.connect
98 1
def _on_board_topic_created(sender, *, event: BoardTopicCreated = None) -> None:
99 1
    enqueue(announce_board_topic_created, event)
100
101
102 1
def announce_board_topic_created(event: BoardTopicCreated) -> None:
103
    """Announce that someone has created a board topic."""
104 1
    topic_creator_screen_name = get_screen_name_or_fallback(
105
        event.topic_creator_screen_name
106
    )
107
108 1
    text = (
109
        f'{topic_creator_screen_name} hat das Thema '
110
        f'"{event.topic_title}" erstellt: <{event.url}>'
111
    )
112
113 1
    send_message(event.board_id, text)
114
115
116 1
@board_signals.posting_created.connect
117 1
def _on_board_posting_created(
118
    sender, *, event: BoardPostingCreated = None
119
) -> None:
120 1
    enqueue(announce_board_posting_created, event)
121
122
123 1
def announce_board_posting_created(event: BoardPostingCreated) -> None:
124
    """Announce that someone has created a board posting."""
125 1
    if event.topic_muted:
126 1
        return
127
128 1
    posting_creator_screen_name = get_screen_name_or_fallback(
129
        event.posting_creator_screen_name
130
    )
131
132 1
    text = (
133
        f'{posting_creator_screen_name} hat auf das Thema '
134
        f'"{event.topic_title}" geantwortet: <{event.url}>'
135
    )
136
137
    send_message(event.board_id, text)
138