Replace rest_framework_swagger with drf_yasg

rest_framework is deprecated see https://github.com/marcgibbons/django-rest-swagger#django-rest-swagger-deprecated-2019-06-04
This commit is contained in:
sonny 2020-07-22 23:49:18 +02:00
parent ec45a661e5
commit a6827e604d
24 changed files with 2728 additions and 311 deletions

View file

@ -6,7 +6,7 @@ import { isEqual } from 'lodash';
import { fetchCategories } from './actions/categories'; import { fetchCategories } from './actions/categories';
import Sidebar from './components/sidebar/Sidebar.js'; import Sidebar from './components/sidebar/Sidebar.js';
import FeedList from './components/feedlist/FeedList.js'; import PostList from './components/postlist/PostList.js';
import PostModal from './components/PostModal.js'; import PostModal from './components/PostModal.js';
import Messages from '../../components/Messages.js'; import Messages from '../../components/Messages.js';
@ -19,7 +19,7 @@ class App extends React.Component {
return ( return (
<> <>
<Sidebar /> <Sidebar />
<FeedList /> <PostList />
{this.props.error && ( {this.props.error && (
<Messages messages={[{ type: 'error', text: this.props.error.message }]} /> <Messages messages={[{ type: 'error', text: this.props.error.message }]} />

View file

@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { unSelectPost, markPostRead } from '../actions/posts.js'; import { unSelectPost, markPostRead } from '../actions/posts.js';
import { CATEGORY_TYPE, RULE_TYPE, FEED, SUBREDDIT } from '../constants.js';
import { formatDatetime } from '../../../utils.js'; import { formatDatetime } from '../../../utils.js';
class PostModal extends React.Component { class PostModal extends React.Component {
@ -43,6 +44,10 @@ class PostModal extends React.Component {
const post = this.props.post; const post = this.props.post;
const publicationDate = formatDatetime(post.publicationDate); const publicationDate = formatDatetime(post.publicationDate);
const titleClassName = post.read ? 'post__title post__title--read' : 'post__title'; const titleClassName = post.read ? 'post__title post__title--read' : 'post__title';
const ruleUrl =
this.props.rule.type === FEED
? `/collection/rules/${this.props.rule.id}/`
: `/collection/rules/subreddits/${this.props.rule.id}/`;
return ( return (
<div className="modal post-modal"> <div className="modal post-modal">
@ -70,11 +75,7 @@ class PostModal extends React.Component {
</span> </span>
)} )}
<span className="badge post__rule" title={this.props.rule.name}> <span className="badge post__rule" title={this.props.rule.name}>
<a <a href={ruleUrl} target="_blank" rel="noopener noreferrer">
href={`/collection/rules/${this.props.rule.id}/`}
target="_blank"
rel="noopener noreferrer"
>
{this.props.rule.name} {this.props.rule.name}
</a> </a>
</span> </span>

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { CATEGORY_TYPE, RULE_TYPE } from '../../constants.js'; import { CATEGORY_TYPE, RULE_TYPE, FEED, SUBREDDIT } from '../../constants.js';
import { selectPost } from '../../actions/posts.js'; import { selectPost } from '../../actions/posts.js';
import { formatDatetime } from '../../../../utils.js'; import { formatDatetime } from '../../../../utils.js';
@ -14,6 +14,11 @@ class PostItem extends React.Component {
? 'posts__header posts__header--read' ? 'posts__header posts__header--read'
: 'posts__header'; : 'posts__header';
const ruleUrl =
rule.type === FEED
? `/collection/rules/${rule.id}/`
: `/collection/rules/subreddits/${rule.id}/`;
return ( return (
<li className="posts__item"> <li className="posts__item">
<h5 <h5
@ -30,11 +35,7 @@ class PostItem extends React.Component {
</span> </span>
{this.props.selected.type == CATEGORY_TYPE && ( {this.props.selected.type == CATEGORY_TYPE && (
<span className="badge"> <span className="badge">
<a <a href={ruleUrl} target="_blank" rel="noopener noreferrer">
href={`/collection/rules/${rule.id}/`}
target="_blank"
rel="noopener noreferrer"
>
{rule.name} {rule.name}
</a> </a>
</span> </span>

View file

@ -8,7 +8,7 @@ import { filterPosts } from './filters.js';
import LoadingIndicator from '../../../../components/LoadingIndicator.js'; import LoadingIndicator from '../../../../components/LoadingIndicator.js';
import PostItem from './PostItem.js'; import PostItem from './PostItem.js';
class FeedList extends React.Component { class PostList extends React.Component {
checkScrollHeight = ::this.checkScrollHeight; checkScrollHeight = ::this.checkScrollHeight;
componentDidMount() { componentDidMount() {
@ -83,4 +83,4 @@ const mapDispatchToProps = dispatch => ({
fetchPostsBySection: (rule, page = false) => dispatch(fetchPostsBySection(rule, page)), fetchPostsBySection: (rule, page = false) => dispatch(fetchPostsBySection(rule, page)),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(FeedList); export default connect(mapStateToProps, mapDispatchToProps)(PostList);

View file

@ -1,2 +1,5 @@
export const RULE_TYPE = 'RULE'; export const RULE_TYPE = 'RULE';
export const CATEGORY_TYPE = 'CATEGORY'; export const CATEGORY_TYPE = 'CATEGORY';
export const SUBREDDIT = 'subreddit';
export const FEED = 'feed';

View file

@ -6,7 +6,14 @@ from newsreader.news.collection.models import CollectionRule
class CollectionRuleAdmin(admin.ModelAdmin): class CollectionRuleAdmin(admin.ModelAdmin):
fields = ("url", "name", "timezone", "category", "favicon", "user") fields = ("url", "name", "timezone", "category", "favicon", "user")
list_display = ("name", "category", "url", "last_suceeded", "succeeded") list_display = (
"name",
"type_display",
"category",
"url",
"last_suceeded",
"succeeded",
)
list_filter = ("user",) list_filter = ("user",)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
@ -14,5 +21,8 @@ class CollectionRuleAdmin(admin.ModelAdmin):
obj.user = request.user obj.user = request.user
obj.save() obj.save()
def type_display(self, rule):
return rule.get_type_display()
admin.site.register(CollectionRule, CollectionRuleAdmin) admin.site.register(CollectionRule, CollectionRuleAdmin)

View file

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -6,15 +7,17 @@ import pytz
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.models import CollectionRule from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.reddit import REDDIT_API_URL
from newsreader.news.core.models import Category from newsreader.news.core.models import Category
def get_reddit_help_text(): def get_reddit_help_text():
return mark_safe( return mark_safe(
"Only subreddits are supported. For example: " "Only subreddits are supported"
"<a className='link' target='_blank' rel='noopener noreferrer'" " see the 'listings' section in <a className='link' target='_blank' rel='noopener noreferrer'"
" href='https://reddit.com/r/aww'>https://www.reddit.com/r/aww</a>." " href='https://www.reddit.com/dev/api#section_listings'>the reddit API docs</a>."
" Note that subreddit urls should NOT include 'www' because Reddit is picky." " For example: <a className='link' target='_blank' rel='noopener noreferrer'"
" href='https://oauth.reddit.com/r/aww'>https://oauth.reddit.com/r/aww</a>"
) )
@ -65,15 +68,19 @@ class SubRedditRuleForm(CollectionRuleForm):
timezone = None timezone = None
def clean_url(self):
url = self.cleaned_data["url"]
if not url.startswith(REDDIT_API_URL):
raise ValidationError(_("This does not look like an Reddit API URL"))
return url
def save(self, commit=True): def save(self, commit=True):
instance = super().save(commit=False) instance = super().save(commit=False)
instance.type = RuleTypeChoices.subreddit instance.type = RuleTypeChoices.subreddit
instance.timezone = str(pytz.utc) instance.timezone = str(pytz.utc)
instance.user = self.user
if not instance.url.endswith(".json"):
instance.url = f"{instance.url}.json"
if commit: if commit:
instance.save() instance.save()

View file

@ -10,6 +10,7 @@ from uuid import uuid4
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.utils import timezone from django.utils import timezone
from django.utils.html import format_html
import bleach import bleach
import pytz import pytz
@ -42,6 +43,12 @@ REDDIT_API_URL = "https://oauth.reddit.com"
RATE_LIMIT = 60 RATE_LIMIT = 60
RATE_LIMIT_DURATION = timedelta(seconds=60) RATE_LIMIT_DURATION = timedelta(seconds=60)
REDDIT_IMAGE_EXTENSIONS = (".jpg", ".png", ".gif")
REDDIT_VIDEO_EXTENSIONS = (".mp4", ".gifv", ".webm")
# see type prefixes on https://www.reddit.com/dev/api/
REDDIT_POST = "t3"
def get_reddit_authorization_url(user): def get_reddit_authorization_url(user):
state = str(uuid4()) state = str(uuid4())
@ -114,18 +121,23 @@ class RedditBuilder(Builder):
results = {} results = {}
for post in posts: for post in posts:
if not "data" in post: if not "data" in post or post["kind"] != REDDIT_POST:
continue continue
remote_identifier = post["data"]["id"] data = post["data"]
title = truncate_text(Post, "title", post["data"]["title"])
author = truncate_text(Post, "author", post["data"]["author"]) remote_identifier = data["id"]
url_fragment = f"{post['data']['permalink']}" title = truncate_text(Post, "title", data["title"])
author = truncate_text(Post, "author", data["author"])
post_url_fragment = data["permalink"]
direct_url = data["url"]
is_text_post = data["is_self"]
if remote_identifier in results: if remote_identifier in results:
continue continue
uncleaned_body = post["data"]["selftext_html"] if is_text_post:
uncleaned_body = data["selftext_html"]
unescaped_body = unescape(uncleaned_body) if uncleaned_body else "" unescaped_body = unescape(uncleaned_body) if uncleaned_body else ""
body = ( body = (
bleach.clean( bleach.clean(
@ -138,6 +150,43 @@ class RedditBuilder(Builder):
if unescaped_body if unescaped_body
else "" else ""
) )
elif direct_url.endswith(REDDIT_IMAGE_EXTENSIONS):
body = format_html(
"<div><img alt='{title}' src='{url}' loading='lazy' /></div>",
url=direct_url,
title=title,
)
elif data["is_video"]:
video_info = data["secure_media"]["reddit_video"]
body = format_html(
"<div><video controls muted><source src='{url}' type='video/mp4' /></video></div>",
url=video_info["fallback_url"],
)
elif direct_url.endswith(REDDIT_VIDEO_EXTENSIONS):
extension = next(
extension.replace(".", "")
for extension in REDDIT_VIDEO_EXTENSIONS
if direct_url.endswith(extension)
)
if extension == "gifv":
body = format_html(
"<div><video controls muted><source src='{url}' type='video/mp4' /></video></div>",
url=direct_url.replace(extension, "mp4"),
)
else:
body = format_html(
"<div><video controls muted><source src='{url}' type='video/{extension}' /></video></div>",
url=direct_url,
extension=extension,
)
else:
body = format_html(
"<div><a target='_blank' rel='noopener noreferrer' alt='{title}' href='{url}' class='link'>Direct url</a></div>",
url=direct_url,
title=title,
)
try: try:
parsed_date = datetime.fromtimestamp(post["data"]["created_utc"]) parsed_date = datetime.fromtimestamp(post["data"]["created_utc"])
@ -146,12 +195,12 @@ class RedditBuilder(Builder):
logging.warning(f"Failed parsing timestamp from {url_fragment}") logging.warning(f"Failed parsing timestamp from {url_fragment}")
created_date = timezone.now() created_date = timezone.now()
data = { post_data = {
"remote_identifier": remote_identifier, "remote_identifier": remote_identifier,
"title": title, "title": title,
"body": body, "body": body,
"author": author, "author": author,
"url": f"{REDDIT_URL}{url_fragment}", "url": f"{REDDIT_URL}{post_url_fragment}",
"publication_date": created_date, "publication_date": created_date,
"rule": rule, "rule": rule,
} }
@ -159,13 +208,13 @@ class RedditBuilder(Builder):
if remote_identifier in self.existing_posts: if remote_identifier in self.existing_posts:
existing_post = self.existing_posts[remote_identifier] existing_post = self.existing_posts[remote_identifier]
for key, value in data.items(): for key, value in post_data.items():
setattr(existing_post, key, value) setattr(existing_post, key, value)
results[existing_post.remote_identifier] = existing_post results[existing_post.remote_identifier] = existing_post
continue continue
results[remote_identifier] = Post(**data) results[remote_identifier] = Post(**post_data)
return results.values() return results.values()
@ -271,7 +320,7 @@ class RedditClient(Client):
yield response_data yield response_data
except StreamDeniedException as e: except StreamDeniedException as e:
logger.exception( logger.warning(
f"Access token expired for user {stream.user.pk}" f"Access token expired for user {stream.user.pk}"
) )

View file

@ -12,4 +12,4 @@ class RuleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CollectionRule model = CollectionRule
fields = ("id", "name", "url", "favicon", "category", "user", "unread") fields = ("id", "type", "name", "url", "favicon", "category", "user", "unread")

View file

@ -4,9 +4,9 @@ from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.models import Post from newsreader.news.core.models import Post
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class CollectionRuleDetailViewTestCase(TestCase): class CollectionRuleDetailViewTestCase(TestCase):
@ -15,7 +15,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_simple(self): def test_simple(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-detail", args=[rule.pk]) reverse("api:news:collection:rules-detail", args=[rule.pk])
@ -29,6 +29,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertTrue("url" in data) self.assertTrue("url" in data)
self.assertTrue("favicon" in data) self.assertTrue("favicon" in data)
self.assertTrue("category" in data) self.assertTrue("category" in data)
self.assertTrue("type" in data)
def test_not_known(self): def test_not_known(self):
response = self.client.get( response = self.client.get(
@ -40,7 +41,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["detail"], "Not found.") self.assertEquals(data["detail"], "Not found.")
def test_post(self): def test_post(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.post( response = self.client.post(
reverse("api:news:collection:rules-detail", args=[rule.pk]) reverse("api:news:collection:rules-detail", args=[rule.pk])
@ -51,7 +52,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["detail"], 'Method "POST" not allowed.') self.assertEquals(data["detail"], 'Method "POST" not allowed.')
def test_patch(self): def test_patch(self):
rule = CollectionRuleFactory(name="BBC", user=self.user) rule = FeedFactory(name="BBC", user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -67,7 +68,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
old_category = CategoryFactory(user=self.user) old_category = CategoryFactory(user=self.user)
new_category = CategoryFactory(user=self.user) new_category = CategoryFactory(user=self.user)
rule = CollectionRuleFactory(name="BBC", category=old_category, user=self.user) rule = FeedFactory(name="BBC", category=old_category, user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -80,7 +81,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["category"], new_category.pk) self.assertEquals(data["category"], new_category.pk)
def test_identifier_cannot_be_changed(self): def test_identifier_cannot_be_changed(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -93,7 +94,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["id"], rule.pk) self.assertEquals(data["id"], rule.pk)
def test_category_change(self): def test_category_change(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
category = CategoryFactory(user=self.user) category = CategoryFactory(user=self.user)
response = self.client.patch( response = self.client.patch(
@ -108,7 +109,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["category"], category.pk) self.assertEquals(data["category"], category.pk)
def test_put(self): def test_put(self):
rule = CollectionRuleFactory(name="BBC", user=self.user) rule = FeedFactory(name="BBC", user=self.user)
response = self.client.put( response = self.client.put(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -121,7 +122,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(data["name"], "BBC") self.assertEquals(data["name"], "BBC")
def test_delete(self): def test_delete(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.delete( response = self.client.delete(
reverse("api:news:collection:rules-detail", args=[rule.pk]) reverse("api:news:collection:rules-detail", args=[rule.pk])
@ -132,7 +133,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
def test_rule_with_unauthenticated_user(self): def test_rule_with_unauthenticated_user(self):
self.client.logout() self.client.logout()
rule = CollectionRuleFactory(name="BBC", user=self.user) rule = FeedFactory(name="BBC", user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -144,7 +145,7 @@ class CollectionRuleDetailViewTestCase(TestCase):
def test_rule_with_unauthorized_user(self): def test_rule_with_unauthorized_user(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory(name="BBC", user=other_user) rule = FeedFactory(name="BBC", user=other_user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-detail", args=[rule.pk]), reverse("api:news:collection:rules-detail", args=[rule.pk]),
@ -155,10 +156,10 @@ class CollectionRuleDetailViewTestCase(TestCase):
self.assertEquals(response.status_code, 403) self.assertEquals(response.status_code, 403)
def test_read_count(self): def test_read_count(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
PostFactory.create_batch(size=20, read=False, rule=rule) FeedPostFactory.create_batch(size=20, read=False, rule=rule)
PostFactory.create_batch(size=20, read=True, rule=rule) FeedPostFactory.create_batch(size=20, read=True, rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-detail", args=[rule.pk]) reverse("api:news:collection:rules-detail", args=[rule.pk])
@ -175,9 +176,9 @@ class CollectionRuleReadTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_rule_read(self): def test_rule_read(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
PostFactory.create_batch(size=20, read=False, rule=rule) FeedPostFactory.create_batch(size=20, read=False, rule=rule)
response = self.client.post( response = self.client.post(
reverse("api:news:collection:rules-read", args=[rule.pk]) reverse("api:news:collection:rules-read", args=[rule.pk])
@ -197,9 +198,9 @@ class CollectionRuleReadTestCase(TestCase):
def test_unauthenticated_user(self): def test_unauthenticated_user(self):
self.client.logout() self.client.logout()
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
PostFactory.create_batch(size=20, read=False, rule=rule) FeedPostFactory.create_batch(size=20, read=False, rule=rule)
response = self.client.post( response = self.client.post(
reverse("api:news:collection:rules-read", args=[rule.pk]) reverse("api:news:collection:rules-read", args=[rule.pk])
@ -209,9 +210,9 @@ class CollectionRuleReadTestCase(TestCase):
def test_unauthorized_user(self): def test_unauthorized_user(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory(user=other_user) rule = FeedFactory(user=other_user)
PostFactory.create_batch(size=20, read=False, rule=rule) FeedPostFactory.create_batch(size=20, read=False, rule=rule)
response = self.client.post( response = self.client.post(
reverse("api:news:collection:rules-read", args=[rule.pk]) reverse("api:news:collection:rules-read", args=[rule.pk])
@ -221,7 +222,7 @@ class CollectionRuleReadTestCase(TestCase):
self.assertEquals(Post.objects.filter(read=False).count(), 20) self.assertEquals(Post.objects.filter(read=False).count(), 20)
def test_get(self): def test_get(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-read", args=[rule.pk]) reverse("api:news:collection:rules-read", args=[rule.pk])
@ -230,7 +231,7 @@ class CollectionRuleReadTestCase(TestCase):
self.assertEquals(response.status_code, 405) self.assertEquals(response.status_code, 405)
def test_patch(self): def test_patch(self):
rule = CollectionRuleFactory(name="BBC", user=self.user) rule = FeedFactory(name="BBC", user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-read", args=[rule.pk]), reverse("api:news:collection:rules-read", args=[rule.pk]),
@ -241,7 +242,7 @@ class CollectionRuleReadTestCase(TestCase):
self.assertEquals(response.status_code, 405) self.assertEquals(response.status_code, 405)
def test_put(self): def test_put(self):
rule = CollectionRuleFactory(name="BBC", user=self.user) rule = FeedFactory(name="BBC", user=self.user)
response = self.client.put( response = self.client.put(
reverse("api:news:collection:rules-read", args=[rule.pk]), reverse("api:news:collection:rules-read", args=[rule.pk]),
@ -252,7 +253,7 @@ class CollectionRuleReadTestCase(TestCase):
self.assertEquals(response.status_code, 405) self.assertEquals(response.status_code, 405)
def test_delete(self): def test_delete(self):
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.delete( response = self.client.delete(
reverse("api:news:collection:rules-read", args=[rule.pk]) reverse("api:news:collection:rules-read", args=[rule.pk])

View file

@ -8,8 +8,8 @@ from django.urls import reverse
import pytz import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class RuleListViewTestCase(TestCase): class RuleListViewTestCase(TestCase):
@ -18,7 +18,7 @@ class RuleListViewTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_simple(self): def test_simple(self):
CollectionRuleFactory.create_batch(size=3, user=self.user) FeedFactory.create_batch(size=3, user=self.user)
response = self.client.get(reverse("api:news:collection:rules-list")) response = self.client.get(reverse("api:news:collection:rules-list"))
data = response.json() data = response.json()
@ -30,19 +30,19 @@ class RuleListViewTestCase(TestCase):
def test_ordering(self): def test_ordering(self):
rules = [ rules = [
CollectionRuleFactory( FeedFactory(
created=datetime.combine( created=datetime.combine(
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
), ),
user=self.user, user=self.user,
), ),
CollectionRuleFactory( FeedFactory(
created=datetime.combine( created=datetime.combine(
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
), ),
user=self.user, user=self.user,
), ),
CollectionRuleFactory( FeedFactory(
created=datetime.combine( created=datetime.combine(
date(2019, 7, 20), time(hour=16, minute=7, second=37), pytz.utc date(2019, 7, 20), time(hour=16, minute=7, second=37), pytz.utc
), ),
@ -63,7 +63,7 @@ class RuleListViewTestCase(TestCase):
self.assertEquals(data["results"][2]["id"], rules[0].pk) self.assertEquals(data["results"][2]["id"], rules[0].pk)
def test_pagination_count(self): def test_pagination_count(self):
CollectionRuleFactory.create_batch(size=80, user=self.user) FeedFactory.create_batch(size=80, user=self.user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-list"), {"count": 30} reverse("api:news:collection:rules-list"), {"count": 30}
@ -124,7 +124,7 @@ class RuleListViewTestCase(TestCase):
def test_rules_with_unauthenticated_user(self): def test_rules_with_unauthenticated_user(self):
self.client.logout() self.client.logout()
CollectionRuleFactory.create_batch(size=3, user=self.user) FeedFactory.create_batch(size=3, user=self.user)
response = self.client.get(reverse("api:news:collection:rules-list")) response = self.client.get(reverse("api:news:collection:rules-list"))
@ -132,7 +132,7 @@ class RuleListViewTestCase(TestCase):
def test_rules_with_unauthorized_user(self): def test_rules_with_unauthorized_user(self):
other_user = UserFactory() other_user = UserFactory()
CollectionRuleFactory.create_batch(size=3, user=other_user) FeedFactory.create_batch(size=3, user=other_user)
response = self.client.get(reverse("api:news:collection:rules-list")) response = self.client.get(reverse("api:news:collection:rules-list"))
data = response.json() data = response.json()
@ -149,8 +149,8 @@ class NestedRuleListViewTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_simple(self): def test_simple(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
PostFactory.create_batch(size=5, rule=rule) FeedPostFactory.create_batch(size=5, rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}) reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
@ -164,8 +164,8 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(data["count"], 5) self.assertEquals(data["count"], 5)
def test_pagination(self): def test_pagination(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
PostFactory.create_batch(size=80, rule=rule) FeedPostFactory.create_batch(size=80, rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -178,7 +178,7 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(len(data["results"]), 30) self.assertEquals(len(data["results"]), 30)
def test_empty(self): def test_empty(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}) reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
@ -197,7 +197,7 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(response.status_code, 404) self.assertEquals(response.status_code, 404)
def test_post(self): def test_post(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
response = self.client.post( response = self.client.post(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -210,7 +210,7 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(data["detail"], 'Method "POST" not allowed.') self.assertEquals(data["detail"], 'Method "POST" not allowed.')
def test_patch(self): def test_patch(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
response = self.client.patch( response = self.client.patch(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -223,7 +223,7 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(data["detail"], 'Method "PATCH" not allowed.') self.assertEquals(data["detail"], 'Method "PATCH" not allowed.')
def test_put(self): def test_put(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
response = self.client.put( response = self.client.put(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -236,7 +236,7 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(data["detail"], 'Method "PUT" not allowed.') self.assertEquals(data["detail"], 'Method "PUT" not allowed.')
def test_delete(self): def test_delete(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
response = self.client.delete( response = self.client.delete(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -251,7 +251,7 @@ class NestedRuleListViewTestCase(TestCase):
def test_rule_with_unauthenticated_user(self): def test_rule_with_unauthenticated_user(self):
self.client.logout() self.client.logout()
rule = CollectionRuleFactory(user=self.user) rule = FeedFactory(user=self.user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}) reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
@ -261,7 +261,7 @@ class NestedRuleListViewTestCase(TestCase):
def test_rule_with_unauthorized_user(self): def test_rule_with_unauthorized_user(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory(user=other_user) rule = FeedFactory(user=other_user)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}) reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
@ -270,26 +270,24 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(response.status_code, 403) self.assertEquals(response.status_code, 403)
def test_posts_ordering(self): def test_posts_ordering(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user)
)
posts = [ posts = [
PostFactory( FeedPostFactory(
title="I'm the first post", title="I'm the first post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory( FeedPostFactory(
title="I'm the second post", title="I'm the second post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory( FeedPostFactory(
title="I'm the third post", title="I'm the third post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
@ -313,11 +311,11 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(data["results"][2]["id"], posts[0].pk) self.assertEquals(data["results"][2]["id"], posts[0].pk)
def test_only_posts_from_rule_are_returned(self): def test_only_posts_from_rule_are_returned(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
other_rule = CollectionRuleFactory.create(user=self.user) other_rule = FeedFactory.create(user=self.user)
PostFactory.create_batch(size=5, rule=rule) FeedPostFactory.create_batch(size=5, rule=rule)
PostFactory.create_batch(size=5, rule=other_rule) FeedPostFactory.create_batch(size=5, rule=other_rule)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}) reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk})
@ -334,10 +332,10 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(post["rule"], rule.pk) self.assertEquals(post["rule"], rule.pk)
def test_unread_posts(self): def test_unread_posts(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
PostFactory.create_batch(size=10, rule=rule, read=False) FeedPostFactory.create_batch(size=10, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),
@ -354,10 +352,10 @@ class NestedRuleListViewTestCase(TestCase):
self.assertEquals(post["read"], False) self.assertEquals(post["read"], False)
def test_read_posts(self): def test_read_posts(self):
rule = CollectionRuleFactory.create(user=self.user) rule = FeedFactory.create(user=self.user)
PostFactory.create_batch(size=20, rule=rule, read=False) FeedPostFactory.create_batch(size=20, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}), reverse("api:news:collection:rules-nested-posts", kwargs={"pk": rule.pk}),

View file

@ -11,7 +11,7 @@ from freezegun import freeze_time
from newsreader.news.collection.feed import FeedBuilder from newsreader.news.collection.feed import FeedBuilder
from newsreader.news.collection.tests.factories import FeedFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.models import Post from newsreader.news.core.models import Post
from newsreader.news.core.tests.factories import PostFactory from newsreader.news.core.tests.factories import FeedPostFactory
from .mocks import * from .mocks import *
@ -287,11 +287,11 @@ class FeedBuilderTestCase(TestCase):
rule = FeedFactory() rule = FeedFactory()
mock_stream = MagicMock(rule=rule) mock_stream = MagicMock(rule=rule)
existing_first_post = PostFactory.create( existing_first_post = FeedPostFactory.create(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule
) )
existing_second_post = PostFactory.create( existing_second_post = FeedPostFactory.create(
remote_identifier="a5479c66-8fae-11e9-8422-00163ef6bee7", rule=rule remote_identifier="a5479c66-8fae-11e9-8422-00163ef6bee7", rule=rule
) )

View file

@ -21,7 +21,7 @@ from newsreader.news.collection.feed import FeedCollector
from newsreader.news.collection.tests.factories import FeedFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.collection.utils import build_publication_date from newsreader.news.collection.utils import build_publication_date
from newsreader.news.core.models import Post from newsreader.news.core.models import Post
from newsreader.news.core.tests.factories import PostFactory from newsreader.news.core.tests.factories import FeedPostFactory
from .mocks import duplicate_mock, empty_mock, multiple_mock, multiple_update_mock from .mocks import duplicate_mock, empty_mock, multiple_mock, multiple_update_mock
@ -143,7 +143,7 @@ class FeedCollectorTestCase(TestCase):
struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), pytz.utc struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), pytz.utc
) )
first_post = PostFactory( first_post = FeedPostFactory(
url="https://www.bbc.co.uk/news/world-us-canada-48338168", url="https://www.bbc.co.uk/news/world-us-canada-48338168",
title="Trump's 'genocidal taunts' will not end Iran - Zarif", title="Trump's 'genocidal taunts' will not end Iran - Zarif",
body="Foreign Minister Mohammad Javad Zarif says the US " body="Foreign Minister Mohammad Javad Zarif says the US "
@ -156,7 +156,7 @@ class FeedCollectorTestCase(TestCase):
struct_time((2019, 5, 20, 12, 19, 19, 0, 140, 0)), pytz.utc struct_time((2019, 5, 20, 12, 19, 19, 0, 140, 0)), pytz.utc
) )
second_post = PostFactory( second_post = FeedPostFactory(
url="https://www.bbc.co.uk/news/technology-48334739", url="https://www.bbc.co.uk/news/technology-48334739",
title="Huawei's Android loss: How it affects you", title="Huawei's Android loss: How it affects you",
body="Google's move to end business ties with Huawei will " body="Google's move to end business ties with Huawei will "
@ -169,7 +169,7 @@ class FeedCollectorTestCase(TestCase):
struct_time((2019, 5, 20, 16, 32, 38, 0, 140, 0)), pytz.utc struct_time((2019, 5, 20, 16, 32, 38, 0, 140, 0)), pytz.utc
) )
third_post = PostFactory( third_post = FeedPostFactory(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Police are investigating the messages while an MP " body="Police are investigating the messages while an MP "
@ -194,7 +194,7 @@ class FeedCollectorTestCase(TestCase):
self.mocked_parse.return_value = multiple_update_mock self.mocked_parse.return_value = multiple_update_mock
rule = FeedFactory() rule = FeedFactory()
first_post = PostFactory( first_post = FeedPostFactory(
remote_identifier="https://www.bbc.co.uk/news/world-us-canada-48338168", remote_identifier="https://www.bbc.co.uk/news/world-us-canada-48338168",
url="https://www.bbc.co.uk/", url="https://www.bbc.co.uk/",
title="Trump", title="Trump",
@ -203,7 +203,7 @@ class FeedCollectorTestCase(TestCase):
rule=rule, rule=rule,
) )
second_post = PostFactory( second_post = FeedPostFactory(
remote_identifier="https://www.bbc.co.uk/news/technology-48334739", remote_identifier="https://www.bbc.co.uk/news/technology-48334739",
url="https://www.bbc.co.uk/", url="https://www.bbc.co.uk/",
title="Huawei's Android loss: How it affects you", title="Huawei's Android loss: How it affects you",
@ -212,7 +212,7 @@ class FeedCollectorTestCase(TestCase):
rule=rule, rule=rule,
) )
third_post = PostFactory( third_post = FeedPostFactory(
remote_identifier="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", remote_identifier="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",

View file

@ -8,7 +8,7 @@ from freezegun import freeze_time
from newsreader.news.collection.feed import FeedDuplicateHandler from newsreader.news.collection.feed import FeedDuplicateHandler
from newsreader.news.collection.tests.factories import FeedFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.models import Post from newsreader.news.core.models import Post
from newsreader.news.core.tests.factories import PostFactory from newsreader.news.core.tests.factories import FeedPostFactory
@freeze_time("2019-10-30 12:30:00") @freeze_time("2019-10-30 12:30:00")
@ -19,17 +19,17 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_duplicate_entries_with_remote_identifiers(self): def test_duplicate_entries_with_remote_identifiers(self):
rule = FeedFactory() rule = FeedFactory()
existing_post = PostFactory.create( existing_post = FeedPostFactory.create(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule
) )
new_posts = PostFactory.build_batch( new_posts = FeedPostFactory.build_batch(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now() - timedelta(days=7), publication_date=timezone.now() - timedelta(days=7),
rule=rule, rule=rule,
size=5, size=5,
) )
last_post = PostFactory.build( last_post = FeedPostFactory.build(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now(), publication_date=timezone.now(),
rule=rule, rule=rule,
@ -54,7 +54,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_duplicate_entries_with_different_remote_identifiers(self): def test_duplicate_entries_with_different_remote_identifiers(self):
rule = FeedFactory() rule = FeedFactory()
existing_post = PostFactory( existing_post = FeedPostFactory(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
url="https://bbc.com", url="https://bbc.com",
title="New post", title="New post",
@ -63,7 +63,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
) )
new_posts = PostFactory.build_batch( new_posts = FeedPostFactory.build_batch(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7Q", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7Q",
url="https://bbc.com", url="https://bbc.com",
title="New post", title="New post",
@ -72,7 +72,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
size=5, size=5,
) )
last_post = PostFactory.build( last_post = FeedPostFactory.build(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7Q", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7Q",
url="https://bbc.com", url="https://bbc.com",
title="New post", title="New post",
@ -100,7 +100,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_duplicate_entries_in_recent_database(self): def test_duplicate_entries_in_recent_database(self):
rule = FeedFactory() rule = FeedFactory()
existing_post = PostFactory( existing_post = FeedPostFactory(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -109,7 +109,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
) )
new_posts = PostFactory.build_batch( new_posts = FeedPostFactory.build_batch(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -119,7 +119,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
size=5, size=5,
) )
last_post = PostFactory.build( last_post = FeedPostFactory.build(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -147,17 +147,17 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_multiple_existing_entries_with_identifier(self): def test_multiple_existing_entries_with_identifier(self):
rule = FeedFactory() rule = FeedFactory()
PostFactory.create_batch( FeedPostFactory.create_batch(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule, size=5 remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule, size=5
) )
new_posts = PostFactory.build_batch( new_posts = FeedPostFactory.build_batch(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now() - timedelta(hours=5), publication_date=timezone.now() - timedelta(hours=5),
rule=rule, rule=rule,
size=5, size=5,
) )
last_post = PostFactory.build( last_post = FeedPostFactory.build(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now() - timedelta(minutes=5), publication_date=timezone.now() - timedelta(minutes=5),
rule=rule, rule=rule,
@ -189,7 +189,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_duplicate_entries_outside_time_slot(self): def test_duplicate_entries_outside_time_slot(self):
rule = FeedFactory() rule = FeedFactory()
existing_post = PostFactory( existing_post = FeedPostFactory(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -198,7 +198,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
) )
new_posts = PostFactory.build_batch( new_posts = FeedPostFactory.build_batch(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -207,7 +207,7 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
size=5, size=5,
) )
last_post = PostFactory.build( last_post = FeedPostFactory.build(
url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080",
title="Birmingham head teacher threatened over LGBT lessons", title="Birmingham head teacher threatened over LGBT lessons",
body="Google's move to end business ties with Huawei will affect current devices", body="Google's move to end business ties with Huawei will affect current devices",
@ -235,14 +235,14 @@ class FeedDuplicateHandlerTestCase(TestCase):
def test_duplicate_entries_in_collected_entries(self): def test_duplicate_entries_in_collected_entries(self):
rule = FeedFactory() rule = FeedFactory()
post_1 = PostFactory.build( post_1 = FeedPostFactory.build(
title="title got updated", title="title got updated",
body="body", body="body",
url="https://bbc.com", url="https://bbc.com",
publication_date=timezone.now(), publication_date=timezone.now(),
rule=rule, rule=rule,
) )
duplicate_post_1 = PostFactory.build( duplicate_post_1 = FeedPostFactory.build(
title="title got updated", title="title got updated",
body="body", body="body",
url="https://bbc.com", url="https://bbc.com",
@ -250,11 +250,11 @@ class FeedDuplicateHandlerTestCase(TestCase):
rule=rule, rule=rule,
) )
post_2 = PostFactory.build( post_2 = FeedPostFactory.build(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now(), publication_date=timezone.now(),
) )
duplicate_post_2 = PostFactory.build( duplicate_post_2 = FeedPostFactory.build(
remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7",
publication_date=timezone.now() - timedelta(minutes=5), publication_date=timezone.now() - timedelta(minutes=5),
) )

File diff suppressed because it is too large Load diff

View file

@ -86,7 +86,7 @@ class RedditBuilderTestCase(TestCase):
def test_update_posts(self): def test_update_posts(self):
subreddit = SubredditFactory() subreddit = SubredditFactory()
existing_post = RedditPostFactory( existing_post = RedditPostFactory(
remote_identifier="hngsj8", remote_identifier="hm0qct",
author="Old author", author="Old author",
title="Old title", title="Old title",
body="Old body", body="Old body",
@ -108,17 +108,24 @@ class RedditBuilderTestCase(TestCase):
existing_post.refresh_from_db() existing_post.refresh_from_db()
self.assertEquals(existing_post.remote_identifier, "hngsj8") self.assertEquals(existing_post.remote_identifier, "hm0qct")
self.assertEquals(existing_post.author, "nixcraft") self.assertEquals(existing_post.author, "AutoModerator")
self.assertEquals(existing_post.title, "KeePassXC 2.6.0 released") self.assertEquals(
self.assertEquals(existing_post.body, "") existing_post.title,
"Linux Experiences/Rants or Education/Certifications thread - July 06, 2020",
)
self.assertIn(
"This megathread is also to hear opinions from anyone just starting out "
"with Linux or those that have used Linux (GNU or otherwise) for a long time.",
existing_post.body,
)
self.assertEquals( self.assertEquals(
existing_post.publication_date, existing_post.publication_date,
pytz.utc.localize(datetime(2020, 7, 8, 15, 11, 6)), pytz.utc.localize(datetime(2020, 7, 6, 6, 11, 22)),
) )
self.assertEquals( self.assertEquals(
existing_post.url, existing_post.url,
"https://www.reddit.com/r/linux/comments/hngsj8/" "keepassxc_260_released/", "https://www.reddit.com/r/linux/comments/hm0qct/linux_experiencesrants_or_educationcertifications/",
) )
def test_html_sanitizing(self): def test_html_sanitizing(self):
@ -219,3 +226,183 @@ class RedditBuilderTestCase(TestCase):
duplicate_post.title, duplicate_post.title,
"Linux Experiences/Rants or Education/Certifications thread - July 06, 2020", "Linux Experiences/Rants or Education/Certifications thread - July 06, 2020",
) )
def test_image_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((image_mock, mock_stream)) as builder:
builder.save()
posts = {post.remote_identifier: post for post in Post.objects.all()}
self.assertCountEqual(("hr64xh", "hr4bxo", "hr14y5", "hr2fv0"), posts.keys())
post = posts["hr64xh"]
title = (
"Yall, I just cant... this is my "
"son, Judah. My wife and I have no "
"idea how we created such a "
"beautiful child."
)
url = "https://i.redd.it/cm2qybia1va51.jpg"
self.assertEquals(
"https://www.reddit.com/r/aww/comments/hr64xh/yall_i_just_cant_this_is_my_son_judah_my_wife_and/",
post.url,
)
self.assertEquals(
f"<div><img alt='{title}' src='{url}' loading='lazy' /></div>", post.body
)
def test_external_image_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((external_image_mock, mock_stream)) as builder:
builder.save()
posts = {post.remote_identifier: post for post in Post.objects.all()}
self.assertCountEqual(("hr41am", "huoldn"), posts.keys())
post = posts["hr41am"]
url = "http://gfycat.com/thatalivedogwoodclubgall"
title = "Excited cows have a new brush!"
self.assertEquals(
f"<div><a target='_blank' rel='noopener noreferrer' alt='{title}' href='{url}' class='link'>Direct url</a></div>",
post.body,
)
self.assertEquals(
"https://www.reddit.com/r/aww/comments/hr41am/excited_cows_have_a_new_brush/",
post.url,
)
post = posts["huoldn"]
url = "https://i.imgur.com/usfMVUJ.jpg"
title = "Novosibirsk Zoo welcomes 16 cobalt-eyed Pallass cat kittens"
self.assertEquals(
f"<div><img alt='{title}' src='{url}' loading='lazy' /></div>", post.body
)
self.assertEquals(
"https://www.reddit.com/r/aww/comments/huoldn/novosibirsk_zoo_welcomes_16_cobalteyed_pallass/",
post.url,
)
def test_video_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((video_mock, mock_stream)) as builder:
builder.save()
posts = {post.remote_identifier: post for post in Post.objects.all()}
self.assertCountEqual(("hr32jf", "hr1r00", "hqy0ny", "hr0uzh"), posts.keys())
post = posts["hr1r00"]
url = "https://v.redd.it/eyvbxaeqtta51/DASH_480.mp4?source=fallback"
self.assertEquals(
post.url,
"https://www.reddit.com/r/aww/comments/hr1r00/cool_catt_and_his_clingy_girlfriend/",
)
self.assertEquals(
f"<div><video controls muted><source src='{url}' type='video/mp4' /></video></div>",
post.body,
)
def test_external_video_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((external_video_mock, mock_stream)) as builder:
builder.save()
post = Post.objects.get()
self.assertEquals(post.remote_identifier, "hulh8k")
self.assertEquals(
post.url,
"https://www.reddit.com/r/aww/comments/hulh8k/dog_splashing_in_water/",
)
title = "Dog splashing in water"
url = "https://gfycat.com/excellentinfantileamericanwigeon"
self.assertEquals(
f"<div><a target='_blank' rel='noopener noreferrer' alt='{title}' href='{url}' class='link'>Direct url</a></div>",
post.body,
)
def test_external_gifv_video_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((external_gifv_mock, mock_stream)) as builder:
builder.save()
post = Post.objects.get()
self.assertEquals(post.remote_identifier, "humdlf")
self.assertEquals(
post.url, "https://www.reddit.com/r/aww/comments/humdlf/if_i_fits_i_sits/"
)
self.assertEquals(
"<div><video controls muted><source src='https://i.imgur.com/grVh2AG.mp4' type='video/mp4' /></video></div>",
post.body,
)
def test_link_only_post(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((simple_mock, mock_stream)) as builder:
builder.save()
post = Post.objects.get(remote_identifier="hngsj8")
title = "KeePassXC 2.6.0 released"
url = "https://keepassxc.org/blog/2020-07-07-2.6.0-released/"
self.assertIn(
f"<div><a target='_blank' rel='noopener noreferrer' alt='{title}' href='{url}' class='link'>Direct url</a></div>",
post.body,
)
self.assertEquals(
post.url,
"https://www.reddit.com/r/linux/comments/hngsj8/keepassxc_260_released/",
)
def test_skip_not_known_post_type(self):
builder = RedditBuilder
subreddit = SubredditFactory()
mock_stream = MagicMock(rule=subreddit)
with builder((unknown_mock, mock_stream)) as builder:
builder.save()
self.assertEquals(Post.objects.count(), 0)

View file

@ -1,11 +1,12 @@
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _
import pytz import pytz
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.models import CollectionRule from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.reddit import REDDIT_URL from newsreader.news.collection.reddit import REDDIT_API_URL, REDDIT_URL
from newsreader.news.collection.tests.factories import SubredditFactory from newsreader.news.collection.tests.factories import SubredditFactory
from newsreader.news.collection.tests.views.base import CollectionRuleViewTestCase from newsreader.news.collection.tests.views.base import CollectionRuleViewTestCase
from newsreader.news.core.tests.factories import CategoryFactory from newsreader.news.core.tests.factories import CategoryFactory
@ -17,7 +18,7 @@ class SubRedditCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.form_data = { self.form_data = {
"name": "new rule", "name": "new rule",
"url": "https://www.reddit.com/r/aww", "url": f"{REDDIT_API_URL}/r/aww",
"category": str(self.category.pk), "category": str(self.category.pk),
} }
@ -31,12 +32,19 @@ class SubRedditCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
rule = CollectionRule.objects.get(name="new rule") rule = CollectionRule.objects.get(name="new rule")
self.assertEquals(rule.type, RuleTypeChoices.subreddit) self.assertEquals(rule.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, "https://www.reddit.com/r/aww.json") self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww")
self.assertEquals(rule.timezone, str(pytz.utc)) self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.favicon, None) self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk) self.assertEquals(rule.user.pk, self.user.pk)
def test_regular_reddit_url(self):
self.form_data.update(url=f"{REDDIT_URL}/r/aww")
response = self.client.post(self.url, self.form_data)
self.assertContains(response, _("This does not look like an Reddit API URL"))
class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase): class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
def setUp(self): def setUp(self):
@ -44,7 +52,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.rule = SubredditFactory( self.rule = SubredditFactory(
name="Python", name="Python",
url=f"{REDDIT_URL}/r/python.json", url=f"{REDDIT_API_URL}/r/python.json",
user=self.user, user=self.user,
category=self.category, category=self.category,
type=RuleTypeChoices.subreddit, type=RuleTypeChoices.subreddit,
@ -97,7 +105,7 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(response.status_code, 404) self.assertEquals(response.status_code, 404)
def test_url_change(self): def test_url_change(self):
self.form_data.update(name="aww", url=f"{REDDIT_URL}/r/aww") self.form_data.update(name="aww", url=f"{REDDIT_API_URL}/r/aww")
response = self.client.post(self.url, self.form_data) response = self.client.post(self.url, self.form_data)
@ -106,8 +114,15 @@ class SubRedditUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
rule = CollectionRule.objects.get(name="aww") rule = CollectionRule.objects.get(name="aww")
self.assertEquals(rule.type, RuleTypeChoices.subreddit) self.assertEquals(rule.type, RuleTypeChoices.subreddit)
self.assertEquals(rule.url, f"{REDDIT_URL}/r/aww.json") self.assertEquals(rule.url, f"{REDDIT_API_URL}/r/aww")
self.assertEquals(rule.timezone, str(pytz.utc)) self.assertEquals(rule.timezone, str(pytz.utc))
self.assertEquals(rule.favicon, None) self.assertEquals(rule.favicon, None)
self.assertEquals(rule.category.pk, self.category.pk) self.assertEquals(rule.category.pk, self.category.pk)
self.assertEquals(rule.user.pk, self.user.pk) self.assertEquals(rule.user.pk, self.user.pk)
def test_regular_reddit_url(self):
self.form_data.update(url=f"{REDDIT_URL}/r/aww")
response = self.client.post(self.url, self.form_data)
self.assertContains(response, _("This does not look like an Reddit API URL"))

View file

@ -4,8 +4,8 @@ from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class CategoryDetailViewTestCase(TestCase): class CategoryDetailViewTestCase(TestCase):
@ -116,11 +116,11 @@ class CategoryDetailViewTestCase(TestCase):
def test_read_count(self): def test_read_count(self):
category = CategoryFactory(user=self.user) category = CategoryFactory(user=self.user)
unread_rule = CollectionRuleFactory(category=category) unread_rule = FeedFactory(category=category)
read_rule = CollectionRuleFactory(category=category) read_rule = FeedFactory(category=category)
PostFactory.create_batch(size=20, read=False, rule=unread_rule) FeedPostFactory.create_batch(size=20, read=False, rule=unread_rule)
PostFactory.create_batch(size=20, read=True, rule=read_rule) FeedPostFactory.create_batch(size=20, read=True, rule=read_rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:categories-detail", args=[category.pk]) reverse("api:news:core:categories-detail", args=[category.pk])
@ -139,8 +139,8 @@ class CategoryReadTestCase(TestCase):
def test_category_read(self): def test_category_read(self):
category = CategoryFactory(user=self.user) category = CategoryFactory(user=self.user)
rules = [ rules = [
PostFactory.create_batch(size=5, read=False, rule=rule) FeedPostFactory.create_batch(size=5, read=False, rule=rule)
for rule in CollectionRuleFactory.create_batch(size=5, category=category) for rule in FeedFactory.create_batch(size=5, category=category)
] ]
response = self.client.post( response = self.client.post(
@ -165,8 +165,8 @@ class CategoryReadTestCase(TestCase):
category = CategoryFactory(user=self.user) category = CategoryFactory(user=self.user)
rules = [ rules = [
PostFactory.create_batch(size=5, read=False, rule=rule) FeedPostFactory.create_batch(size=5, read=False, rule=rule)
for rule in CollectionRuleFactory.create_batch( for rule in FeedFactory.create_batch(
size=5, category=category, user=self.user size=5, category=category, user=self.user
) )
] ]
@ -182,8 +182,8 @@ class CategoryReadTestCase(TestCase):
category = CategoryFactory(user=other_user) category = CategoryFactory(user=other_user)
rules = [ rules = [
PostFactory.create_batch(size=5, read=False, rule=rule) FeedPostFactory.create_batch(size=5, read=False, rule=rule)
for rule in CollectionRuleFactory.create_batch( for rule in FeedFactory.create_batch(
size=5, category=category, user=other_user size=5, category=category, user=other_user
) )
] ]

View file

@ -8,8 +8,8 @@ from django.urls import reverse
import pytz import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class CategoryListViewTestCase(TestCase): class CategoryListViewTestCase(TestCase):
@ -125,7 +125,7 @@ class NestedCategoryListViewTestCase(TestCase):
def test_simple(self): def test_simple(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = CollectionRuleFactory.create_batch(size=5, category=category) rules = FeedFactory.create_batch(size=5, category=category)
response = self.client.get( response = self.client.get(
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
@ -219,7 +219,7 @@ class NestedCategoryListViewTestCase(TestCase):
self.client.logout() self.client.logout()
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = CollectionRuleFactory.create_batch(size=5, category=category) rules = FeedFactory.create_batch(size=5, category=category)
response = self.client.get( response = self.client.get(
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
@ -231,7 +231,7 @@ class NestedCategoryListViewTestCase(TestCase):
other_user = UserFactory.create() other_user = UserFactory.create()
category = CategoryFactory.create(user=other_user) category = CategoryFactory.create(user=other_user)
rules = CollectionRuleFactory.create_batch(size=5, category=category) rules = FeedFactory.create_batch(size=5, category=category)
response = self.client.get( response = self.client.get(
reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk})
@ -242,9 +242,9 @@ class NestedCategoryListViewTestCase(TestCase):
def test_ordering(self): def test_ordering(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = [ rules = [
CollectionRuleFactory.create(category=category, name="Durp"), FeedFactory.create(category=category, name="Durp"),
CollectionRuleFactory.create(category=category, name="Slurp"), FeedFactory.create(category=category, name="Slurp"),
CollectionRuleFactory.create(category=category, name="Burp"), FeedFactory.create(category=category, name="Burp"),
] ]
response = self.client.get( response = self.client.get(
@ -261,13 +261,13 @@ class NestedCategoryListViewTestCase(TestCase):
def test_only_rules_from_category_are_returned(self): def test_only_rules_from_category_are_returned(self):
other_category = CategoryFactory(user=self.user) other_category = CategoryFactory(user=self.user)
CollectionRuleFactory.create_batch(size=5, category=other_category) FeedFactory.create_batch(size=5, category=other_category)
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = [ rules = [
CollectionRuleFactory.create(category=category, name="Durp"), FeedFactory.create(category=category, name="Durp"),
CollectionRuleFactory.create(category=category, name="Slurp"), FeedFactory.create(category=category, name="Slurp"),
CollectionRuleFactory.create(category=category, name="Burp"), FeedFactory.create(category=category, name="Burp"),
] ]
response = self.client.get( response = self.client.get(
@ -291,8 +291,8 @@ class NestedCategoryPostView(TestCase):
def test_simple(self): def test_simple(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = { rules = {
rule.pk: PostFactory.create_batch(size=5, rule=rule) rule.pk: FeedPostFactory.create_batch(size=5, rule=rule)
for rule in CollectionRuleFactory.create_batch( for rule in FeedFactory.create_batch(
size=5, category=category, user=self.user size=5, category=category, user=self.user
) )
} }
@ -327,9 +327,7 @@ class NestedCategoryPostView(TestCase):
def test_no_posts(self): def test_no_posts(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rules = CollectionRuleFactory.create_batch( rules = FeedFactory.create_batch(size=5, user=self.user, category=category)
size=5, user=self.user, category=category
)
response = self.client.get( response = self.client.get(
reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk}) reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk})
@ -427,25 +425,23 @@ class NestedCategoryPostView(TestCase):
def test_ordering(self): def test_ordering(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
bbc_rule = CollectionRuleFactory.create( bbc_rule = FeedFactory.create(name="BBC", category=category, user=self.user)
name="BBC", category=category, user=self.user guardian_rule = FeedFactory.create(
)
guardian_rule = CollectionRuleFactory.create(
name="The Guardian", category=category, user=self.user name="The Guardian", category=category, user=self.user
) )
reuters_rule = CollectionRuleFactory.create( reuters_rule = FeedFactory.create(
name="Reuters", category=category, user=self.user name="Reuters", category=category, user=self.user
) )
reuters_rule = [ reuters_rule = [
PostFactory.create( FeedPostFactory.create(
title="Second Reuters post", title="Second Reuters post",
rule=reuters_rule, rule=reuters_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory.create( FeedPostFactory.create(
title="First Reuters post", title="First Reuters post",
rule=reuters_rule, rule=reuters_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
@ -455,14 +451,14 @@ class NestedCategoryPostView(TestCase):
] ]
guardian_posts = [ guardian_posts = [
PostFactory.create( FeedPostFactory.create(
title="Second Guardian post", title="Second Guardian post",
rule=guardian_rule, rule=guardian_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory.create( FeedPostFactory.create(
title="First Guardian post", title="First Guardian post",
rule=guardian_rule, rule=guardian_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
@ -472,14 +468,14 @@ class NestedCategoryPostView(TestCase):
] ]
bbc_posts = [ bbc_posts = [
PostFactory.create( FeedPostFactory.create(
title="Second BBC post", title="Second BBC post",
rule=bbc_rule, rule=bbc_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 21), time(hour=16, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory.create( FeedPostFactory.create(
title="First BBC post", title="First BBC post",
rule=bbc_rule, rule=bbc_rule,
publication_date=datetime.combine( publication_date=datetime.combine(
@ -509,19 +505,19 @@ class NestedCategoryPostView(TestCase):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
other_category = CategoryFactory.create(user=self.user) other_category = CategoryFactory.create(user=self.user)
guardian_rule = CollectionRuleFactory.create( guardian_rule = FeedFactory.create(
name="BBC", category=category, user=self.user name="BBC", category=category, user=self.user
) )
other_rule = CollectionRuleFactory.create(name="The Guardian", user=self.user) other_rule = FeedFactory.create(name="The Guardian", user=self.user)
guardian_posts = [ guardian_posts = [
PostFactory.create(rule=guardian_rule), FeedPostFactory.create(rule=guardian_rule),
PostFactory.create(rule=guardian_rule), FeedPostFactory.create(rule=guardian_rule),
] ]
other_posts = [ other_posts = [
PostFactory.create(rule=other_rule), FeedPostFactory.create(rule=other_rule),
PostFactory.create(rule=other_rule), FeedPostFactory.create(rule=other_rule),
] ]
response = self.client.get( response = self.client.get(
@ -538,10 +534,10 @@ class NestedCategoryPostView(TestCase):
def test_unread_posts(self): def test_unread_posts(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rule = CollectionRuleFactory(category=category) rule = FeedFactory(category=category)
PostFactory.create_batch(size=10, rule=rule, read=False) FeedPostFactory.create_batch(size=10, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse( reverse(
@ -561,10 +557,10 @@ class NestedCategoryPostView(TestCase):
def test_read_posts(self): def test_read_posts(self):
category = CategoryFactory.create(user=self.user) category = CategoryFactory.create(user=self.user)
rule = CollectionRuleFactory(category=category) rule = FeedFactory(category=category)
PostFactory.create_batch(size=20, rule=rule, read=False) FeedPostFactory.create_batch(size=20, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse( reverse(

View file

@ -4,8 +4,8 @@ from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class PostDetailViewTestCase(TestCase): class PostDetailViewTestCase(TestCase):
@ -14,10 +14,8 @@ class PostDetailViewTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_simple(self): def test_simple(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -43,10 +41,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["detail"], "Not found.") self.assertEquals(data["detail"], "Not found.")
def test_post(self): def test_post(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.post( response = self.client.post(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -57,10 +53,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["detail"], 'Method "POST" not allowed.') self.assertEquals(data["detail"], 'Method "POST" not allowed.')
def test_patch(self): def test_patch(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(title="This is clickbait for sure", rule=rule)
)
post = PostFactory(title="This is clickbait for sure", rule=rule)
response = self.client.patch( response = self.client.patch(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),
@ -73,10 +67,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["title"], "This title is very accurate") self.assertEquals(data["title"], "This title is very accurate")
def test_identifier_cannot_be_changed(self): def test_identifier_cannot_be_changed(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(title="This is clickbait for sure", rule=rule)
)
post = PostFactory(title="This is clickbait for sure", rule=rule)
response = self.client.patch( response = self.client.patch(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),
@ -89,13 +81,9 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["id"], post.pk) self.assertEquals(data["id"], post.pk)
def test_rule_cannot_be_changed(self): def test_rule_cannot_be_changed(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) new_rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
) post = FeedPostFactory(title="This is clickbait for sure", rule=rule)
new_rule = CollectionRuleFactory(
user=self.user, category=CategoryFactory(user=self.user)
)
post = PostFactory(title="This is clickbait for sure", rule=rule)
response = self.client.patch( response = self.client.patch(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),
@ -115,10 +103,8 @@ class PostDetailViewTestCase(TestCase):
self.assertTrue(data["rule"], rule.pk) self.assertTrue(data["rule"], rule.pk)
def test_put(self): def test_put(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(title="This is clickbait for sure", rule=rule)
)
post = PostFactory(title="This is clickbait for sure", rule=rule)
response = self.client.put( response = self.client.put(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),
@ -131,10 +117,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["title"], "This title is very accurate") self.assertEquals(data["title"], "This title is very accurate")
def test_delete(self): def test_delete(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.delete( response = self.client.delete(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -147,8 +131,8 @@ class PostDetailViewTestCase(TestCase):
def test_post_with_unauthenticated_user_without_category(self): def test_post_with_unauthenticated_user_without_category(self):
self.client.logout() self.client.logout()
rule = CollectionRuleFactory(user=self.user, category=None) rule = FeedFactory(user=self.user, category=None)
post = PostFactory(rule=rule) post = FeedPostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -159,10 +143,8 @@ class PostDetailViewTestCase(TestCase):
def test_post_with_unauthenticated_user_with_category(self): def test_post_with_unauthenticated_user_with_category(self):
self.client.logout() self.client.logout()
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -172,8 +154,8 @@ class PostDetailViewTestCase(TestCase):
def test_post_with_unauthorized_user_without_category(self): def test_post_with_unauthorized_user_without_category(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory(user=other_user, category=None) rule = FeedFactory(user=other_user, category=None)
post = PostFactory(rule=rule) post = FeedPostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -183,10 +165,8 @@ class PostDetailViewTestCase(TestCase):
def test_post_with_unauthorized_user_with_category(self): def test_post_with_unauthorized_user_with_category(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory( rule = FeedFactory(user=other_user, category=CategoryFactory(user=other_user))
user=other_user, category=CategoryFactory(user=other_user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -196,10 +176,8 @@ class PostDetailViewTestCase(TestCase):
def test_post_with_different_user_for_category_and_rule(self): def test_post_with_different_user_for_category_and_rule(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=other_user))
user=self.user, category=CategoryFactory(user=other_user) post = FeedPostFactory(rule=rule)
)
post = PostFactory(rule=rule)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-detail", args=[post.pk]) reverse("api:news:core:posts-detail", args=[post.pk])
@ -208,10 +186,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(response.status_code, 403) self.assertEquals(response.status_code, 403)
def test_mark_read(self): def test_mark_read(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule, read=False)
)
post = PostFactory(rule=rule, read=False)
response = self.client.patch( response = self.client.patch(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),
@ -224,10 +200,8 @@ class PostDetailViewTestCase(TestCase):
self.assertEquals(data["read"], True) self.assertEquals(data["read"], True)
def test_mark_unread(self): def test_mark_unread(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) post = FeedPostFactory(rule=rule, read=True)
)
post = PostFactory(rule=rule, read=True)
response = self.client.patch( response = self.client.patch(
reverse("api:news:core:posts-detail", args=[post.pk]), reverse("api:news:core:posts-detail", args=[post.pk]),

View file

@ -6,8 +6,8 @@ from django.urls import reverse
import pytz import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.tests.factories import CollectionRuleFactory from newsreader.news.collection.tests.factories import FeedFactory
from newsreader.news.core.tests.factories import CategoryFactory, PostFactory from newsreader.news.core.tests.factories import CategoryFactory, FeedPostFactory
class PostListViewTestCase(TestCase): class PostListViewTestCase(TestCase):
@ -16,10 +16,8 @@ class PostListViewTestCase(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
def test_simple(self): def test_simple(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) FeedPostFactory.create_batch(size=3, rule=rule)
)
PostFactory.create_batch(size=3, rule=rule)
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
data = response.json() data = response.json()
@ -30,26 +28,24 @@ class PostListViewTestCase(TestCase):
self.assertEquals(data["count"], 3) self.assertEquals(data["count"], 3)
def test_ordering(self): def test_ordering(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user)
)
posts = [ posts = [
PostFactory( FeedPostFactory(
title="I'm the first post", title="I'm the first post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc date(2019, 5, 20), time(hour=16, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory( FeedPostFactory(
title="I'm the second post", title="I'm the second post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc date(2019, 7, 20), time(hour=18, minute=7, second=37), pytz.utc
), ),
), ),
PostFactory( FeedPostFactory(
title="I'm the third post", title="I'm the third post",
rule=rule, rule=rule,
publication_date=datetime.combine( publication_date=datetime.combine(
@ -71,10 +67,8 @@ class PostListViewTestCase(TestCase):
self.assertEquals(data["results"][2]["id"], posts[0].pk) self.assertEquals(data["results"][2]["id"], posts[0].pk)
def test_pagination_count(self): def test_pagination_count(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user) FeedPostFactory.create_batch(size=80, rule=rule)
)
PostFactory.create_batch(size=80, rule=rule)
page_size = 50 page_size = 50
response = self.client.get(reverse("api:news:core:posts-list"), {"count": 50}) response = self.client.get(reverse("api:news:core:posts-list"), {"count": 50})
@ -126,7 +120,7 @@ class PostListViewTestCase(TestCase):
def test_posts_with_unauthenticated_user_without_category(self): def test_posts_with_unauthenticated_user_without_category(self):
self.client.logout() self.client.logout()
PostFactory.create_batch(size=3, rule=CollectionRuleFactory(user=self.user)) FeedPostFactory.create_batch(size=3, rule=FeedFactory(user=self.user))
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
@ -137,8 +131,8 @@ class PostListViewTestCase(TestCase):
category = CategoryFactory(user=self.user) category = CategoryFactory(user=self.user)
PostFactory.create_batch( FeedPostFactory.create_batch(
size=3, rule=CollectionRuleFactory(user=self.user, category=category) size=3, rule=FeedFactory(user=self.user, category=category)
) )
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
@ -148,8 +142,8 @@ class PostListViewTestCase(TestCase):
def test_posts_with_unauthorized_user_without_category(self): def test_posts_with_unauthorized_user_without_category(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory(user=other_user, category=None) rule = FeedFactory(user=other_user, category=None)
PostFactory.create_batch(size=3, rule=rule) FeedPostFactory.create_batch(size=3, rule=rule)
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
data = response.json() data = response.json()
@ -162,8 +156,8 @@ class PostListViewTestCase(TestCase):
other_user = UserFactory() other_user = UserFactory()
category = CategoryFactory(user=other_user) category = CategoryFactory(user=other_user)
PostFactory.create_batch( FeedPostFactory.create_batch(
size=3, rule=CollectionRuleFactory(user=other_user, category=category) size=3, rule=FeedFactory(user=other_user, category=category)
) )
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
@ -178,10 +172,8 @@ class PostListViewTestCase(TestCase):
def test_posts_with_authorized_rule_unauthorized_category(self): def test_posts_with_authorized_rule_unauthorized_category(self):
other_user = UserFactory() other_user = UserFactory()
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=other_user))
user=self.user, category=CategoryFactory(user=other_user) FeedPostFactory.create_batch(size=3, rule=rule)
)
PostFactory.create_batch(size=3, rule=rule)
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
data = response.json() data = response.json()
@ -192,8 +184,8 @@ class PostListViewTestCase(TestCase):
self.assertEquals(data["count"], 0) self.assertEquals(data["count"], 0)
def test_posts_with_authorized_user_without_category(self): def test_posts_with_authorized_user_without_category(self):
rule = CollectionRuleFactory(user=self.user, category=None) rule = FeedFactory(user=self.user, category=None)
PostFactory.create_batch(size=3, rule=rule) FeedPostFactory.create_batch(size=3, rule=rule)
response = self.client.get(reverse("api:news:core:posts-list")) response = self.client.get(reverse("api:news:core:posts-list"))
data = response.json() data = response.json()
@ -204,12 +196,10 @@ class PostListViewTestCase(TestCase):
self.assertEquals(data["count"], 3) self.assertEquals(data["count"], 3)
def test_unread_posts(self): def test_unread_posts(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user)
)
PostFactory.create_batch(size=10, rule=rule, read=False) FeedPostFactory.create_batch(size=10, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-list"), {"read": "false"} reverse("api:news:core:posts-list"), {"read": "false"}
@ -225,12 +215,10 @@ class PostListViewTestCase(TestCase):
self.assertEquals(post["read"], False) self.assertEquals(post["read"], False)
def test_read_posts(self): def test_read_posts(self):
rule = CollectionRuleFactory( rule = FeedFactory(user=self.user, category=CategoryFactory(user=self.user))
user=self.user, category=CategoryFactory(user=self.user)
)
PostFactory.create_batch(size=20, rule=rule, read=False) FeedPostFactory.create_batch(size=20, rule=rule, read=False)
PostFactory.create_batch(size=10, rule=rule, read=True) FeedPostFactory.create_batch(size=10, rule=rule, read=True)
response = self.client.get( response = self.client.get(
reverse("api:news:core:posts-list"), {"read": "true"} reverse("api:news:core:posts-list"), {"read": "true"}

View file

@ -3,7 +3,7 @@ import factory.fuzzy
import pytz import pytz
from newsreader.accounts.tests.factories import UserFactory from newsreader.accounts.tests.factories import UserFactory
from newsreader.news.collection.reddit import REDDIT_URL from newsreader.news.collection.reddit import REDDIT_API_URL
from newsreader.news.core.models import Category, Post from newsreader.news.core.models import Category, Post
@ -33,9 +33,12 @@ class PostFactory(factory.django.DjangoModelFactory):
model = Post model = Post
class FeedPostFactory(PostFactory):
rule = factory.SubFactory("newsreader.news.collection.tests.factories.FeedFactory")
class RedditPostFactory(PostFactory): class RedditPostFactory(PostFactory):
remote_identifier = factory.Faker("uuid4") url = factory.fuzzy.FuzzyText(length=10, prefix=f"{REDDIT_API_URL}/")
url = factory.fuzzy.FuzzyText(length=10, prefix=f"{REDDIT_URL}/")
rule = factory.SubFactory( rule = factory.SubFactory(
"newsreader.news.collection.tests.factories.SubredditFactory" "newsreader.news.collection.tests.factories.SubredditFactory"
) )

View file

@ -68,14 +68,9 @@
margin: 20px 0 5px 0; margin: 20px 0 5px 0;
} }
& img { & img, video {
padding: 10px 10px 30px 10px; padding: 10px 0;
max-width: 100%;
max-width: 70%;
width: inherit;
height: 100%;
align-self: center;
} }
} }