Refactor apps to be in repo folder

This commit is contained in:
Isaac Bythewood
2018-02-08 21:57:49 -05:00
parent 9d00c74d18
commit 1fcdf2a9a3
33 changed files with 15 additions and 15 deletions

1
users/__init__.py Normal file
View File

@@ -0,0 +1 @@

7
users/apps.py Normal file
View File

@@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'

0
users/auth/__init__.py Normal file
View File

43
users/auth/backends.py Normal file
View File

@@ -0,0 +1,43 @@
import re
from core.models import Pin
from users.models import User
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
# quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)'
# domain
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
class CombinedAuthBackend(object):
def authenticate(self, username=None, password=None):
is_email = email_re.match(username)
if is_email:
qs = User.objects.filter(email=username)
else:
qs = User.objects.filter(username=username)
try:
user = qs.get()
except User.DoesNotExist:
return None
if user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def has_perm(self, user, perm, obj=None):
"""
A very simplistic authorization mechanism for now. Basically a pin owner can do anything with the pin.
"""
if obj and isinstance(obj, Pin):
return obj.submitter == user
return False

38
users/forms.py Normal file
View File

@@ -0,0 +1,38 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username,
email, and password.
"""
error_messages = {
'duplicate_username': _("A user with that username already exists."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w-]+$')
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
class Meta:
model = User
fields = ("username", "email")
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user

15
users/middleware.py Normal file
View File

@@ -0,0 +1,15 @@
from django.conf import settings
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
class Public(object):
def process_request(self, request):
if settings.PUBLIC == False and not request.user.is_authenticated():
acceptable_paths = [
'/login/',
'/private/',
'/register/',
]
if request.path not in acceptable_paths:
return HttpResponseRedirect(reverse('users:private'))

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.contrib.auth.models
class Migration(migrations.Migration):
dependencies = [
('auth', '0006_require_contenttypes_0002'),
]
operations = [
migrations.CreateModel(
name='User',
fields=[
],
options={
'proxy': True,
},
bases=('auth.user',),
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]

View File

12
users/models.py Normal file
View File

@@ -0,0 +1,12 @@
import hashlib
from django.contrib.auth.models import User as BaseUser
class User(BaseUser):
@property
def gravatar(self):
return hashlib.md5(self.email.encode('utf-8')).hexdigest()
class Meta:
proxy = True

77
users/tests.py Normal file
View File

@@ -0,0 +1,77 @@
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings
import mock
from .auth.backends import CombinedAuthBackend
from ..core.models import Image, Pin
from .models import User
def mock_requests_get(url):
response = mock.Mock(content=open('logo.png', 'rb').read())
return response
class CombinedAuthBackendTest(TestCase):
def setUp(self):
self.backend = CombinedAuthBackend()
self.username = 'jdoe'
self.email = 'jdoe@example.com'
self.password = 'password'
User.objects.create_user(username=self.username, email=self.email, password=self.password)
def test_authenticate_username(self):
self.assertTrue(self.backend.authenticate(username=self.username, password=self.password))
def test_authenticate_email(self):
self.assertTrue(self.backend.authenticate(username=self.email, password=self.password))
def test_authenticate_wrong_password(self):
self.assertIsNone(self.backend.authenticate(username=self.username, password='wrong-password'))
def test_authenticate_unknown_user(self):
self.assertIsNone(self.backend.authenticate(username='wrong-username', password='wrong-password'))
@mock.patch('requests.get', mock_requests_get)
def test_has_perm_on_pin(self):
image = Image.objects.create_for_url('http://testserver/mocked/screenshot.png')
user = User.objects.get(username=self.username)
pin = Pin.objects.create(submitter=user, image=image)
self.assertTrue(self.backend.has_perm(user, 'add_pin', pin))
@mock.patch('requests.get', mock_requests_get)
def test_has_perm_on_pin_unauthorized(self):
image = Image.objects.create_for_url('http://testserver/mocked/screenshot.png')
user = User.objects.get(username=self.username)
other_user = User.objects.create_user('test', 'test@example.com', 'test')
pin = Pin.objects.create(submitter=user, image=image)
self.assertFalse(self.backend.has_perm(other_user, 'add_pin', pin))
class CreateUserTest(TestCase):
def test_create_post(self):
data = {
'username': 'jdoe',
'email': 'jdoe@example.com',
'password': 'password'
}
response = self.client.post(reverse('users:register'), data=data)
self.assertRedirects(response, reverse('core:recent-pins'))
self.assertIn('_auth_user_id', self.client.session)
@override_settings(ALLOW_NEW_REGISTRATIONS=False)
def test_create_post_not_allowed(self):
response = self.client.get(reverse('users:register'))
self.assertRedirects(response, reverse('core:recent-pins'))
class LogoutViewTest(TestCase):
def setUp(self):
User.objects.create_user(username='jdoe', password='password')
self.client.login(username='jdoe', password='password')
def test_logout_view(self):
response = self.client.get(reverse('users:logout'))
self.assertRedirects(response, reverse('core:recent-pins'))

11
users/urls.py Normal file
View File

@@ -0,0 +1,11 @@
from django.conf.urls import patterns, url
from .views import CreateUser
urlpatterns = patterns('',
url(r'^private/$', 'users.views.private', name='private'),
url(r'^register/$', CreateUser.as_view(), name='register'),
url(r'^login/$', 'django.contrib.auth.views.login',
{'template_name': 'users/login.html'}, name='login'),
url(r'^logout/$', 'users.views.logout_user', name='logout'),
)

49
users/views.py Normal file
View File

@@ -0,0 +1,49 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Permission
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils.functional import lazy
from django.views.generic import CreateView
from .forms import UserCreationForm
from users.models import User
reverse_lazy = lambda name=None, *args: lazy(reverse, str)(name, args=args)
class CreateUser(CreateView):
template_name = 'users/register.html'
model = User
form_class = UserCreationForm
success_url = reverse_lazy('core:recent-pins')
def get(self, request, *args, **kwargs):
if not settings.ALLOW_NEW_REGISTRATIONS:
messages.error(request, "The admin of this service is not allowing new registrations.")
return HttpResponseRedirect(reverse('core:recent-pins'))
return super(CreateUser, self).get(request, *args, **kwargs)
def form_valid(self, form):
redirect = super(CreateUser, self).form_valid(form)
permissions = Permission.objects.filter(codename__in=['add_pin', 'add_image'])
user = authenticate(username=form.cleaned_data['username'],
password=form.cleaned_data['password'])
user.user_permissions = permissions
login(self.request, user)
return redirect
@login_required
def logout_user(request):
logout(request)
messages.success(request, 'You have successfully logged out.')
return HttpResponseRedirect(reverse('core:recent-pins'))
def private(request):
return TemplateResponse(request, 'users/private.html', None)