Completed
Push — master ( fbed40...6fa740 )
by Jochen
05:48
created

blueprints/api/tourney/match/comments/views.py (1 issue)

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 match_comment_service, match_service
16
from ......services.user import service as user_service
17
from ......util.framework.blueprint import create_blueprint
18
from ......util.framework.templating import templated
19
from ......util.views import respond_created, respond_no_content
20
21
from ....decorators import api_token_required
22
23
from ... import signals
24
25
from .schemas import (
26
    CreateMatchCommentRequest,
27
    ModerateMatchCommentRequest,
28
    UpdateMatchCommentRequest,
29
)
30
31
32
blueprint = create_blueprint('api_tourney_match_comments', __name__)
33
34
35
@blueprint.route('/matches/<uuid:match_id>/comments')
36
@api_token_required
37
@templated
38
def view_for_match(match_id):
39
    """Render the comments on a match."""
40
    match = _get_match_or_404(match_id)
41
42
    party_id = request.args.get('party_id')
43
44
    comments = match_comment_service.get_comments(
45
        match.id, party_id=party_id, include_hidden=False
46
    )
47
48
    return {
49
        'comments': comments,
50
    }
51
52
53
@blueprint.route('/matches/<uuid:match_id>/comments.json')
54
@api_token_required
55
def view_for_match_as_json(match_id):
56
    """Render the comments on a match as JSON."""
57
    match = _get_match_or_404(match_id)
58
59
    party_id = request.args.get('party_id')
60
61
    comments = match_comment_service.get_comments(
62
        match.id, party_id=party_id, include_hidden=True
63
    )
64
65
    comment_dtos = list(map(_comment_to_json, comments))
66
67
    return jsonify({
68
        'comments': comment_dtos,
69
    })
70
71
72
def _comment_to_json(comment):
73
    creator = comment.creator
74
75
    return {
76
        'comment_id': str(comment.id),
77
        'match_id': str(comment.match_id),
78
        'created_at': comment.created_at.isoformat(),
79
        'creator': {
80
            'user_id': str(creator.id),
81
            'screen_name': creator.screen_name,
82
            'suspended': creator.suspended,
83
            'deleted': creator.deleted,
84
            'avatar_url': creator.avatar_url,
85
            'is_orga': creator.is_orga,
86
        },
87
        'body': comment.body_rendered,
88
        'hidden': comment.hidden,
89
        'hidden_at': comment.hidden_at.isoformat() \
90
                     if (comment.hidden_at is not None) else None,
91
        'hidden_by_id': comment.hidden_by_id,
92
    }
93
94
95
blueprint.add_url_rule(
96
    '/match_comments/<uuid:comment_id>',
97
    endpoint='view',
98
    build_only=True,
99
)
100
101
102
@blueprint.route('/match_comments', methods=['POST'])
103
@api_token_required
104
@respond_created
105
def create():
106
    """Create a comment on a match."""
107
    req = _parse_request(CreateMatchCommentRequest)
108
109
    match = match_service.find_match(req['match_id'])
110
    if not match:
111
        abort(400, 'Unknown match ID')
112
113
    creator = user_service.find_active_user(req['creator_id'])
114
    if not creator:
115
        abort(400, 'Creator ID does not reference an active user.')
116
117
    body = req['body'].strip()
118
119
    comment = match_comment_service.create_comment(match.id, creator.id, body)
120
121
    signals.match_comment_created.send(None, comment_id=comment.id)
122
123
    return url_for('.view', comment_id=comment.id)
124
125
126
@blueprint.route('/match_comments/<uuid:comment_id>', methods=['PATCH'])
127
@api_token_required
128
@respond_no_content
129
def update(comment_id):
130
    """Update a comment on a match."""
131
    comment = _get_comment_or_404(comment_id)
132
133
    req = _parse_request(UpdateMatchCommentRequest)
134
135
    editor = user_service.find_active_user(req['editor_id'])
136
    if not editor:
137
        abort(400, 'Editor ID does not reference an active user.')
138
139
    body = req['body'].strip()
140
141
    match_comment_service.update_comment(comment.id, editor.id, body)
142
143
144
@blueprint.route(
1 ignored issue
show
This code seems to be duplicated in your project.
Loading history...
145
    '/match_comments/<uuid:comment_id>/flags/hidden', methods=['POST']
146
)
147
@api_token_required
148
@respond_no_content
149
def hide(comment_id):
150
    """Hide the match comment."""
151
    comment = _get_comment_or_404(comment_id)
152
153
    req = _parse_request(ModerateMatchCommentRequest)
154
155
    initiator = user_service.find_active_user(req['initiator_id'])
156
    if not initiator:
157
        abort(400, 'Initiator ID does not reference an active user.')
158
159
    match_comment_service.hide_comment(comment.id, initiator.id)
160
161
162
@blueprint.route(
163
    '/match_comments/<uuid:comment_id>/flags/hidden',
164
    methods=['DELETE'],
165
)
166
@api_token_required
167
@respond_no_content
168
def unhide(comment_id):
169
    """Un-hide the match comment."""
170
    comment = _get_comment_or_404(comment_id)
171
172
    req = _parse_request(ModerateMatchCommentRequest)
173
174
    initiator = user_service.find_active_user(req['initiator_id'])
175
    if not initiator:
176
        abort(400, 'Initiator ID does not reference an active user.')
177
178
    match_comment_service.unhide_comment(comment.id, initiator.id)
179
180
181
def _get_match_or_404(match_id):
182
    match = match_service.find_match(match_id)
183
184
    if match is None:
185
        abort(404)
186
187
    return match
188
189
190
def _get_comment_or_404(comment_id):
191
    comment = match_comment_service.find_comment(comment_id)
192
193
    if comment is None:
194
        abort(404)
195
196
    return comment
197
198
199
def _parse_request(schema_class: SchemaMeta) -> Dict[str, Any]:
200
    schema = schema_class()
201
    request_data = request.get_json()
202
203
    try:
204
        req = schema.load(request_data)
205
    except ValidationError as e:
206
        abort(400, str(e.normalized_messages()))
207
208
    return req
209