From 5fb6911960fe8e1803d2d6c05eb536482a8b49ae Mon Sep 17 00:00:00 2001 From: Evert Date: Mon, 13 Nov 2017 19:38:51 +0200 Subject: [PATCH 1/8] Authentication - Rewrite auth system to use Django's user model --- EpisodesCommunity/settings.py | 5 +++ LandingPage/admin.py | 2 +- LandingPage/backends.py | 64 +++++++++++++++++++++++++++++++++ LandingPage/models.py | 24 +++++++------ LandingPage/templates/base.html | 4 +-- LandingPage/views.py | 54 +++++++--------------------- 6 files changed, 98 insertions(+), 55 deletions(-) create mode 100644 LandingPage/backends.py diff --git a/EpisodesCommunity/settings.py b/EpisodesCommunity/settings.py index 8b9743e..6dd7465 100644 --- a/EpisodesCommunity/settings.py +++ b/EpisodesCommunity/settings.py @@ -42,6 +42,11 @@ ALLOWED_HOSTS = [] # Application definition +AUTHENTICATION_BACKENDS = ( + 'LandingPage.backends.OAuthBackend', + 'django.contrib.auth.backends.ModelBackend', +) + INSTALLED_APPS = [ 'LandingPage.apps.LandingpageConfig', 'Show.apps.ShowConfig', diff --git a/LandingPage/admin.py b/LandingPage/admin.py index 77fe1f1..5515ecf 100644 --- a/LandingPage/admin.py +++ b/LandingPage/admin.py @@ -3,7 +3,7 @@ from .models import * # Register your models here. admin.site.register(Show) -admin.site.register(User) +admin.site.register(ExternalUser) admin.site.register(Admin) admin.site.register(Ban) admin.site.register(ShowModerator) diff --git a/LandingPage/backends.py b/LandingPage/backends.py new file mode 100644 index 0000000..be13a4c --- /dev/null +++ b/LandingPage/backends.py @@ -0,0 +1,64 @@ +import requests +import hashlib +import json +import logging +from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend +from .models import ExternalUser + +class OAuthBackend(ModelBackend): + def authenticate(self, code=None): + resp = requests.post( + settings.AUTH_TOKEN_ENDPOINT+"token", + data={ + 'grant_type':'authorization_code', + 'code':code, + 'redirect_uri':settings.AUTH_REDIRECT_URL, + 'client_id':settings.AUTH_CLIENT_ID + }, + headers = { + 'Authorization':'Basic %s'%settings.AUTH_B64 + } + ) + resp_json = resp.json() + if 'error' in resp_json: + logging.warn('OAuth server returned an error: %s'%json.dumps(resp_json)) + else: + user_info = requests.get( + settings.AUTH_TOKEN_ENDPOINT+"user", + headers = { + 'Authorization': 'Bearer ' + resp_json['access_token'] + } + ).json() + + usermodel = get_user_model() + matches = usermodel.objects.filter(externaluser__icy_id=user_info['uuid']) + match = None + + if not len(matches): + user = usermodel.objects.create_user( + username = user_info['username'], + email = user_info['email'], + ) + + if 'privilege' in user_info: + priv = user_info['privilege'] + user.is_superuser = (priv == 5) + user.is_staff = (priv > 0) + + user.save() + user.externaluser = ExternalUser( + user = user, + icy_id = user_info['uuid'], + display_name = user_info['display_name'] + ) + user.externaluser.save() + match = user + else: + match = matches[0] + + match.access_token = resp_json['access_token'] + + return match + return None diff --git a/LandingPage/models.py b/LandingPage/models.py index e03a920..309acf8 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.contrib.auth.models import User from django.core.files.storage import FileSystemStorage from django.conf import settings import os @@ -71,14 +72,17 @@ class Show(TimestampedModel): def __str__(self): return '%s [%s]'%(self.name,self.abbr) -class User(TimestampedModel): - user_id = models.CharField( +class ExternalUser(TimestampedModel): + user = models.OneToOneField( + User, + on_delete=models.CASCADE, + help_text='The internal Django user', + verbose_name="User" + ) + icy_id = models.CharField( max_length=36, help_text='The UUID assigned to this user by IcyNet\'s auth servers' ) - email = models.EmailField( - help_text='This user\'s email address' - ) display_name=models.CharField( max_length=20, help_text="The name shown to other users", @@ -95,7 +99,7 @@ class User(TimestampedModel): through='Watch' ) def __str__(self): - return self.email + return 'External for %s (%s)'%(self.user.email, self.display_name) class Admin(User): pass @@ -285,7 +289,7 @@ class Submission(TimestampedModel): verbose_name='Submitted For' ) user = models.ForeignKey( - 'User', + User, on_delete=models.SET_NULL, null=True, related_name='submissions', @@ -309,7 +313,7 @@ class SubmissionVote(TimestampedModel): help_text='What this submission was cast on' ) user = models.ForeignKey( - 'User', + User, on_delete=models.CASCADE, related_name='votes', help_text='The user who cast this vote' @@ -322,7 +326,7 @@ class SubmissionVote(TimestampedModel): class Favorite(TimestampedModel): user = models.ForeignKey( - User, + ExternalUser, on_delete=models.CASCADE ) episode = models.ForeignKey( @@ -334,7 +338,7 @@ class Favorite(TimestampedModel): class Watch(TimestampedModel): user = models.ForeignKey( - User, + ExternalUser, on_delete=models.CASCADE ) episode = models.ForeignKey( diff --git a/LandingPage/templates/base.html b/LandingPage/templates/base.html index 9d3499a..d729237 100644 --- a/LandingPage/templates/base.html +++ b/LandingPage/templates/base.html @@ -20,8 +20,8 @@
- {% if request.session.user_id %} - {{ request.session.disp_name }} + {% if user.is_authenticated %} + {{ user.externaluser.display_name }} {% else %} Log in {% endif %} diff --git a/LandingPage/views.py b/LandingPage/views.py index 84eeb7f..0c277f2 100644 --- a/LandingPage/views.py +++ b/LandingPage/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render from django.views import View from django.views.generic.base import TemplateView +from django.contrib.auth import login as auth_login, authenticate from django.conf import settings from django.http import HttpResponse from django.http import HttpResponseRedirect @@ -29,52 +30,21 @@ class LoginRedirect(View): userstate = generateState(req) if userstate == req.GET['state']: code = req.GET['code'] - resp = requests.post( - settings.AUTH_TOKEN_ENDPOINT+"token", - data={ - 'grant_type':'authorization_code', - 'code':code, - 'redirect_uri':settings.AUTH_REDIRECT_URL, - 'client_id':settings.AUTH_CLIENT_ID - }, - headers = { - 'Authorization':'Basic %s'%settings.AUTH_B64 - } - ) - resp_json = resp.json() - if 'error' in resp_json: - r = HttpResponse('

OAuth Error

%s
'%json.dumps(resp_json)) - r.status = 500 - return r - else: - user_info = requests.get( - settings.AUTH_TOKEN_ENDPOINT+"user", - headers = { - 'Authorization': 'Bearer ' + resp_json['access_token'] - } - ).json() - req.session['user_id'] = user_info['uuid'] - matches = User.objects.filter(user_id=user_info['uuid']) - match = None - if not len(matches): - user = User( - user_id = user_info['uuid'], - email = user_info['email'], - display_name = user_info['display_name'] - ) - user.save() - match = user - else: - match = matches[0] - req.session['token'] = resp_json['access_token'] - req.session['disp_name'] = match.display_name + + user = authenticate(code=code) + + if user is not None and user.is_active: + auth_login(req, user) + return HttpResponseRedirect('/') - else: - return HttpResponse('

Unmatching state tokens


It looks like the request to login wasn\'t started by you. Try going back to the home page and logging in again.

', status=400) + + return HttpResponse('

Error


It looks like something went wrong while trying to authenticate you. Please try again later.

', status=500) + + return HttpResponse('

Unmatching state tokens


It looks like the request to login wasn\'t started by you. Try going back to the home page and logging in again.

', status=400) class Login(View): def get(self, req): - url = '%sauthorize?response_type=code&client_id=%s&redirect_uri=%s&scope=email&state=%s'%(settings.AUTH_TOKEN_ENDPOINT,settings.AUTH_CLIENT_ID,settings.AUTH_REDIRECT_URL, generateState(req)) + url = '%sauthorize?response_type=code&client_id=%s&redirect_uri=%s&scope=email privilege&state=%s'%(settings.AUTH_TOKEN_ENDPOINT,settings.AUTH_CLIENT_ID,settings.AUTH_REDIRECT_URL, generateState(req)) response = HttpResponse("Redirecting you to the IcyNet auth page...") response.status_code = 302 response['Location'] = url From 926ecbceb32a81818944a37c58ca6dcfcbcc0573 Mon Sep 17 00:00:00 2001 From: Evert Date: Mon, 13 Nov 2017 19:42:10 +0200 Subject: [PATCH 2/8] Authentication - Rewrite Show views to use django user model --- Show/templates/episode.html | 2 +- Show/views.py | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Show/templates/episode.html b/Show/templates/episode.html index 9563ae7..0fa4fbe 100644 --- a/Show/templates/episode.html +++ b/Show/templates/episode.html @@ -30,7 +30,7 @@
 Show Index - {% if request.session.user_id %} + {% if user.is_authenticated %}  Submit New Link {% else %} Log in to submit a link diff --git a/Show/views.py b/Show/views.py index ba23497..f2e2ce4 100644 --- a/Show/views.py +++ b/Show/views.py @@ -2,11 +2,13 @@ from django.template import RequestContext from django.shortcuts import render from django.views import View from django.views.generic.base import TemplateView +from django.contrib.auth.decorators import login_required from django.conf import settings from django.http import Http404 from django.http import HttpResponse from django.http import HttpResponseRedirect from django.db.models import Case, When, Value, IntegerField, Count, F +from django.contrib.auth.mixins import LoginRequiredMixin from LandingPage.models import User from LandingPage.models import Show @@ -85,15 +87,11 @@ class EpisodeView(TemplateView): return ctx # Submission form GET and POST +@login_required def SubmissionForm(req, abbreviation, season, episode): show = Show.objects.get(abbr=abbreviation) episode = Episode.objects.filter(show=show,season__number=season,episode=episode).first() - - # Check for login status - if not 'user_id' in req.session: - return HttpResponse('

Error

You need to be logged in to submit. Please log in

', status=400) - - user = User.objects.get(user_id=req.session['user_id']) + user = req.user # 404's if not show: @@ -144,16 +142,12 @@ def SubmissionForm(req, abbreviation, season, episode): # Vote request # /show/{{abbr}}/vote/{{submission id}}/{{positive == 1}} -class SubmissionVoteSubmit(View): +class SubmissionVoteSubmit(LoginRequiredMixin, View): def post (self, req, abbreviation, subid, positive): # Convert positive parameter into a boolean pos_bool = int(positive) == 1 - # Check for login status - if not 'user_id' in req.session: - return HttpResponse('

Error

You need to be logged in to vote. Please log in

', status=400) - - user = User.objects.get(user_id=req.session['user_id']) + user = req.user # Get the submission from the database submission = Submission.objects.filter(id=subid).first() From 20d3ac7aecad6834e6c864e572b177f36694c35a Mon Sep 17 00:00:00 2001 From: Tsa6 Date: Mon, 13 Nov 2017 16:13:25 -0500 Subject: [PATCH 3/8] Updated tests to new user model --- tests/LandingPage/test_views.py | 38 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/tests/LandingPage/test_views.py b/tests/LandingPage/test_views.py index 4615965..76de993 100644 --- a/tests/LandingPage/test_views.py +++ b/tests/LandingPage/test_views.py @@ -1,7 +1,8 @@ from django.test import TestCase,Client,override_settings import responses -from LandingPage.models import User +from LandingPage.models import ExternalUser from urllib import parse +from django.contrib.auth import get_user_model @override_settings( AUTH_TOKEN_ENDPOINT='http://icynet.test/api/', @@ -15,7 +16,7 @@ class TestLogin(TestCase): # Set up responses to control network flow with responses.RequestsMock() as rm: rm.add(responses.POST,'http://icynet.test/api/token',json={'access_token':'1accesstoken1'}) - rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith'}) + rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith','username':'mrsmith'}) # Make initial request to redirect endpoint client = Client() @@ -26,24 +27,23 @@ class TestLogin(TestCase): self.assertEqual(query['client_id'][0],'clid') self.assertEqual(query['response_type'][0],'code') self.assertEqual(query['redirect_uri'][0],'http://redirect.test') - self.assertEqual(query['scope'][0],'email') + self.assertSetEqual(set(query['scope'][0].split()),set(['email','privilege'])) # Make connection to the real endpoint resp = client.get('/login/redirect?state=%s&code=%s'%(state, 'code')) self.assertEqual(resp.status_code, 302) # Check that the database is all good - users = User.objects.all() + users = ExternalUser.objects.all() self.assertEqual(len(users), 1) user = users[0] - self.assertEqual(user.user_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(user.email,'johnsmith@gmail.com') + self.assertEqual(user.icy_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') + self.assertEqual(user.user.email,'johnsmith@gmail.com') + self.assertEqual(user.user.username,'mrsmith') self.assertEqual(user.display_name, 'Mr. Smith') - - # Check appropriate values are in the session - self.assertEqual(client.session['user_id'], '935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(client.session['token'],'1accesstoken1') - self.assertEqual(client.session['disp_name'], 'Mr. Smith') + + # Check that the user has been logged in + self.assertEqual(client.get('/').context['user'], user.user) def test_reject_bad_state(self): with responses.RequestsMock() as rm: @@ -58,7 +58,7 @@ class TestLogin(TestCase): rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith'}) # Set up the database - user = User(user_id='935a41b5-b38d-42c3-96ef-653402fc44ca',email='johnsmith@gmail.com',display_name='Mr. Smith') + user = ExternalUser(user=get_user_model().objects.create_user(username='mrsmith',email='johnsmith@gmail.com'),icy_id='935a41b5-b38d-42c3-96ef-653402fc44ca',display_name='Mr. Smith') user.save() # Make initial request to redirect endpoint @@ -71,17 +71,15 @@ class TestLogin(TestCase): self.assertEqual(resp.status_code, 302) # Check that the database is all good - users = User.objects.all() + users = ExternalUser.objects.all() self.assertEqual(len(users), 1) user = users[0] - self.assertEqual(user.user_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(user.email,'johnsmith@gmail.com') + self.assertEqual(user.icy_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') + self.assertEqual(user.user.email,'johnsmith@gmail.com') self.assertEqual(user.display_name, 'Mr. Smith') - - # Check appropriate values are in the session - self.assertEqual(client.session['user_id'], '935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(client.session['token'],'1accesstoken1') - self.assertEqual(client.session['disp_name'], 'Mr. Smith') + + # Check that the user has been logged in + self.assertEqual(client.get('/').context['user'], user.user) def test_states_unique(self): with responses.RequestsMock() as rm: From 9f725b4c468836bf8550d8f44de8f22437a7731d Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 14 Nov 2017 14:56:44 +0200 Subject: [PATCH 4/8] Authentication - Made Django use a custom User model WARNING! This commit requires you to re-migrate the database from the beginning, because AUTH_USER_MODEL can only be set before the initial migration. --- EpisodesCommunity/settings.py | 2 ++ LandingPage/admin.py | 12 ++++++++++-- LandingPage/backends.py | 12 ++++-------- LandingPage/forms.py | 6 ++++++ LandingPage/models.py | 16 ++++------------ LandingPage/templates/base.html | 2 +- 6 files changed, 27 insertions(+), 23 deletions(-) create mode 100644 LandingPage/forms.py diff --git a/EpisodesCommunity/settings.py b/EpisodesCommunity/settings.py index 6dd7465..0774f06 100644 --- a/EpisodesCommunity/settings.py +++ b/EpisodesCommunity/settings.py @@ -47,6 +47,8 @@ AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', ) +AUTH_USER_MODEL = 'LandingPage.User' + INSTALLED_APPS = [ 'LandingPage.apps.LandingpageConfig', 'Show.apps.ShowConfig', diff --git a/LandingPage/admin.py b/LandingPage/admin.py index 5515ecf..13aef35 100644 --- a/LandingPage/admin.py +++ b/LandingPage/admin.py @@ -1,9 +1,18 @@ from django.contrib import admin +from django.contrib.auth.admin import UserAdmin from .models import * +from .forms import SpecialUserChangeForm + +class SpecialUserAdmin(UserAdmin): + form = SpecialUserChangeForm + + fieldsets = UserAdmin.fieldsets + ( + (None, {'fields': ('display_name',)}), + ) # Register your models here. admin.site.register(Show) -admin.site.register(ExternalUser) +admin.site.register(User, SpecialUserAdmin) admin.site.register(Admin) admin.site.register(Ban) admin.site.register(ShowModerator) @@ -18,4 +27,3 @@ admin.site.register(Watch) admin.site.register(DiscussionBoard) admin.site.register(DiscussionReply) admin.site.register(DiscussionVote) - diff --git a/LandingPage/backends.py b/LandingPage/backends.py index be13a4c..27673ee 100644 --- a/LandingPage/backends.py +++ b/LandingPage/backends.py @@ -5,7 +5,6 @@ import logging from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend -from .models import ExternalUser class OAuthBackend(ModelBackend): def authenticate(self, code=None): @@ -33,13 +32,15 @@ class OAuthBackend(ModelBackend): ).json() usermodel = get_user_model() - matches = usermodel.objects.filter(externaluser__icy_id=user_info['uuid']) + matches = usermodel.objects.filter(icy_id=user_info['uuid']) match = None if not len(matches): user = usermodel.objects.create_user( username = user_info['username'], email = user_info['email'], + icy_id = user_info['uuid'], + display_name = user_info['display_name'] ) if 'privilege' in user_info: @@ -48,12 +49,7 @@ class OAuthBackend(ModelBackend): user.is_staff = (priv > 0) user.save() - user.externaluser = ExternalUser( - user = user, - icy_id = user_info['uuid'], - display_name = user_info['display_name'] - ) - user.externaluser.save() + match = user else: match = matches[0] diff --git a/LandingPage/forms.py b/LandingPage/forms.py new file mode 100644 index 0000000..773d760 --- /dev/null +++ b/LandingPage/forms.py @@ -0,0 +1,6 @@ +from django.contrib.auth.forms import UserChangeForm +from .models import User + +class SpecialUserChangeForm(UserChangeForm): + class Meta(UserChangeForm.Meta): + model = User diff --git a/LandingPage/models.py b/LandingPage/models.py index 309acf8..879998c 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.contrib.auth.models import User +from django.contrib.auth.models import AbstractUser from django.core.files.storage import FileSystemStorage from django.conf import settings import os @@ -72,13 +72,7 @@ class Show(TimestampedModel): def __str__(self): return '%s [%s]'%(self.name,self.abbr) -class ExternalUser(TimestampedModel): - user = models.OneToOneField( - User, - on_delete=models.CASCADE, - help_text='The internal Django user', - verbose_name="User" - ) +class User(AbstractUser): icy_id = models.CharField( max_length=36, help_text='The UUID assigned to this user by IcyNet\'s auth servers' @@ -98,8 +92,6 @@ class ExternalUser(TimestampedModel): related_name='watched_by', through='Watch' ) - def __str__(self): - return 'External for %s (%s)'%(self.user.email, self.display_name) class Admin(User): pass @@ -326,7 +318,7 @@ class SubmissionVote(TimestampedModel): class Favorite(TimestampedModel): user = models.ForeignKey( - ExternalUser, + User, on_delete=models.CASCADE ) episode = models.ForeignKey( @@ -338,7 +330,7 @@ class Favorite(TimestampedModel): class Watch(TimestampedModel): user = models.ForeignKey( - ExternalUser, + User, on_delete=models.CASCADE ) episode = models.ForeignKey( diff --git a/LandingPage/templates/base.html b/LandingPage/templates/base.html index d729237..44580b1 100644 --- a/LandingPage/templates/base.html +++ b/LandingPage/templates/base.html @@ -21,7 +21,7 @@
{% if user.is_authenticated %} - {{ user.externaluser.display_name }} + {{ user.display_name }} {% else %} Log in {% endif %} From 0bded3afc75839f27f34800fab1ee2932761e9ab Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 14 Nov 2017 15:32:26 +0200 Subject: [PATCH 5/8] Authentication - Add logout view and set login url in settings --- EpisodesCommunity/settings.py | 1 + LandingPage/urls.py | 1 + LandingPage/views.py | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/EpisodesCommunity/settings.py b/EpisodesCommunity/settings.py index 0774f06..63e691d 100644 --- a/EpisodesCommunity/settings.py +++ b/EpisodesCommunity/settings.py @@ -72,6 +72,7 @@ MIDDLEWARE = [ ] ROOT_URLCONF = 'EpisodesCommunity.urls' +LOGIN_URL = '/login' TEMPLATES = [ { diff --git a/LandingPage/urls.py b/LandingPage/urls.py index 8c4c86d..7b2ab2c 100644 --- a/LandingPage/urls.py +++ b/LandingPage/urls.py @@ -3,6 +3,7 @@ from django.conf.urls import url from . import views urlpatterns = [ + url(r'^logout/$', views.LogoutView), url(r'^login/redirect$', views.LoginRedirect.as_view()), url(r'^login$', views.Login.as_view()), url(r'^$', views.LandingPage.as_view()), diff --git a/LandingPage/views.py b/LandingPage/views.py index 0c277f2..b515f80 100644 --- a/LandingPage/views.py +++ b/LandingPage/views.py @@ -6,6 +6,7 @@ from django.conf import settings from django.http import HttpResponse from django.http import HttpResponseRedirect from django.db.models import Max +from django.contrib.auth.views import logout import requests import hashlib import json @@ -50,6 +51,10 @@ class Login(View): response['Location'] = url return response +def LogoutView(request): + logout(request) + return HttpResponseRedirect('/') + def generateState(request): request.session.save() From 70832a685c6c1e3c38a5d84a77c4825d1a227af1 Mon Sep 17 00:00:00 2001 From: Evert Date: Thu, 16 Nov 2017 21:13:13 +0200 Subject: [PATCH 6/8] Remove the "Admin" model since it's not necessary --- LandingPage/admin.py | 1 - LandingPage/models.py | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/LandingPage/admin.py b/LandingPage/admin.py index 13aef35..44f4c55 100644 --- a/LandingPage/admin.py +++ b/LandingPage/admin.py @@ -13,7 +13,6 @@ class SpecialUserAdmin(UserAdmin): # Register your models here. admin.site.register(Show) admin.site.register(User, SpecialUserAdmin) -admin.site.register(Admin) admin.site.register(Ban) admin.site.register(ShowModerator) admin.site.register(Report) diff --git a/LandingPage/models.py b/LandingPage/models.py index 879998c..0cfb149 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -93,9 +93,6 @@ class User(AbstractUser): through='Watch' ) -class Admin(User): - pass - class Ban(TimestampedModel): user = models.OneToOneField( User, @@ -104,7 +101,7 @@ class Ban(TimestampedModel): verbose_name="Banned User" ) admin = models.ForeignKey( - Admin, + User, on_delete=models.SET_NULL, null=True, help_text='The admin which banned this user', From 35cb450f1f59428e8c4c943c51a278415a4a3543 Mon Sep 17 00:00:00 2001 From: Evert Date: Mon, 11 Dec 2017 15:37:15 +0200 Subject: [PATCH 7/8] Revert the tests commit --- tests/LandingPage/test_views.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/LandingPage/test_views.py b/tests/LandingPage/test_views.py index 76de993..998dbdc 100644 --- a/tests/LandingPage/test_views.py +++ b/tests/LandingPage/test_views.py @@ -1,8 +1,7 @@ from django.test import TestCase,Client,override_settings import responses -from LandingPage.models import ExternalUser +from LandingPage.models import User from urllib import parse -from django.contrib.auth import get_user_model @override_settings( AUTH_TOKEN_ENDPOINT='http://icynet.test/api/', @@ -16,7 +15,7 @@ class TestLogin(TestCase): # Set up responses to control network flow with responses.RequestsMock() as rm: rm.add(responses.POST,'http://icynet.test/api/token',json={'access_token':'1accesstoken1'}) - rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith','username':'mrsmith'}) + rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith','username':'jsmith'}) # Make initial request to redirect endpoint client = Client() @@ -27,23 +26,19 @@ class TestLogin(TestCase): self.assertEqual(query['client_id'][0],'clid') self.assertEqual(query['response_type'][0],'code') self.assertEqual(query['redirect_uri'][0],'http://redirect.test') - self.assertSetEqual(set(query['scope'][0].split()),set(['email','privilege'])) + self.assertEqual(query['scope'][0],'email privilege') # Make connection to the real endpoint resp = client.get('/login/redirect?state=%s&code=%s'%(state, 'code')) self.assertEqual(resp.status_code, 302) # Check that the database is all good - users = ExternalUser.objects.all() + users = User.objects.all() self.assertEqual(len(users), 1) user = users[0] self.assertEqual(user.icy_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(user.user.email,'johnsmith@gmail.com') - self.assertEqual(user.user.username,'mrsmith') + self.assertEqual(user.email,'johnsmith@gmail.com') self.assertEqual(user.display_name, 'Mr. Smith') - - # Check that the user has been logged in - self.assertEqual(client.get('/').context['user'], user.user) def test_reject_bad_state(self): with responses.RequestsMock() as rm: @@ -55,10 +50,10 @@ class TestLogin(TestCase): # Set up responses to control network flow with responses.RequestsMock() as rm: rm.add(responses.POST,'http://icynet.test/api/token',json={'access_token':'1accesstoken1'}) - rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith'}) + rm.add(responses.GET,'http://icynet.test/api/user',json={'uuid':'935a41b5-b38d-42c3-96ef-653402fc44ca','email':'johnsmith@gmail.com','display_name':'Mr. Smith','username':'jsmith'}) # Set up the database - user = ExternalUser(user=get_user_model().objects.create_user(username='mrsmith',email='johnsmith@gmail.com'),icy_id='935a41b5-b38d-42c3-96ef-653402fc44ca',display_name='Mr. Smith') + user = User(icy_id='935a41b5-b38d-42c3-96ef-653402fc44ca',email='johnsmith@gmail.com',display_name='Mr. Smith') user.save() # Make initial request to redirect endpoint @@ -71,15 +66,12 @@ class TestLogin(TestCase): self.assertEqual(resp.status_code, 302) # Check that the database is all good - users = ExternalUser.objects.all() + users = User.objects.all() self.assertEqual(len(users), 1) user = users[0] self.assertEqual(user.icy_id,'935a41b5-b38d-42c3-96ef-653402fc44ca') - self.assertEqual(user.user.email,'johnsmith@gmail.com') + self.assertEqual(user.email,'johnsmith@gmail.com') self.assertEqual(user.display_name, 'Mr. Smith') - - # Check that the user has been logged in - self.assertEqual(client.get('/').context['user'], user.user) def test_states_unique(self): with responses.RequestsMock() as rm: From 08ffa3fc5080b6c5f971cbcccebe680e805349a3 Mon Sep 17 00:00:00 2001 From: Evert Date: Mon, 11 Dec 2017 15:39:01 +0200 Subject: [PATCH 8/8] oops, forgot the logged in test --- tests/LandingPage/test_views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/LandingPage/test_views.py b/tests/LandingPage/test_views.py index 998dbdc..d2322cd 100644 --- a/tests/LandingPage/test_views.py +++ b/tests/LandingPage/test_views.py @@ -40,6 +40,9 @@ class TestLogin(TestCase): self.assertEqual(user.email,'johnsmith@gmail.com') self.assertEqual(user.display_name, 'Mr. Smith') + # Check that the user has been logged in + self.assertEqual(client.get('/').context['user'], user) + def test_reject_bad_state(self): with responses.RequestsMock() as rm: client = Client() @@ -73,6 +76,9 @@ class TestLogin(TestCase): self.assertEqual(user.email,'johnsmith@gmail.com') self.assertEqual(user.display_name, 'Mr. Smith') + # Check that the user has been logged in + self.assertEqual(client.get('/').context['user'], user) + def test_states_unique(self): with responses.RequestsMock() as rm: client1 = Client()