diff --git a/src/newsreader/js/pages/homepage/components/PostModal.js b/src/newsreader/js/pages/homepage/components/PostModal.js
index 08033bc..3d7a888 100644
--- a/src/newsreader/js/pages/homepage/components/PostModal.js
+++ b/src/newsreader/js/pages/homepage/components/PostModal.js
@@ -44,6 +44,8 @@ class PostModal extends React.Component {
const post = this.props.post;
const publicationDate = formatDatetime(post.publicationDate);
const titleClassName = post.read ? 'post__title post__title--read' : 'post__title';
+
+ // TODO add mapping & get urls from backend
const ruleUrl =
this.props.rule.type === FEED
? `/collection/rules/${this.props.rule.id}/`
diff --git a/src/newsreader/js/pages/homepage/constants.js b/src/newsreader/js/pages/homepage/constants.js
index 66b6365..22184b9 100644
--- a/src/newsreader/js/pages/homepage/constants.js
+++ b/src/newsreader/js/pages/homepage/constants.js
@@ -3,3 +3,4 @@ export const CATEGORY_TYPE = 'CATEGORY';
export const SUBREDDIT = 'subreddit';
export const FEED = 'feed';
+export const TWITTER_TIMELINE = 'twitter_timeline';
diff --git a/src/newsreader/news/collection/forms/__init__.py b/src/newsreader/news/collection/forms/__init__.py
new file mode 100644
index 0000000..88a51c7
--- /dev/null
+++ b/src/newsreader/news/collection/forms/__init__.py
@@ -0,0 +1,4 @@
+from newsreader.news.collection.forms.feed import FeedForm, OPMLImportForm
+from newsreader.news.collection.forms.reddit import SubRedditForm
+from newsreader.news.collection.forms.rules import CollectionRuleBulkForm
+from newsreader.news.collection.forms.twitter import TwitterTimelineForm
diff --git a/src/newsreader/news/collection/forms/base.py b/src/newsreader/news/collection/forms/base.py
new file mode 100644
index 0000000..0826919
--- /dev/null
+++ b/src/newsreader/news/collection/forms/base.py
@@ -0,0 +1,30 @@
+from django import forms
+
+
+from newsreader.news.collection.models import CollectionRule
+from newsreader.news.core.models import Category
+
+
+class CollectionRuleForm(forms.ModelForm):
+ category = forms.ModelChoiceField(required=False, queryset=Category.objects.all())
+
+ def __init__(self, *args, **kwargs):
+ self.user = kwargs.pop("user")
+
+ super().__init__(*args, **kwargs)
+
+ self.fields["category"].queryset = Category.objects.filter(user=self.user)
+
+ def save(self, commit=True):
+ instance = super().save(commit=False)
+ instance.user = self.user
+
+ if commit:
+ instance.save()
+ self.save_m2m()
+
+ return instance
+
+ class Meta:
+ model = CollectionRule
+ fields = "__all__"
diff --git a/src/newsreader/news/collection/forms/feed.py b/src/newsreader/news/collection/forms/feed.py
new file mode 100644
index 0000000..4a22a2e
--- /dev/null
+++ b/src/newsreader/news/collection/forms/feed.py
@@ -0,0 +1,28 @@
+from django import forms
+from django.utils.translation import gettext_lazy as _
+
+import pytz
+
+from newsreader.core.forms import CheckboxInput
+from newsreader.news.collection.forms.base import CollectionRuleForm
+from newsreader.news.collection.models import CollectionRule
+
+
+class FeedForm(CollectionRuleForm):
+ timezone = forms.ChoiceField(
+ widget=forms.Select(attrs={"size": len(pytz.all_timezones)}),
+ choices=((timezone, timezone) for timezone in pytz.all_timezones),
+ help_text=_("The timezone which the feed uses"),
+ initial=pytz.utc,
+ )
+
+ class Meta:
+ model = CollectionRule
+ fields = ("name", "url", "timezone", "favicon", "category")
+
+
+class OPMLImportForm(forms.Form):
+ file = forms.FileField(allow_empty_file=False)
+ skip_existing = forms.BooleanField(
+ initial=False, required=False, widget=CheckboxInput
+ )
diff --git a/src/newsreader/news/collection/forms.py b/src/newsreader/news/collection/forms/reddit.py
similarity index 51%
rename from src/newsreader/news/collection/forms.py
rename to src/newsreader/news/collection/forms/reddit.py
index c79a867..0bcde9f 100644
--- a/src/newsreader/news/collection/forms.py
+++ b/src/newsreader/news/collection/forms/reddit.py
@@ -9,6 +9,7 @@ from newsreader.core.forms import CheckboxInput
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.reddit import REDDIT_API_URL
+from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.core.models import Category
@@ -22,53 +23,9 @@ def get_reddit_help_text():
)
-class CollectionRuleForm(forms.ModelForm):
- category = forms.ModelChoiceField(required=False, queryset=Category.objects.all())
- timezone = forms.ChoiceField(
- widget=forms.Select(attrs={"size": len(pytz.all_timezones)}),
- choices=((timezone, timezone) for timezone in pytz.all_timezones),
- help_text=_("The timezone which the feed uses"),
- initial=pytz.utc,
- )
-
- def __init__(self, *args, **kwargs):
- self.user = kwargs.pop("user")
-
- super().__init__(*args, **kwargs)
-
- self.fields["category"].queryset = Category.objects.filter(user=self.user)
-
- def save(self, commit=True):
- instance = super().save(commit=False)
- instance.user = self.user
-
- if commit:
- instance.save()
- self.save_m2m()
-
- return instance
-
- class Meta:
- model = CollectionRule
- fields = ("name", "url", "timezone", "favicon", "category")
-
-
-class CollectionRuleBulkForm(forms.Form):
- rules = forms.ModelMultipleChoiceField(queryset=CollectionRule.objects.none())
-
- def __init__(self, user, *args, **kwargs):
- self.user = user
-
- super().__init__(*args, **kwargs)
-
- self.fields["rules"].queryset = CollectionRule.objects.filter(user=user)
-
-
-class SubRedditRuleForm(CollectionRuleForm):
+class SubRedditForm(CollectionRuleForm):
url = forms.URLField(max_length=1024, help_text=get_reddit_help_text)
- timezone = None
-
def clean_url(self):
url = self.cleaned_data["url"]
@@ -92,10 +49,3 @@ class SubRedditRuleForm(CollectionRuleForm):
class Meta:
model = CollectionRule
fields = ("name", "url", "favicon", "category")
-
-
-class OPMLImportForm(forms.Form):
- file = forms.FileField(allow_empty_file=False)
- skip_existing = forms.BooleanField(
- initial=False, required=False, widget=CheckboxInput
- )
diff --git a/src/newsreader/news/collection/forms/rules.py b/src/newsreader/news/collection/forms/rules.py
new file mode 100644
index 0000000..e5dccf9
--- /dev/null
+++ b/src/newsreader/news/collection/forms/rules.py
@@ -0,0 +1,15 @@
+from django import forms
+
+
+from newsreader.news.collection.models import CollectionRule
+
+
+class CollectionRuleBulkForm(forms.Form):
+ rules = forms.ModelMultipleChoiceField(queryset=CollectionRule.objects.none())
+
+ def __init__(self, user, *args, **kwargs):
+ self.user = user
+
+ super().__init__(*args, **kwargs)
+
+ self.fields["rules"].queryset = CollectionRule.objects.filter(user=user)
diff --git a/src/newsreader/news/collection/forms/twitter.py b/src/newsreader/news/collection/forms/twitter.py
new file mode 100644
index 0000000..441b243
--- /dev/null
+++ b/src/newsreader/news/collection/forms/twitter.py
@@ -0,0 +1,32 @@
+from django import forms
+from django.utils.translation import gettext_lazy as _
+
+import pytz
+
+from newsreader.news.collection.choices import RuleTypeChoices
+from newsreader.news.collection.forms.base import CollectionRuleForm
+from newsreader.news.collection.models import CollectionRule
+
+
+class TwitterTimelineForm(CollectionRuleForm):
+ screen_name = forms.CharField(
+ max_length=255,
+ label=_("Twitter profile name"),
+ help_text=_("Profile name without hashtags"),
+ )
+
+ def save(self, commit=True):
+ instance = super().save(commit=False)
+
+ instance.type = RuleTypeChoices.twitter_timeline
+ instance.timezone = str(pytz.utc)
+
+ if commit:
+ instance.save()
+ self.save_m2m()
+
+ return instance
+
+ class Meta:
+ model = CollectionRule
+ fields = ("name", "screen_name", "favicon", "category")
diff --git a/src/newsreader/news/collection/models.py b/src/newsreader/news/collection/models.py
index 0cbfa22..d1d8024 100644
--- a/src/newsreader/news/collection/models.py
+++ b/src/newsreader/news/collection/models.py
@@ -70,4 +70,4 @@ class CollectionRule(TimeStampedModel):
if self.type == RuleTypeChoices.subreddit:
return reverse("news:collection:subreddit-update", kwargs={"pk": self.pk})
- return reverse("news:collection:rule-update", kwargs={"pk": self.pk})
+ return reverse("news:collection:feed-update", kwargs={"pk": self.pk})
diff --git a/src/newsreader/news/collection/templates/news/collection/views/rule-create.html b/src/newsreader/news/collection/templates/news/collection/views/feed-create.html
similarity index 78%
rename from src/newsreader/news/collection/templates/news/collection/views/rule-create.html
rename to src/newsreader/news/collection/templates/news/collection/views/feed-create.html
index 82ed6c5..c24791a 100644
--- a/src/newsreader/news/collection/templates/news/collection/views/rule-create.html
+++ b/src/newsreader/news/collection/templates/news/collection/views/feed-create.html
@@ -4,6 +4,6 @@
{% block content %}
{% url "news:collection:rules" as cancel_url %}
- {% include "components/form/form.html" with form=form title="Create rule" cancel_url=cancel_url confirm_text="Create rule" %}
+ {% include "components/form/form.html" with form=form title="Add a feed" cancel_url=cancel_url confirm_text="Add feed" %}
{% endblock %}
diff --git a/src/newsreader/news/collection/templates/news/collection/views/rule-update.html b/src/newsreader/news/collection/templates/news/collection/views/feed-update.html
similarity index 72%
rename from src/newsreader/news/collection/templates/news/collection/views/rule-update.html
rename to src/newsreader/news/collection/templates/news/collection/views/feed-update.html
index 0a705b8..33b1faf 100644
--- a/src/newsreader/news/collection/templates/news/collection/views/rule-update.html
+++ b/src/newsreader/news/collection/templates/news/collection/views/feed-update.html
@@ -3,12 +3,12 @@
{% block content %}
- {% if rule.error %}
+ {% if feed.error %}
{% trans "Failed to retrieve posts" as title %}
- {% include "components/textbox/textbox.html" with title=title body=rule.error class="text-section--error" only %}
+ {% include "components/textbox/textbox.html" with title=title body=feed.error class="text-section--error" only %}
{% endif %}
{% url "news:collection:rules" as cancel_url %}
- {% include "components/form/form.html" with form=form title="Update rule" cancel_url=cancel_url confirm_text="Save rule" only %}
+ {% include "components/form/form.html" with form=form title="Update feed" cancel_url=cancel_url confirm_text="Save feed" only %}
{% endblock %}
diff --git a/src/newsreader/news/collection/templates/news/collection/views/import.html b/src/newsreader/news/collection/templates/news/collection/views/import.html
index df19887..9719847 100644
--- a/src/newsreader/news/collection/templates/news/collection/views/import.html
+++ b/src/newsreader/news/collection/templates/news/collection/views/import.html
@@ -4,6 +4,6 @@
{% block content %}
{% url "news:collection:rules" as cancel_url %}
- {% include "components/form/form.html" with form=form title="Import an OPML file" cancel_url=cancel_url confirm_text="Import rules" %}
+ {% include "components/form/form.html" with form=form title="Import an OPML file" cancel_url=cancel_url confirm_text="Import feeds" %}
{% endblock %}
diff --git a/src/newsreader/news/collection/templates/news/collection/views/rules.html b/src/newsreader/news/collection/templates/news/collection/views/rules.html
index 0cd1870..cd98b29 100644
--- a/src/newsreader/news/collection/templates/news/collection/views/rules.html
+++ b/src/newsreader/news/collection/templates/news/collection/views/rules.html
@@ -14,8 +14,9 @@
diff --git a/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-create.html b/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-create.html
new file mode 100644
index 0000000..7c8eb13
--- /dev/null
+++ b/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-create.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+{% load static %}
+
+{% block content %}
+
+ {% url "news:collection:rules" as cancel_url %}
+ {% include "components/form/form.html" with form=form title="Add a Twitter profile" cancel_url=cancel_url confirm_text="Add profile" %}
+
+{% endblock %}
diff --git a/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-update.html b/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-update.html
new file mode 100644
index 0000000..51de47a
--- /dev/null
+++ b/src/newsreader/news/collection/templates/news/collection/views/twitter/timeline-update.html
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+{% load static i18n %}
+
+{% block content %}
+
+ {% if timeline.error %}
+ {% trans "Failed to retrieve posts" as title %}
+ {% include "components/textbox/textbox.html" with title=title body=timeline.error class="text-section--error" only %}
+ {% endif %}
+
+ {% url "news:collection:rules" as cancel_url %}
+ {% include "components/form/form.html" with form=form title="Update profile" cancel_url=cancel_url confirm_text="Save profile" %}
+
+{% endblock %}
diff --git a/src/newsreader/news/collection/tests/views/base.py b/src/newsreader/news/collection/tests/views/base.py
index d7de171..17f232c 100644
--- a/src/newsreader/news/collection/tests/views/base.py
+++ b/src/newsreader/news/collection/tests/views/base.py
@@ -49,7 +49,7 @@ class CollectionRuleViewTestCase:
timezone=other_rule.timezone,
)
- other_url = reverse("news:collection:rule-update", args=[other_rule.pk])
+ other_url = reverse("news:collection:feed-update", args=[other_rule.pk])
response = self.client.post(other_url, self.form_data)
self.assertEquals(response.status_code, 404)
diff --git a/src/newsreader/news/collection/tests/views/test_crud.py b/src/newsreader/news/collection/tests/views/test_crud.py
index 61f6835..e10f997 100644
--- a/src/newsreader/news/collection/tests/views/test_crud.py
+++ b/src/newsreader/news/collection/tests/views/test_crud.py
@@ -10,11 +10,11 @@ from newsreader.news.collection.tests.views.base import CollectionRuleViewTestCa
from newsreader.news.core.tests.factories import CategoryFactory
-class CollectionRuleCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
+class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
def setUp(self):
super().setUp()
- self.url = reverse("news:collection:rule-create")
+ self.url = reverse("news:collection:feed-create")
self.form_data.update(
name="new rule",
@@ -38,14 +38,14 @@ class CollectionRuleCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.user.pk, self.user.pk)
-class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
+class FeedUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
def setUp(self):
super().setUp()
self.rule = FeedFactory(
name="collection rule", user=self.user, category=self.category
)
- self.url = reverse("news:collection:rule-update", kwargs={"pk": self.rule.pk})
+ self.url = reverse("news:collection:feed-update", kwargs={"pk": self.rule.pk})
self.form_data.update(
name=self.rule.name,
@@ -94,7 +94,7 @@ class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
category=self.category,
type=RuleTypeChoices.subreddit,
)
- url = reverse("news:collection:rule-update", kwargs={"pk": rule.pk})
+ url = reverse("news:collection:feed-update", kwargs={"pk": rule.pk})
response = self.client.get(url)
diff --git a/src/newsreader/news/collection/tests/views/test_import_view.py b/src/newsreader/news/collection/tests/views/test_import_view.py
index f4188e7..a1f0017 100644
--- a/src/newsreader/news/collection/tests/views/test_import_view.py
+++ b/src/newsreader/news/collection/tests/views/test_import_view.py
@@ -84,7 +84,7 @@ class OPMLImportTestCase(TestCase):
rules = CollectionRule.objects.all()
self.assertEquals(len(rules), 0)
- self.assertFormError(response, "form", "file", _("No (new) rules found"))
+ self.assertFormError(response, "form", "file", _("No (new) feeds found"))
def test_invalid_feeds(self):
file_path = self._get_file_path("invalid-url-feeds.opml")
@@ -99,7 +99,7 @@ class OPMLImportTestCase(TestCase):
rules = CollectionRule.objects.all()
self.assertEquals(len(rules), 0)
- self.assertFormError(response, "form", "file", _("No (new) rules found"))
+ self.assertFormError(response, "form", "file", _("No (new) feeds found"))
def test_invalid_file(self):
file_path = self._get_file_path("test.png")
diff --git a/src/newsreader/news/collection/urls.py b/src/newsreader/news/collection/urls.py
index 5253210..7d883f2 100644
--- a/src/newsreader/news/collection/urls.py
+++ b/src/newsreader/news/collection/urls.py
@@ -11,12 +11,14 @@ from newsreader.news.collection.views import (
CollectionRuleBulkDeleteView,
CollectionRuleBulkDisableView,
CollectionRuleBulkEnableView,
- CollectionRuleCreateView,
CollectionRuleListView,
- CollectionRuleUpdateView,
+ FeedCreateView,
+ FeedUpdateView,
OPMLImportView,
SubRedditCreateView,
SubRedditUpdateView,
+ TwitterTimelineCreateView,
+ TwitterTimelineUpdateView,
)
@@ -28,17 +30,13 @@ endpoints = [
]
urlpatterns = [
+ # Feeds
+ path(
+ "feeds//", login_required(FeedUpdateView.as_view()), name="feed-update"
+ ),
+ path("feeds/create/", login_required(FeedCreateView.as_view()), name="feed-create"),
+ # Generic rules
path("rules/", login_required(CollectionRuleListView.as_view()), name="rules"),
- path(
- "rules//",
- login_required(CollectionRuleUpdateView.as_view()),
- name="rule-update",
- ),
- path(
- "rules/create/",
- login_required(CollectionRuleCreateView.as_view()),
- name="rule-create",
- ),
path(
"rules/delete/",
login_required(CollectionRuleBulkDeleteView.as_view()),
@@ -54,15 +52,27 @@ urlpatterns = [
login_required(CollectionRuleBulkDisableView.as_view()),
name="rules-disable",
),
+ path("rules/import/", login_required(OPMLImportView.as_view()), name="import"),
+ # Reddit
path(
- "rules/subreddits/create/",
+ "subreddits/create/",
login_required(SubRedditCreateView.as_view()),
name="subreddit-create",
),
path(
- "rules/subreddits//",
+ "subreddits//",
login_required(SubRedditUpdateView.as_view()),
name="subreddit-update",
),
- path("rules/import/", login_required(OPMLImportView.as_view()), name="import"),
+ # Twitter
+ path(
+ "twitter/timelines/create/",
+ login_required(TwitterTimelineCreateView.as_view()),
+ name="twitter-timeline-create",
+ ),
+ path(
+ "twitter/timelines//",
+ login_required(TwitterTimelineUpdateView.as_view()),
+ name="twitter-timeline-update",
+ ),
]
diff --git a/src/newsreader/news/collection/views/__init__.py b/src/newsreader/news/collection/views/__init__.py
index 20769f3..c66c5a5 100644
--- a/src/newsreader/news/collection/views/__init__.py
+++ b/src/newsreader/news/collection/views/__init__.py
@@ -1,3 +1,8 @@
+from newsreader.news.collection.views.feed import (
+ FeedCreateView,
+ FeedUpdateView,
+ OPMLImportView,
+)
from newsreader.news.collection.views.reddit import (
SubRedditCreateView,
SubRedditUpdateView,
@@ -6,8 +11,9 @@ from newsreader.news.collection.views.rules import (
CollectionRuleBulkDeleteView,
CollectionRuleBulkDisableView,
CollectionRuleBulkEnableView,
- CollectionRuleCreateView,
CollectionRuleListView,
- CollectionRuleUpdateView,
- OPMLImportView,
+)
+from newsreader.news.collection.views.twitter import (
+ TwitterTimelineCreateView,
+ TwitterTimelineUpdateView,
)
diff --git a/src/newsreader/news/collection/views/base.py b/src/newsreader/news/collection/views/base.py
index e7f7b63..982a4d3 100644
--- a/src/newsreader/news/collection/views/base.py
+++ b/src/newsreader/news/collection/views/base.py
@@ -2,7 +2,6 @@ from django.urls import reverse_lazy
import pytz
-from newsreader.news.collection.forms import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule
from newsreader.news.core.models import Category
@@ -17,7 +16,6 @@ class CollectionRuleViewMixin:
class CollectionRuleDetailMixin:
success_url = reverse_lazy("news:collection:rules")
- form_class = CollectionRuleForm
def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
diff --git a/src/newsreader/news/collection/views/feed.py b/src/newsreader/news/collection/views/feed.py
new file mode 100644
index 0000000..872d716
--- /dev/null
+++ b/src/newsreader/news/collection/views/feed.py
@@ -0,0 +1,62 @@
+from django.contrib import messages
+from django.urls import reverse
+from django.utils.translation import gettext as _
+from django.views.generic.edit import CreateView, FormView, UpdateView
+
+from newsreader.news.collection.choices import RuleTypeChoices
+from newsreader.news.collection.forms import (
+ CollectionRuleBulkForm,
+ FeedForm,
+ OPMLImportForm,
+)
+from newsreader.news.collection.models import CollectionRule
+from newsreader.news.collection.views.base import (
+ CollectionRuleDetailMixin,
+ CollectionRuleViewMixin,
+)
+from newsreader.utils.opml import parse_opml
+
+
+class FeedUpdateView(CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView):
+ template_name = "news/collection/views/feed-update.html"
+ form_class = FeedForm
+
+ def get_queryset(self):
+ queryset = super().get_queryset()
+ return queryset.filter(type=RuleTypeChoices.feed)
+
+
+class FeedCreateView(CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView):
+ template_name = "news/collection/views/feed-create.html"
+ form_class = FeedForm
+ context_object_name = "feed"
+
+
+class OPMLImportView(FormView):
+ form_class = OPMLImportForm
+ template_name = "news/collection/views/import.html"
+
+ def form_valid(self, form):
+ user = self.request.user
+ file = form.cleaned_data["file"]
+ skip_existing = form.cleaned_data["skip_existing"]
+
+ instances = parse_opml(file, user, skip_existing=skip_existing)
+
+ try:
+ feeds = CollectionRule.objects.bulk_create(instances)
+ except IOError:
+ form.add_error("file", _("Invalid OPML file"))
+ return self.form_invalid(form)
+
+ if not feeds:
+ form.add_error("file", _("No (new) feeds found"))
+ return self.form_invalid(form)
+
+ message = _(f"{len(feeds)} new feeds created")
+ messages.success(self.request, message)
+
+ return super().form_valid(form)
+
+ def get_success_url(self):
+ return reverse("news:collection:rules")
diff --git a/src/newsreader/news/collection/views/reddit.py b/src/newsreader/news/collection/views/reddit.py
index 62ec408..4e44e3f 100644
--- a/src/newsreader/news/collection/views/reddit.py
+++ b/src/newsreader/news/collection/views/reddit.py
@@ -1,7 +1,7 @@
from django.views.generic.edit import CreateView, UpdateView
from newsreader.news.collection.choices import RuleTypeChoices
-from newsreader.news.collection.forms import SubRedditRuleForm
+from newsreader.news.collection.forms import SubRedditForm
from newsreader.news.collection.views.base import (
CollectionRuleDetailMixin,
CollectionRuleViewMixin,
@@ -11,14 +11,14 @@ from newsreader.news.collection.views.base import (
class SubRedditCreateView(
CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView
):
- form_class = SubRedditRuleForm
+ form_class = SubRedditForm
template_name = "news/collection/views/subreddit-create.html"
class SubRedditUpdateView(
CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView
):
- form_class = SubRedditRuleForm
+ form_class = SubRedditForm
template_name = "news/collection/views/subreddit-update.html"
context_object_name = "subreddit"
diff --git a/src/newsreader/news/collection/views/rules.py b/src/newsreader/news/collection/views/rules.py
index e020b67..902eedf 100644
--- a/src/newsreader/news/collection/views/rules.py
+++ b/src/newsreader/news/collection/views/rules.py
@@ -2,17 +2,14 @@ from django.contrib import messages
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext as _
-from django.views.generic.edit import CreateView, FormView, UpdateView
+from django.views.generic.edit import FormView
from django.views.generic.list import ListView
-from newsreader.news.collection.choices import RuleTypeChoices
-from newsreader.news.collection.forms import CollectionRuleBulkForm, OPMLImportForm
-from newsreader.news.collection.models import CollectionRule
+from newsreader.news.collection.forms import CollectionRuleBulkForm
from newsreader.news.collection.views.base import (
CollectionRuleDetailMixin,
CollectionRuleViewMixin,
)
-from newsreader.utils.opml import parse_opml
class CollectionRuleListView(CollectionRuleViewMixin, ListView):
@@ -21,23 +18,6 @@ class CollectionRuleListView(CollectionRuleViewMixin, ListView):
context_object_name = "rules"
-class CollectionRuleUpdateView(
- CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView
-):
- template_name = "news/collection/views/rule-update.html"
- context_object_name = "rule"
-
- def get_queryset(self):
- queryset = super().get_queryset()
- return queryset.filter(type=RuleTypeChoices.feed)
-
-
-class CollectionRuleCreateView(
- CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView
-):
- template_name = "news/collection/views/rule-create.html"
-
-
class CollectionRuleBulkView(FormView):
form_class = CollectionRuleBulkForm
@@ -90,33 +70,3 @@ class CollectionRuleBulkDeleteView(CollectionRuleBulkView):
rule.delete()
return response
-
-
-class OPMLImportView(FormView):
- form_class = OPMLImportForm
- template_name = "news/collection/views/import.html"
-
- def form_valid(self, form):
- user = self.request.user
- file = form.cleaned_data["file"]
- skip_existing = form.cleaned_data["skip_existing"]
-
- instances = parse_opml(file, user, skip_existing=skip_existing)
-
- try:
- rules = CollectionRule.objects.bulk_create(instances)
- except IOError:
- form.add_error("file", _("Invalid OPML file"))
- return self.form_invalid(form)
-
- if not rules:
- form.add_error("file", _("No (new) rules found"))
- return self.form_invalid(form)
-
- message = _(f"{len(rules)} new rules created")
- messages.success(self.request, message)
-
- return super().form_valid(form)
-
- def get_success_url(self):
- return reverse("news:collection:rules")
diff --git a/src/newsreader/news/collection/views/twitter.py b/src/newsreader/news/collection/views/twitter.py
new file mode 100644
index 0000000..db87030
--- /dev/null
+++ b/src/newsreader/news/collection/views/twitter.py
@@ -0,0 +1,29 @@
+from django.views.generic.edit import CreateView, UpdateView
+
+from newsreader.news.collection.choices import RuleTypeChoices
+from newsreader.news.collection.forms import TwitterTimelineForm
+from newsreader.news.collection.views.base import (
+ CollectionRuleDetailMixin,
+ CollectionRuleViewMixin,
+)
+
+
+# TODO add tests
+class TwitterTimelineCreateView(
+ CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView
+):
+ form_class = TwitterTimelineForm
+ template_name = "news/collection/views/twitter/timeline-create.html"
+
+
+# TODO add tests
+class TwitterTimelineUpdateView(
+ CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView
+):
+ form_class = TwitterTimelineForm
+ template_name = "news/collection/views/twitter/timeline-update.html"
+ context_object_name = "timeline"
+
+ def get_queryset(self):
+ queryset = super().get_queryset()
+ return queryset.filter(type=RuleTypeChoices.twitter_timeline)
diff --git a/src/newsreader/utils/opml.py b/src/newsreader/utils/opml.py
index 55a9387..1aca0fd 100644
--- a/src/newsreader/utils/opml.py
+++ b/src/newsreader/utils/opml.py
@@ -38,4 +38,5 @@ def parse_opml(file, user, skip_existing=False):
logging.info(f"Skipped due to invalid URL: {e}")
continue
+ # TODO create feed type rules
yield CollectionRule(url=feed_url, name=name, user=user)