diff --git a/django_reddit/urls.py b/django_reddit/urls.py index c93dcce..0cf271a 100644 --- a/django_reddit/urls.py +++ b/django_reddit/urls.py @@ -22,5 +22,6 @@ url(settings.ADMIN_URL, include(admin.site.urls)), # url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"), # url(r'^users/', include('users.urls')), - url(r'^', include("reddit.urls")) + url(r'^', include("reddit.urls")), + url(r'^', include("users.urls")) ] diff --git a/reddit/migrations/0001_initial.py b/reddit/migrations/0001_initial.py index 0e94e6f..0f85e86 100644 --- a/reddit/migrations/0001_initial.py +++ b/reddit/migrations/0001_initial.py @@ -65,7 +65,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='Vote', + name='vote', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('vote_object_id', models.PositiveIntegerField()), diff --git a/reddit/tests/test_comments.py b/reddit/tests/test_comments.py index b478ab8..6d9fcbd 100644 --- a/reddit/tests/test_comments.py +++ b/reddit/tests/test_comments.py @@ -66,7 +66,7 @@ def setUp(self): def test_valid_public_comment_view(self): self.c.logout() - r = self.c.get(reverse('Thread', args=(1,))) + r = self.c.get(reverse('thread', args=(1,))) submission = Submission.objects.get(id=1) self.assertEqual(r.status_code, 200) self.assertEqual(r.context['submission'], submission) @@ -78,7 +78,7 @@ def test_valid_public_comment_view(self): def test_comment_votes(self): self.c.login(**self.credentials) - r = self.c.get(reverse('Thread', args=(1,))) + r = self.c.get(reverse('thread', args=(1,))) self.assertEqual(r.status_code, 200) self.assertEqual(r.context['sub_vote'], 1) self.assertEqual(r.context['comment_votes'], {1: 1, 5: -1}) @@ -86,7 +86,7 @@ def test_comment_votes(self): self.assertContains(r, 'reply comment', count=2) def test_invalid_thread_id(self): - r = self.c.get(reverse('Thread', args=(123,))) + r = self.c.get(reverse('thread', args=(123,))) self.assertEqual(r.status_code, 404) @@ -107,11 +107,11 @@ def setUp(self): ) def test_post_only(self): - r = self.c.get(reverse('Post Comment')) + r = self.c.get(reverse('post_comment')) self.assertIsInstance(r, HttpResponseNotAllowed) def test_logged_out(self): - r = self.c.post(reverse('Post Comment')) + r = self.c.post(reverse('post_comment')) self.assertEqual(r.status_code, 200) json_response = json.loads(r.content.decode("utf-8")) self.assertEqual(json_response['msg'], "You need to log in to post new comments.") @@ -119,10 +119,10 @@ def test_logged_out(self): def test_missing_type_or_id(self): self.c.login(**self.credentials) for key in ['parentType', 'parentId']: - r = self.c.post(reverse('Post Comment'), + r = self.c.post(reverse('post_comment'), data={key: 'comment'}) self.assertIsInstance(r, HttpResponseBadRequest) - r = self.c.post(reverse('Post Comment'), + r = self.c.post(reverse('post_comment'), data={'parentType': 'InvalidType', 'parentId': 1}) self.assertIsInstance(r, HttpResponseBadRequest) @@ -134,7 +134,7 @@ def test_no_comment_text(self): 'parentId': 1, 'commentContent': '' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertEqual(r.status_code, 200) json_response = json.loads(r.content.decode("utf-8")) self.assertEqual(json_response['msg'], @@ -147,7 +147,7 @@ def test_invalid_or_wrong_parent_id(self): 'parentId': 'invalid', 'commentContent': 'content' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertIsInstance(r, HttpResponseBadRequest) test_data = { @@ -156,7 +156,7 @@ def test_invalid_or_wrong_parent_id(self): 'commentContent': 'content' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertIsInstance(r, HttpResponseBadRequest) test_data = { @@ -165,7 +165,7 @@ def test_invalid_or_wrong_parent_id(self): 'commentContent': 'content' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertIsInstance(r, HttpResponseBadRequest) def test_valid_comment_posting_thread(self): @@ -176,7 +176,7 @@ def test_valid_comment_posting_thread(self): 'commentContent': 'thread root comment' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertEqual(r.status_code, 200) json_r = json.loads(r.content.decode("utf-8")) self.assertEqual(json_r['msg'], 'Your comment has been posted.') @@ -204,7 +204,7 @@ def test_valid_comment_posting_reply(self): 'commentContent': 'thread reply comment' } - r = self.c.post(reverse('Post Comment'), data=test_data) + r = self.c.post(reverse('post_comment'), data=test_data) self.assertEqual(r.status_code, 200) json_r = json.loads(r.content.decode("utf-8")) self.assertEqual(json_r['msg'], 'Your comment has been posted.') diff --git a/reddit/tests/test_frontpage.py b/reddit/tests/test_frontpage.py index 987a5ae..f65e0eb 100644 --- a/reddit/tests/test_frontpage.py +++ b/reddit/tests/test_frontpage.py @@ -21,19 +21,19 @@ def test_submission_count(self): self.assertEqual(Submission.objects.all().count(), 50) def test_no_page_number(self): - r = self.c.get(reverse('Frontpage')) + r = self.c.get(reverse('frontpage')) self.assertEqual(len(r.context['submissions']), 25) self.assertEqual(r.context['submissions'].number, 1) self.assertFalse(r.context['submissions'].has_previous()) self.assertTrue(r.context['submissions'].has_next()) def test_valid_page_number(self): - r = self.c.get(reverse('Frontpage'), data={'page': 1}) + r = self.c.get(reverse('frontpage'), data={'page': 1}) self.assertEqual(len(r.context['submissions']), 25) first_page_submissions = r.context['submissions'] self.assertFalse(r.context['submissions'].has_previous()) - r = self.c.get(reverse('Frontpage'), data={'page': 2}) + r = self.c.get(reverse('frontpage'), data={'page': 2}) self.assertEqual(len(r.context['submissions']), 25) second_page_submissions = r.context['submissions'] self.assertNotEqual(first_page_submissions, second_page_submissions) @@ -41,11 +41,11 @@ def test_valid_page_number(self): self.assertFalse(r.context['submissions'].has_next()) def test_invalid_page_number(self): - r = self.c.get(reverse('Frontpage'), data={'page': "something"}, follow=True) + r = self.c.get(reverse('frontpage'), data={'page': "something"}, follow=True) self.assertEqual(r.status_code, 404) def test_wrong_page_number(self): - r = self.c.get(reverse('Frontpage'), data={'page': 10}, follow=True) + r = self.c.get(reverse('frontpage'), data={'page': 10}, follow=True) self.assertEqual(r.context['submissions'].number, 2) self.assertFalse(r.context['submissions'].has_next()) @@ -78,13 +78,13 @@ def setUp(self): vote_value=-1).save() def test_logged_out(self): - r = self.c.get(reverse('Frontpage')) + r = self.c.get(reverse('frontpage')) self.assertEqual(r.context['submission_votes'], {}, msg="Logged out user got some submission votes data") def test_logged_in(self): self.c.login(username='username', password='password') - r = self.c.get(reverse('Frontpage')) + r = self.c.get(reverse('frontpage')) self.assertEqual(len(r.context['submission_votes']), 5) upvote_keys = [] @@ -102,7 +102,7 @@ def test_logged_in(self): def test_second_page(self): self.c.login(username='username', password='password') - r = self.c.get(reverse('Frontpage'), data={'page': 2}) + r = self.c.get(reverse('frontpage'), data={'page': 2}) self.assertEqual(len(r.context['submission_votes']), 4) upvote_keys = [] diff --git a/reddit/tests/test_profile.py b/reddit/tests/test_profile.py index 840b82c..9aa4178 100644 --- a/reddit/tests/test_profile.py +++ b/reddit/tests/test_profile.py @@ -21,7 +21,7 @@ def setUp(self): r.github = "example" def test_existing_username(self): - r = self.c.get(reverse('User Profile', args=('username',))) + r = self.c.get(reverse('user_profile', args=('username',))) self.assertEqual(r.status_code, 200) self.assertContains(r, '(username)') self.assertContains(r, 'compose?to=username') @@ -33,13 +33,13 @@ def test_existing_username(self): def test_own_username(self): self.assertTrue(self.c.login(username='username', password='password')) - r = self.c.get(reverse('User Profile', args=('username',))) + r = self.c.get(reverse('user_profile', args=('username',))) self.assertContains(r, '/profile/edit') self.assertNotContains(r, 'compose?to=username') self.c.logout() def test_invalid_username(self): - r = self.c.get(reverse('User Profile', args=('none',))) + r = self.c.get(reverse('user_profile', args=('none',))) self.assertEqual(r.status_code, 404) @@ -116,26 +116,26 @@ def setUp(self): } def test_not_logged_in(self): - r = self.c.get(reverse('Edit Profile')) - self.assertRedirects(r, reverse('Login') + '?next=' + reverse('Edit Profile')) + r = self.c.get(reverse('edit_profile')) + self.assertRedirects(r, reverse('login') + '?next=' + reverse('edit_profile')) def test_invalid_request(self): self.c.login(username='profiletest', password='password') - r = self.c.delete(reverse('Edit Profile')) + r = self.c.delete(reverse('edit_profile')) self.assertEqual(r.status_code, 404) def test_form_view(self): self.c.login(username='profiletest', password='password') - r = self.c.get(reverse('Edit Profile')) + r = self.c.get(reverse('edit_profile')) self.assertIsInstance(r.context['form'], ProfileForm) def test_form_submit(self): self.c.login(username='profiletest', password='password') - r = self.c.post(reverse('Edit Profile'), data=self.valid_data) + r = self.c.post(reverse('edit_profile'), data=self.valid_data) self.assertEqual(r.status_code, 200) user = RedditUser.objects.get(user=User.objects.get( diff --git a/reddit/tests/test_submission.py b/reddit/tests/test_submission.py index 997a3a7..50e36fe 100644 --- a/reddit/tests/test_submission.py +++ b/reddit/tests/test_submission.py @@ -47,14 +47,14 @@ def setUp(self): ) def test_logged_out(self): - r = self.c.get(reverse('Submit')) + r = self.c.get(reverse('submit')) self.assertRedirects(r, "{}?next={}".format( - reverse('Login'), reverse('Submit') + reverse('login'), reverse('submit') )) def test_logged_in_GET(self): self.c.login(**self.login_data) - r = self.c.get(reverse('Submit')) + r = self.c.get(reverse('submit')) self.assertIsInstance(r.context['form'], SubmissionForm) def test_making_a_submission(self): @@ -64,10 +64,10 @@ def test_making_a_submission(self): 'url': 'http://example.com', 'text': 'submission text' } - r = self.c.post(reverse('Submit'), data=test_data, follow=True) + r = self.c.post(reverse('submit'), data=test_data, follow=True) submission = Submission.objects.filter(**test_data).first() self.assertIsNotNone(submission) - self.assertRedirects(r, reverse('Thread', args=(submission.id,))) + self.assertRedirects(r, reverse('thread', args=(submission.id,))) self.assertContains(r, 'Submission created') def test_missing_fields(self): @@ -77,6 +77,6 @@ def test_missing_fields(self): 'url': 'http://example.com', 'text': 'submission text' } - r = self.c.post(reverse('Submit'), data=test_data) + r = self.c.post(reverse('submit'), data=test_data) self.assertNotContains(r, 'Submission created') self.assertContains(r, 'This field is required.') diff --git a/reddit/tests/test_voting.py b/reddit/tests/test_voting.py index c5899e3..970eb7d 100644 --- a/reddit/tests/test_voting.py +++ b/reddit/tests/test_voting.py @@ -32,7 +32,7 @@ def setUp(self): parent=submission).save() def test_post_only(self): - r = self.c.get(reverse('Vote')) + r = self.c.get(reverse('vote')) self.assertIsInstance(r, HttpResponseNotAllowed) def test_logged_out(self): @@ -42,7 +42,7 @@ def test_logged_out(self): 'vote_value': 1 } - r = self.c.post(reverse('Vote'), data=test_data) + r = self.c.post(reverse('vote'), data=test_data) self.assertIsInstance(r, HttpResponseForbidden) def test_invalid_vote_value(self): @@ -52,30 +52,30 @@ def test_invalid_vote_value(self): 'what_id': 1, 'vote_value': '2' } - r = self.c.post(reverse('Vote'), data=test_data) + r = self.c.post(reverse('vote'), data=test_data) self.assertIsInstance(r, HttpResponseBadRequest) def test_missing_arugmnets(self): self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'submission', 'what_id': 1 }) self.assertIsInstance(r, HttpResponseBadRequest) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'submission', 'vote_value': '1' }) self.assertIsInstance(r, HttpResponseBadRequest) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what_id': '1', 'vote_value': '1' }) self.assertIsInstance(r, HttpResponseBadRequest) - r = self.c.post(reverse('Vote'), data={}) + r = self.c.post(reverse('vote'), data={}) self.assertIsInstance(r, HttpResponseBadRequest) def test_invalid_vote_object_id(self): @@ -86,14 +86,14 @@ def test_invalid_vote_object_id(self): 'what_id': 9999, 'what_value': '1' } - r = self.c.post(reverse('Vote'), data=test_data) + r = self.c.post(reverse('vote'), data=test_data) self.assertIsInstance(r, HttpResponseBadRequest) def test_submission_first_vote(self): submission = Submission.objects.filter(title="vote testing").first() self.assertIsNotNone(submission) self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'submission', 'what_id': submission.id, @@ -115,7 +115,7 @@ def test_submission_vote_cancel_or_reverse(self): Vote.create(user=user, vote_object=submission, vote_value=1).save() self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'submission', 'what_id': submission.id, @@ -133,7 +133,7 @@ def test_submission_vote_cancel_or_reverse(self): vote.save() self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'submission', 'what_id': submission.id, @@ -150,7 +150,7 @@ def test_comment_first_vote(self): comment = Comment.objects.filter(submission=submission).first() self.assertIsNotNone(comment) self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'comment', 'what_id': comment.id, @@ -174,7 +174,7 @@ def test_comment_vote_cancel_or_reverse(self): Vote.create(user=user, vote_object=comment, vote_value=1).save() self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'comment', 'what_id': comment.id, @@ -192,7 +192,7 @@ def test_comment_vote_cancel_or_reverse(self): vote.save() self.c.login(**self.credentials) - r = self.c.post(reverse('Vote'), + r = self.c.post(reverse('vote'), data={ 'what': 'comment', 'what_id': comment.id, diff --git a/reddit/urls.py b/reddit/urls.py index 64c8b8b..c33c9e3 100644 --- a/reddit/urls.py +++ b/reddit/urls.py @@ -13,21 +13,15 @@ 1. Add an import: from blog import urls as blog_urls 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) """ -from django.conf.urls import include, url -from . import views +from django.conf.urls import url +from . import views urlpatterns = [ - url(r'^$', views.frontpage, name="Frontpage"), - url(r'^comments/(?P[0-9]+)$', views.comments, name="Thread"), - url(r'^login/$', views.user_login, name="Login"), - url(r'^logout/$', views.user_logout, name="Logout"), - url(r'^register/$', views.register, name="Register"), - url(r'^submit/$', views.submit, name="Submit"), - url(r'^user/(?P[0-9a-zA-Z_]*)$', views.user_profile, name="User Profile"), - url(r'^profile/edit/$', views.edit_profile, name="Edit Profile"), - - url(r'^post/comment/$', views.post_comment, name="Post Comment"), - url(r'^vote/$', views.vote, name="Vote"), + url(r'^$', views.frontpage, name="frontpage"), + url(r'^comments/(?P[0-9]+)$', views.comments, name="thread"), + url(r'^submit/$', views.submit, name="submit"), + url(r'^post/comment/$', views.post_comment, name="post_comment"), + url(r'^vote/$', views.vote, name="vote"), ] diff --git a/reddit/views.py b/reddit/views.py index 0b244f1..654928d 100644 --- a/reddit/views.py +++ b/reddit/views.py @@ -1,20 +1,18 @@ +from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.http import JsonResponse, HttpResponseBadRequest, Http404, \ + HttpResponseForbidden from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib.auth import login, logout, authenticate -from django.contrib import messages from django.template.defaulttags import register -from django.http import JsonResponse, HttpResponseBadRequest, Http404, \ - HttpResponseForbidden, HttpResponse -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger - -from django.contrib.auth.models import User -from django.views.decorators.csrf import csrf_exempt -from reddit.forms import UserForm, SubmissionForm, ProfileForm +from reddit.forms import SubmissionForm from reddit.models import Submission, Comment, Vote -from reddit.utils.helpers import post_only, get_only +from reddit.utils.helpers import post_only from users.models import RedditUser + @register.filter def get_item(dictionary, key): # pragma: no cover """ @@ -59,7 +57,7 @@ def frontpage(request): except Vote.DoesNotExist: pass - return render(request, 'public/frontpage.html', {'submissions': submissions, + return render(request, 'public/frontpage.html', {'submissions' : submissions, 'submission_votes': submission_votes}) @@ -111,117 +109,10 @@ def comments(request, thread_id=None): pass return render(request, 'public/comments.html', - {'submission': this_submission, - 'comments': thread_comments, + {'submission' : this_submission, + 'comments' : thread_comments, 'comment_votes': comment_votes, - 'sub_vote': sub_vote_value}) - - -def user_profile(request, username): - user = get_object_or_404(User, username=username) - profile = RedditUser.objects.get(user=user) - - return render(request, 'public/profile.html', {'profile': profile}) - - -@login_required -def edit_profile(request): - user = RedditUser.objects.get(user=request.user) - - if request.method == 'GET': - profile_form = ProfileForm(instance=user) - - elif request.method == 'POST': - profile_form = ProfileForm(request.POST, instance=user) - if profile_form.is_valid(): - profile = profile_form.save(commit=False) - profile.update_profile_data() - profile.save() - messages.success(request, "Profile settings saved") - else: - raise Http404 - - return render(request, 'private/edit_profile.html', {'form': profile_form}) - - -def user_login(request): - """ - Pretty straighforward user authentication using password and username - supplied in the POST request. - """ - - if request.user.is_authenticated(): - messages.warning(request, "You are already logged in.") - return render(request, 'public/login.html') - - if request.method == "POST": - username = request.POST.get('username') - password = request.POST.get('password') - if not username or not password: - return HttpResponseBadRequest() - - user = authenticate(username=username, - password=password) - - if user: - if user.is_active: - login(request, user) - redirect_url = request.POST.get('next') or 'Frontpage' - return redirect(redirect_url) - else: - return render(request, 'public/login.html', - {'login_error': "Account disabled"}) - else: - return render(request, 'public/login.html', - {'login_error': "Wrong username or password."}) - - return render(request, 'public/login.html') - - -@post_only -def user_logout(request): - """ - Log out user if one is logged in and redirect them to frontpage. - """ - - if request.user.is_authenticated(): - redirect_page = request.POST.get('current_page', '/') - logout(request) - messages.success(request, 'Logged out!') - return redirect(redirect_page) - return redirect('Frontpage') - - -def register(request): - """ - Handles user registration using UserForm from forms.py - Creates new User and new RedditUser models if appropriate data - has been supplied. - - If account has been created user is redirected to login page. - """ - user_form = UserForm() - if request.user.is_authenticated(): - messages.warning(request, - 'You are already registered and logged in.') - return render(request, 'public/register.html', {'form': user_form}) - - if request.method == "POST": - user_form = UserForm(request.POST) - - if user_form.is_valid(): - user = user_form.save() - user.set_password(user.password) - user.save() - reddit_user = RedditUser() - reddit_user.user = user - reddit_user.save() - user = authenticate(username=request.POST['username'], - password=request.POST['password']) - login(request, user) - return redirect('Frontpage') - - return render(request, 'public/register.html', {'form': user_form}) + 'sub_vote' : sub_vote_value}) @post_only @@ -234,8 +125,8 @@ def post_comment(request): raw_comment = request.POST.get('commentContent', None) if not all([parent_id, parent_type]) or \ - parent_type not in ['comment', 'submission'] or \ - not parent_id.isdigit(): + parent_type not in ['comment', 'submission'] or \ + not parent_id.isdigit(): return HttpResponseBadRequest() if not raw_comment: @@ -293,7 +184,7 @@ def vote(request): # if one of the objects is None, 0 or some other bool(value) == False value # or if the object type isn't 'comment' or 'submission' it's a bad request if not all([vote_object_type, vote_object_id, new_vote_value]) or \ - vote_object_type not in ['comment', 'submission']: + vote_object_type not in ['comment', 'submission']: return HttpResponseBadRequest() # Try and get the actual object we're voting on. @@ -322,7 +213,7 @@ def vote(request): vote_value=new_vote_value) vote.save() vote_diff = new_vote_value - return JsonResponse({'error': None, + return JsonResponse({'error' : None, 'voteDiff': vote_diff}) # User already voted on this item, this means the vote is either @@ -340,7 +231,7 @@ def vote(request): return HttpResponseBadRequest( 'Wrong values for old/new vote combination') - return JsonResponse({'error': None, + return JsonResponse({'error' : None, 'voteDiff': vote_diff}) diff --git a/templates/__layout/navbar.html b/templates/__layout/navbar.html index bbc106b..b94c04d 100644 --- a/templates/__layout/navbar.html +++ b/templates/__layout/navbar.html @@ -8,13 +8,13 @@ - DjangoReddit + DjangoReddit - \ No newline at end of file + diff --git a/templates/public/login.html b/templates/public/login.html index d971520..4bbc8c7 100644 --- a/templates/public/login.html +++ b/templates/public/login.html @@ -2,7 +2,7 @@ {% block content %} - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/public/register.html b/templates/public/register.html index 8fb545e..3eadbc9 100644 --- a/templates/public/register.html +++ b/templates/public/register.html @@ -2,7 +2,7 @@ {% block content %} - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/reddit/tests/test_login.py b/users/tests/test_login.py similarity index 67% rename from reddit/tests/test_login.py rename to users/tests/test_login.py index 4bce3c9..e20a74c 100644 --- a/reddit/tests/test_login.py +++ b/users/tests/test_login.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import User -class TestLoginPOST(TestCase): +class TestloginPOST(TestCase): def setUp(self): self.c = Client() self.valid_data = {"username": "user", @@ -13,12 +13,12 @@ def setUp(self): User.objects.create_user(**self.valid_data) def test_valid_login(self): - r = self.c.post(reverse('Login'), data=self.valid_data, follow=True) - self.assertRedirects(r, reverse('Frontpage')) + r = self.c.post(reverse('login'), data=self.valid_data, follow=True) + self.assertRedirects(r, reverse('frontpage')) self.assertTrue(self.c.login(**self.valid_data)) def test_invalid_login(self): - r = self.c.post(reverse('Login'), data=self.invalid_data) + r = self.c.post(reverse('login'), data=self.invalid_data) self.assertEqual(r.status_code, 200) self.assertContains(r, "Wrong username or password.") self.assertFalse(self.c.login(**self.invalid_data)) @@ -27,21 +27,21 @@ def test_disabled_account(self): u = User.objects.get(username=self.valid_data['username']) u.is_active = False u.save() - r = self.c.post(reverse('Login'), data=self.valid_data) + r = self.c.post(reverse('login'), data=self.valid_data) self.assertContains(r, "Account disabled", status_code=200) def test_already_logged_in(self): - self.c.post(reverse('Login'), data=self.valid_data) - r = self.c.post(reverse('Login'), data=self.valid_data) + self.c.post(reverse('login'), data=self.valid_data) + r = self.c.post(reverse('login'), data=self.valid_data) self.assertContains(r, 'You are already logged in.') def test_login_redirect(self): redirect_data = {'username': self.valid_data['username'], 'password': self.valid_data['password'], - 'next': reverse('Submit')} - r = self.c.post(reverse('Login'), data=redirect_data) - self.assertRedirects(r, reverse('Submit')) + 'next': reverse('submit')} + r = self.c.post(reverse('login'), data=redirect_data) + self.assertRedirects(r, reverse('submit')) def test_malformed_request(self): - r = self.c.post(reverse('Login'), data={"a": "a", 1: "b"}) + r = self.c.post(reverse('login'), data={"a": "a", 1: "b"}) self.assertEqual(r.status_code, 400) diff --git a/reddit/tests/test_logout.py b/users/tests/test_logout.py similarity index 66% rename from reddit/tests/test_logout.py rename to users/tests/test_logout.py index 6b962f8..1cb3990 100644 --- a/reddit/tests/test_logout.py +++ b/users/tests/test_logout.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import User -class TestLogout(TestCase): +class Testlogout(TestCase): def setUp(self): self.c = Client() self.login_data = {'username': 'username', @@ -12,18 +12,18 @@ def setUp(self): def test_valid_logout(self): self.assertTrue(self.c.login(**self.login_data)) - r = self.c.post(reverse('Logout'), follow=True) - self.assertRedirects(r, reverse('Frontpage')) + r = self.c.post(reverse('logout'), follow=True) + self.assertRedirects(r, reverse('frontpage')) self.assertContains(r, 'Logged out!') def test_custom_logout_redirect(self): self.assertTrue(self.c.login(**self.login_data)) - r = self.c.post(reverse('Logout'), data={'current_page': reverse('Login')}, follow=True) - self.assertRedirects(r, reverse('Login')) + r = self.c.post(reverse('logout'), data={'current_page': reverse('login')}, follow=True) + self.assertRedirects(r, reverse('login')) self.assertContains(r, 'Logged out!') def test_invalid_logout_request(self): - r = self.c.post(reverse('Logout'), follow=True) - self.assertRedirects(r, reverse('Frontpage')) + r = self.c.post(reverse('logout'), follow=True) + self.assertRedirects(r, reverse('frontpage')) self.assertTrue('Logged out!' not in r, msg="User that was not logged in told he logged out successfully") diff --git a/reddit/tests/test_registration.py b/users/tests/test_registration.py similarity index 93% rename from reddit/tests/test_registration.py rename to users/tests/test_registration.py index 5743b10..86bb04f 100644 --- a/reddit/tests/test_registration.py +++ b/users/tests/test_registration.py @@ -75,7 +75,7 @@ def setUp(self): def test_logged_in(self): User.objects.create_user(username='regtest', password='password') self.c.login(username='regtest', password='password') - r = self.c.get(reverse('Register')) + r = self.c.get(reverse('register')) self.assertContains(r, 'You are already registered and logged in.') self.assertContains(r, 'type="submit" disabled') @@ -83,8 +83,8 @@ def test_valid_data(self): test_data = {'username': 'username', 'password': 'password'} - response = self.c.post(reverse('Register'), data=test_data) - self.assertRedirects(response, reverse('Frontpage')) + response = self.c.post(reverse('register'), data=test_data) + self.assertRedirects(response, reverse('frontpage')) user = User.objects.filter(username=test_data['username']).first() self.assertIsNotNone(user, @@ -103,7 +103,7 @@ def test_invalid_data(self): test_data = {'username': 'invalid_too_long_username', 'password': '_'} - response = self.c.post(reverse('Register'), data=test_data) + response = self.c.post(reverse('register'), data=test_data) self.assertEqual(response.status_code, 200, msg="Form submission failed, but a registration page was not returned again") self.assertIsNone( @@ -113,5 +113,5 @@ def test_invalid_data(self): msg="Invalid user data can be used to login") def test_malformed_post_request(self): - response = self.c.post(reverse('Register'), data={'a': "a", 1: "b"}) + response = self.c.post(reverse('register'), data={'a': "a", 1: "b"}) self.assertContains(response, 'This field is required.', count=2) diff --git a/users/urls.py b/users/urls.py index e69de29..851ab72 100644 --- a/users/urls.py +++ b/users/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^register/$', views.register, name="register"), + url(r'^login/$', views.user_login, name="login"), + url(r'^logout/$', views.user_logout, name="logout"), + url(r'^user/(?P[0-9a-zA-Z_]*)$', views.user_profile, name="user_profile"), + url(r'^profile/edit/$', views.edit_profile, name="edit_profile"), +] diff --git a/users/views.py b/users/views.py index 91ea44a..1d3cf78 100644 --- a/users/views.py +++ b/users/views.py @@ -1,3 +1,117 @@ -from django.shortcuts import render +from django.contrib import messages +from django.contrib.auth import logout, login, authenticate +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.http import HttpResponseBadRequest, Http404 +from django.shortcuts import render, redirect, get_object_or_404 -# Create your views here. +from reddit.forms import UserForm, ProfileForm +from reddit.utils.helpers import post_only +from users.models import RedditUser + + +def user_profile(request, username): + user = get_object_or_404(User, username=username) + profile = RedditUser.objects.get(user=user) + + return render(request, 'public/profile.html', {'profile': profile}) + + +@login_required +def edit_profile(request): + user = RedditUser.objects.get(user=request.user) + + if request.method == 'GET': + profile_form = ProfileForm(instance=user) + + elif request.method == 'POST': + profile_form = ProfileForm(request.POST, instance=user) + if profile_form.is_valid(): + profile = profile_form.save(commit=False) + profile.update_profile_data() + profile.save() + messages.success(request, "Profile settings saved") + else: + raise Http404 + + return render(request, 'private/edit_profile.html', {'form': profile_form}) + + +def user_login(request): + """ + Pretty straighforward user authentication using password and username + supplied in the POST request. + """ + + if request.user.is_authenticated(): + messages.warning(request, "You are already logged in.") + return render(request, 'public/login.html') + + if request.method == "POST": + username = request.POST.get('username') + password = request.POST.get('password') + if not username or not password: + return HttpResponseBadRequest() + + user = authenticate(username=username, + password=password) + + if user: + if user.is_active: + login(request, user) + redirect_url = request.POST.get('next') or 'frontpage' + return redirect(redirect_url) + else: + return render(request, 'public/login.html', + {'login_error': "Account disabled"}) + else: + return render(request, 'public/login.html', + {'login_error': "Wrong username or password."}) + + return render(request, 'public/login.html') + + +@post_only +def user_logout(request): + """ + Log out user if one is logged in and redirect them to frontpage. + """ + + if request.user.is_authenticated(): + redirect_page = request.POST.get('current_page', '/') + logout(request) + messages.success(request, 'Logged out!') + return redirect(redirect_page) + return redirect('frontpage') + + +def register(request): + """ + Handles user registration using UserForm from forms.py + Creates new User and new RedditUser models if appropriate data + has been supplied. + + If account has been created user is redirected to login page. + """ + user_form = UserForm() + if request.user.is_authenticated(): + messages.warning(request, + 'You are already registered and logged in.') + return render(request, 'public/register.html', {'form': user_form}) + + if request.method == "POST": + user_form = UserForm(request.POST) + + if user_form.is_valid(): + user = user_form.save() + user.set_password(user.password) + user.save() + reddit_user = RedditUser() + reddit_user.user = user + reddit_user.save() + user = authenticate(username=request.POST['username'], + password=request.POST['password']) + login(request, user) + return redirect('frontpage') + + return render(request, 'public/register.html', {'form': user_form})