diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3159668..d7c9f02 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,6 +18,7 @@ javascript build: python tests: services: - postgres:11 + - memcached:1.5.22 image: python:3.7.4-slim-stretch stage: test variables: diff --git a/docker-compose.yml b/docker-compose.yml index f4ab666..b940476 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,14 @@ services: - .:/app depends_on: - rabbitmq + memcached: + image: memcached:1.5.22 + container_name: memcached + ports: + - "11211:11211" + entrypoint: + - memcached + - -m 64 web: build: . container_name: web diff --git a/requirements/base.txt b/requirements/base.txt index 033f18c..e362370 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,6 +3,7 @@ beautifulsoup4==4.7.1 celery==4.3.0 certifi==2019.3.9 chardet==3.0.4 +django-axes==5.2.2 Django==2.2 django-celery-beat==1.5.0 djangorestframework==3.9.4 @@ -11,6 +12,7 @@ django-registration-redux==2.6 lxml==4.4.2 feedparser==5.2.1 idna==2.8 +python-memcached==1.59 pytz==2018.9 requests==2.21.0 sqlparse==0.3.0 diff --git a/src/newsreader/conf/base.py b/src/newsreader/conf/base.py index 632aff3..3914705 100644 --- a/src/newsreader/conf/base.py +++ b/src/newsreader/conf/base.py @@ -1,15 +1,3 @@ -""" -Django settings for newsreader project. - -Generated by "django-admin startproject" using Django 2.2. - -For more information on this file, see -https://docs.djangoproject.com/en/2.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/2.2/ref/settings/ -""" - import os from pathlib import Path @@ -43,12 +31,18 @@ INSTALLED_APPS = [ "celery", "django_celery_beat", "registration", + "axes", # app modules "newsreader.accounts", "newsreader.news.core", "newsreader.news.collection", ] +AUTHENTICATION_BACKENDS = [ + "axes.backends.AxesBackend", + "django.contrib.auth.backends.ModelBackend", +] + MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", @@ -57,6 +51,7 @@ MIDDLEWARE = [ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "axes.middleware.AxesMiddleware", ] ROOT_URLCONF = "newsreader.urls" @@ -125,6 +120,12 @@ STATICFILES_FINDERS = [ ] # Third party settings +AXES_HANDLER = "axes.handlers.cache.AxesCacheHandler" +AXES_CACHE = "axes" +AXES_FAILURE_LIMIT = 5 +AXES_COOLOFF_TIME = 3 # in hours +AXES_RESET_ON_SUCCESS = True + REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework.authentication.SessionAuthentication", diff --git a/src/newsreader/conf/docker.py b/src/newsreader/conf/docker.py index c616942..fe20d06 100644 --- a/src/newsreader/conf/docker.py +++ b/src/newsreader/conf/docker.py @@ -4,3 +4,14 @@ from .dev import * # Celery # https://docs.celeryproject.org/en/latest/userguide/configuration.html BROKER_URL = "amqp://guest:guest@rabbitmq:5672//" + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", + "LOCATION": "memcached:11211", + }, + "axes": { + "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", + "LOCATION": "memcached:11211", + }, +} diff --git a/src/newsreader/conf/gitlab.py b/src/newsreader/conf/gitlab.py index ddacab9..3108245 100644 --- a/src/newsreader/conf/gitlab.py +++ b/src/newsreader/conf/gitlab.py @@ -4,3 +4,16 @@ from .base import * # noqa DEBUG = True EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + +AXES_ENABLED = False + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", + "LOCATION": "memcached:11211", + }, + "axes": { + "BACKEND": "django.core.cache.backends.memcached.MemcachedCache", + "LOCATION": "memcached:11211", + }, +} diff --git a/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py b/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py index 8dc75d0..a489d55 100644 --- a/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py +++ b/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py @@ -12,7 +12,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class CollectionRuleDetailViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): rule = CollectionRuleFactory(user=self.user) @@ -162,7 +162,7 @@ class CollectionRuleDetailViewTestCase(TestCase): class CollectionRuleReadTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_rule_read(self): rule = CollectionRuleFactory(user=self.user) diff --git a/src/newsreader/news/collection/tests/endpoints/rule/list/tests.py b/src/newsreader/news/collection/tests/endpoints/rule/list/tests.py index 4526bdd..a84a093 100644 --- a/src/newsreader/news/collection/tests/endpoints/rule/list/tests.py +++ b/src/newsreader/news/collection/tests/endpoints/rule/list/tests.py @@ -15,7 +15,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class RuleListViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): CollectionRuleFactory.create_batch(size=3, user=self.user) @@ -148,7 +148,7 @@ class RuleListViewTestCase(TestCase): class NestedRuleListViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): rule = CollectionRuleFactory.create(user=self.user) diff --git a/src/newsreader/news/collection/tests/test_views.py b/src/newsreader/news/collection/tests/test_views.py index 5a1a59e..1b87ae6 100644 --- a/src/newsreader/news/collection/tests/test_views.py +++ b/src/newsreader/news/collection/tests/test_views.py @@ -16,7 +16,7 @@ from newsreader.news.core.tests.factories import CategoryFactory class CollectionRuleViewTestCase: def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) self.category = CategoryFactory(user=self.user) self.form_data = {"name": "", "category": "", "url": "", "timezone": ""} @@ -155,7 +155,7 @@ class CollectionRuleUpdateViewTestCase(CollectionRuleViewTestCase, TestCase): class OPMLImportTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) self.form_data = {"file": "", "skip_existing": False} self.url = reverse("import") diff --git a/src/newsreader/news/core/tests/endpoints/category/detail/tests.py b/src/newsreader/news/core/tests/endpoints/category/detail/tests.py index 787d8a9..ffe9278 100644 --- a/src/newsreader/news/core/tests/endpoints/category/detail/tests.py +++ b/src/newsreader/news/core/tests/endpoints/category/detail/tests.py @@ -11,7 +11,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class CategoryDetailViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): category = CategoryFactory(user=self.user) @@ -122,7 +122,7 @@ class CategoryDetailViewTestCase(TestCase): class CategoryReadTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_category_read(self): category = CategoryFactory(user=self.user) diff --git a/src/newsreader/news/core/tests/endpoints/category/list/tests.py b/src/newsreader/news/core/tests/endpoints/category/list/tests.py index f58832e..54058fd 100644 --- a/src/newsreader/news/core/tests/endpoints/category/list/tests.py +++ b/src/newsreader/news/core/tests/endpoints/category/list/tests.py @@ -15,7 +15,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class CategoryListViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): CategoryFactory.create_batch(size=3, user=self.user) @@ -121,7 +121,7 @@ class CategoryListViewTestCase(TestCase): class NestedCategoryListViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): category = CategoryFactory.create(user=self.user) @@ -280,7 +280,7 @@ class NestedCategoryListViewTestCase(TestCase): class NestedCategoryPostView(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): category = CategoryFactory.create(user=self.user) diff --git a/src/newsreader/news/core/tests/endpoints/post/detail/tests.py b/src/newsreader/news/core/tests/endpoints/post/detail/tests.py index bc184a3..f012cc2 100644 --- a/src/newsreader/news/core/tests/endpoints/post/detail/tests.py +++ b/src/newsreader/news/core/tests/endpoints/post/detail/tests.py @@ -11,7 +11,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class PostDetailViewTestCase(TestCase): def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): rule = CollectionRuleFactory( diff --git a/src/newsreader/news/core/tests/endpoints/post/list/tests.py b/src/newsreader/news/core/tests/endpoints/post/list/tests.py index 013decd..ba7aba9 100644 --- a/src/newsreader/news/core/tests/endpoints/post/list/tests.py +++ b/src/newsreader/news/core/tests/endpoints/post/list/tests.py @@ -13,7 +13,7 @@ from newsreader.news.core.tests.factories import CategoryFactory, PostFactory class PostListViewTestCase(TestCase): def setUp(self): self.user = UserFactory(is_staff=True, password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): rule = CollectionRuleFactory( diff --git a/src/newsreader/news/core/tests/test_views.py b/src/newsreader/news/core/tests/test_views.py index ad1dc1d..8b62b85 100644 --- a/src/newsreader/news/core/tests/test_views.py +++ b/src/newsreader/news/core/tests/test_views.py @@ -10,7 +10,7 @@ from newsreader.news.core.tests.factories import CategoryFactory class CategoryViewTestCase: def setUp(self): self.user = UserFactory(password="test") - self.client.login(email=self.user.email, password="test") + self.client.force_login(self.user) def test_simple(self): response = self.client.get(self.url)