0.2.3 #99
15 changed files with 95 additions and 30 deletions
|
|
@ -11,6 +11,7 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelManagers(
|
migrations.AlterModelManagers(
|
||||||
name="user", managers=[("objects", newsreader.accounts.models.UserManager())]
|
name="user",
|
||||||
|
managers=[("objects", newsreader.accounts.models.UserManager())],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ urlpatterns = [
|
||||||
path("logout/", LogoutView.as_view(), name="logout"),
|
path("logout/", LogoutView.as_view(), name="logout"),
|
||||||
path("register/", RegistrationView.as_view(), name="register"),
|
path("register/", RegistrationView.as_view(), name="register"),
|
||||||
path(
|
path(
|
||||||
"register/complete/", RegistrationCompleteView.as_view(), name="register-complete"
|
"register/complete/",
|
||||||
|
RegistrationCompleteView.as_view(),
|
||||||
|
name="register-complete",
|
||||||
),
|
),
|
||||||
path("register/closed/", RegistrationClosedView.as_view(), name="register-closed"),
|
path("register/closed/", RegistrationClosedView.as_view(), name="register-closed"),
|
||||||
path(
|
path(
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,12 @@ from newsreader.news.collection.exceptions import StreamException
|
||||||
from newsreader.news.collection.feed import FeedClient
|
from newsreader.news.collection.feed import FeedClient
|
||||||
|
|
||||||
|
|
||||||
LINK_RELS = ["icon", "shortcut icon", "apple-touch-icon", "apple-touch-icon-precomposed"]
|
LINK_RELS = [
|
||||||
|
"icon",
|
||||||
|
"shortcut icon",
|
||||||
|
"apple-touch-icon",
|
||||||
|
"apple-touch-icon-precomposed",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class FaviconBuilder(Builder):
|
class FaviconBuilder(Builder):
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ import pytz
|
||||||
from feedparser import parse
|
from feedparser import parse
|
||||||
|
|
||||||
from newsreader.news.collection.base import Builder, Client, Collector, Stream
|
from newsreader.news.collection.base import Builder, Client, Collector, Stream
|
||||||
from newsreader.news.collection.constants import WHITELISTED_ATTRIBUTES, WHITELISTED_TAGS
|
from newsreader.news.collection.constants import (
|
||||||
|
WHITELISTED_ATTRIBUTES,
|
||||||
|
WHITELISTED_TAGS,
|
||||||
|
)
|
||||||
from newsreader.news.collection.exceptions import (
|
from newsreader.news.collection.exceptions import (
|
||||||
StreamDeniedException,
|
StreamDeniedException,
|
||||||
StreamException,
|
StreamException,
|
||||||
|
|
@ -30,7 +33,8 @@ class FeedBuilder(Builder):
|
||||||
_, stream = self.stream
|
_, stream = self.stream
|
||||||
self.instances = []
|
self.instances = []
|
||||||
self.existing_posts = {
|
self.existing_posts = {
|
||||||
post.remote_identifier: post for post in Post.objects.filter(rule=stream.rule)
|
post.remote_identifier: post
|
||||||
|
for post in Post.objects.filter(rule=stream.rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
return super().__enter__()
|
return super().__enter__()
|
||||||
|
|
|
||||||
|
|
@ -112,15 +112,24 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
|
("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
|
||||||
("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
|
("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
|
||||||
("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"),
|
(
|
||||||
|
"America/Argentina/La_Rioja",
|
||||||
|
"America/Argentina/La_Rioja",
|
||||||
|
),
|
||||||
("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
|
("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
|
||||||
(
|
(
|
||||||
"America/Argentina/Rio_Gallegos",
|
"America/Argentina/Rio_Gallegos",
|
||||||
"America/Argentina/Rio_Gallegos",
|
"America/Argentina/Rio_Gallegos",
|
||||||
),
|
),
|
||||||
("America/Argentina/Salta", "America/Argentina/Salta"),
|
("America/Argentina/Salta", "America/Argentina/Salta"),
|
||||||
("America/Argentina/San_Juan", "America/Argentina/San_Juan"),
|
(
|
||||||
("America/Argentina/San_Luis", "America/Argentina/San_Luis"),
|
"America/Argentina/San_Juan",
|
||||||
|
"America/Argentina/San_Juan",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"America/Argentina/San_Luis",
|
||||||
|
"America/Argentina/San_Luis",
|
||||||
|
),
|
||||||
("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
|
("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
|
||||||
("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
|
("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
|
||||||
("America/Aruba", "America/Aruba"),
|
("America/Aruba", "America/Aruba"),
|
||||||
|
|
@ -183,7 +192,10 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
("America/Indiana/Knox", "America/Indiana/Knox"),
|
("America/Indiana/Knox", "America/Indiana/Knox"),
|
||||||
("America/Indiana/Marengo", "America/Indiana/Marengo"),
|
("America/Indiana/Marengo", "America/Indiana/Marengo"),
|
||||||
("America/Indiana/Petersburg", "America/Indiana/Petersburg"),
|
(
|
||||||
|
"America/Indiana/Petersburg",
|
||||||
|
"America/Indiana/Petersburg",
|
||||||
|
),
|
||||||
("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
|
("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
|
||||||
("America/Indiana/Vevay", "America/Indiana/Vevay"),
|
("America/Indiana/Vevay", "America/Indiana/Vevay"),
|
||||||
("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
|
("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ class CollectionRule(TimeStampedModel):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
url = models.URLField(max_length=1024)
|
url = models.URLField(max_length=1024)
|
||||||
website_url = models.URLField(max_length=1024, editable=False, blank=True, null=True)
|
website_url = models.URLField(
|
||||||
|
max_length=1024, editable=False, blank=True, null=True
|
||||||
|
)
|
||||||
favicon = models.URLField(blank=True, null=True)
|
favicon = models.URLField(blank=True, null=True)
|
||||||
|
|
||||||
timezone = models.CharField(
|
timezone = models.CharField(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ class CollectionRuleFactory(factory.django.DjangoModelFactory):
|
||||||
url = factory.Faker("url")
|
url = factory.Faker("url")
|
||||||
website_url = factory.Faker("url")
|
website_url = factory.Faker("url")
|
||||||
|
|
||||||
category = factory.SubFactory("newsreader.news.core.tests.factories.CategoryFactory")
|
category = factory.SubFactory(
|
||||||
|
"newsreader.news.core.tests.factories.CategoryFactory"
|
||||||
|
)
|
||||||
|
|
||||||
user = factory.SubFactory(UserFactory)
|
user = factory.SubFactory(UserFactory)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,13 @@ class FeedBuilderTestCase(TestCase):
|
||||||
self.assertEquals(Post.objects.count(), 1)
|
self.assertEquals(Post.objects.count(), 1)
|
||||||
|
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
post.remote_identifier, "https://www.bbc.co.uk/news/world-us-canada-48338168"
|
post.remote_identifier,
|
||||||
|
"https://www.bbc.co.uk/news/world-us-canada-48338168",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(post.url, "https://www.bbc.co.uk/news/world-us-canada-48338168")
|
self.assertEquals(
|
||||||
|
post.url, "https://www.bbc.co.uk/news/world-us-canada-48338168"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
post.title, "Trump's 'genocidal taunts' will not end Iran - Zarif"
|
post.title, "Trump's 'genocidal taunts' will not end Iran - Zarif"
|
||||||
|
|
@ -92,7 +95,9 @@ class FeedBuilderTestCase(TestCase):
|
||||||
second_post.url, "https://www.bbc.co.uk/news/technology-48334739"
|
second_post.url, "https://www.bbc.co.uk/news/technology-48334739"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(second_post.title, "Huawei's Android loss: How it affects you")
|
self.assertEquals(
|
||||||
|
second_post.title, "Huawei's Android loss: How it affects you"
|
||||||
|
)
|
||||||
|
|
||||||
def test_entry_without_remote_identifier(self):
|
def test_entry_without_remote_identifier(self):
|
||||||
builder = FeedBuilder
|
builder = FeedBuilder
|
||||||
|
|
@ -332,7 +337,9 @@ class FeedBuilderTestCase(TestCase):
|
||||||
|
|
||||||
self.assertEquals(Post.objects.count(), 1)
|
self.assertEquals(Post.objects.count(), 1)
|
||||||
|
|
||||||
self.assertFalse("Foreign Minister Mohammad Javad Zarif says the US" in post.body)
|
self.assertFalse(
|
||||||
|
"Foreign Minister Mohammad Javad Zarif says the US" in post.body
|
||||||
|
)
|
||||||
self.assertTrue("Federal Communications Commission" in post.body)
|
self.assertTrue("Federal Communications Commission" in post.body)
|
||||||
|
|
||||||
def test_content_detail_is_not_prioritized_if_shorter(self):
|
def test_content_detail_is_not_prioritized_if_shorter(self):
|
||||||
|
|
@ -347,7 +354,9 @@ class FeedBuilderTestCase(TestCase):
|
||||||
|
|
||||||
self.assertEquals(Post.objects.count(), 1)
|
self.assertEquals(Post.objects.count(), 1)
|
||||||
|
|
||||||
self.assertTrue("Foreign Minister Mohammad Javad Zarif says the US" in post.body)
|
self.assertTrue(
|
||||||
|
"Foreign Minister Mohammad Javad Zarif says the US" in post.body
|
||||||
|
)
|
||||||
|
|
||||||
def test_content_detail_is_concatinated(self):
|
def test_content_detail_is_concatinated(self):
|
||||||
builder = FeedBuilder
|
builder = FeedBuilder
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,9 @@ class FeedCollectorTestCase(TestCase):
|
||||||
first_post.title, "Trump's 'genocidal taunts' will not end Iran - Zarif"
|
first_post.title, "Trump's 'genocidal taunts' will not end Iran - Zarif"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(second_post.title, "Huawei's Android loss: How it affects you")
|
self.assertEquals(
|
||||||
|
second_post.title, "Huawei's Android loss: How it affects you"
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
third_post.title, "Birmingham head teacher threatened over LGBT lessons"
|
third_post.title, "Birmingham head teacher threatened over LGBT lessons"
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,9 @@ class OPMLImportTestCase(TestCase):
|
||||||
self.assertEquals(len(rules), 4)
|
self.assertEquals(len(rules), 4)
|
||||||
|
|
||||||
def test_existing_rules(self):
|
def test_existing_rules(self):
|
||||||
CollectionRuleFactory(url="http://www.engadget.com/rss-full.xml", user=self.user)
|
CollectionRuleFactory(
|
||||||
|
url="http://www.engadget.com/rss-full.xml", user=self.user
|
||||||
|
)
|
||||||
CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user)
|
CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user)
|
||||||
CollectionRuleFactory(
|
CollectionRuleFactory(
|
||||||
url="http://feeds.feedburner.com/Techcrunch", user=self.user
|
url="http://feeds.feedburner.com/Techcrunch", user=self.user
|
||||||
|
|
@ -200,7 +202,9 @@ class OPMLImportTestCase(TestCase):
|
||||||
self.assertEquals(len(rules), 8)
|
self.assertEquals(len(rules), 8)
|
||||||
|
|
||||||
def test_skip_existing_rules(self):
|
def test_skip_existing_rules(self):
|
||||||
CollectionRuleFactory(url="http://www.engadget.com/rss-full.xml", user=self.user)
|
CollectionRuleFactory(
|
||||||
|
url="http://www.engadget.com/rss-full.xml", user=self.user
|
||||||
|
)
|
||||||
CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user)
|
CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user)
|
||||||
CollectionRuleFactory(
|
CollectionRuleFactory(
|
||||||
url="http://feeds.feedburner.com/Techcrunch", user=self.user
|
url="http://feeds.feedburner.com/Techcrunch", user=self.user
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ class Migration(migrations.Migration):
|
||||||
model_name="category",
|
model_name="category",
|
||||||
name="user",
|
name="user",
|
||||||
field=models.ForeignKey(
|
field=models.ForeignKey(
|
||||||
on_delete="Owner", related_name="categories", to=settings.AUTH_USER_MODEL
|
on_delete="Owner",
|
||||||
|
related_name="categories",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ from newsreader.news.core.models import Category, Post
|
||||||
|
|
||||||
|
|
||||||
class PostSerializer(serializers.ModelSerializer):
|
class PostSerializer(serializers.ModelSerializer):
|
||||||
publicationDate = serializers.DateTimeField(source="publication_date", required=False)
|
publicationDate = serializers.DateTimeField(
|
||||||
|
source="publication_date", required=False
|
||||||
|
)
|
||||||
remoteIdentifier = serializers.CharField(source="remote_identifier", required=False)
|
remoteIdentifier = serializers.CharField(source="remote_identifier", required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ class CategoryDetailViewTestCase(TestCase):
|
||||||
def test_post(self):
|
def test_post(self):
|
||||||
category = CategoryFactory(user=self.user)
|
category = CategoryFactory(user=self.user)
|
||||||
|
|
||||||
response = self.client.post(reverse("api:categories-detail", args=[category.pk]))
|
response = self.client.post(
|
||||||
|
reverse("api:categories-detail", args=[category.pk])
|
||||||
|
)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEquals(response.status_code, 405)
|
||||||
|
|
@ -206,6 +208,8 @@ class CategoryReadTestCase(TestCase):
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
category = CategoryFactory(name="Clickbait", user=self.user)
|
category = CategoryFactory(name="Clickbait", user=self.user)
|
||||||
|
|
||||||
response = self.client.delete(reverse("api:categories-read", args=[category.pk]))
|
response = self.client.delete(
|
||||||
|
reverse("api:categories-read", args=[category.pk])
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 405)
|
self.assertEquals(response.status_code, 405)
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,9 @@ class CategoryUpdateViewTestCase(CategoryViewTestCase, TestCase):
|
||||||
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
||||||
self.category.rules.set([*current_rules])
|
self.category.rules.set([*current_rules])
|
||||||
|
|
||||||
self.assertCountEqual(self.category.rule_ids, [rule.pk for rule in current_rules])
|
self.assertCountEqual(
|
||||||
|
self.category.rule_ids, [rule.pk for rule in current_rules]
|
||||||
|
)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"name": self.category.name,
|
"name": self.category.name,
|
||||||
|
|
@ -142,7 +144,9 @@ class CategoryUpdateViewTestCase(CategoryViewTestCase, TestCase):
|
||||||
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
||||||
self.category.rules.set([*current_rules])
|
self.category.rules.set([*current_rules])
|
||||||
|
|
||||||
self.assertCountEqual(self.category.rule_ids, [rule.pk for rule in current_rules])
|
self.assertCountEqual(
|
||||||
|
self.category.rule_ids, [rule.pk for rule in current_rules]
|
||||||
|
)
|
||||||
|
|
||||||
data = {"name": "durp", "user": self.user.pk}
|
data = {"name": "durp", "user": self.user.pk}
|
||||||
self.client.post(self.url, data)
|
self.client.post(self.url, data)
|
||||||
|
|
@ -187,7 +191,9 @@ class CategoryUpdateViewTestCase(CategoryViewTestCase, TestCase):
|
||||||
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
current_rules = CollectionRuleFactory.create_batch(size=3, user=self.user)
|
||||||
self.category.rules.set([*current_rules])
|
self.category.rules.set([*current_rules])
|
||||||
|
|
||||||
self.assertCountEqual(self.category.rule_ids, [rule.pk for rule in current_rules])
|
self.assertCountEqual(
|
||||||
|
self.category.rule_ids, [rule.pk for rule in current_rules]
|
||||||
|
)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"name": self.category.name,
|
"name": self.category.name,
|
||||||
|
|
@ -200,10 +206,14 @@ class CategoryUpdateViewTestCase(CategoryViewTestCase, TestCase):
|
||||||
self.assertContains(response, "not one of the available choices")
|
self.assertContains(response, "not one of the available choices")
|
||||||
|
|
||||||
self.category.refresh_from_db()
|
self.category.refresh_from_db()
|
||||||
self.assertCountEqual(self.category.rule_ids, [rule.pk for rule in current_rules])
|
self.assertCountEqual(
|
||||||
|
self.category.rule_ids, [rule.pk for rule in current_rules]
|
||||||
|
)
|
||||||
|
|
||||||
other_category.refresh_from_db()
|
other_category.refresh_from_db()
|
||||||
self.assertCountEqual(other_category.rule_ids, [rule.pk for rule in other_rules])
|
self.assertCountEqual(
|
||||||
|
other_category.rule_ids, [rule.pk for rule in other_rules]
|
||||||
|
)
|
||||||
|
|
||||||
def test_unique_together(self):
|
def test_unique_together(self):
|
||||||
other_category = CategoryFactory(name="other category", user=self.user)
|
other_category = CategoryFactory(name="other category", user=self.user)
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,12 @@ endpoints = [
|
||||||
path("posts/", ListPostView.as_view(), name="posts-list"),
|
path("posts/", ListPostView.as_view(), name="posts-list"),
|
||||||
path("posts/<int:pk>/", DetailPostView.as_view(), name="posts-detail"),
|
path("posts/<int:pk>/", DetailPostView.as_view(), name="posts-detail"),
|
||||||
path("categories/", ListCategoryView.as_view(), name="categories-list"),
|
path("categories/", ListCategoryView.as_view(), name="categories-list"),
|
||||||
path("categories/<int:pk>/", DetailCategoryView.as_view(), name="categories-detail"),
|
path(
|
||||||
path("categories/<int:pk>/read/", CategoryReadView.as_view(), name="categories-read"),
|
"categories/<int:pk>/", DetailCategoryView.as_view(), name="categories-detail"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"categories/<int:pk>/read/", CategoryReadView.as_view(), name="categories-read"
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"categories/<int:pk>/rules/",
|
"categories/<int:pk>/rules/",
|
||||||
NestedRuleCategoryView.as_view(),
|
NestedRuleCategoryView.as_view(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue