Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ django = "==1.11.4"
coverage = "*"
prospector = "*"
"django-widget-tweaks" = "*"
"autopep8" = "*"



Expand Down
Empty file added myproject/accounts/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions myproject/accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
5 changes: 5 additions & 0 deletions myproject/accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
name = 'accounts'
12 changes: 12 additions & 0 deletions myproject/accounts/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User


class SignUpForm(UserCreationForm):
email = forms.CharField(
max_length=254, required=True, widget=forms.EmailInput())

class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
Empty file.
3 changes: 3 additions & 0 deletions myproject/accounts/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
Empty file.
11 changes: 11 additions & 0 deletions myproject/accounts/tests/test_form_signup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.test import TestCase
from ..forms import SignUpForm


class SignUpFormTests(TestCase):

def test_form_has_fields(self):
form = SignUpForm()
expected = ['username', 'email', 'password1', 'password2']
actual = list(form.fields)
self.assertSequenceEqual(expected, actual)
92 changes: 92 additions & 0 deletions myproject/accounts/tests/test_view_signup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from django.contrib.auth.models import User
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import resolve
from ..views import signup
from ..forms import SignUpForm

# Create your tests here.


class SignUpTests(TestCase):

def setUp(self):
url = reverse('signup')
self.response = self.client.get(url)

def test_signup_status_code(self):
self.assertEquals(self.response.status_code, 200)

def test_signup_url_resolves_signup_view(self):
view = resolve('/signup/')
self.assertEquals(view.func, signup)

def test_csrf(self):
self.assertContains(self.response, 'csrfmiddlewaretoken')

def test_contains_form(self):
form = self.response.context.get('form')
self.assertIsInstance(form, SignUpForm)

def test_form_inputs(self):
'''
The view must contain five inputs: csrf, username, email,
password1, password2
'''
self.assertContains(self.response, '<input', 5)
self.assertContains(self.response, 'type="text"', 1)
self.assertContains(self.response, 'type="email"', 1)
self.assertContains(self.response, 'type="password"', 2)


class SuccessfulSignUpTests(TestCase):

def setUp(self):
url = reverse('signup')
data = {
'username': 'john',
'email': 'john@doe.com',
'password1': 'abcdef123456',
'password2': 'abcdef123456'
}
self.response = self.client.post(url, data)
self.home_url = reverse('home')

def test_redirection(self):
'''
A valid form submission should redirect the user to home page
'''
self.assertRedirects(self.response, self.home_url)

def test_user_creation(self):
self.assertTrue(User.objects.exists())

def test_user_authentication(self):
'''
Create a new request to an arbitrary page
The resulting response should now have a `user` to its context,
after a successful sign up.
'''
response = self.client.get(self.home_url)
user = response.context.get('user')
self.assertTrue(user.is_authenticated)


class InvalidSignUpTests(TestCase):

def setUp(self):
url = reverse('signup')
self.response = self.client.post(url, {})

def test_signup_status_code(self):
'''
An invalid form submission should return to the same page
'''
self.assertEquals(self.response.status_code, 200)

def test_form_errors(self):
form = self.response.context.get('form')
self.assertTrue(form.errors)

def test_dont_create_user(self):
self.assertFalse(User.objects.exists())
16 changes: 16 additions & 0 deletions myproject/accounts/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.shortcuts import render, redirect
from django.contrib.auth import login as auth_login
from .forms import SignUpForm
# Create your views here.


def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
auth_login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
Empty file.
17 changes: 17 additions & 0 deletions myproject/boards/templatetags/form_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django import template

register = template.Library()

@register.filter
def field_type(bound_field):
return bound_field.field.widget.__class__.__name__

@register.filter
def input_class(bound_field):
css_class = ''
if bound_field.form.is_bound:
if bound_field.errors:
css_class = 'is-invalid'
elif field_type(bound_field) != 'PasswordInput':
css_class = 'is-valid'
return 'form-control {}'.format(css_class)
Empty file.
33 changes: 33 additions & 0 deletions myproject/boards/tests/test_templatetags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django import forms
from django.test import TestCase
from ..templatetags.form_tags import field_type, input_class


class ExampleForm(forms.Form):
name = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput())

class Meta:
fields = ('name', 'password')


class FieldTypeTests(TestCase):
def test_field_widget_type(self):
form = ExampleForm()
self.assertEquals('TextInput', field_type(form['name']))
self.assertEquals('PasswordInput', field_type(form['password']))


class InputClassTests(TestCase):
def test_unbound_field_initial_state(self):
form = ExampleForm()
self.assertEquals('form-control ', input_class(form['name']))

def test_valid_bound_field(self):
form = ExampleForm({'name': 'john', 'password': '123'})
self.assertEquals('form-control is-valid', input_class(form['name']))
self.assertEquals('form-control ', input_class(form['password']))

def test_invalid_bound_field(self):
form = ExampleForm({'name': '', 'password': '123'})
self.assertEquals('form-control is-invalid', input_class(form['name']))
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import resolve
from .views import home, board_topics, new_topic
from .models import Board, Topic, Post
from ..views import home, board_topics, new_topic
from ..models import Board, Topic, Post
from django.contrib.auth.models import User
from .forms import NewTopicForm
from ..forms import NewTopicForm
# Create your tests here.


Expand Down Expand Up @@ -133,4 +133,4 @@ def test_contains_form(self):
url = reverse('new_topic', kwargs={'pk': 1})
response = self.client.get(url)
form = response.context.get('form')
self.assertIsInstance(form, NewTopicForm)
self.assertIsInstance(form, NewTopicForm)
5 changes: 4 additions & 1 deletion myproject/myproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
'django.contrib.staticfiles',

'widget_tweaks',

'accounts',
'boards'
]

Expand Down Expand Up @@ -128,3 +128,6 @@
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]

LOGOUT_REDIRECT_URL = 'home'
LOGIN_REDIRECT_URL = 'home'
7 changes: 6 additions & 1 deletion myproject/myproject/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
"""
from django.contrib import admin
from django.conf.urls import url

from django.contrib.auth import views as auth_views
from accounts import views as account_views
from boards import views

urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^signup/$', account_views.signup, name='signup'),
url(r'^login/$', auth_views.LoginView.as_view(
template_name='login.html'), name='login'),
url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
url(r'^boards/(?P<pk>\d+)/$', views.board_topics, name='board_topics'),
url(r'^boards/(?P<pk>\d+)/new/$', views.new_topic, name='new_topic'),
url(r'^admin/', admin.site.urls)
Expand Down
16 changes: 16 additions & 0 deletions myproject/static/css/accounts.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
body {
background-image: url(../img/city.png);
}

.logo {
font-family: 'Peralta', cursive;
}

.logo a {
color: rgba(0, 0, 0, 0.9);
}

.logo a:hover,
.logo a:active {
text-decoration: none;
}
Binary file added myproject/static/img/city.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions myproject/static/js/bootstrap.min.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions myproject/static/js/jquery-3.2.1.min.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions myproject/static/js/popper.min.js

Large diffs are not rendered by default.

34 changes: 31 additions & 3 deletions myproject/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,38 @@
</title>
<link href="https://fonts.googleapis.com/css?family=Peralta" rel="stylesheet">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/app.css' %}">
<link rel="stylesheet" href="{% static 'css/app.css' %}"> {% block stylesheet %} {% endblock %}
</head>

<body>

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
{% block body %}
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'home' %}">Django Boards</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainMenu">
{% if user.is_authenticated %}
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" id="userMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ user.username }}</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
<a href="#" class="dropdown-item">My account</a>
<a href="#" class="dropdown-item">Change password</a>
<div class="dropdown-divider"></div>
<a href="{% url 'logout' %}" class="dropdown-item">Log out</a>
</div>
</li>
</ul>
{% else %}
<form class="form-inline ml-auto">
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in</a>
<a href="{% url 'signup' %}" class="btn btn-primary ml-2">Sign up</a>
</form>
{% endif %}
</div>
</div>
</nav>

Expand All @@ -31,6 +55,10 @@
{% block content %} {% endblock %}

</div>
{% endblock body %}
<script src="{% static 'js/jquery-3.2.1.min.js' %}"></script>
<script src="{% static 'js/popper.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>

</html>
20 changes: 20 additions & 0 deletions myproject/templates/base_accounts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends 'base.html' %}

{% load static %}


{% block stylesheet %}
<link rel="stylesheet" href="{% static 'css/accounts.css' %}">
{% endblock %}


{% block body %}
<div class="container">
<h1 class="text-center logo my-4">
<a href="{% url 'home' %}">Django Boards</a>
</h1>
{% block content %}
{% endblock %}
</div>
{% endblock %}

Loading