Passed
Push — master ( 307301...a898f8 )
by Jochen
02:51
created

_comment_to_json()   B

Complexity

Conditions 5

Size

Total Lines 25
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 24
nop 1
dl 0
loc 25
rs 8.8373
c 0
b 0
f 0
1
"""
2
byceps.blueprints.api.tourney.match.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2019 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9
from typing import Any, Dict
10
11
from flask import abort, jsonify, request, url_for
12
from marshmallow import ValidationError
13
from marshmallow.schema import SchemaMeta
14
15
from ......services.tourney import (
16
    match_comment_service as comment_service,
17
    match_service,
18
)
19
from ......services.tourney.transfer.models import (
20
    Match,
21
    MatchID,
22
    MatchComment,
23
    MatchCommentID,
24
)
25
from ......services.user import service as user_service
26
from ......services.user.transfer.models import User
27
from ......util.framework.blueprint import create_blueprint
28
from ......util.views import respond_created, respond_no_content
29
30
from ....decorators import api_token_required
31
32
from ... import signals
33
34
from .schemas import (
35
    CreateMatchCommentRequest,
36
    ModerateMatchCommentRequest,
37
    UpdateMatchCommentRequest,
38
)
39
40
41
blueprint = create_blueprint('api_tourney_match_comments', __name__)
42
43
44
@blueprint.route('/match_comments/<uuid:comment_id>')
45
@api_token_required
46
def get_comment(comment_id):
47
    """Return the comment."""
48
    comment = _get_comment_or_404(comment_id)
49
50
    comment_dto = _comment_to_json(comment)
51
52
    return jsonify(comment_dto)
53
54
55
@blueprint.route('/matches/<uuid:match_id>/comments')
56
@api_token_required
57
def get_comments_for_match(match_id):
58
    """Return the comments on the match."""
59
    match = _get_match_or_404(match_id)
60
61
    party_id = request.args.get('party_id')
62
63
    comments = comment_service.get_comments(
64
        match.id, party_id=party_id, include_hidden=True
65
    )
66
67
    comment_dtos = list(map(_comment_to_json, comments))
68
69
    return jsonify({
70
        'comments': comment_dtos,
71
    })
72
73
74
def _comment_to_json(comment: MatchComment) -> Dict[str, Any]:
75
    creator = comment.created_by
76
    last_editor = comment.last_edited_by
77
    moderator = comment.hidden_by
78
79
    return {
80
        'comment_id': str(comment.id),
81
        'match_id': str(comment.match_id),
82
        'created_at': comment.created_at.isoformat(),
83
        'creator': _user_to_json(creator),
84
        'body_text': comment.body_text,
85
        'body_html': comment.body_html,
86
        'last_edited_at': comment.last_edited_at.isoformat()
87
            if comment.last_edited_at is not None
88
            else None,
89
        'last_editor': _user_to_json(last_editor)
90
            if last_editor is not None
91
            else None,
92
        'hidden': comment.hidden,
93
        'hidden_at': comment.hidden_at.isoformat()
94
            if comment.hidden_at is not None
95
            else None,
96
        'hidden_by_id': _user_to_json(moderator)
97
            if moderator is not None
98
            else None,
99
    }
100
101
102
def _user_to_json(user: User) -> Dict[str, Any]:
103
    return {
104
        'user_id': str(user.id),
105
        'screen_name': user.screen_name,
106
        'suspended': user.suspended,
107
        'deleted': user.deleted,
108
        'avatar_url': user.avatar_url,
109
        'is_orga': user.is_orga,
110
    }
111
112
113
blueprint.add_url_rule(
114
    '/match_comments/<uuid:comment_id>',
115
    endpoint='view',
116
    build_only=True,
117
)
118
119
120
@blueprint.route('/match_comments', methods=['POST'])
121
@api_token_required
122
@respond_created
123
def create():
124
    """Create a comment on a match."""
125
    req = _parse_request(CreateMatchCommentRequest)
126
127
    match = match_service.find_match(req['match_id'])
128
    if not match:
129
        abort(400, 'Unknown match ID')
130
131
    creator = user_service.find_active_user(req['creator_id'])
132
    if not creator:
133
        abort(400, 'Creator ID does not reference an active user.')
134
135
    body = req['body'].strip()
136
137
    comment = comment_service.create_comment(match.id, creator.id, body)
138
139
    signals.match_comment_created.send(None, comment_id=comment.id)
140
141
    return url_for('.view', comment_id=comment.id)
142
143
144
@blueprint.route('/match_comments/<uuid:comment_id>', methods=['PATCH'])
145
@api_token_required
146
@respond_no_content
147
def update(comment_id):
148
    """Update a comment on a match."""
149
    comment = _get_comment_or_404(comment_id)
150
151
    req = _parse_request(UpdateMatchCommentRequest)
152
153
    editor = user_service.find_active_user(req['editor_id'])
154
    if not editor:
155
        abort(400, 'Editor ID does not reference an active user.')
156
157
    body = req['body'].strip()
158
159
    comment_service.update_comment(comment.id, editor.id, body)
160
161
162
@blueprint.route(
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
163
    '/match_comments/<uuid:comment_id>/flags/hidden', methods=['POST']
164
)
165
@api_token_required
166
@respond_no_content
167
def hide(comment_id):
168
    """Hide the match comment."""
169
    comment = _get_comment_or_404(comment_id)
170
171
    req = _parse_request(ModerateMatchCommentRequest)
172
173
    initiator = user_service.find_active_user(req['initiator_id'])
174
    if not initiator:
175
        abort(400, 'Initiator ID does not reference an active user.')
176
177
    comment_service.hide_comment(comment.id, initiator.id)
178
179
180
@blueprint.route(
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
181
    '/match_comments/<uuid:comment_id>/flags/hidden',
182
    methods=['DELETE'],
183
)
184
@api_token_required
185
@respond_no_content
186
def unhide(comment_id):
187
    """Un-hide the match comment."""
188
    comment = _get_comment_or_404(comment_id)
189
190
    req = _parse_request(ModerateMatchCommentRequest)
191
192
    initiator = user_service.find_active_user(req['initiator_id'])
193
    if not initiator:
194
        abort(400, 'Initiator ID does not reference an active user.')
195
196
    comment_service.unhide_comment(comment.id, initiator.id)
197
198
199
def _get_match_or_404(match_id: MatchID) -> Match:
200
    match = match_service.find_match(match_id)
201
202
    if match is None:
203
        abort(404)
204
205
    return match
206
207
208
def _get_comment_or_404(comment_id: MatchCommentID) -> MatchComment:
209
    comment = comment_service.find_comment(comment_id)
210
211
    if comment is None:
212
        abort(404)
213
214
    return comment
215
216
217
def _parse_request(schema_class: SchemaMeta) -> Dict[str, Any]:
218
    schema = schema_class()
219
    request_data = request.get_json()
220
221
    try:
222
        req = schema.load(request_data)
223
    except ValidationError as e:
224
        abort(400, str(e.normalized_messages()))
225
226
    return req
227