Commit e12ebd45 authored by okhin's avatar okhin 🚴

Merge branch '51-migration-en-django-2-x' into 'rp2'

Resolve "Migration en django 2.X"

Closes #51

See merge request !48
parents 2314060a bd8b8825
Pipeline #2643 passed with stages
in 3 minutes and 49 seconds
......@@ -17,9 +17,9 @@ unit tests:
script:
- virtualenv -p python3 env
- source ./env/bin/activate
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
- pip install -r requirements-tests.txt
- pip install -U -r requirements.txt
- pip install -U -r requirements-dev.txt
- pip install -U -r requirements-tests.txt
- echo "DEBUG = True" > ./project/settings/env.py
- echo "SECRET_KEY = '$(pwgen 20 1)'" >> ./project/settings/env.py
- ./manage.py migrate --run-syncdb
......
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
class EmailOrUsernameModelBackend(ModelBackend):
"""
Authentification backend to allow email
overide AUTHENTICATION_BACKENDS with
fabauth.auth_backends.EmailOrUsernameModelBackend
We allow for email or username to be used as a login.
Case insensitive.
"""
def authenticate(self, username=None, password=None, **kwargs):
if "@" in username:
kwargs = {"email": username}
else:
kwargs = {"username": username}
def authenticate(self, request, username=None, password=None):
# If we call this function, it means we're not authenticated yet.
# Since we're going through the classic Model backend first, it means
# that the user does not exists.
UserModel = get_user_model()
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
user = UserModel.objects.get(email=username)
if user.check_password(raw_password=password):
return user
except User.DoesNotExist:
except UserModel.DoesNotExist:
# The User does not exist. Hashing the password anyway,
# to limit Time attacks efficiency
UserModel().set_password(raw_password=password)
return None
def get_user(self, user_id):
# This is used to get the User objects
UserModel = get_user_model()
print("get_user: {}".format(user_id))
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
from django.test import TestCase
from django.test import Client
from django.test import Client, override_settings
from django_factory_boy import auth as auth_factories
AUTHENTICATION_BACKENDS = [
@override_settings(AUTHENTICATION_BACKENDS=[
# Default
"django.contrib.auth.backends.ModelBackend",
# Email or Username for login
"core.auth_backends.EmailOrUsernameModelBackend"
]
])
class ApiTest(TestCase):
def setUp(self):
self.client = Client()
self.user = auth_factories.UserFactory(password="dummypassword")
def test_authenticate(self):
with self.settings(AUTHENTICATION_BACKENDS=AUTHENTICATION_BACKENDS):
# username, wrong password
login_status = self.client.login(
username=self.user.username,
password="notthepassword"
)
assert not login_status
# username, correct password
login_status = self.client.login(
username=self.user.username,
password="dummypassword"
)
assert login_status
# email, wrong password
login_status = self.client.login(
username=self.user.email,
password="notthepassowrd"
)
assert not login_status
# email, correct password
login_status = self.client.login(
username=self.user.email,
password="dummypassword"
)
assert login_status
# username, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.username),
password="dummypassword"
)
assert not login_status
# email, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.email),
password="dummypassword"
)
assert not login_status
# username, wrong password
login_status = self.client.login(
username=self.user.username,
password="notthepassword"
)
assert not login_status
# username, correct password
login_status = self.client.login(
username=self.user.username,
password="dummypassword"
)
assert login_status
# email, wrong password
login_status = self.client.login(
username=self.user.email,
password="notthepassowrd"
)
assert not login_status
# email, correct password
login_status = self.client.login(
username=self.user.email,
password="dummypassword"
)
assert login_status
# username, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.username),
password="dummypassword"
)
assert not login_status
# email, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.email),
password="dummypassword"
)
assert not login_status
from django_fsm import has_transition_perm, can_proceed
from rest_framework.decorators import detail_route
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
import inspect
def get_transition_viewset_method(model, transition_name):
@detail_route(methods=['post'])
def inner_func(self, request, pk=None, *args, **kwargs):
object = self.get_object()
transition_method = getattr(object, transition_name)
if not can_proceed(transition_method):
raise PermissionDenied
if not has_transition_perm(transition_method, request.user):
raise PermissionDenied
if 'by' in inspect.getargspec(transition_method).args:
transition_method(*args, by=request.user, **kwargs)
else:
transition_method(*args, **kwargs)
if self.save_after_transition:
object.save()
serializer = self.get_serializer(object)
return Response(serializer.data)
return inner_func
def get_viewset_transition_actions_mixin(model):
"""
Automatically generate methods for Django REST Framework from transition
rules.
"""
instance = model()
class Mixin(object):
save_after_transition = True
transitions = instance.get_all_status_transitions()
transition_names = set(x.name for x in transitions)
for transition_name in transition_names:
setattr(Mixin, transition_name,
get_transition_viewset_method(model, transition_name))
return Mixin
from django.db.models import Q
from rest_framework import viewsets, mixins
from djangorestframework_fsm.viewset_mixins import get_drf_fsm_mixin
from rp.models import Article
from .serializers import ArticleSerializer
from rp.views.articles import ArticleFilterMixin
from .mixins import get_viewset_transition_actions_mixin
ArticleMixin = get_viewset_transition_actions_mixin(Article)
from .serializers import ArticleSerializer
ArticleMixin = get_drf_fsm_mixin(Article, fieldname='status')
class ArticleViewSet(ArticleMixin, ArticleFilterMixin, viewsets.ModelViewSet):
......
......@@ -201,11 +201,14 @@ class TestArticleViews(TestCase):
codename='can_edit'))
self.client.force_login(user=self.user)
a = json.loads(serializers.serialize('json', [self.articles[0]]))[0]
a['fields']['title'] = 'Zog Zog'
r = self.client.post('/rp/article/edit/{}/'.format(a['pk']), a['fields'])
a = Article.objects.get(pk=a['pk'])
assert r.status_code == 302 # We're redirecting after edit
pk = self.articles[0].pk
a = {'title': 'Zog Zog',
'status': 'NEW',
'lang': 'FR',
'url': 'https://www.example.org/'}
r = self.client.post('/rp/article/edit/{}/'.format(pk), a)
a = Article.objects.get(pk=pk)
assert r.status_code == 302 # We're redirecting to the view or preview of the article
assert a.title == 'Zog Zog'
......@@ -243,8 +246,8 @@ class TestArticleApi(TestCase):
article = {'title': 'Zog Zog',
'url': 'https://article.org/Zog+Zog'}
r = self.client.put('/api/articles/{}/'.format(pk),
article,
format='json')
article,
format='json')
assert r.status_code == 200
assert Article.objects.get(pk=pk).title == 'Zog Zog'
......@@ -265,7 +268,7 @@ class TestArticleApi(TestCase):
assert r.status_code == 200
a = Article.objects.get(pk=pk)
assert list(a.tags.values('name',).order_by('name')) == [{'name': 'New Tag 1'},
{'name': 'New Tag 2'}]
{'name': 'New Tag 2'}]
def test_api_filter_tag(self):
tag = 'Tag 1'
......@@ -346,7 +349,7 @@ class TestArticleApi(TestCase):
# We cannot recover a published article
a = ArticleFactory(status='PUBLISHED')
r = self.client.post('/api/articles/{}/recover/'.format(a.id))
assert r.status_code == 403
assert r.status_code == 400
def test_api_set_priority(self):
self.user.user_permissions.add(Permission.objects.get(
......@@ -354,7 +357,7 @@ class TestArticleApi(TestCase):
self.client.force_login(user=self.user)
a = ArticleFactory(status='DRAFT')
assert a.priority is False
r = self.client.post('/api/articles/{}/set_priority/'.format(a.id))
r = self.client.post('/api/articles/{}/set-priority/'.format(a.id))
assert r.status_code == 200
assert r.data['priority']
......@@ -364,6 +367,6 @@ class TestArticleApi(TestCase):
self.client.force_login(user=self.user)
a = ArticleFactory(status='DRAFT', priority=True)
assert a.priority
r = self.client.post('/api/articles/{}/unset_priority/'.format(a.id))
r = self.client.post('/api/articles/{}/unset-priority/'.format(a.id))
assert r.status_code == 200
assert r.data['priority'] is False
......@@ -22,11 +22,11 @@ urlpatterns = [
url(r"^admin/", admin.site.urls),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r"^api/", include(router.urls, namespace="api")),
url(r"^feeds/", include("rp.feeds.urls", namespace="feeds")),
url(r"^rp/", include("rp.urls", namespace="rp")),
url(r"^api/", include((router.urls, "api"))),
url(r"^feeds/", include(("rp.feeds.urls", "feeds"))),
url(r"^rp/", include(("rp.urls", "rp"))),
url(r'^accounts/', include('allauth.urls')),
url(r"^users/", include('userprofile.urls', namespace="users")),
url(r"^users/", include(('userprofile.urls', "users"))),
url(r"^docs/api/", include_docs_urls(title="API de la revue de presse")),
]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment