Form / view file refactor

This commit is contained in:
Sonny Bakker 2020-09-19 17:00:41 +02:00
parent 355f16b387
commit abb5328feb
26 changed files with 285 additions and 143 deletions

View file

@ -44,6 +44,8 @@ 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';
// TODO add mapping & get urls from backend
const ruleUrl = const ruleUrl =
this.props.rule.type === FEED this.props.rule.type === FEED
? `/collection/rules/${this.props.rule.id}/` ? `/collection/rules/${this.props.rule.id}/`

View file

@ -3,3 +3,4 @@ export const CATEGORY_TYPE = 'CATEGORY';
export const SUBREDDIT = 'subreddit'; export const SUBREDDIT = 'subreddit';
export const FEED = 'feed'; export const FEED = 'feed';
export const TWITTER_TIMELINE = 'twitter_timeline';

View file

@ -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

View file

@ -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__"

View file

@ -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
)

View file

@ -9,6 +9,7 @@ from newsreader.core.forms import CheckboxInput
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.collection.reddit import REDDIT_API_URL
from newsreader.news.collection.forms.base import CollectionRuleForm
from newsreader.news.core.models import Category from newsreader.news.core.models import Category
@ -22,53 +23,9 @@ def get_reddit_help_text():
) )
class CollectionRuleForm(forms.ModelForm): class SubRedditForm(CollectionRuleForm):
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):
url = forms.URLField(max_length=1024, help_text=get_reddit_help_text) url = forms.URLField(max_length=1024, help_text=get_reddit_help_text)
timezone = None
def clean_url(self): def clean_url(self):
url = self.cleaned_data["url"] url = self.cleaned_data["url"]
@ -92,10 +49,3 @@ class SubRedditRuleForm(CollectionRuleForm):
class Meta: class Meta:
model = CollectionRule model = CollectionRule
fields = ("name", "url", "favicon", "category") 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
)

View file

@ -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)

View file

@ -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")

View file

@ -70,4 +70,4 @@ class CollectionRule(TimeStampedModel):
if self.type == RuleTypeChoices.subreddit: if self.type == RuleTypeChoices.subreddit:
return reverse("news:collection:subreddit-update", kwargs={"pk": self.pk}) 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})

View file

@ -4,6 +4,6 @@
{% block content %} {% block content %}
<main id="rule--page" class="main"> <main id="rule--page" class="main">
{% url "news:collection:rules" as cancel_url %} {% 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" %}
</main> </main>
{% endblock %} {% endblock %}

View file

@ -3,12 +3,12 @@
{% block content %} {% block content %}
<main id="rule--page" class="main"> <main id="rule--page" class="main">
{% if rule.error %} {% if feed.error %}
{% trans "Failed to retrieve posts" as title %} {% 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 %} {% endif %}
{% url "news:collection:rules" as cancel_url %} {% 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 %}
</main> </main>
{% endblock %} {% endblock %}

View file

@ -4,6 +4,6 @@
{% block content %} {% block content %}
<main id="import--page" class="main"> <main id="import--page" class="main">
{% url "news:collection:rules" as cancel_url %} {% 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" %}
</main> </main>
{% endblock %} {% endblock %}

View file

@ -14,8 +14,9 @@
</fieldset> </fieldset>
<div class="form__actions"> <div class="form__actions">
<a class="link button button--confirm" href="{% url "news:collection:rule-create" %}">{% trans "Add a rule" %}</a> <a class="link button button--confirm" href="{% url "news:collection:feed-create" %}">{% trans "Add a feed" %}</a>
<a class="link button button--confirm" href="{% url "news:collection:subreddit-create" %}">{% trans "Add a subreddit" %}</a> <a class="link button button--reddit" href="{% url "news:collection:subreddit-create" %}">{% trans "Add a subreddit" %}</a>
<a class="link button button--twitter" href="{% url "news:collection:twitter-timeline-create" %}">{% trans "Add a Twitter profile" %}</a>
<a class="link button button--confirm" href="{% url "news:collection:import" %}">{% trans "Import rules" %}</a> <a class="link button button--confirm" href="{% url "news:collection:import" %}">{% trans "Import rules" %}</a>
</div> </div>
</section> </section>

View file

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<main id="twitter--page" class="main">
{% 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" %}
</main>
{% endblock %}

View file

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load static i18n %}
{% block content %}
<main id="twitter--page" class="main">
{% 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" %}
</main>
{% endblock %}

View file

@ -49,7 +49,7 @@ class CollectionRuleViewTestCase:
timezone=other_rule.timezone, 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) response = self.client.post(other_url, self.form_data)
self.assertEquals(response.status_code, 404) self.assertEquals(response.status_code, 404)

View file

@ -10,11 +10,11 @@ from newsreader.news.collection.tests.views.base import CollectionRuleViewTestCa
from newsreader.news.core.tests.factories import CategoryFactory from newsreader.news.core.tests.factories import CategoryFactory
class CollectionRuleCreateViewTestCase(CollectionRuleViewTestCase, TestCase): class FeedCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.url = reverse("news:collection:rule-create") self.url = reverse("news:collection:feed-create")
self.form_data.update( self.form_data.update(
name="new rule", name="new rule",
@ -38,14 +38,14 @@ class CollectionRuleCreateViewTestCase(CollectionRuleViewTestCase, TestCase):
self.assertEquals(rule.user.pk, self.user.pk) self.assertEquals(rule.user.pk, self.user.pk)
class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase): class FeedUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.rule = FeedFactory( self.rule = FeedFactory(
name="collection rule", user=self.user, category=self.category 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( self.form_data.update(
name=self.rule.name, name=self.rule.name,
@ -94,7 +94,7 @@ class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase):
category=self.category, category=self.category,
type=RuleTypeChoices.subreddit, 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) response = self.client.get(url)

View file

@ -84,7 +84,7 @@ class OPMLImportTestCase(TestCase):
rules = CollectionRule.objects.all() rules = CollectionRule.objects.all()
self.assertEquals(len(rules), 0) 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): def test_invalid_feeds(self):
file_path = self._get_file_path("invalid-url-feeds.opml") file_path = self._get_file_path("invalid-url-feeds.opml")
@ -99,7 +99,7 @@ class OPMLImportTestCase(TestCase):
rules = CollectionRule.objects.all() rules = CollectionRule.objects.all()
self.assertEquals(len(rules), 0) 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): def test_invalid_file(self):
file_path = self._get_file_path("test.png") file_path = self._get_file_path("test.png")

View file

@ -11,12 +11,14 @@ from newsreader.news.collection.views import (
CollectionRuleBulkDeleteView, CollectionRuleBulkDeleteView,
CollectionRuleBulkDisableView, CollectionRuleBulkDisableView,
CollectionRuleBulkEnableView, CollectionRuleBulkEnableView,
CollectionRuleCreateView,
CollectionRuleListView, CollectionRuleListView,
CollectionRuleUpdateView, FeedCreateView,
FeedUpdateView,
OPMLImportView, OPMLImportView,
SubRedditCreateView, SubRedditCreateView,
SubRedditUpdateView, SubRedditUpdateView,
TwitterTimelineCreateView,
TwitterTimelineUpdateView,
) )
@ -28,17 +30,13 @@ endpoints = [
] ]
urlpatterns = [ urlpatterns = [
# Feeds
path(
"feeds/<int:pk>/", 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(CollectionRuleListView.as_view()), name="rules"),
path(
"rules/<int:pk>/",
login_required(CollectionRuleUpdateView.as_view()),
name="rule-update",
),
path(
"rules/create/",
login_required(CollectionRuleCreateView.as_view()),
name="rule-create",
),
path( path(
"rules/delete/", "rules/delete/",
login_required(CollectionRuleBulkDeleteView.as_view()), login_required(CollectionRuleBulkDeleteView.as_view()),
@ -54,15 +52,27 @@ urlpatterns = [
login_required(CollectionRuleBulkDisableView.as_view()), login_required(CollectionRuleBulkDisableView.as_view()),
name="rules-disable", name="rules-disable",
), ),
path("rules/import/", login_required(OPMLImportView.as_view()), name="import"),
# Reddit
path( path(
"rules/subreddits/create/", "subreddits/create/",
login_required(SubRedditCreateView.as_view()), login_required(SubRedditCreateView.as_view()),
name="subreddit-create", name="subreddit-create",
), ),
path( path(
"rules/subreddits/<int:pk>/", "subreddits/<int:pk>/",
login_required(SubRedditUpdateView.as_view()), login_required(SubRedditUpdateView.as_view()),
name="subreddit-update", 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/<int:pk>/",
login_required(TwitterTimelineUpdateView.as_view()),
name="twitter-timeline-update",
),
] ]

View file

@ -1,3 +1,8 @@
from newsreader.news.collection.views.feed import (
FeedCreateView,
FeedUpdateView,
OPMLImportView,
)
from newsreader.news.collection.views.reddit import ( from newsreader.news.collection.views.reddit import (
SubRedditCreateView, SubRedditCreateView,
SubRedditUpdateView, SubRedditUpdateView,
@ -6,8 +11,9 @@ from newsreader.news.collection.views.rules import (
CollectionRuleBulkDeleteView, CollectionRuleBulkDeleteView,
CollectionRuleBulkDisableView, CollectionRuleBulkDisableView,
CollectionRuleBulkEnableView, CollectionRuleBulkEnableView,
CollectionRuleCreateView,
CollectionRuleListView, CollectionRuleListView,
CollectionRuleUpdateView, )
OPMLImportView, from newsreader.news.collection.views.twitter import (
TwitterTimelineCreateView,
TwitterTimelineUpdateView,
) )

View file

@ -2,7 +2,6 @@ from django.urls import reverse_lazy
import pytz import pytz
from newsreader.news.collection.forms import CollectionRuleForm
from newsreader.news.collection.models import CollectionRule from newsreader.news.collection.models import CollectionRule
from newsreader.news.core.models import Category from newsreader.news.core.models import Category
@ -17,7 +16,6 @@ class CollectionRuleViewMixin:
class CollectionRuleDetailMixin: class CollectionRuleDetailMixin:
success_url = reverse_lazy("news:collection:rules") success_url = reverse_lazy("news:collection:rules")
form_class = CollectionRuleForm
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)

View file

@ -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")

View file

@ -1,7 +1,7 @@
from django.views.generic.edit import CreateView, UpdateView from django.views.generic.edit import CreateView, UpdateView
from newsreader.news.collection.choices import RuleTypeChoices 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 ( from newsreader.news.collection.views.base import (
CollectionRuleDetailMixin, CollectionRuleDetailMixin,
CollectionRuleViewMixin, CollectionRuleViewMixin,
@ -11,14 +11,14 @@ from newsreader.news.collection.views.base import (
class SubRedditCreateView( class SubRedditCreateView(
CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView CollectionRuleViewMixin, CollectionRuleDetailMixin, CreateView
): ):
form_class = SubRedditRuleForm form_class = SubRedditForm
template_name = "news/collection/views/subreddit-create.html" template_name = "news/collection/views/subreddit-create.html"
class SubRedditUpdateView( class SubRedditUpdateView(
CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView CollectionRuleViewMixin, CollectionRuleDetailMixin, UpdateView
): ):
form_class = SubRedditRuleForm form_class = SubRedditForm
template_name = "news/collection/views/subreddit-update.html" template_name = "news/collection/views/subreddit-update.html"
context_object_name = "subreddit" context_object_name = "subreddit"

View file

@ -2,17 +2,14 @@ from django.contrib import messages
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _ 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 django.views.generic.list import ListView
from newsreader.news.collection.choices import RuleTypeChoices from newsreader.news.collection.forms import CollectionRuleBulkForm
from newsreader.news.collection.forms import CollectionRuleBulkForm, OPMLImportForm
from newsreader.news.collection.models import CollectionRule
from newsreader.news.collection.views.base import ( from newsreader.news.collection.views.base import (
CollectionRuleDetailMixin, CollectionRuleDetailMixin,
CollectionRuleViewMixin, CollectionRuleViewMixin,
) )
from newsreader.utils.opml import parse_opml
class CollectionRuleListView(CollectionRuleViewMixin, ListView): class CollectionRuleListView(CollectionRuleViewMixin, ListView):
@ -21,23 +18,6 @@ class CollectionRuleListView(CollectionRuleViewMixin, ListView):
context_object_name = "rules" 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): class CollectionRuleBulkView(FormView):
form_class = CollectionRuleBulkForm form_class = CollectionRuleBulkForm
@ -90,33 +70,3 @@ class CollectionRuleBulkDeleteView(CollectionRuleBulkView):
rule.delete() rule.delete()
return response 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")

View file

@ -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)

View file

@ -38,4 +38,5 @@ def parse_opml(file, user, skip_existing=False):
logging.info(f"Skipped due to invalid URL: {e}") logging.info(f"Skipped due to invalid URL: {e}")
continue continue
# TODO create feed type rules
yield CollectionRule(url=feed_url, name=name, user=user) yield CollectionRule(url=feed_url, name=name, user=user)