From bec3488e633d6f0166bc17587b0bf375020ab498 Mon Sep 17 00:00:00 2001 From: sonny Date: Sun, 10 May 2020 20:11:12 +0200 Subject: [PATCH] Resolve "Feeds list view" --- src/newsreader/fixtures/default-fixture.json | 2571 ++++++++++++++++- src/newsreader/js/components/Selector.js | 23 + src/newsreader/js/index.js | 2 +- src/newsreader/js/pages/rules/App.js | 106 - .../js/pages/rules/components/RuleCard.js | 65 - .../js/pages/rules/components/RuleModal.js | 35 - src/newsreader/js/pages/rules/index.js | 10 +- src/newsreader/news/collection/forms.py | 11 + .../migrations/0007_collectionrule_enabled.py | 18 + src/newsreader/news/collection/models.py | 7 +- .../templates/collection/rules.html | 85 +- .../collection/tests/views/test_bulk_views.py | 244 ++ .../{test_views.py => views/test_crud.py} | 132 - .../tests/views/test_import_view.py | 141 + src/newsreader/news/collection/urls.py | 18 + src/newsreader/news/collection/views.py | 66 +- .../scss/components/form/_form.scss | 8 + .../scss/components/form/_rules-form.scss | 5 + .../scss/components/form/index.scss | 1 + src/newsreader/scss/components/index.scss | 2 + .../components/pagination/_pagination.scss | 18 + .../scss/components/pagination/index.scss | 1 + .../scss/components/table/_rules-table.scss | 38 + .../scss/components/table/_table.scss | 32 + .../scss/components/table/index.scss | 2 + .../scss/elements/button/_button.scss | 4 +- .../scss/elements/button/_mixins.scss | 3 + src/newsreader/scss/elements/link/_link.scss | 4 - src/newsreader/scss/lib/_css.gg.scss | 8 + src/newsreader/scss/lib/_mixins.scss | 3 + src/newsreader/scss/pages/index.scss | 2 +- src/newsreader/scss/pages/rules/index.scss | 6 +- 32 files changed, 3199 insertions(+), 472 deletions(-) create mode 100644 src/newsreader/js/components/Selector.js delete mode 100644 src/newsreader/js/pages/rules/App.js delete mode 100644 src/newsreader/js/pages/rules/components/RuleCard.js delete mode 100644 src/newsreader/js/pages/rules/components/RuleModal.js create mode 100644 src/newsreader/news/collection/migrations/0007_collectionrule_enabled.py create mode 100644 src/newsreader/news/collection/tests/views/test_bulk_views.py rename src/newsreader/news/collection/tests/{test_views.py => views/test_crud.py} (52%) create mode 100644 src/newsreader/news/collection/tests/views/test_import_view.py create mode 100644 src/newsreader/scss/components/form/_rules-form.scss create mode 100644 src/newsreader/scss/components/pagination/_pagination.scss create mode 100644 src/newsreader/scss/components/pagination/index.scss create mode 100644 src/newsreader/scss/components/table/_rules-table.scss create mode 100644 src/newsreader/scss/components/table/_table.scss create mode 100644 src/newsreader/scss/components/table/index.scss create mode 100644 src/newsreader/scss/elements/button/_mixins.scss create mode 100644 src/newsreader/scss/lib/_mixins.scss diff --git a/src/newsreader/fixtures/default-fixture.json b/src/newsreader/fixtures/default-fixture.json index 7b7ecdf..a6a9162 100644 --- a/src/newsreader/fixtures/default-fixture.json +++ b/src/newsreader/fixtures/default-fixture.json @@ -1,68 +1,143 @@ [ { - "model": "django_celery_beat.periodictask", - "pk": 10, + "model": "contenttypes.contenttype", "fields": { - "name": "sonny@bakker.nl-collection-task", - "task": "newsreader.news.collection.tasks.FeedTask", - "interval": 4, - "crontab": null, - "solar": null, - "clocked": null, - "args": "[2]", - "kwargs": "{}", - "queue": null, - "exchange": null, - "routing_key": null, - "headers": "{}", - "priority": null, - "expires": null, - "one_off": false, - "start_time": null, - "enabled": true, - "last_run_at": "2019-11-29T22:29:08.345Z", - "total_run_count": 290, - "date_changed": "2019-11-29T22:29:18.378Z", - "description": "" + "app_label": "admin", + "model": "logentry" } }, { - "model": "django_celery_beat.periodictask", - "pk": 26, + "model": "contenttypes.contenttype", "fields": { - "name": "sonnyba871@gmail.com-collection-task", - "task": "newsreader.news.collection.tasks.FeedTask", - "interval": 4, - "crontab": null, - "solar": null, - "clocked": null, - "args": "[18]", - "kwargs": "{}", - "queue": null, - "exchange": null, - "routing_key": null, - "headers": "{}", - "priority": null, - "expires": null, - "one_off": false, - "start_time": null, - "enabled": true, - "last_run_at": "2019-11-29T22:35:19.134Z", - "total_run_count": 103, - "date_changed": "2019-11-29T22:38:19.464Z", - "description": "" + "app_label": "auth", + "model": "permission" } }, { - "model": "django_celery_beat.crontabschedule", - "pk": 1, + "model": "contenttypes.contenttype", "fields": { - "minute": "0", - "hour": "4", - "day_of_week": "*", - "day_of_month": "*", - "month_of_year": "*", - "timezone": "UTC" + "app_label": "auth", + "model": "group" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "contenttypes", + "model": "contenttype" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "sessions", + "model": "session" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "crontabschedule" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "intervalschedule" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "periodictask" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "periodictasks" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "solarschedule" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "django_celery_beat", + "model": "clockedschedule" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "registration", + "model": "registrationprofile" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "registration", + "model": "supervisedregistrationprofile" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "axes", + "model": "accessattempt" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "axes", + "model": "accesslog" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "accounts", + "model": "user" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "core", + "model": "post" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "core", + "model": "category" + } +}, +{ + "model": "contenttypes.contenttype", + "fields": { + "app_label": "collection", + "model": "collectionrule" + } +}, +{ + "model": "sessions.session", + "pk": "3sumq22krk8tsvexcs4b8czu82yhvuer", + "fields": { + "session_data": "OWZkZTQyZDQ2NzNkYzdkOTBhM2ZlOWU3MDhhNDkyMWQ0MDdmZTc5ODp7Il9hdXRoX3VzZXJfaWQiOiIxIiwiX2F1dGhfdXNlcl9iYWNrZW5kIjoiZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmQiLCJfYXV0aF91c2VyX2hhc2giOiJhZTMwMWFlMzI5OGFlOThkNjY1MTY1NDIxM2EyMmM0NDA0Y2FkZTc3In0=", + "expire_date": "2020-05-16T18:29:04.049Z" } }, { @@ -97,11 +172,950 @@ "period": "hours" } }, +{ + "model": "django_celery_beat.crontabschedule", + "pk": 1, + "fields": { + "minute": "0", + "hour": "4", + "day_of_week": "*", + "day_of_month": "*", + "month_of_year": "*", + "timezone": "UTC" + } +}, +{ + "model": "django_celery_beat.periodictasks", + "pk": 1, + "fields": { + "last_update": "2020-05-02T20:40:29.029Z" + } +}, +{ + "model": "django_celery_beat.periodictask", + "pk": 1, + "fields": { + "name": "celery.backend_cleanup", + "task": "celery.backend_cleanup", + "interval": null, + "crontab": 1, + "solar": null, + "clocked": null, + "args": "[]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": 43200, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": null, + "total_run_count": 0, + "date_changed": "2020-05-02T20:06:23.985Z", + "description": "" + } +}, +{ + "model": "django_celery_beat.periodictask", + "pk": 10, + "fields": { + "name": "sonny@bakker.nl-collection-task", + "task": "newsreader.news.collection.tasks.FeedTask", + "interval": 4, + "crontab": null, + "solar": null, + "clocked": null, + "args": "[2]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": null, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": "2020-05-02T20:06:24.012Z", + "total_run_count": 292, + "date_changed": "2020-05-02T20:06:24.027Z", + "description": "" + } +}, +{ + "model": "django_celery_beat.periodictask", + "pk": 26, + "fields": { + "name": "sonnyba871@gmail.com-collection-task", + "task": "newsreader.news.collection.tasks.FeedTask", + "interval": 4, + "crontab": null, + "solar": null, + "clocked": null, + "args": "[18]", + "kwargs": "{}", + "queue": null, + "exchange": null, + "routing_key": null, + "headers": "{}", + "priority": null, + "expires": null, + "expire_seconds": null, + "one_off": false, + "start_time": null, + "enabled": true, + "last_run_at": "2020-05-02T20:06:24.045Z", + "total_run_count": 105, + "date_changed": "2020-05-02T20:09:24.331Z", + "description": "" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add log entry", + "content_type": [ + "admin", + "logentry" + ], + "codename": "add_logentry" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change log entry", + "content_type": [ + "admin", + "logentry" + ], + "codename": "change_logentry" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete log entry", + "content_type": [ + "admin", + "logentry" + ], + "codename": "delete_logentry" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view log entry", + "content_type": [ + "admin", + "logentry" + ], + "codename": "view_logentry" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add permission", + "content_type": [ + "auth", + "permission" + ], + "codename": "add_permission" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change permission", + "content_type": [ + "auth", + "permission" + ], + "codename": "change_permission" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete permission", + "content_type": [ + "auth", + "permission" + ], + "codename": "delete_permission" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view permission", + "content_type": [ + "auth", + "permission" + ], + "codename": "view_permission" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add group", + "content_type": [ + "auth", + "group" + ], + "codename": "add_group" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change group", + "content_type": [ + "auth", + "group" + ], + "codename": "change_group" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete group", + "content_type": [ + "auth", + "group" + ], + "codename": "delete_group" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view group", + "content_type": [ + "auth", + "group" + ], + "codename": "view_group" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add content type", + "content_type": [ + "contenttypes", + "contenttype" + ], + "codename": "add_contenttype" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change content type", + "content_type": [ + "contenttypes", + "contenttype" + ], + "codename": "change_contenttype" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete content type", + "content_type": [ + "contenttypes", + "contenttype" + ], + "codename": "delete_contenttype" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view content type", + "content_type": [ + "contenttypes", + "contenttype" + ], + "codename": "view_contenttype" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add session", + "content_type": [ + "sessions", + "session" + ], + "codename": "add_session" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change session", + "content_type": [ + "sessions", + "session" + ], + "codename": "change_session" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete session", + "content_type": [ + "sessions", + "session" + ], + "codename": "delete_session" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view session", + "content_type": [ + "sessions", + "session" + ], + "codename": "view_session" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add crontab", + "content_type": [ + "django_celery_beat", + "crontabschedule" + ], + "codename": "add_crontabschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change crontab", + "content_type": [ + "django_celery_beat", + "crontabschedule" + ], + "codename": "change_crontabschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete crontab", + "content_type": [ + "django_celery_beat", + "crontabschedule" + ], + "codename": "delete_crontabschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view crontab", + "content_type": [ + "django_celery_beat", + "crontabschedule" + ], + "codename": "view_crontabschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add interval", + "content_type": [ + "django_celery_beat", + "intervalschedule" + ], + "codename": "add_intervalschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change interval", + "content_type": [ + "django_celery_beat", + "intervalschedule" + ], + "codename": "change_intervalschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete interval", + "content_type": [ + "django_celery_beat", + "intervalschedule" + ], + "codename": "delete_intervalschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view interval", + "content_type": [ + "django_celery_beat", + "intervalschedule" + ], + "codename": "view_intervalschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add periodic task", + "content_type": [ + "django_celery_beat", + "periodictask" + ], + "codename": "add_periodictask" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change periodic task", + "content_type": [ + "django_celery_beat", + "periodictask" + ], + "codename": "change_periodictask" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete periodic task", + "content_type": [ + "django_celery_beat", + "periodictask" + ], + "codename": "delete_periodictask" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view periodic task", + "content_type": [ + "django_celery_beat", + "periodictask" + ], + "codename": "view_periodictask" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add periodic tasks", + "content_type": [ + "django_celery_beat", + "periodictasks" + ], + "codename": "add_periodictasks" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change periodic tasks", + "content_type": [ + "django_celery_beat", + "periodictasks" + ], + "codename": "change_periodictasks" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete periodic tasks", + "content_type": [ + "django_celery_beat", + "periodictasks" + ], + "codename": "delete_periodictasks" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view periodic tasks", + "content_type": [ + "django_celery_beat", + "periodictasks" + ], + "codename": "view_periodictasks" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add solar event", + "content_type": [ + "django_celery_beat", + "solarschedule" + ], + "codename": "add_solarschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change solar event", + "content_type": [ + "django_celery_beat", + "solarschedule" + ], + "codename": "change_solarschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete solar event", + "content_type": [ + "django_celery_beat", + "solarschedule" + ], + "codename": "delete_solarschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view solar event", + "content_type": [ + "django_celery_beat", + "solarschedule" + ], + "codename": "view_solarschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add clocked", + "content_type": [ + "django_celery_beat", + "clockedschedule" + ], + "codename": "add_clockedschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change clocked", + "content_type": [ + "django_celery_beat", + "clockedschedule" + ], + "codename": "change_clockedschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete clocked", + "content_type": [ + "django_celery_beat", + "clockedschedule" + ], + "codename": "delete_clockedschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view clocked", + "content_type": [ + "django_celery_beat", + "clockedschedule" + ], + "codename": "view_clockedschedule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add registration profile", + "content_type": [ + "registration", + "registrationprofile" + ], + "codename": "add_registrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change registration profile", + "content_type": [ + "registration", + "registrationprofile" + ], + "codename": "change_registrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete registration profile", + "content_type": [ + "registration", + "registrationprofile" + ], + "codename": "delete_registrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view registration profile", + "content_type": [ + "registration", + "registrationprofile" + ], + "codename": "view_registrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add supervised registration profile", + "content_type": [ + "registration", + "supervisedregistrationprofile" + ], + "codename": "add_supervisedregistrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change supervised registration profile", + "content_type": [ + "registration", + "supervisedregistrationprofile" + ], + "codename": "change_supervisedregistrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete supervised registration profile", + "content_type": [ + "registration", + "supervisedregistrationprofile" + ], + "codename": "delete_supervisedregistrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view supervised registration profile", + "content_type": [ + "registration", + "supervisedregistrationprofile" + ], + "codename": "view_supervisedregistrationprofile" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add access attempt", + "content_type": [ + "axes", + "accessattempt" + ], + "codename": "add_accessattempt" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change access attempt", + "content_type": [ + "axes", + "accessattempt" + ], + "codename": "change_accessattempt" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete access attempt", + "content_type": [ + "axes", + "accessattempt" + ], + "codename": "delete_accessattempt" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view access attempt", + "content_type": [ + "axes", + "accessattempt" + ], + "codename": "view_accessattempt" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add access log", + "content_type": [ + "axes", + "accesslog" + ], + "codename": "add_accesslog" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change access log", + "content_type": [ + "axes", + "accesslog" + ], + "codename": "change_accesslog" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete access log", + "content_type": [ + "axes", + "accesslog" + ], + "codename": "delete_accesslog" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view access log", + "content_type": [ + "axes", + "accesslog" + ], + "codename": "view_accesslog" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add user", + "content_type": [ + "accounts", + "user" + ], + "codename": "add_user" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change user", + "content_type": [ + "accounts", + "user" + ], + "codename": "change_user" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete user", + "content_type": [ + "accounts", + "user" + ], + "codename": "delete_user" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view user", + "content_type": [ + "accounts", + "user" + ], + "codename": "view_user" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add post", + "content_type": [ + "core", + "post" + ], + "codename": "add_post" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change post", + "content_type": [ + "core", + "post" + ], + "codename": "change_post" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete post", + "content_type": [ + "core", + "post" + ], + "codename": "delete_post" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view post", + "content_type": [ + "core", + "post" + ], + "codename": "view_post" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add Category", + "content_type": [ + "core", + "category" + ], + "codename": "add_category" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change Category", + "content_type": [ + "core", + "category" + ], + "codename": "change_category" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete Category", + "content_type": [ + "core", + "category" + ], + "codename": "delete_category" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view Category", + "content_type": [ + "core", + "category" + ], + "codename": "view_category" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can add collection rule", + "content_type": [ + "collection", + "collectionrule" + ], + "codename": "add_collectionrule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can change collection rule", + "content_type": [ + "collection", + "collectionrule" + ], + "codename": "change_collectionrule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can delete collection rule", + "content_type": [ + "collection", + "collectionrule" + ], + "codename": "delete_collectionrule" + } +}, +{ + "model": "auth.permission", + "fields": { + "name": "Can view collection rule", + "content_type": [ + "collection", + "collectionrule" + ], + "codename": "view_collectionrule" + } +}, { "model": "accounts.user", "fields": { - "password": "pbkdf2_sha256$150000$5lBD7JemxYfE$B+lM5wWUW2n/ZulPFaWHtzWjyQ/QZ6iwjAC2I0R/VzU=", - "last_login": "2019-11-27T18:57:36.686Z", + "password": "pbkdf2_sha256$180000$KGKGsPnSwyiN$RqQAD46r4Kzqndqp5dmpj+H/drDrPRI0r6j4gLtYBjE=", + "last_login": "2020-05-02T18:29:04.047Z", "is_superuser": true, "first_name": "", "last_name": "", @@ -114,23 +1128,6 @@ "user_permissions": [] } }, -{ - "model": "accounts.user", - "fields": { - "password": "pbkdf2_sha256$150000$vUwxT8T25R8C$S+Eq2tMRbSDE31/X5KGJ/M+Nblh7kKfzuM/z7HraR/Q=", - "last_login": null, - "is_superuser": false, - "first_name": "", - "last_name": "", - "is_staff": false, - "is_active": false, - "date_joined": "2019-11-25T15:35:14.051Z", - "email": "sonnyba871@gmail.com", - "task": 26, - "groups": [], - "user_permissions": [] - } -}, { "model": "core.category", "pk": 8, @@ -160,14 +1157,14 @@ "pk": 3, "fields": { "created": "2019-07-14T13:08:10.374Z", - "modified": "2019-11-29T22:35:20.346Z", + "modified": "2020-05-02T20:06:25.841Z", "name": "Hackers News", "url": "https://news.ycombinator.com/rss", "website_url": "https://news.ycombinator.com/", "favicon": "https://news.ycombinator.com/favicon.ico", "timezone": "UTC", "category": 9, - "last_suceeded": "2019-11-29T22:35:20.235Z", + "last_suceeded": "2020-05-02T20:06:25.793Z", "succeeded": true, "error": null, "user": [ @@ -180,14 +1177,14 @@ "pk": 4, "fields": { "created": "2019-07-20T11:24:32.745Z", - "modified": "2019-11-29T22:35:19.525Z", + "modified": "2020-05-02T20:06:24.719Z", "name": "BBC", "url": "http://feeds.bbci.co.uk/news/world/rss.xml", "website_url": "https://www.bbc.co.uk/news/", "favicon": "https://m.files.bbci.co.uk/modules/bbc-morph-news-waf-page-meta/2.5.2/apple-touch-icon-57x57-precomposed.png", "timezone": "UTC", "category": 8, - "last_suceeded": "2019-11-29T22:35:19.241Z", + "last_suceeded": "2020-05-02T20:06:24.128Z", "succeeded": true, "error": null, "user": [ @@ -200,14 +1197,14 @@ "pk": 5, "fields": { "created": "2019-07-20T11:24:50.411Z", - "modified": "2019-11-29T22:35:20.010Z", + "modified": "2020-05-02T20:06:25.548Z", "name": "Ars Technica", "url": "http://feeds.arstechnica.com/arstechnica/index?fmt=xml", "website_url": "https://arstechnica.com", "favicon": "https://cdn.arstechnica.net/favicon.ico", "timezone": "UTC", "category": 9, - "last_suceeded": "2019-11-29T22:35:19.808Z", + "last_suceeded": "2020-05-02T20:06:25.364Z", "succeeded": true, "error": null, "user": [ @@ -220,14 +1217,14 @@ "pk": 6, "fields": { "created": "2019-07-20T11:25:02.089Z", - "modified": "2019-11-29T22:35:20.233Z", + "modified": "2020-05-02T20:06:25.741Z", "name": "The Guardian", "url": "https://www.theguardian.com/world/rss", "website_url": "https://www.theguardian.com/world", "favicon": "https://assets.guim.co.uk/images/favicons/873381bf11d58e20f551905d51575117/72x72.png", "timezone": "UTC", "category": 8, - "last_suceeded": "2019-11-29T22:35:20.076Z", + "last_suceeded": "2020-05-02T20:06:25.620Z", "succeeded": true, "error": null, "user": [ @@ -240,14 +1237,14 @@ "pk": 7, "fields": { "created": "2019-07-20T11:25:30.121Z", - "modified": "2019-11-29T22:35:19.695Z", + "modified": "2020-05-02T20:06:25.352Z", "name": "Tweakers", "url": "http://feeds.feedburner.com/tweakers/mixed?fmt=xml", "website_url": "https://tweakers.net/", "favicon": null, "timezone": "UTC", "category": 9, - "last_suceeded": "2019-11-29T22:35:19.528Z", + "last_suceeded": "2020-05-02T20:06:24.730Z", "succeeded": true, "error": null, "user": [ @@ -260,14 +1257,14 @@ "pk": 8, "fields": { "created": "2019-07-20T11:25:46.256Z", - "modified": "2019-11-29T22:35:20.074Z", + "modified": "2020-05-02T20:06:25.792Z", "name": "The Verge", "url": "https://www.theverge.com/rss/index.xml", "website_url": "https://www.theverge.com/", "favicon": "https://cdn.vox-cdn.com/uploads/chorus_asset/file/7395367/favicon-16x16.0.png", "timezone": "UTC", "category": 9, - "last_suceeded": "2019-11-29T22:35:20.012Z", + "last_suceeded": "2020-05-02T20:06:25.742Z", "succeeded": true, "error": null, "user": [ @@ -280,19 +1277,1419 @@ "pk": 9, "fields": { "created": "2019-11-24T15:28:41.399Z", - "modified": "2019-11-29T22:35:19.807Z", + "modified": "2020-05-02T20:06:25.619Z", "name": "NOS", "url": "http://feeds.nos.nl/nosnieuwsalgemeen", "website_url": null, "favicon": null, "timezone": "Europe/Amsterdam", "category": 8, - "last_suceeded": "2019-11-29T22:35:19.697Z", + "last_suceeded": "2020-05-02T20:06:25.549Z", "succeeded": true, "error": null, "user": [ "sonny@bakker.nl" ] } +}, +{ + "model": "collection.collectionrule", + "pk": 10, + "fields": { + "created": "2020-05-02T20:32:34.107Z", + "modified": "2020-05-02T20:32:34.107Z", + "name": "CollectionRule-0", + "url": "http://rasmussen-guerra.com/", + "website_url": "https://ritter.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 11, + "fields": { + "created": "2020-05-02T20:32:34.164Z", + "modified": "2020-05-02T20:32:34.164Z", + "name": "CollectionRule-1", + "url": "https://www.evans.com/", + "website_url": "https://taylor.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 12, + "fields": { + "created": "2020-05-02T20:32:34.220Z", + "modified": "2020-05-02T20:32:34.220Z", + "name": "CollectionRule-2", + "url": "http://weaver-quinn.net/", + "website_url": "https://www.mcintyre.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 13, + "fields": { + "created": "2020-05-02T20:32:34.277Z", + "modified": "2020-05-02T20:32:34.277Z", + "name": "CollectionRule-3", + "url": "http://www.palmer.com/", + "website_url": "http://www.riggs.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 14, + "fields": { + "created": "2020-05-02T20:32:34.333Z", + "modified": "2020-05-02T20:32:34.333Z", + "name": "CollectionRule-4", + "url": "http://moody-stein.net/", + "website_url": "https://www.lewis.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 15, + "fields": { + "created": "2020-05-02T20:32:34.390Z", + "modified": "2020-05-02T20:32:34.391Z", + "name": "CollectionRule-5", + "url": "http://www.ochoa.com/", + "website_url": "https://brown.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 16, + "fields": { + "created": "2020-05-02T20:32:34.448Z", + "modified": "2020-05-02T20:32:34.448Z", + "name": "CollectionRule-6", + "url": "https://www.pearson.biz/", + "website_url": "http://acosta-johnson.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 17, + "fields": { + "created": "2020-05-02T20:32:34.506Z", + "modified": "2020-05-02T20:32:34.506Z", + "name": "CollectionRule-7", + "url": "https://jones.com/", + "website_url": "https://www.thornton.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 18, + "fields": { + "created": "2020-05-02T20:32:34.562Z", + "modified": "2020-05-02T20:32:34.562Z", + "name": "CollectionRule-8", + "url": "http://www.matthews-graves.com/", + "website_url": "http://stewart.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 19, + "fields": { + "created": "2020-05-02T20:32:34.618Z", + "modified": "2020-05-02T20:32:34.618Z", + "name": "CollectionRule-9", + "url": "http://www.kelly-martinez.com/", + "website_url": "https://www.freeman.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 20, + "fields": { + "created": "2020-05-02T20:32:34.674Z", + "modified": "2020-05-02T20:32:34.674Z", + "name": "CollectionRule-10", + "url": "https://www.roberts.biz/", + "website_url": "http://www.lopez.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 21, + "fields": { + "created": "2020-05-02T20:32:34.730Z", + "modified": "2020-05-02T20:32:34.730Z", + "name": "CollectionRule-11", + "url": "https://www.holmes-cross.com/", + "website_url": "https://www.ramirez.net/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 22, + "fields": { + "created": "2020-05-02T20:32:34.786Z", + "modified": "2020-05-02T20:32:34.786Z", + "name": "CollectionRule-12", + "url": "https://www.jenkins.com/", + "website_url": "https://www.faulkner.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 23, + "fields": { + "created": "2020-05-02T20:32:34.841Z", + "modified": "2020-05-02T20:32:34.842Z", + "name": "CollectionRule-13", + "url": "https://www.adkins.com/", + "website_url": "https://www.munoz-brown.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 24, + "fields": { + "created": "2020-05-02T20:32:34.897Z", + "modified": "2020-05-02T20:32:34.898Z", + "name": "CollectionRule-14", + "url": "https://www.rodriguez-ortega.biz/", + "website_url": "http://www.santos.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 25, + "fields": { + "created": "2020-05-02T20:32:34.953Z", + "modified": "2020-05-02T20:32:34.954Z", + "name": "CollectionRule-15", + "url": "https://www.hawkins-stewart.com/", + "website_url": "http://www.jones.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 26, + "fields": { + "created": "2020-05-02T20:32:35.010Z", + "modified": "2020-05-02T20:32:35.010Z", + "name": "CollectionRule-16", + "url": "http://mullins.net/", + "website_url": "https://www.curtis.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 27, + "fields": { + "created": "2020-05-02T20:32:35.067Z", + "modified": "2020-05-02T20:32:35.067Z", + "name": "CollectionRule-17", + "url": "http://frederick.com/", + "website_url": "https://www.fowler.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 28, + "fields": { + "created": "2020-05-02T20:32:35.124Z", + "modified": "2020-05-02T20:32:35.124Z", + "name": "CollectionRule-18", + "url": "http://schmidt.com/", + "website_url": "http://bryant-hoffman.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 29, + "fields": { + "created": "2020-05-02T20:32:35.180Z", + "modified": "2020-05-02T20:32:35.180Z", + "name": "CollectionRule-19", + "url": "https://www.jones.net/", + "website_url": "http://benjamin.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 30, + "fields": { + "created": "2020-05-02T20:32:35.237Z", + "modified": "2020-05-02T20:32:35.237Z", + "name": "CollectionRule-20", + "url": "https://www.parker-lewis.com/", + "website_url": "http://www.anderson.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 31, + "fields": { + "created": "2020-05-02T20:32:35.294Z", + "modified": "2020-05-02T20:32:35.294Z", + "name": "CollectionRule-21", + "url": "http://martinez.com/", + "website_url": "http://burton-scott.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 32, + "fields": { + "created": "2020-05-02T20:32:35.350Z", + "modified": "2020-05-02T20:32:35.350Z", + "name": "CollectionRule-22", + "url": "https://gibbs.com/", + "website_url": "https://www.robertson.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 33, + "fields": { + "created": "2020-05-02T20:32:35.407Z", + "modified": "2020-05-02T20:32:35.407Z", + "name": "CollectionRule-23", + "url": "http://www.fisher.com/", + "website_url": "https://mcclure-miller.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 34, + "fields": { + "created": "2020-05-02T20:32:35.463Z", + "modified": "2020-05-02T20:32:35.463Z", + "name": "CollectionRule-24", + "url": "https://schneider-lopez.org/", + "website_url": "https://andrews-williams.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 35, + "fields": { + "created": "2020-05-02T20:32:35.522Z", + "modified": "2020-05-02T20:32:35.522Z", + "name": "CollectionRule-25", + "url": "http://www.rogers.info/", + "website_url": "https://www.petersen-stewart.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 36, + "fields": { + "created": "2020-05-02T20:32:35.581Z", + "modified": "2020-05-02T20:32:35.581Z", + "name": "CollectionRule-26", + "url": "http://torres.com/", + "website_url": "https://hart-tapia.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 37, + "fields": { + "created": "2020-05-02T20:32:35.637Z", + "modified": "2020-05-02T20:32:35.638Z", + "name": "CollectionRule-27", + "url": "http://www.pham-scott.com/", + "website_url": "http://smith-diaz.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 38, + "fields": { + "created": "2020-05-02T20:32:35.699Z", + "modified": "2020-05-02T20:32:35.699Z", + "name": "CollectionRule-28", + "url": "http://www.gonzalez-castillo.com/", + "website_url": "http://www.conley.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 39, + "fields": { + "created": "2020-05-02T20:32:35.758Z", + "modified": "2020-05-02T20:32:35.758Z", + "name": "CollectionRule-29", + "url": "https://rogers-smith.net/", + "website_url": "http://www.sharp.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 40, + "fields": { + "created": "2020-05-02T20:32:35.814Z", + "modified": "2020-05-02T20:32:35.814Z", + "name": "CollectionRule-30", + "url": "https://neal-salinas.com/", + "website_url": "https://www.baird-warner.net/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 41, + "fields": { + "created": "2020-05-02T20:32:35.873Z", + "modified": "2020-05-02T20:32:35.874Z", + "name": "CollectionRule-31", + "url": "http://www.williams.com/", + "website_url": "http://www.wood.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 42, + "fields": { + "created": "2020-05-02T20:32:35.930Z", + "modified": "2020-05-02T20:32:35.930Z", + "name": "CollectionRule-32", + "url": "https://www.mueller.com/", + "website_url": "http://www.miller-ramirez.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 43, + "fields": { + "created": "2020-05-02T20:32:35.988Z", + "modified": "2020-05-02T20:32:35.989Z", + "name": "CollectionRule-33", + "url": "http://lee.com/", + "website_url": "http://www.moody.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 44, + "fields": { + "created": "2020-05-02T20:32:36.044Z", + "modified": "2020-05-02T20:32:36.045Z", + "name": "CollectionRule-34", + "url": "http://estrada.com/", + "website_url": "http://www.hicks.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 45, + "fields": { + "created": "2020-05-02T20:32:36.102Z", + "modified": "2020-05-02T20:32:36.102Z", + "name": "CollectionRule-35", + "url": "https://griffin-brewer.org/", + "website_url": "http://jones.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 46, + "fields": { + "created": "2020-05-02T20:32:36.161Z", + "modified": "2020-05-02T20:32:36.161Z", + "name": "CollectionRule-36", + "url": "http://www.dixon-johnson.com/", + "website_url": "https://mason.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 47, + "fields": { + "created": "2020-05-02T20:32:36.217Z", + "modified": "2020-05-02T20:32:36.217Z", + "name": "CollectionRule-37", + "url": "https://perez.com/", + "website_url": "http://www.miller.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 48, + "fields": { + "created": "2020-05-02T20:32:36.278Z", + "modified": "2020-05-02T20:32:36.279Z", + "name": "CollectionRule-38", + "url": "https://www.grant.net/", + "website_url": "https://www.clayton.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 49, + "fields": { + "created": "2020-05-02T20:32:36.336Z", + "modified": "2020-05-02T20:32:36.336Z", + "name": "CollectionRule-39", + "url": "http://www.lewis.org/", + "website_url": "http://cook.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 50, + "fields": { + "created": "2020-05-02T20:32:36.395Z", + "modified": "2020-05-02T20:32:36.395Z", + "name": "CollectionRule-40", + "url": "https://galloway-allen.net/", + "website_url": "http://www.rodriguez-callahan.info/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 51, + "fields": { + "created": "2020-05-02T20:32:36.453Z", + "modified": "2020-05-02T20:32:36.453Z", + "name": "CollectionRule-41", + "url": "https://www.macias.com/", + "website_url": "https://jarvis-green.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 52, + "fields": { + "created": "2020-05-02T20:32:36.510Z", + "modified": "2020-05-02T20:32:36.510Z", + "name": "CollectionRule-42", + "url": "http://mccullough-grant.com/", + "website_url": "https://shannon.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 53, + "fields": { + "created": "2020-05-02T20:32:36.566Z", + "modified": "2020-05-02T20:32:36.566Z", + "name": "CollectionRule-43", + "url": "http://www.foster-oneal.org/", + "website_url": "http://johns.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 54, + "fields": { + "created": "2020-05-02T20:32:36.623Z", + "modified": "2020-05-02T20:32:36.623Z", + "name": "CollectionRule-44", + "url": "http://www.wright.net/", + "website_url": "http://www.ali.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 55, + "fields": { + "created": "2020-05-02T20:32:36.682Z", + "modified": "2020-05-02T20:32:36.682Z", + "name": "CollectionRule-45", + "url": "http://www.payne-gibbs.info/", + "website_url": "http://knight.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 56, + "fields": { + "created": "2020-05-02T20:32:36.740Z", + "modified": "2020-05-02T20:32:36.740Z", + "name": "CollectionRule-46", + "url": "http://hammond.biz/", + "website_url": "http://www.nelson.net/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 57, + "fields": { + "created": "2020-05-02T20:32:36.797Z", + "modified": "2020-05-02T20:32:36.797Z", + "name": "CollectionRule-47", + "url": "http://gilmore.com/", + "website_url": "http://coleman.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 58, + "fields": { + "created": "2020-05-02T20:32:36.855Z", + "modified": "2020-05-02T20:32:36.855Z", + "name": "CollectionRule-48", + "url": "https://www.hernandez.com/", + "website_url": "https://www.phillips.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 59, + "fields": { + "created": "2020-05-02T20:32:36.912Z", + "modified": "2020-05-02T20:32:36.912Z", + "name": "CollectionRule-49", + "url": "https://www.nguyen.com/", + "website_url": "http://www.floyd.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 60, + "fields": { + "created": "2020-05-02T20:32:36.969Z", + "modified": "2020-05-02T20:32:36.969Z", + "name": "CollectionRule-50", + "url": "https://meyer-brown.net/", + "website_url": "https://www.blankenship.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 61, + "fields": { + "created": "2020-05-02T20:32:37.026Z", + "modified": "2020-05-02T20:32:37.027Z", + "name": "CollectionRule-51", + "url": "https://marks.net/", + "website_url": "http://gregory.net/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 62, + "fields": { + "created": "2020-05-02T20:32:37.087Z", + "modified": "2020-05-02T20:32:37.087Z", + "name": "CollectionRule-52", + "url": "http://www.baxter.com/", + "website_url": "http://barrera.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 63, + "fields": { + "created": "2020-05-02T20:32:37.143Z", + "modified": "2020-05-02T20:32:37.143Z", + "name": "CollectionRule-53", + "url": "http://johnson.com/", + "website_url": "https://abbott.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 64, + "fields": { + "created": "2020-05-02T20:32:37.202Z", + "modified": "2020-05-02T20:32:37.202Z", + "name": "CollectionRule-54", + "url": "https://hebert-marshall.biz/", + "website_url": "https://www.ashley-walsh.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 65, + "fields": { + "created": "2020-05-02T20:32:37.261Z", + "modified": "2020-05-02T20:32:37.261Z", + "name": "CollectionRule-55", + "url": "https://miller.com/", + "website_url": "https://www.hoffman.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 66, + "fields": { + "created": "2020-05-02T20:32:37.320Z", + "modified": "2020-05-02T20:32:37.320Z", + "name": "CollectionRule-56", + "url": "http://frey.com/", + "website_url": "https://long.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 67, + "fields": { + "created": "2020-05-02T20:32:37.379Z", + "modified": "2020-05-02T20:32:37.379Z", + "name": "CollectionRule-57", + "url": "https://edwards.com/", + "website_url": "http://www.nixon-doyle.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 68, + "fields": { + "created": "2020-05-02T20:32:37.435Z", + "modified": "2020-05-02T20:32:37.435Z", + "name": "CollectionRule-58", + "url": "https://www.bennett.com/", + "website_url": "http://sullivan.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 69, + "fields": { + "created": "2020-05-02T20:32:37.493Z", + "modified": "2020-05-02T20:32:37.493Z", + "name": "CollectionRule-59", + "url": "http://stokes-thomas.com/", + "website_url": "http://morgan.net/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 70, + "fields": { + "created": "2020-05-02T20:32:37.550Z", + "modified": "2020-05-02T20:32:37.550Z", + "name": "CollectionRule-60", + "url": "https://moore.net/", + "website_url": "http://www.hubbard.biz/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 71, + "fields": { + "created": "2020-05-02T20:32:37.609Z", + "modified": "2020-05-02T20:32:37.609Z", + "name": "CollectionRule-61", + "url": "https://baker-edwards.com/", + "website_url": "https://www.anderson.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 72, + "fields": { + "created": "2020-05-02T20:32:37.666Z", + "modified": "2020-05-02T20:32:37.666Z", + "name": "CollectionRule-62", + "url": "https://www.jackson.com/", + "website_url": "https://www.edwards.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 73, + "fields": { + "created": "2020-05-02T20:32:37.724Z", + "modified": "2020-05-02T20:32:37.724Z", + "name": "CollectionRule-63", + "url": "https://kemp-pollard.biz/", + "website_url": "http://www.fuentes.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 74, + "fields": { + "created": "2020-05-02T20:32:37.782Z", + "modified": "2020-05-02T20:32:37.782Z", + "name": "CollectionRule-64", + "url": "https://hanna-cook.com/", + "website_url": "http://www.bowen.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 75, + "fields": { + "created": "2020-05-02T20:32:37.839Z", + "modified": "2020-05-02T20:32:37.839Z", + "name": "CollectionRule-65", + "url": "http://www.williams.net/", + "website_url": "http://www.chandler.org/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 76, + "fields": { + "created": "2020-05-02T20:32:37.896Z", + "modified": "2020-05-02T20:32:37.896Z", + "name": "CollectionRule-66", + "url": "https://www.alexander.com/", + "website_url": "https://johnson-ellis.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 77, + "fields": { + "created": "2020-05-02T20:32:37.951Z", + "modified": "2020-05-02T20:32:37.951Z", + "name": "CollectionRule-67", + "url": "https://www.cisneros.com/", + "website_url": "http://fox.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 78, + "fields": { + "created": "2020-05-02T20:32:38.008Z", + "modified": "2020-05-02T20:32:38.008Z", + "name": "CollectionRule-68", + "url": "http://www.foster-burton.com/", + "website_url": "https://grant.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } +}, +{ + "model": "collection.collectionrule", + "pk": 79, + "fields": { + "created": "2020-05-02T20:32:38.066Z", + "modified": "2020-05-02T20:32:38.066Z", + "name": "CollectionRule-69", + "url": "https://www.hayes.net/", + "website_url": "http://morgan.com/", + "favicon": null, + "timezone": "UTC", + "category": null, + "last_suceeded": null, + "succeeded": false, + "error": null, + "user": [ + "sonny@bakker.nl" + ] + } } ] diff --git a/src/newsreader/js/components/Selector.js b/src/newsreader/js/components/Selector.js new file mode 100644 index 0000000..8b701f5 --- /dev/null +++ b/src/newsreader/js/components/Selector.js @@ -0,0 +1,23 @@ +class Selector { + onClick = ::this.onClick; + + inputs = []; + + constructor() { + const selectAllInput = document.querySelector('#select-all'); + + this.inputs = document.querySelectorAll(`[name=${selectAllInput.dataset.input}`); + + selectAllInput.onchange = this.onClick; + } + + onClick(e) { + const targetValue = e.target.checked; + + this.inputs.forEach(input => { + input.checked = targetValue; + }); + } +} + +export default Selector; diff --git a/src/newsreader/js/index.js b/src/newsreader/js/index.js index 48db0b2..1ed14ed 100644 --- a/src/newsreader/js/index.js +++ b/src/newsreader/js/index.js @@ -1,3 +1,3 @@ import './pages/homepage/index.js'; -import './pages/rules/index.js'; import './pages/categories/index.js'; +import './pages/rules/index.js'; diff --git a/src/newsreader/js/pages/rules/App.js b/src/newsreader/js/pages/rules/App.js deleted file mode 100644 index 7ceae4a..0000000 --- a/src/newsreader/js/pages/rules/App.js +++ /dev/null @@ -1,106 +0,0 @@ -import React from 'react'; - -import Cookies from 'js-cookie'; - -import Card from '../../components/Card.js'; -import RuleCard from './components/RuleCard.js'; -import RuleModal from './components/RuleModal.js'; -import Messages from '../../components/Messages.js'; - -class App extends React.Component { - selectRule = ::this.selectRule; - deselectRule = ::this.deselectRule; - deleteRule = ::this.deleteRule; - - constructor(props) { - super(props); - - this.token = Cookies.get('csrftoken'); - this.state = { - rules: props.rules, - selectedRuleId: null, - message: null, - }; - } - - selectRule(ruleId) { - this.setState({ selectedRuleId: ruleId }); - } - - deselectRule() { - this.setState({ selectedRuleId: null }); - } - - deleteRule(ruleId) { - const url = `/api/rules/${ruleId}/`; - const options = { - method: 'DELETE', - headers: { - 'X-CSRFToken': this.token, - }, - }; - - fetch(url, options).then(response => { - if (response.ok) { - const rules = this.state.rules.filter(rule => { - return rule.pk != ruleId; - }); - - return this.setState({ - rules: rules, - selectedRuleId: null, - message: null, - }); - } - }); - - const message = { - type: 'error', - text: 'Unable to remove rule, try again later', - }; - return this.setState({ selectedRuleId: null, message: message }); - } - - render() { - const { rules } = this.state; - const cards = rules.map(rule => { - return ; - }); - - const selectedRule = rules.find(rule => { - return rule.pk === this.state.selectedRuleId; - }); - - const pageHeader = ( - <> -

Rules

- -
- - Import rules - - - Create rule - -
- - ); - - return ( - <> - {this.state.message && } - - {cards} - {selectedRule && ( - - )} - - ); - } -} - -export default App; diff --git a/src/newsreader/js/pages/rules/components/RuleCard.js b/src/newsreader/js/pages/rules/components/RuleCard.js deleted file mode 100644 index d74b8d1..0000000 --- a/src/newsreader/js/pages/rules/components/RuleCard.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; - -import Card from '../../../components/Card.js'; - -const RuleCard = props => { - const { rule } = props; - let favicon = null; - - if (rule.favicon) { - favicon = ; - } else { - favicon = ; - } - - const stateIcon = !rule.error ? 'gg-check' : 'gg-danger'; - - const cardHeader = ( - <> - -

{rule.name}

- {favicon} - - ); - - const cardContent = ( - <> -
    - {rule.error && ( -
      -
    • {rule.error}
    • -
    - )} - - {rule.category &&
  • {rule.category}
  • } -
  • - - {rule.url} - -
  • -
  • {rule.created}
  • -
  • {rule.timezone}
  • -
- - ); - - const cardFooter = ( - <> - - Edit - - - - ); - - return ; -}; - -export default RuleCard; diff --git a/src/newsreader/js/pages/rules/components/RuleModal.js b/src/newsreader/js/pages/rules/components/RuleModal.js deleted file mode 100644 index d174cc3..0000000 --- a/src/newsreader/js/pages/rules/components/RuleModal.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; - -import Modal from '../../../components/Modal.js'; - -const RuleModal = props => { - const content = ( - <> -
-
-

Delete rule

-
- -
-

Are you sure you want to delete {props.rule.name}?

-
- -
- - -
-
- - ); - - return ; -}; - -export default RuleModal; diff --git a/src/newsreader/js/pages/rules/index.js b/src/newsreader/js/pages/rules/index.js index d0b46e9..b888121 100644 --- a/src/newsreader/js/pages/rules/index.js +++ b/src/newsreader/js/pages/rules/index.js @@ -1,13 +1,7 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; +import Selector from '../../components/Selector.js'; const page = document.getElementById('rules--page'); if (page) { - const dataScript = document.getElementById('rules-data'); - const rules = JSON.parse(dataScript.textContent); - - ReactDOM.render(, page); + new Selector(); } diff --git a/src/newsreader/news/collection/forms.py b/src/newsreader/news/collection/forms.py index d0b02be..bfa0d90 100644 --- a/src/newsreader/news/collection/forms.py +++ b/src/newsreader/news/collection/forms.py @@ -36,6 +36,17 @@ class CollectionRuleForm(forms.ModelForm): 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 OPMLImportForm(forms.Form): file = forms.FileField(allow_empty_file=False) skip_existing = forms.BooleanField(initial=False, required=False) diff --git a/src/newsreader/news/collection/migrations/0007_collectionrule_enabled.py b/src/newsreader/news/collection/migrations/0007_collectionrule_enabled.py new file mode 100644 index 0000000..fe6b0eb --- /dev/null +++ b/src/newsreader/news/collection/migrations/0007_collectionrule_enabled.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.5 on 2020-05-10 13:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [("collection", "0006_auto_20200412_1955")] + + operations = [ + migrations.AddField( + model_name="collectionrule", + name="enabled", + field=models.BooleanField( + default=True, help_text="Wether or not to collect items from this feed" + ), + ) + ] diff --git a/src/newsreader/news/collection/models.py b/src/newsreader/news/collection/models.py index d1d62ce..a5bfdfb 100644 --- a/src/newsreader/news/collection/models.py +++ b/src/newsreader/news/collection/models.py @@ -10,9 +10,7 @@ class CollectionRule(TimeStampedModel): name = models.CharField(max_length=100) 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) timezone = models.CharField( @@ -34,6 +32,9 @@ class CollectionRule(TimeStampedModel): last_suceeded = models.DateTimeField(blank=True, null=True) succeeded = models.BooleanField(default=False) error = models.CharField(max_length=1024, blank=True, null=True) + enabled = models.BooleanField( + default=True, help_text=_("Wether or not to collect items from this feed") + ) user = models.ForeignKey( "accounts.User", diff --git a/src/newsreader/news/collection/templates/collection/rules.html b/src/newsreader/news/collection/templates/collection/rules.html index 508916a..23b3fe7 100644 --- a/src/newsreader/news/collection/templates/collection/rules.html +++ b/src/newsreader/news/collection/templates/collection/rules.html @@ -1,30 +1,71 @@ {% extends "base.html" %} +{% load i18n %} {% load static %} {% block content %} -
-{% endblock %} +
+
+ {% csrf_token %} -{% block scripts %} - +
+ + + +
+ + + + + + + + + + + + + + {% for rule in rules %} + + + + + + + + + + {% endfor %} + +
+ + {% trans "Name" %}{% trans "Category" %}{% trans "URL" %}{% trans "Successfuly ran" %}{% trans "Enabled" %}
{{ rule.name }}{{ rule.category.name }}{{ rule.url }}{{ rule.succeeded }}{{ rule.enabled }} + +
+
+ +
{% endblock %} diff --git a/src/newsreader/news/collection/tests/views/test_bulk_views.py b/src/newsreader/news/collection/tests/views/test_bulk_views.py new file mode 100644 index 0000000..7679907 --- /dev/null +++ b/src/newsreader/news/collection/tests/views/test_bulk_views.py @@ -0,0 +1,244 @@ + +from django.conf import settings +from django.test import TestCase +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ + +import pytz + +from newsreader.accounts.tests.factories import UserFactory +from newsreader.news.collection.models import CollectionRule +from newsreader.news.collection.tests.factories import CollectionRuleFactory +from newsreader.news.core.tests.factories import CategoryFactory + + +class CollectionRuleBulkViewTestCase: + def setUp(self): + self.redirect_url = reverse("rules") + + self.user = UserFactory() + self.client.force_login(self.user) + + +class CollectionRuleBulkEnableViewTestCase(CollectionRuleBulkViewTestCase, TestCase): + def setUp(self): + super().setUp() + + self.url = reverse("rules-enable") + + self.rules = CollectionRuleFactory.create_batch( + size=5, user=self.user, enabled=False + ) + + def test_simple(self): + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, True) + + self.assertNotContains(response, _("The form contains errors, try again later")) + + def test_empty_rules(self): + response = self.client.post(self.url, {"rules": []}, follow=True) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, False) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_rule_from_other_user(self): + other_user = UserFactory() + other_rules = CollectionRuleFactory.create_batch( + size=5, user=other_user, enabled=False + ) + + response = self.client.post( + self.url, + {"rules": [other_rule.pk for other_rule in other_rules]}, + follow=True, + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=other_user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, False) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_unauthenticated(self): + self.client.logout() + + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects( + response, f"{reverse('accounts:login')}?next={reverse('rules-enable')}" + ) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, False) + + +class CollectionRuleBulkDisableViewTestCase(CollectionRuleBulkViewTestCase, TestCase): + def setUp(self): + super().setUp() + + self.url = reverse("rules-disable") + + self.rules = CollectionRuleFactory.create_batch( + size=5, user=self.user, enabled=True + ) + + def test_simple(self): + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, False) + + self.assertNotContains(response, _("The form contains errors, try again later")) + + def test_empty_rules(self): + response = self.client.post(self.url, {"rules": []}, follow=True) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, True) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_rule_from_other_user(self): + other_user = UserFactory() + other_rules = CollectionRuleFactory.create_batch( + size=5, user=other_user, enabled=True + ) + + response = self.client.post( + self.url, + {"rules": [other_rule.pk for other_rule in other_rules]}, + follow=True, + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=other_user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, True) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_unauthenticated(self): + self.client.logout() + + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects( + response, f"{reverse('accounts:login')}?next={reverse('rules-disable')}" + ) + + rules = CollectionRule.objects.filter(user=self.user) + + for rule in rules: + with self.subTest(rule=rule): + self.assertEqual(rule.enabled, True) + + +class CollectionRuleBulkDeleteViewTestCase(CollectionRuleBulkViewTestCase, TestCase): + def setUp(self): + super().setUp() + + self.url = reverse("rules-delete") + + self.rules = CollectionRuleFactory.create_batch(size=5, user=self.user) + + def test_simple(self): + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + self.assertCountEqual(rules, []) + + self.assertNotContains(response, _("The form contains errors, try again later")) + + def test_empty_rules(self): + response = self.client.post(self.url, {"rules": []}, follow=True) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=self.user) + + self.assertCountEqual(rules, self.rules) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_rule_from_other_user(self): + other_user = UserFactory() + other_rules = CollectionRuleFactory.create_batch( + size=5, user=other_user, enabled=True + ) + + response = self.client.post( + self.url, + {"rules": [other_rule.pk for other_rule in other_rules]}, + follow=True, + ) + + self.assertRedirects(response, self.redirect_url) + + rules = CollectionRule.objects.filter(user=other_user) + + self.assertCountEqual(rules, other_rules) + + self.assertContains(response, _("The form contains errors, try again later")) + + def test_unauthenticated(self): + self.client.logout() + + response = self.client.post( + self.url, {"rules": [rule.pk for rule in self.rules]}, follow=True + ) + + self.assertRedirects( + response, f"{reverse('accounts:login')}?next={reverse('rules-delete')}" + ) + + rules = CollectionRule.objects.filter(user=self.user) + + self.assertCountEqual(rules, self.rules) diff --git a/src/newsreader/news/collection/tests/test_views.py b/src/newsreader/news/collection/tests/views/test_crud.py similarity index 52% rename from src/newsreader/news/collection/tests/test_views.py rename to src/newsreader/news/collection/tests/views/test_crud.py index 0acd3ed..d77bcf6 100644 --- a/src/newsreader/news/collection/tests/test_views.py +++ b/src/newsreader/news/collection/tests/views/test_crud.py @@ -150,135 +150,3 @@ class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase): self.rule.refresh_from_db() self.assertEquals(self.rule.category, None) - - -class OPMLImportTestCase(TestCase): - def setUp(self): - self.user = UserFactory(password="test") - self.client.force_login(self.user) - - self.form_data = {"file": "", "skip_existing": False} - self.url = reverse("import") - - def _get_file_path(self, name): - file_dir = os.path.join(settings.DJANGO_PROJECT_DIR, "utils", "tests", "files") - return os.path.join(file_dir, name) - - def test_simple(self): - file_path = self._get_file_path("feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertRedirects(response, reverse("rules")) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 4) - - def test_existing_rules(self): - CollectionRuleFactory( - url="http://www.engadget.com/rss-full.xml", user=self.user - ) - CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user) - CollectionRuleFactory( - url="http://feeds.feedburner.com/Techcrunch", user=self.user - ) - CollectionRuleFactory( - url="http://feeds.feedburner.com/tweakers/nieuws", user=self.user - ) - - file_path = self._get_file_path("feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertRedirects(response, reverse("rules")) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 8) - - def test_skip_existing_rules(self): - CollectionRuleFactory( - url="http://www.engadget.com/rss-full.xml", user=self.user - ) - CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user) - CollectionRuleFactory( - url="http://feeds.feedburner.com/Techcrunch", user=self.user - ) - CollectionRuleFactory( - url="http://feeds.feedburner.com/tweakers/nieuws", user=self.user - ) - - file_path = self._get_file_path("feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file, skip_existing=True) - - response = self.client.post(self.url, self.form_data) - - self.assertEquals(response.status_code, 200) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 4) - - def test_empty_feed_file(self): - file_path = self._get_file_path("empty-feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertEquals(response.status_code, 200) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 0) - - self.assertFormError(response, "form", "file", _("No (new) rules found")) - - def test_invalid_feeds(self): - file_path = self._get_file_path("invalid-url-feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertEquals(response.status_code, 200) - - rules = CollectionRule.objects.all() - - self.assertEquals(len(rules), 0) - self.assertFormError(response, "form", "file", _("No (new) rules found")) - - def test_invalid_file(self): - file_path = self._get_file_path("test.png") - - with open(file_path, "rb") as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertEquals(response.status_code, 200) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 0) - - self.assertFormError(response, "form", "file", _("Invalid OPML file")) - - def test_feeds_with_missing_attr(self): - file_path = self._get_file_path("missing-feeds.opml") - - with open(file_path) as file: - self.form_data.update(file=file) - - response = self.client.post(self.url, self.form_data) - - self.assertRedirects(response, reverse("rules")) - - rules = CollectionRule.objects.all() - self.assertEquals(len(rules), 2) diff --git a/src/newsreader/news/collection/tests/views/test_import_view.py b/src/newsreader/news/collection/tests/views/test_import_view.py new file mode 100644 index 0000000..57ac502 --- /dev/null +++ b/src/newsreader/news/collection/tests/views/test_import_view.py @@ -0,0 +1,141 @@ +import os + +from django.conf import settings +from django.test import TestCase +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ + +import pytz + +from newsreader.accounts.tests.factories import UserFactory +from newsreader.news.collection.models import CollectionRule +from newsreader.news.collection.tests.factories import CollectionRuleFactory +from newsreader.news.core.tests.factories import CategoryFactory + + +class OPMLImportTestCase(TestCase): + def setUp(self): + self.user = UserFactory(password="test") + self.client.force_login(self.user) + + self.form_data = {"file": "", "skip_existing": False} + self.url = reverse("import") + + def _get_file_path(self, name): + file_dir = os.path.join(settings.DJANGO_PROJECT_DIR, "utils", "tests", "files") + return os.path.join(file_dir, name) + + def test_simple(self): + file_path = self._get_file_path("feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertRedirects(response, reverse("rules")) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 4) + + def test_existing_rules(self): + CollectionRuleFactory(url="http://www.engadget.com/rss-full.xml", user=self.user) + CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user) + CollectionRuleFactory( + url="http://feeds.feedburner.com/Techcrunch", user=self.user + ) + CollectionRuleFactory( + url="http://feeds.feedburner.com/tweakers/nieuws", user=self.user + ) + + file_path = self._get_file_path("feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertRedirects(response, reverse("rules")) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 8) + + def test_skip_existing_rules(self): + CollectionRuleFactory(url="http://www.engadget.com/rss-full.xml", user=self.user) + CollectionRuleFactory(url="https://news.ycombinator.com/rss", user=self.user) + CollectionRuleFactory( + url="http://feeds.feedburner.com/Techcrunch", user=self.user + ) + CollectionRuleFactory( + url="http://feeds.feedburner.com/tweakers/nieuws", user=self.user + ) + + file_path = self._get_file_path("feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file, skip_existing=True) + + response = self.client.post(self.url, self.form_data) + + self.assertEquals(response.status_code, 200) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 4) + + def test_empty_feed_file(self): + file_path = self._get_file_path("empty-feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertEquals(response.status_code, 200) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 0) + + self.assertFormError(response, "form", "file", _("No (new) rules found")) + + def test_invalid_feeds(self): + file_path = self._get_file_path("invalid-url-feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertEquals(response.status_code, 200) + + rules = CollectionRule.objects.all() + + self.assertEquals(len(rules), 0) + self.assertFormError(response, "form", "file", _("No (new) rules found")) + + def test_invalid_file(self): + file_path = self._get_file_path("test.png") + + with open(file_path, "rb") as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertEquals(response.status_code, 200) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 0) + + self.assertFormError(response, "form", "file", _("Invalid OPML file")) + + def test_feeds_with_missing_attr(self): + file_path = self._get_file_path("missing-feeds.opml") + + with open(file_path) as file: + self.form_data.update(file=file) + + response = self.client.post(self.url, self.form_data) + + self.assertRedirects(response, reverse("rules")) + + rules = CollectionRule.objects.all() + self.assertEquals(len(rules), 2) diff --git a/src/newsreader/news/collection/urls.py b/src/newsreader/news/collection/urls.py index 28b6f38..1ea17d6 100644 --- a/src/newsreader/news/collection/urls.py +++ b/src/newsreader/news/collection/urls.py @@ -8,6 +8,9 @@ from newsreader.news.collection.endpoints import ( RuleReadView, ) from newsreader.news.collection.views import ( + CollectionRuleBulkDeleteView, + CollectionRuleBulkDisableView, + CollectionRuleBulkEnableView, CollectionRuleCreateView, CollectionRuleListView, CollectionRuleUpdateView, @@ -34,5 +37,20 @@ urlpatterns = [ login_required(CollectionRuleCreateView.as_view()), name="rule-create", ), + path( + "rules/delete/", + login_required(CollectionRuleBulkDeleteView.as_view()), + name="rules-delete", + ), + path( + "rules/enable/", + login_required(CollectionRuleBulkEnableView.as_view()), + name="rules-enable", + ), + path( + "rules/disable/", + login_required(CollectionRuleBulkDisableView.as_view()), + name="rules-disable", + ), path("rules/import/", login_required(OPMLImportView.as_view()), name="import"), ] diff --git a/src/newsreader/news/collection/views.py b/src/newsreader/news/collection/views.py index 8d254e2..ca531fb 100644 --- a/src/newsreader/news/collection/views.py +++ b/src/newsreader/news/collection/views.py @@ -1,12 +1,17 @@ from django.contrib import messages -from django.urls import reverse_lazy +from django.shortcuts import redirect +from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic.edit import CreateView, FormView, UpdateView from django.views.generic.list import ListView import pytz -from newsreader.news.collection.forms import CollectionRuleForm, OPMLImportForm +from newsreader.news.collection.forms import ( + CollectionRuleBulkForm, + CollectionRuleForm, + OPMLImportForm, +) from newsreader.news.collection.models import CollectionRule from newsreader.news.core.models import Category from newsreader.utils.opml import parse_opml @@ -17,7 +22,7 @@ class CollectionRuleViewMixin: def get_queryset(self): user = self.request.user - return self.queryset.filter(user=user) + return self.queryset.filter(user=user).order_by("name") class CollectionRuleDetailMixin: @@ -42,6 +47,7 @@ class CollectionRuleDetailMixin: class CollectionRuleListView(CollectionRuleViewMixin, ListView): + paginate_by = 50 template_name = "collection/rules.html" context_object_name = "rules" @@ -59,6 +65,60 @@ class CollectionRuleCreateView( template_name = "collection/rule-create.html" +class CollectionRuleBulkView(FormView): + form_class = CollectionRuleBulkForm + + def get_redirect_url(self): + return reverse("rules") + + def get_success_url(self): + return self.get_redirect_url() + + def get_form(self, form_class=None): + if form_class is None: + form_class = self.get_form_class() + return form_class(self.request.user, **self.get_form_kwargs()) + + def form_invalid(self, form): + url = self.get_redirect_url() + + messages.error(self.request, _("The form contains errors, try again later")) + + return redirect(url) + + +class CollectionRuleBulkEnableView(CollectionRuleBulkView): + def form_valid(self, form): + response = super().form_valid(form) + + for rule in form.cleaned_data["rules"]: + rule.enabled = True + rule.save() + + return response + + +class CollectionRuleBulkDisableView(CollectionRuleBulkView): + def form_valid(self, form): + response = super().form_valid(form) + + for rule in form.cleaned_data["rules"]: + rule.enabled = False + rule.save() + + return response + + +class CollectionRuleBulkDeleteView(CollectionRuleBulkView): + def form_valid(self, form): + response = super().form_valid(form) + + for rule in form.cleaned_data["rules"]: + rule.delete() + + return response + + class OPMLImportView(FormView): form_class = OPMLImportForm success_url = reverse_lazy("rules") diff --git a/src/newsreader/scss/components/form/_form.scss b/src/newsreader/scss/components/form/_form.scss index 931fba9..5b97958 100644 --- a/src/newsreader/scss/components/form/_form.scss +++ b/src/newsreader/scss/components/form/_form.scss @@ -19,6 +19,14 @@ padding: 15px; } + &__actions { + display: flex; + justify-content: space-between; + + width: 50%; + padding: 15px; + } + &__title { font-size: 18px; } diff --git a/src/newsreader/scss/components/form/_rules-form.scss b/src/newsreader/scss/components/form/_rules-form.scss new file mode 100644 index 0000000..44d4765 --- /dev/null +++ b/src/newsreader/scss/components/form/_rules-form.scss @@ -0,0 +1,5 @@ +.rules-form { + @extend .form; + + width: 90%; +} diff --git a/src/newsreader/scss/components/form/index.scss b/src/newsreader/scss/components/form/index.scss index 2c70cdd..547da89 100644 --- a/src/newsreader/scss/components/form/index.scss +++ b/src/newsreader/scss/components/form/index.scss @@ -2,6 +2,7 @@ @import "category-form"; @import "rule-form"; +@import "rules-form"; @import "import-form"; @import "login-form"; diff --git a/src/newsreader/scss/components/index.scss b/src/newsreader/scss/components/index.scss index 4bddb31..53e0f71 100644 --- a/src/newsreader/scss/components/index.scss +++ b/src/newsreader/scss/components/index.scss @@ -12,7 +12,9 @@ @import "section/index"; @import "errorlist/index"; @import "fieldset/index"; +@import "pagination/index"; @import "sidebar/index"; +@import "table/index"; @import "rules/index"; @import "category/index"; diff --git a/src/newsreader/scss/components/pagination/_pagination.scss b/src/newsreader/scss/components/pagination/_pagination.scss new file mode 100644 index 0000000..d4ba4a9 --- /dev/null +++ b/src/newsreader/scss/components/pagination/_pagination.scss @@ -0,0 +1,18 @@ +@import "../../elements/button/mixins"; + +.pagination { + display: flex; + justify-content: space-evenly; + + &__previous, &__current, &__next { + display: flex; + justify-content: space-evenly; + + width: 33%; + text-align: center; + } + + &__current { + @include button-padding; + } +} diff --git a/src/newsreader/scss/components/pagination/index.scss b/src/newsreader/scss/components/pagination/index.scss new file mode 100644 index 0000000..d92e61f --- /dev/null +++ b/src/newsreader/scss/components/pagination/index.scss @@ -0,0 +1 @@ +@import "pagination"; diff --git a/src/newsreader/scss/components/table/_rules-table.scss b/src/newsreader/scss/components/table/_rules-table.scss new file mode 100644 index 0000000..3eaf3b3 --- /dev/null +++ b/src/newsreader/scss/components/table/_rules-table.scss @@ -0,0 +1,38 @@ +.rules-table { + &__heading { + &--select { + width: 5%; + } + + &--name { + width: 20%; + } + + &--category { + width: 15%; + } + + &--url { + width: 40%; + } + + &--succeeded { + width: 15%; + } + + &--enabled { + width: 10%; + } + + &--link { + width: 5%; + } + } + + & .link { + display: flex; + justify-content: center; + + padding: 10px; + } +} diff --git a/src/newsreader/scss/components/table/_table.scss b/src/newsreader/scss/components/table/_table.scss new file mode 100644 index 0000000..60ab7e8 --- /dev/null +++ b/src/newsreader/scss/components/table/_table.scss @@ -0,0 +1,32 @@ +@import "../../lib/mixins"; + +.table { + @include rounded; + + table-layout: fixed; + background-color: $white; + width: 90%; + padding: 20px; + + text-align: left; + white-space: nowrap; + + &__heading { + @extend .h1; + } + + &__item { + padding: 10px 0; + + border-bottom: 1px solid $border-gray; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__footer { + width: 80%; + padding: 10px 0; + } +} diff --git a/src/newsreader/scss/components/table/index.scss b/src/newsreader/scss/components/table/index.scss new file mode 100644 index 0000000..d175a21 --- /dev/null +++ b/src/newsreader/scss/components/table/index.scss @@ -0,0 +1,2 @@ +@import "table"; +@import "rules-table"; diff --git a/src/newsreader/scss/elements/button/_button.scss b/src/newsreader/scss/elements/button/_button.scss index a6bec19..3a06cd3 100644 --- a/src/newsreader/scss/elements/button/_button.scss +++ b/src/newsreader/scss/elements/button/_button.scss @@ -1,10 +1,12 @@ +@import "mixins"; + .button { display: flex; align-items: center; justify-content: center; - padding: 10px 50px; + @include button-padding; border: none; border-radius: 2px; diff --git a/src/newsreader/scss/elements/button/_mixins.scss b/src/newsreader/scss/elements/button/_mixins.scss new file mode 100644 index 0000000..06a912c --- /dev/null +++ b/src/newsreader/scss/elements/button/_mixins.scss @@ -0,0 +1,3 @@ +@mixin button-padding { + padding: 10px 50px; +} diff --git a/src/newsreader/scss/elements/link/_link.scss b/src/newsreader/scss/elements/link/_link.scss index 1843c0b..b485cb3 100644 --- a/src/newsreader/scss/elements/link/_link.scss +++ b/src/newsreader/scss/elements/link/_link.scss @@ -10,7 +10,3 @@ a { @extend .link; } - -.gg-link { - color: initial; -} diff --git a/src/newsreader/scss/lib/_css.gg.scss b/src/newsreader/scss/lib/_css.gg.scss index 389e533..e7096d5 100644 --- a/src/newsreader/scss/lib/_css.gg.scss +++ b/src/newsreader/scss/lib/_css.gg.scss @@ -1 +1,9 @@ @import "~css.gg/icons-scss/icons"; + +.gg-link { + color: initial; +} + +.gg-pen { + color: initial; +} diff --git a/src/newsreader/scss/lib/_mixins.scss b/src/newsreader/scss/lib/_mixins.scss new file mode 100644 index 0000000..e2d28aa --- /dev/null +++ b/src/newsreader/scss/lib/_mixins.scss @@ -0,0 +1,3 @@ +@mixin rounded { + border-radius: 5px; +} diff --git a/src/newsreader/scss/pages/index.scss b/src/newsreader/scss/pages/index.scss index 872ac89..27f0bc6 100644 --- a/src/newsreader/scss/pages/index.scss +++ b/src/newsreader/scss/pages/index.scss @@ -8,5 +8,5 @@ @import "password-reset/index"; @import "register/index"; -@import "rules/index"; @import "rule/index"; +@import "rules/index"; diff --git a/src/newsreader/scss/pages/rules/index.scss b/src/newsreader/scss/pages/rules/index.scss index 68b92cb..64f46b4 100644 --- a/src/newsreader/scss/pages/rules/index.scss +++ b/src/newsreader/scss/pages/rules/index.scss @@ -1,7 +1,5 @@ #rules--page { - .list__item { - & .link { - margin: 0; - } + & .table { + width: 100%; } }