Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix bug 1303794: Add blog feeds for about/technology page
* Add command for updating blog feeds * Add settings for first set of blogs * Add model for caching blog articles
- Loading branch information
1 parent
8c58431
commit 8d95971
Showing
12 changed files
with
1,934 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from __future__ import print_function | ||
|
||
from django.conf import settings | ||
from django.core.management.base import BaseCommand | ||
from django.db import DatabaseError | ||
from django.db import transaction | ||
|
||
from feedparser import parse | ||
|
||
from bedrock.mozorg.models import BlogArticle | ||
|
||
|
||
class Command(BaseCommand): | ||
def add_arguments(self, parser): | ||
parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', default=False, | ||
help='If no error occurs, swallow all output.'), | ||
parser.add_argument('--database', default='default', | ||
help=('Specifies the database to use, if using a db. ' | ||
'Defaults to "default".')), | ||
parser.add_argument('--articles', default=5, type=int, | ||
help='Number of articles to store from each feed. Defaults to 5.') | ||
|
||
def handle(self, *args, **options): | ||
for feed_id, feed_options in settings.BLOG_FEEDS.items(): | ||
feed_url = feed_options.get('feed_url', None) | ||
if feed_url is None: | ||
feed_url = '%s/feed/atom/' % feed_options['url'].rstrip('/') | ||
feed = parse(feed_url) | ||
if feed.entries: | ||
with transaction.atomic(using=options['database']): | ||
count = 0 | ||
BlogArticle.objects.filter(blog_slug=feed_id).delete() | ||
for article in feed.entries: | ||
try: | ||
BlogArticle.objects.create( | ||
blog_slug=feed_id, | ||
blog_name=feed_options['name'], | ||
published=article.published, | ||
updated=article.updated, | ||
title=article.title, | ||
summary=article.summary, | ||
link=article.link, | ||
) | ||
except DatabaseError: | ||
continue | ||
count += 1 | ||
if count >= options['articles']: | ||
break |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('mozorg', '0001_initial'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='BlogArticle', | ||
fields=[ | ||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), | ||
('blog_slug', models.CharField(max_length=30)), | ||
('blog_name', models.CharField(max_length=50)), | ||
('published', models.DateTimeField()), | ||
('updated', models.DateTimeField()), | ||
('title', models.CharField(max_length=255)), | ||
('summary', models.TextField()), | ||
('link', models.URLField()), | ||
], | ||
options={ | ||
'ordering': ['-published'], | ||
'get_latest_by': 'published', | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
from django.core.management import call_command | ||
from django.db import IntegrityError | ||
from django.test import override_settings | ||
|
||
from mock import patch | ||
from pathlib import Path | ||
|
||
from bedrock.mozorg.tests import TestCase | ||
from bedrock.mozorg.models import BlogArticle | ||
|
||
|
||
HACKS_FILE = Path(__file__).parent.joinpath('test_files', 'data', 'hacks-blog.xml') | ||
TEST_BLOG_FEEDS = { | ||
'hacks': { | ||
'name': 'Hacks', | ||
'url': 'https://hacks.mozilla.org', | ||
'feed_url': str(HACKS_FILE), | ||
} | ||
} | ||
|
||
|
||
@override_settings(BLOG_FEEDS=TEST_BLOG_FEEDS) | ||
class TestUpdateBlogFeeds(TestCase): | ||
def test_load_feed(self): | ||
call_command('update_blog_feeds', articles=4) | ||
self.assertEqual(BlogArticle.objects.count(), 4) | ||
|
||
@patch('bedrock.mozorg.management.commands.update_blog_feeds.BlogArticle') | ||
def test_error_loading_feed(self, mock_model): | ||
mock_model.objects.create.side_effect = [IntegrityError] + [None] * 4 | ||
call_command('update_blog_feeds', articles=4) | ||
# 5 calls since first fails and we want 4 articles | ||
self.assertEqual(mock_model.objects.create.call_count, 5) |
Oops, something went wrong.