Passed
Push — master ( a65c88...e2c8b9 )
by Jochen
02:49
created

byceps.blueprints.board.views_topic.topic_view()   C

Complexity

Conditions 8

Size

Total Lines 72
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 45
nop 2
dl 0
loc 72
rs 6.9333
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""
2
byceps.blueprints.board.views_topic
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2019 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9
from flask import abort, g, redirect, request
10
11
from ...services.board import \
12
    category_query_service as board_category_query_service, \
13
    last_view_service as board_last_view_service, \
14
    posting_query_service as board_posting_query_service, \
15
    topic_command_service as board_topic_command_service, \
16
    topic_query_service as board_topic_query_service
17
from ...services.party import service as party_service
18
from ...services.text_markup.service import get_smileys
19
from ...services.user import service as user_service
20
from ...util.framework.flash import flash_error, flash_success
21
from ...util.framework.templating import templated
22
from ...util.views import respond_no_content_with_location
23
24
from ..authorization.decorators import permission_required
25
26
from .authorization import BoardPermission, BoardTopicPermission
27
from .blueprint import blueprint
28
from .forms import PostingCreateForm, TopicCreateForm, TopicUpdateForm
29
from . import _helpers as h, service, signals
30
31
32
@blueprint.route('/topics', defaults={'page': 1})
33
@blueprint.route('/topics/pages/<int:page>')
34
@templated
35
def topic_index(page):
36
    """List latest topics in all categories."""
37
    board_id = h.get_board_id()
38
    user = g.current_user
39
40
    h.require_board_access(board_id, user.id)
41
42
    topics_per_page = service.get_topics_per_page_value()
43
44
    topics = board_topic_query_service \
45
        .paginate_topics(board_id, user, page, topics_per_page)
46
47
    service.add_topic_creators(topics.items)
48
    service.add_topic_unseen_flag(topics.items, user)
49
50
    return {
51
        'topics': topics,
52
    }
53
54
55
@blueprint.route('/topics/<uuid:topic_id>', defaults={'page': 0})
56
@blueprint.route('/topics/<uuid:topic_id>/pages/<int:page>')
57
@templated
58
def topic_view(topic_id, page):
59
    """List postings for the topic."""
60
    user = g.current_user
61
62
    topic = board_topic_query_service \
63
        .find_topic_visible_for_user(topic_id, user)
64
65
    if topic is None:
66
        abort(404)
67
68
    board_id = h.get_board_id()
69
70
    if topic.category.hidden:
71
        abort(404)
72
73
    if topic.category.board_id != board_id:
74
        abort(404)
75
76
    h.require_board_access(board_id, user.id)
77
78
    # Copy last view timestamp for later use to compare postings
79
    # against it.
80
    last_viewed_at = board_last_view_service.find_topic_last_viewed_at(
81
        topic.id, user.id)
82
83
    postings_per_page = service.get_postings_per_page_value()
84
    if page == 0:
85
        posting = board_topic_query_service \
86
            .find_default_posting_to_jump_to(topic.id, user, last_viewed_at)
87
88
        if posting is None:
89
            page = 1
90
        else:
91
            page = service.calculate_posting_page_number(posting,
92
                                                         g.current_user)
93
            # Jump to a specific posting. This requires a redirect.
94
            url = h.build_url_for_posting_in_topic_view(posting, page)
95
            return redirect(url, code=307)
96
97
    if not user.is_anonymous:
98
        # Mark as viewed before aborting so a user can itself remove the
99
        # 'new' tag from a locked topic.
100
        board_last_view_service.mark_topic_as_just_viewed(topic.id, user.id)
101
102
    postings = board_posting_query_service \
103
        .paginate_postings(topic.id, user, g.party_id, page, postings_per_page)
104
105
    service.add_unseen_flag_to_postings(postings.items, user, last_viewed_at)
106
107
    is_last_page = not postings.has_next
108
109
    service.enrich_creators(postings.items, g.brand_id, g.party_id)
110
111
    party = party_service.find_party(g.party_id)
112
113
    context = {
114
        'topic': topic,
115
        'postings': postings,
116
        'is_last_page': is_last_page,
117
        'party_title': party.title,
118
    }
119
120
    if is_last_page:
121
        context.update({
122
            'form': PostingCreateForm(),
123
            'smileys': get_smileys(),
124
        })
125
126
    return context
127
128
129
@blueprint.route('/categories/<category_id>/create')
130
@permission_required(BoardTopicPermission.create)
131
@templated
132
def topic_create_form(category_id, erroneous_form=None):
133
    """Show a form to create a topic in the category."""
134
    category = h.get_category_or_404(category_id)
135
136
    form = erroneous_form if erroneous_form else TopicCreateForm()
137
138
    return {
139
        'category': category,
140
        'form': form,
141
        'smileys': get_smileys(),
142
    }
143
144
145
@blueprint.route('/categories/<category_id>/create', methods=['POST'])
146
@permission_required(BoardTopicPermission.create)
147
def topic_create(category_id):
148
    """Create a topic in the category."""
149
    category = h.get_category_or_404(category_id)
150
151
    form = TopicCreateForm(request.form)
152
    if not form.validate():
153
        return topic_create_form(category.id, form)
154
155
    creator = g.current_user
156
    title = form.title.data.strip()
157
    body = form.body.data.strip()
158
159
    topic = board_topic_command_service \
160
        .create_topic(category.id, creator.id, title, body)
161
    topic_url = h.build_external_url_for_topic(topic.id)
162
163
    flash_success('Das Thema "{}" wurde hinzugefügt.', topic.title)
164
    signals.topic_created.send(None, topic_id=topic.id, url=topic_url)
165
166
    return redirect(topic_url)
167
168
169
@blueprint.route('/topics/<uuid:topic_id>/update')
170
@permission_required(BoardTopicPermission.update)
171
@templated
172
def topic_update_form(topic_id, erroneous_form=None):
173
    """Show form to update a topic."""
174
    topic = h.get_topic_or_404(topic_id)
175
    url = h.build_url_for_topic(topic.id)
176
177
    user_may_update = topic.may_be_updated_by_user(g.current_user)
178
179
    if topic.locked and not user_may_update:
180
        flash_error(
181
            'Das Thema darf nicht bearbeitet werden weil es gesperrt ist.')
182
        return redirect(url)
183
184
    if topic.hidden:
185
        flash_error('Das Thema darf nicht bearbeitet werden.')
186
        return redirect(url)
187
188
    if not user_may_update:
189
        flash_error('Du darfst dieses Thema nicht bearbeiten.')
190
        return redirect(url)
191
192
    form = erroneous_form if erroneous_form \
193
            else TopicUpdateForm(obj=topic, body=topic.initial_posting.body)
194
195
    return {
196
        'form': form,
197
        'topic': topic,
198
        'smileys': get_smileys(),
199
    }
200
201
202
@blueprint.route('/topics/<uuid:topic_id>', methods=['POST'])
203
@permission_required(BoardTopicPermission.update)
204
def topic_update(topic_id):
205
    """Update a topic."""
206
    topic = h.get_topic_or_404(topic_id)
207
    url = h.build_url_for_topic(topic.id)
208
209
    user_may_update = topic.may_be_updated_by_user(g.current_user)
210
211
    if topic.locked and not user_may_update:
212
        flash_error(
213
            'Das Thema darf nicht bearbeitet werden weil es gesperrt ist.')
214
        return redirect(url)
215
216
    if topic.hidden:
217
        flash_error('Das Thema darf nicht bearbeitet werden.')
218
        return redirect(url)
219
220
    if not user_may_update:
221
        flash_error('Du darfst dieses Thema nicht bearbeiten.')
222
        return redirect(url)
223
224
    form = TopicUpdateForm(request.form)
225
    if not form.validate():
226
        return topic_update_form(topic_id, form)
227
228
    board_topic_command_service \
229
        .update_topic(topic, g.current_user.id, form.title.data, form.body.data)
230
231
    flash_success('Das Thema "{}" wurde aktualisiert.', topic.title)
232
    return redirect(url)
233
234
235
@blueprint.route('/topics/<uuid:topic_id>/moderate')
236
@permission_required(BoardPermission.hide)
237
@templated
238
def topic_moderate_form(topic_id):
239
    """Show a form to moderate the topic."""
240
    board_id = h.get_board_id()
241
    topic = h.get_topic_or_404(topic_id)
242
243
    topic.creator = user_service.find_user(topic.creator_id)
244
245
    categories = board_category_query_service \
246
        .get_categories_excluding(board_id, topic.category_id)
247
248
    return {
249
        'topic': topic,
250
        'categories': categories,
251
    }
252
253
254
@blueprint.route('/topics/<uuid:topic_id>/flags/hidden', methods=['POST'])
255
@permission_required(BoardPermission.hide)
256
@respond_no_content_with_location
257
def topic_hide(topic_id):
258
    """Hide a topic."""
259
    topic = h.get_topic_or_404(topic_id)
260
    moderator_id = g.current_user.id
261
262
    board_topic_command_service.hide_topic(topic, moderator_id)
263
264
    flash_success('Das Thema "{}" wurde versteckt.', topic.title, icon='hidden')
265
266
    signals.topic_hidden.send(None, topic_id=topic.id,
267
                              moderator_id=moderator_id,
268
                              url=h.build_external_url_for_topic(topic.id))
269
270
    return h.build_url_for_topic_in_category_view(topic)
271
272
273
@blueprint.route('/topics/<uuid:topic_id>/flags/hidden', methods=['DELETE'])
274
@permission_required(BoardPermission.hide)
275
@respond_no_content_with_location
276
def topic_unhide(topic_id):
277
    """Un-hide a topic."""
278
    topic = h.get_topic_or_404(topic_id)
279
    moderator_id = g.current_user.id
280
281
    board_topic_command_service.unhide_topic(topic, moderator_id)
282
283
    flash_success(
284
        'Das Thema "{}" wurde wieder sichtbar gemacht.', topic.title, icon='view')
285
286
    signals.topic_unhidden.send(None, topic_id=topic.id,
287
                                moderator_id=moderator_id,
288
                                url=h.build_external_url_for_topic(topic.id))
289
290
    return h.build_url_for_topic_in_category_view(topic)
291
292
293
@blueprint.route('/topics/<uuid:topic_id>/flags/locked', methods=['POST'])
294
@permission_required(BoardTopicPermission.lock)
295
@respond_no_content_with_location
296
def topic_lock(topic_id):
297
    """Lock a topic."""
298
    topic = h.get_topic_or_404(topic_id)
299
    moderator_id = g.current_user.id
300
301
    board_topic_command_service.lock_topic(topic, moderator_id)
302
303
    flash_success('Das Thema "{}" wurde geschlossen.', topic.title, icon='lock')
304
305
    signals.topic_locked.send(None, topic_id=topic.id,
306
                              moderator_id=moderator_id,
307
                              url=h.build_external_url_for_topic(topic.id))
308
309
    return h.build_url_for_topic_in_category_view(topic)
310
311
312
@blueprint.route('/topics/<uuid:topic_id>/flags/locked', methods=['DELETE'])
313
@permission_required(BoardTopicPermission.lock)
314
@respond_no_content_with_location
315
def topic_unlock(topic_id):
316
    """Unlock a topic."""
317
    topic = h.get_topic_or_404(topic_id)
318
    moderator_id = g.current_user.id
319
320
    board_topic_command_service.unlock_topic(topic, moderator_id)
321
322
    flash_success('Das Thema "{}" wurde wieder geöffnet.', topic.title,
323
                  icon='unlock')
324
325
    signals.topic_unlocked.send(None, topic_id=topic.id,
326
                                moderator_id=moderator_id,
327
                                url=h.build_external_url_for_topic(topic.id))
328
329
    return h.build_url_for_topic_in_category_view(topic)
330
331
332
@blueprint.route('/topics/<uuid:topic_id>/flags/pinned', methods=['POST'])
333
@permission_required(BoardTopicPermission.pin)
334
@respond_no_content_with_location
335
def topic_pin(topic_id):
336
    """Pin a topic."""
337
    topic = h.get_topic_or_404(topic_id)
338
    moderator_id = g.current_user.id
339
340
    board_topic_command_service.pin_topic(topic, moderator_id)
341
342
    flash_success('Das Thema "{}" wurde angepinnt.', topic.title, icon='pin')
343
344
    signals.topic_pinned.send(None, topic_id=topic.id,
345
                              moderator_id=moderator_id,
346
                              url=h.build_external_url_for_topic(topic.id))
347
348
    return h.build_url_for_topic_in_category_view(topic)
349
350
351
@blueprint.route('/topics/<uuid:topic_id>/flags/pinned', methods=['DELETE'])
352
@permission_required(BoardTopicPermission.pin)
353
@respond_no_content_with_location
354
def topic_unpin(topic_id):
355
    """Unpin a topic."""
356
    topic = h.get_topic_or_404(topic_id)
357
    moderator_id = g.current_user.id
358
359
    board_topic_command_service.unpin_topic(topic, moderator_id)
360
361
    flash_success('Das Thema "{}" wurde wieder gelöst.', topic.title)
362
363
    signals.topic_unpinned.send(None, topic_id=topic.id,
364
                                moderator_id=moderator_id,
365
                                url=h.build_external_url_for_topic(topic.id))
366
367
    return h.build_url_for_topic_in_category_view(topic)
368
369
370
@blueprint.route('/topics/<uuid:topic_id>/move', methods=['POST'])
371
@permission_required(BoardTopicPermission.move)
372
def topic_move(topic_id):
373
    """Move a topic from one category to another."""
374
    topic = h.get_topic_or_404(topic_id)
375
    moderator_id = g.current_user.id
376
377
    new_category_id = request.form.get('category_id')
378
    if not new_category_id:
379
        abort(400, 'No target category ID given.')
380
381
    new_category = h.get_category_or_404(new_category_id)
382
383
    old_category = topic.category
384
385
    board_topic_command_service.move_topic(topic, new_category.id)
386
387
    flash_success('Das Thema "{}" wurde aus der Kategorie "{}" '
388
                  'in die Kategorie "{}" verschoben.',
389
                  topic.title, old_category.title, new_category.title,
390
                  icon='move')
391
392
    signals.topic_moved.send(None, topic_id=topic.id,
393
                             old_category_id=old_category.id,
394
                             new_category_id=new_category.id,
395
                             moderator_id=moderator_id,
396
                             url=h.build_external_url_for_topic(topic.id))
397
398
    return redirect(h.build_url_for_topic_in_category_view(topic))
399
400
401
@blueprint.route('/topics/<uuid:topic_id>/flags/announcements', methods=['POST'])
402
@permission_required(BoardPermission.announce)
403
@respond_no_content_with_location
404
def topic_limit_to_announcements(topic_id):
405
    """Limit posting in the topic to moderators."""
406
    topic = h.get_topic_or_404(topic_id)
407
408
    board_topic_command_service.limit_topic_to_announcements(topic)
409
410
    flash_success('Das Thema "{}" wurde auf Ankündigungen beschränkt.',
411
                  topic.title, icon='announce')
412
413
    return h.build_url_for_topic_in_category_view(topic)
414
415
416
@blueprint.route('/topics/<uuid:topic_id>/flags/announcements', methods=['DELETE'])
417
@permission_required(BoardPermission.announce)
418
@respond_no_content_with_location
419
def topic_remove_limit_to_announcements(topic_id):
420
    """Allow non-moderators to post in the topic again."""
421
    topic = h.get_topic_or_404(topic_id)
422
423
    board_topic_command_service.remove_limit_of_topic_to_announcements(topic)
424
425
    flash_success('Das Thema "{}" wurde für normale Beiträge geöffnet.',
426
                  topic.title)
427
428
    return h.build_url_for_topic_in_category_view(topic)
429