Total Complexity | 54 |
Total Lines | 628 |
Duplicated Lines | 1.91 % |
Coverage | 72.76% |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like byceps.blueprints.admin.news.views often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | """ |
||
2 | byceps.blueprints.admin.news.views |
||
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
4 | |||
5 | :Copyright: 2006-2021 Jochen Kupperschmidt |
||
6 | :License: Revised BSD (see `LICENSE` file for details) |
||
7 | """ |
||
8 | |||
9 | 1 | from datetime import date, datetime |
|
10 | |||
11 | 1 | from flask import abort, g, request |
|
12 | 1 | from flask_babel import gettext |
|
13 | |||
14 | 1 | from ....services.brand import service as brand_service |
|
15 | 1 | from ....services.image import service as image_service |
|
16 | 1 | from ....services.news import channel_service as news_channel_service |
|
17 | 1 | from ....services.news import html_service as news_html_service |
|
18 | 1 | from ....services.news import image_service as news_image_service |
|
19 | 1 | from ....services.news import service as news_item_service |
|
20 | 1 | from ....services.news.transfer.models import Channel |
|
21 | 1 | from ....services.site import service as site_service |
|
22 | 1 | from ....services.text_diff import service as text_diff_service |
|
23 | 1 | from ....services.user.service import UserIdRejected |
|
24 | 1 | from ....signals import news as news_signals |
|
25 | 1 | from ....util.authorization import register_permission_enum |
|
26 | 1 | from ....util.datetime.format import format_datetime_short |
|
27 | 1 | from ....util.framework.blueprint import create_blueprint |
|
28 | 1 | from ....util.framework.flash import flash_error, flash_success |
|
29 | 1 | from ....util.framework.templating import templated |
|
30 | 1 | from ....util.iterables import pairwise |
|
31 | 1 | from ....util.templatefilters import local_tz_to_utc |
|
32 | 1 | from ....util.views import permission_required, redirect_to, respond_no_content |
|
33 | |||
34 | 1 | from .authorization import NewsChannelPermission, NewsItemPermission |
|
35 | 1 | from .forms import ( |
|
36 | ChannelCreateForm, |
||
37 | ImageCreateForm, |
||
38 | ImageUpdateForm, |
||
39 | ItemCreateForm, |
||
40 | ItemPublishLaterForm, |
||
41 | ItemUpdateForm, |
||
42 | ) |
||
43 | |||
44 | |||
45 | 1 | blueprint = create_blueprint('news_admin', __name__) |
|
46 | |||
47 | |||
48 | 1 | register_permission_enum(NewsChannelPermission) |
|
49 | 1 | register_permission_enum(NewsItemPermission) |
|
50 | |||
51 | |||
52 | # -------------------------------------------------------------------- # |
||
53 | # channels |
||
54 | |||
55 | |||
56 | 1 | @blueprint.get('/brands/<brand_id>') |
|
57 | 1 | @permission_required(NewsItemPermission.view) |
|
58 | 1 | @templated |
|
59 | def channel_index_for_brand(brand_id): |
||
60 | """List channels for that brand.""" |
||
61 | 1 | brand = _get_brand_or_404(brand_id) |
|
62 | |||
63 | 1 | channels = news_channel_service.get_channels_for_brand(brand.id) |
|
64 | |||
65 | 1 | item_count_by_channel_id = news_item_service.get_item_count_by_channel_id() |
|
66 | |||
67 | 1 | return { |
|
68 | 'brand': brand, |
||
69 | 'channels': channels, |
||
70 | 'item_count_by_channel_id': item_count_by_channel_id, |
||
71 | } |
||
72 | |||
73 | |||
74 | 1 | @blueprint.get('/for_brand/<brand_id>/channels/create') |
|
75 | 1 | @permission_required(NewsChannelPermission.create) |
|
76 | 1 | @templated |
|
77 | 1 | def channel_create_form(brand_id, erroneous_form=None): |
|
78 | """Show form to create a channel.""" |
||
79 | 1 | brand = _get_brand_or_404(brand_id) |
|
80 | |||
81 | 1 | form = erroneous_form if erroneous_form else ChannelCreateForm() |
|
82 | |||
83 | 1 | return { |
|
84 | 'brand': brand, |
||
85 | 'form': form, |
||
86 | } |
||
87 | |||
88 | |||
89 | 1 | @blueprint.post('/for_brand/<brand_id>/channels') |
|
90 | 1 | @permission_required(NewsChannelPermission.create) |
|
91 | def channel_create(brand_id): |
||
92 | """Create a channel.""" |
||
93 | 1 | brand = _get_brand_or_404(brand_id) |
|
94 | |||
95 | 1 | form = ChannelCreateForm(request.form) |
|
96 | 1 | if not form.validate(): |
|
97 | return channel_create_form(brand.id, form) |
||
98 | |||
99 | 1 | channel_id = form.channel_id.data.strip().lower() |
|
100 | 1 | url_prefix = form.url_prefix.data.strip() |
|
101 | |||
102 | 1 | channel = news_channel_service.create_channel( |
|
103 | brand.id, channel_id, url_prefix |
||
104 | ) |
||
105 | |||
106 | 1 | flash_success( |
|
107 | gettext( |
||
108 | 'News channel "%(channel_id)s" has been created.', |
||
109 | channel_id=channel.id, |
||
110 | ) |
||
111 | ) |
||
112 | 1 | return redirect_to('.channel_view', channel_id=channel.id) |
|
113 | |||
114 | |||
115 | 1 | @blueprint.get('/channels/<channel_id>', defaults={'page': 1}) |
|
116 | 1 | @blueprint.get('/channels/<channel_id>/pages/<int:page>') |
|
117 | 1 | @permission_required(NewsItemPermission.view) |
|
118 | 1 | @templated |
|
119 | def channel_view(channel_id, page): |
||
120 | """View that channel and list its news items.""" |
||
121 | 1 | channel = _get_channel_or_404(channel_id) |
|
122 | |||
123 | 1 | brand = brand_service.find_brand(channel.brand_id) |
|
124 | |||
125 | 1 | channel_ids = {channel.id} |
|
126 | 1 | per_page = request.args.get('per_page', type=int, default=15) |
|
127 | |||
128 | 1 | items = news_item_service.get_items_paginated(channel_ids, page, per_page) |
|
129 | |||
130 | 1 | return { |
|
131 | 'channel': channel, |
||
132 | 'brand': brand, |
||
133 | 'items': items, |
||
134 | } |
||
135 | |||
136 | |||
137 | 1 | @blueprint.delete('/channels/<channel_id>') |
|
138 | 1 | @permission_required(NewsChannelPermission.create) |
|
139 | 1 | @respond_no_content |
|
140 | def channel_delete(channel_id): |
||
141 | """Delete the channel.""" |
||
142 | channel = _get_channel_or_404(channel_id) |
||
143 | |||
144 | if news_item_service.has_channel_items(channel.id): |
||
145 | flash_error( |
||
146 | gettext( |
||
147 | 'News channel "%(channel_id)s" cannot be deleted because it contains news items.', |
||
148 | channel_id=channel.id, |
||
149 | ) |
||
150 | ) |
||
151 | return |
||
152 | |||
153 | sites_for_brand = site_service.get_sites_for_brand(channel.brand_id) |
||
154 | linked_sites = { |
||
155 | site for site in sites_for_brand if channel.id in site.news_channel_ids |
||
156 | } |
||
157 | if linked_sites: |
||
158 | flash_error( |
||
159 | gettext( |
||
160 | 'News channel "%(channel_id)s" cannot be deleted because it is referenced by %(site_count)s site(s).', |
||
161 | channel_id=channel.id, |
||
162 | site_count=len(linked_sites), |
||
163 | ) |
||
164 | ) |
||
165 | return |
||
166 | |||
167 | news_channel_service.delete_channel(channel.id) |
||
168 | |||
169 | flash_success( |
||
170 | gettext( |
||
171 | 'News channel "%(channel_id)s" has been deleted.', |
||
172 | channel_id=channel_id, |
||
173 | ) |
||
174 | ) |
||
175 | |||
176 | |||
177 | # -------------------------------------------------------------------- # |
||
178 | # images |
||
179 | |||
180 | |||
181 | 1 | @blueprint.get('/for_item/<item_id>/create') |
|
182 | 1 | @permission_required(NewsItemPermission.update) |
|
183 | 1 | @templated |
|
184 | 1 | def image_create_form(item_id, erroneous_form=None): |
|
185 | """Show form to create a news image.""" |
||
186 | 1 | item = _get_item_or_404(item_id) |
|
187 | |||
188 | 1 | form = erroneous_form if erroneous_form else ImageCreateForm() |
|
189 | |||
190 | 1 | image_type_names = image_service.get_image_type_names( |
|
191 | news_image_service.ALLOWED_IMAGE_TYPES |
||
192 | ) |
||
193 | |||
194 | 1 | return { |
|
195 | 'item': item, |
||
196 | 'form': form, |
||
197 | 'allowed_types': image_type_names, |
||
198 | 'maximum_dimensions': news_image_service.MAXIMUM_DIMENSIONS, |
||
199 | } |
||
200 | |||
201 | |||
202 | 1 | @blueprint.post('/for_item/<item_id>') |
|
203 | 1 | @permission_required(NewsItemPermission.update) |
|
204 | def image_create(item_id): |
||
205 | """Create a news image.""" |
||
206 | item = _get_item_or_404(item_id) |
||
207 | |||
208 | # Make `InputRequired` work on `FileField`. |
||
209 | form_fields = request.form.copy() |
||
210 | if request.files: |
||
211 | form_fields.update(request.files) |
||
212 | |||
213 | form = ImageCreateForm(form_fields) |
||
214 | if not form.validate(): |
||
215 | return image_create_form(item.id, form) |
||
216 | |||
217 | creator_id = g.user.id |
||
218 | image = request.files.get('image') |
||
219 | alt_text = form.alt_text.data.strip() |
||
220 | caption = form.caption.data.strip() |
||
221 | attribution = form.attribution.data.strip() |
||
222 | |||
223 | if not image or not image.filename: |
||
224 | abort(400, 'No file to upload has been specified.') |
||
225 | |||
226 | try: |
||
227 | image = news_image_service.create_image( |
||
228 | creator_id, |
||
229 | item.id, |
||
230 | image.stream, |
||
231 | alt_text=alt_text, |
||
232 | caption=caption, |
||
233 | attribution=attribution, |
||
234 | ) |
||
235 | except UserIdRejected as e: |
||
236 | abort(400, 'Invalid creator ID') |
||
237 | except image_service.ImageTypeProhibited as e: |
||
238 | abort(400, str(e)) |
||
239 | except FileExistsError: |
||
240 | abort(409, 'File already exists, not overwriting.') |
||
241 | |||
242 | flash_success( |
||
243 | gettext( |
||
244 | 'News image #%(image_number)s has been created.', |
||
245 | image_number=image.number, |
||
246 | ) |
||
247 | ) |
||
248 | |||
249 | return redirect_to('.item_view', item_id=image.item_id) |
||
250 | |||
251 | |||
252 | 1 | @blueprint.get('/images/<uuid:image_id>/update') |
|
253 | 1 | @permission_required(NewsItemPermission.update) |
|
254 | 1 | @templated |
|
255 | 1 | def image_update_form(image_id, erroneous_form=None): |
|
256 | """Show form to update a news image.""" |
||
257 | image = _get_image_or_404(image_id) |
||
258 | item = news_item_service.find_item(image.item_id) |
||
259 | |||
260 | form = erroneous_form if erroneous_form else ImageUpdateForm(obj=image) |
||
261 | |||
262 | return { |
||
263 | 'image': image, |
||
264 | 'item': item, |
||
265 | 'form': form, |
||
266 | } |
||
267 | |||
268 | |||
269 | 1 | @blueprint.post('/images/<uuid:image_id>') |
|
270 | 1 | @permission_required(NewsItemPermission.update) |
|
271 | def image_update(image_id): |
||
272 | """Update a news image.""" |
||
273 | image = _get_image_or_404(image_id) |
||
274 | |||
275 | form = ImageUpdateForm(request.form) |
||
276 | if not form.validate(): |
||
277 | return image_update_form(image.id, form) |
||
278 | |||
279 | alt_text = form.alt_text.data.strip() |
||
280 | caption = form.caption.data.strip() |
||
281 | attribution = form.attribution.data.strip() |
||
282 | |||
283 | image = news_image_service.update_image( |
||
284 | image.id, |
||
285 | alt_text=alt_text, |
||
286 | caption=caption, |
||
287 | attribution=attribution, |
||
288 | ) |
||
289 | |||
290 | flash_success( |
||
291 | gettext( |
||
292 | 'News image #%(image_number)s has been updated.', |
||
293 | image_number=image.number, |
||
294 | ) |
||
295 | ) |
||
296 | |||
297 | return redirect_to('.item_view', item_id=image.item_id) |
||
298 | |||
299 | |||
300 | # -------------------------------------------------------------------- # |
||
301 | # items |
||
302 | |||
303 | |||
304 | 1 | @blueprint.get('/items/<uuid:item_id>') |
|
305 | 1 | @permission_required(NewsItemPermission.view) |
|
306 | 1 | @templated('admin/news/item_view_version') |
|
307 | def item_view(item_id): |
||
308 | """Show the current version of the news item.""" |
||
309 | 1 | item = _get_item_or_404(item_id) |
|
310 | |||
311 | 1 | version = news_item_service.get_current_item_version(item.id) |
|
312 | |||
313 | 1 | return _render_item_version(version, item) |
|
314 | |||
315 | |||
316 | 1 | @blueprint.get('/versions/<uuid:version_id>') |
|
317 | 1 | @permission_required(NewsItemPermission.view) |
|
318 | 1 | @templated |
|
319 | def item_view_version(version_id): |
||
320 | """Show the news item with the given version.""" |
||
321 | 1 | version = _find_version(version_id) |
|
322 | |||
323 | 1 | item = news_item_service.find_item(version.item_id) |
|
324 | |||
325 | 1 | return _render_item_version(version, item) |
|
326 | |||
327 | |||
328 | 1 | def _render_item_version(version, item): |
|
329 | """Render the news item version.""" |
||
330 | 1 | channel = item.channel |
|
331 | 1 | brand = brand_service.find_brand(channel.brand_id) |
|
332 | |||
333 | 1 | current_version = news_item_service.get_current_item_version(item.id) |
|
334 | 1 | is_current_version = version.id == current_version.id |
|
335 | |||
336 | 1 | context = { |
|
337 | 'version': version, |
||
338 | 'brand': brand, |
||
339 | 'is_current_version': is_current_version, |
||
340 | } |
||
341 | |||
342 | 1 | try: |
|
343 | 1 | rendered_body = news_html_service.render_body( |
|
344 | version.body, channel.id, item.images |
||
345 | ) |
||
346 | |||
347 | 1 | context.update( |
|
348 | { |
||
349 | 'rendered_body': rendered_body, |
||
350 | 'error_occurred': False, |
||
351 | } |
||
352 | ) |
||
353 | except Exception as e: |
||
354 | context.update( |
||
355 | { |
||
356 | 'error_occurred': True, |
||
357 | 'error_message': str(e), |
||
358 | } |
||
359 | ) |
||
360 | |||
361 | 1 | return context |
|
362 | |||
363 | |||
364 | 1 | @blueprint.get('/items/<uuid:item_id>/versions') |
|
365 | 1 | @permission_required(NewsItemPermission.view) |
|
366 | 1 | @templated |
|
367 | def item_list_versions(item_id): |
||
368 | """List news item's versions.""" |
||
369 | 1 | item = _get_item_or_404(item_id) |
|
370 | |||
371 | 1 | channel = item.channel |
|
372 | 1 | brand = brand_service.find_brand(channel.brand_id) |
|
373 | |||
374 | 1 | versions = news_item_service.get_item_versions(item.id) |
|
375 | 1 | versions_pairwise = list(pairwise(versions + [None])) |
|
376 | |||
377 | 1 | return { |
|
378 | 'item': item, |
||
379 | 'brand': brand, |
||
380 | 'versions_pairwise': versions_pairwise, |
||
381 | } |
||
382 | |||
383 | |||
384 | 1 | @blueprint.get('/items/<uuid:from_version_id>/compare_to/<uuid:to_version_id>') |
|
385 | 1 | @permission_required(NewsItemPermission.view) |
|
386 | 1 | @templated |
|
387 | def item_compare_versions(from_version_id, to_version_id): |
||
388 | """Show the difference between two news item versions.""" |
||
389 | 1 | from_version = _find_version(from_version_id) |
|
390 | 1 | to_version = _find_version(to_version_id) |
|
391 | |||
392 | 1 | if from_version.item_id != to_version.item_id: |
|
393 | abort(400, 'The versions do not belong to the same item.') |
||
394 | |||
395 | 1 | item = news_item_service.find_item(from_version.item_id) |
|
396 | 1 | channel = item.channel |
|
397 | 1 | brand = brand_service.find_brand(channel.brand_id) |
|
398 | |||
399 | 1 | html_diff_title = _create_html_diff(from_version, to_version, 'title') |
|
400 | 1 | html_diff_body = _create_html_diff(from_version, to_version, 'body') |
|
401 | 1 | html_diff_image_url_path = _create_html_diff( |
|
402 | from_version, to_version, 'image_url_path' |
||
403 | ) |
||
404 | |||
405 | 1 | return { |
|
406 | 'brand': brand, |
||
407 | 'diff_title': html_diff_title, |
||
408 | 'diff_body': html_diff_body, |
||
409 | 'diff_image_url_path': html_diff_image_url_path, |
||
410 | } |
||
411 | |||
412 | |||
413 | 1 | @blueprint.get('/for_channel/<channel_id>/create') |
|
414 | 1 | @permission_required(NewsItemPermission.create) |
|
415 | 1 | @templated |
|
416 | 1 | def item_create_form(channel_id, erroneous_form=None): |
|
417 | """Show form to create a news item.""" |
||
418 | 1 | channel = _get_channel_or_404(channel_id) |
|
419 | |||
420 | 1 | if erroneous_form: |
|
421 | form = erroneous_form |
||
422 | else: |
||
423 | 1 | slug_prefix = date.today().strftime('%Y-%m-%d-') |
|
424 | 1 | form = ItemCreateForm(slug=slug_prefix) |
|
425 | |||
426 | 1 | return { |
|
427 | 'channel': channel, |
||
428 | 'form': form, |
||
429 | } |
||
430 | |||
431 | |||
432 | 1 | @blueprint.post('/for_channel/<channel_id>') |
|
433 | 1 | @permission_required(NewsItemPermission.create) |
|
434 | def item_create(channel_id): |
||
435 | """Create a news item.""" |
||
436 | 1 | channel = _get_channel_or_404(channel_id) |
|
437 | |||
438 | 1 | form = ItemCreateForm(request.form) |
|
439 | 1 | if not form.validate(): |
|
440 | return item_create_form(channel.id, form) |
||
441 | |||
442 | 1 | slug = form.slug.data.strip().lower() |
|
443 | 1 | creator = g.user |
|
444 | 1 | title = form.title.data.strip() |
|
445 | 1 | body = form.body.data.strip() |
|
446 | 1 | image_url_path = form.image_url_path.data.strip() |
|
447 | |||
448 | 1 | item = news_item_service.create_item( |
|
449 | channel.id, slug, creator.id, title, body, image_url_path=image_url_path |
||
450 | ) |
||
451 | |||
452 | 1 | flash_success( |
|
453 | gettext('News item "%(title)s" has been created.', title=item.title) |
||
454 | ) |
||
455 | |||
456 | 1 | return redirect_to('.item_view', item_id=item.id) |
|
457 | |||
458 | |||
459 | 1 | @blueprint.get('/items/<uuid:item_id>/update') |
|
460 | 1 | @permission_required(NewsItemPermission.update) |
|
461 | 1 | @templated |
|
462 | 1 | def item_update_form(item_id, erroneous_form=None): |
|
463 | """Show form to update a news item.""" |
||
464 | 1 | item = _get_item_or_404(item_id) |
|
465 | |||
466 | 1 | current_version = news_item_service.get_current_item_version(item.id) |
|
467 | |||
468 | 1 | form = ( |
|
469 | erroneous_form |
||
470 | if erroneous_form |
||
471 | else ItemUpdateForm(obj=current_version, slug=item.slug) |
||
472 | ) |
||
473 | |||
474 | 1 | return { |
|
475 | 'item': item, |
||
476 | 'form': form, |
||
477 | } |
||
478 | |||
479 | |||
480 | 1 | @blueprint.post('/items/<uuid:item_id>') |
|
481 | 1 | @permission_required(NewsItemPermission.update) |
|
482 | def item_update(item_id): |
||
483 | """Update a news item.""" |
||
484 | item = _get_item_or_404(item_id) |
||
485 | |||
486 | form = ItemUpdateForm(request.form) |
||
487 | if not form.validate(): |
||
488 | return item_update_form(item.id, form) |
||
489 | |||
490 | creator = g.user |
||
491 | slug = form.slug.data.strip().lower() |
||
492 | title = form.title.data.strip() |
||
493 | body = form.body.data.strip() |
||
494 | image_url_path = form.image_url_path.data.strip() |
||
495 | |||
496 | item = news_item_service.update_item( |
||
497 | item.id, slug, creator.id, title, body, image_url_path=image_url_path |
||
498 | ) |
||
499 | |||
500 | flash_success( |
||
501 | gettext('News item "%(title)s" has been updated.', title=item.title) |
||
502 | ) |
||
503 | |||
504 | return redirect_to('.item_view', item_id=item.id) |
||
505 | |||
506 | |||
507 | 1 | @blueprint.get('/items/<uuid:item_id>/publish_later') |
|
508 | 1 | @permission_required(NewsItemPermission.publish) |
|
509 | 1 | @templated |
|
510 | 1 | def item_publish_later_form(item_id, erroneous_form=None): |
|
511 | """Show form to publish a news item at a time in the future.""" |
||
512 | 1 | item = _get_item_or_404(item_id) |
|
513 | |||
514 | 1 | form = erroneous_form if erroneous_form else ItemPublishLaterForm() |
|
515 | |||
516 | 1 | return { |
|
517 | 'item': item, |
||
518 | 'form': form, |
||
519 | } |
||
520 | |||
521 | |||
522 | 1 | @blueprint.post('/items/<uuid:item_id>/publish_later') |
|
523 | 1 | @permission_required(NewsItemPermission.publish) |
|
524 | def item_publish_later(item_id): |
||
525 | """Publish a news item at a time in the future.""" |
||
526 | 1 | item = _get_item_or_404(item_id) |
|
527 | |||
528 | 1 | form = ItemPublishLaterForm(request.form) |
|
529 | 1 | if not form.validate(): |
|
530 | return item_publish_later_form(item.id, form) |
||
531 | |||
532 | 1 | publish_at = local_tz_to_utc( |
|
533 | datetime.combine(form.publish_on.data, form.publish_at.data) |
||
534 | ) |
||
535 | |||
536 | 1 | event = news_item_service.publish_item( |
|
537 | item.id, publish_at=publish_at, initiator_id=g.user.id |
||
538 | ) |
||
539 | |||
540 | 1 | news_signals.item_published.send(None, event=event) |
|
541 | |||
542 | 1 | flash_success( |
|
543 | gettext( |
||
544 | 'News item "%(title)s" will be published later.', title=item.title |
||
545 | ) |
||
546 | ) |
||
547 | |||
548 | 1 | return redirect_to('.item_view', item_id=item.id) |
|
549 | |||
550 | |||
551 | 1 | @blueprint.post('/items/<uuid:item_id>/publish_now') |
|
552 | 1 | @permission_required(NewsItemPermission.publish) |
|
553 | 1 | @respond_no_content |
|
554 | def item_publish_now(item_id): |
||
555 | """Publish a news item now.""" |
||
556 | 1 | item = _get_item_or_404(item_id) |
|
557 | |||
558 | 1 | event = news_item_service.publish_item(item.id, initiator_id=g.user.id) |
|
559 | |||
560 | 1 | news_signals.item_published.send(None, event=event) |
|
561 | |||
562 | 1 | flash_success( |
|
563 | gettext('News item "%(title)s" has been published.', title=item.title) |
||
564 | ) |
||
565 | |||
566 | |||
567 | # -------------------------------------------------------------------- # |
||
568 | # helpers |
||
569 | |||
570 | |||
571 | 1 | def _get_brand_or_404(brand_id): |
|
572 | 1 | brand = brand_service.find_brand(brand_id) |
|
573 | |||
574 | 1 | if brand is None: |
|
575 | abort(404) |
||
576 | |||
577 | 1 | return brand |
|
578 | |||
579 | |||
580 | 1 | def _get_channel_or_404(channel_id) -> Channel: |
|
581 | 1 | channel = news_channel_service.find_channel(channel_id) |
|
582 | |||
583 | 1 | if channel is None: |
|
584 | abort(404) |
||
585 | |||
586 | 1 | return channel |
|
587 | |||
588 | |||
589 | 1 | def _get_item_or_404(item_id): |
|
590 | 1 | item = news_item_service.find_item(item_id) |
|
591 | |||
592 | 1 | if item is None: |
|
593 | abort(404) |
||
594 | |||
595 | 1 | return item |
|
596 | |||
597 | |||
598 | 1 | def _get_image_or_404(image_id): |
|
599 | image = news_image_service.find_image(image_id) |
||
600 | |||
601 | if image is None: |
||
602 | abort(404) |
||
603 | |||
604 | return image |
||
605 | |||
606 | |||
607 | 1 | def _find_version(version_id): |
|
608 | 1 | version = news_item_service.find_item_version(version_id) |
|
609 | |||
610 | 1 | if version is None: |
|
611 | abort(404) |
||
612 | |||
613 | 1 | return version |
|
614 | |||
615 | |||
616 | 1 | View Code Duplication | def _create_html_diff(from_version, to_version, attribute_name): |
617 | """Create an HTML diff between the named attribute's value of each |
||
618 | of the two versions. |
||
619 | """ |
||
620 | 1 | from_description = format_datetime_short(from_version.created_at) |
|
621 | 1 | to_description = format_datetime_short(to_version.created_at) |
|
622 | |||
623 | 1 | from_text = getattr(from_version, attribute_name) |
|
624 | 1 | to_text = getattr(to_version, attribute_name) |
|
625 | |||
626 | 1 | return text_diff_service.create_html_diff( |
|
627 | from_text, to_text, from_description, to_description |
||
628 | ) |
||
629 |