Skip to content

Commit

Permalink
Merge pull request #124 from Cadasta/feature/org-roles-ui
Browse files Browse the repository at this point in the history
Organization UI
  • Loading branch information
ian-ross committed Apr 1, 2016
2 parents 0952384 + c32a321 commit 8fc9517
Show file tree
Hide file tree
Showing 51 changed files with 1,201 additions and 315 deletions.
10 changes: 5 additions & 5 deletions SHELF.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@

- Add translations to templates

# Clean up

- URL config
- Functionality to add contacts to organizations/projects

- Make naming of template files consistent
- Catch not found exceptions and display error message

- Make page titles consistent
# Clean up

- Entry point for creating new projects, should it be the root level of an
organization dashboard

# Bugs

- Adding project step 3 throws `Role matching query does not exist`

- Creating user not added to new organizations
23 changes: 23 additions & 0 deletions cadasta/accounts/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.db.models import Q
from django.contrib.auth.models import UserManager as DjangoUserManager
from django.utils.translation import ugettext as _


class UserManager(DjangoUserManager):
def get_from_username_or_email(self, identifier=None):
users = self.filter(Q(username=identifier) | Q(email=identifier))
users_count = len(users)

if users_count == 1:
return users[0]

if users_count == 0:
error = _(
"User with username or email {} does not exist"
).format(identifier)
raise self.model.DoesNotExist(error)
elif users_count > 1:
error = _(
"More than one user found for username or email {}"
).format(identifier)
raise self.model.MultipleObjectsReturned(error)
22 changes: 22 additions & 0 deletions cadasta/accounts/migrations/0002_auto_20160330_1730.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-03-30 17:30
from __future__ import unicode_literals

import accounts.manager
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('accounts', '0001_initial'),
]

operations = [
migrations.AlterModelManagers(
name='user',
managers=[
('objects', accounts.manager.UserManager()),
],
),
]
4 changes: 4 additions & 0 deletions cadasta/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.contrib.auth.models import AbstractUser
from tutelary.decorators import permissioned_model

from .manager import UserManager


def now_plus_48_hours():
return datetime.now(tz=timezone.utc) + timedelta(hours=48)
Expand All @@ -15,6 +17,8 @@ class User(AbstractUser):

REQUIRED_FIELDS = ['email', 'first_name', 'last_name']

objects = UserManager()

class TutelaryMeta:
perm_type = 'user'
path_fields = ('username',)
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions cadasta/accounts/templates/accounts/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% include "accounts/snippets/registration_form.html" %}
1 change: 0 additions & 1 deletion cadasta/accounts/templates/register.html

This file was deleted.

31 changes: 31 additions & 0 deletions cadasta/accounts/tests/test_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from django.test import TestCase

from pytest import raises

from ..models import User
from .factories import UserFactory


class UserManagerTest(TestCase):
def test_get_from_usernamel(self):
user = UserFactory.create()
found = User.objects.get_from_username_or_email(identifier=user.username)

assert found == user

def test_get_from_email(self):
user = UserFactory.create()
found = User.objects.get_from_username_or_email(identifier=user.email)

assert found == user

def test_user_not_found(self):
with raises(User.DoesNotExist):
User.objects.get_from_username_or_email(identifier='username')

def test_mulitple_users_found(self):
UserFactory.create(username='[email protected]')
UserFactory.create(email='[email protected]')

with raises(User.MultipleObjectsReturned):
User.objects.get_from_username_or_email(identifier='[email protected]')
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_get_profile(self):
context = RequestContext(self.request)
context['form'] = form

expected = render_to_string('profile.html', context)
expected = render_to_string('accounts/profile.html', context)

assert response.status_code == 200
assert content == expected
Expand All @@ -49,8 +49,7 @@ def test_update_profile(self):
'last_name': 'Lennon',
})

response = self.view(self.request)
assert response.status_code == 302
self.view(self.request)

user.refresh_from_db()
assert user.first_name == 'John'
Expand Down
2 changes: 1 addition & 1 deletion cadasta/accounts/views/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class AccountProfile(LoginRequiredMixin, UpdateView):
model = User
form_class = ProfileForm
template_name = 'profile.html'
template_name = 'accounts/profile.html'
success_url = reverse_lazy('account:profile')

def get_object(self, *args, **kwargs):
Expand Down
8 changes: 7 additions & 1 deletion cadasta/config/settings/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
),
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
'DEFAULT_VERSION': 'v1',
'EXCEPTION_HANDLER': 'core.views.exception_handler'
'EXCEPTION_HANDLER': 'core.views.api.exception_handler'
}

ROOT_URLCONF = 'config.urls'
Expand Down Expand Up @@ -136,6 +136,12 @@
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_LOGOUT_REDIRECT_URL = LOGIN_URL

LEAFLET_CONFIG = {
'TILES': [('OpenStreetMap',
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{'attribution': 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'})], # noqa
'RESET_VIEW': False
}

LEAFLET_CONFIG = {
'TILES': [('OpenStreetMap',
Expand Down
18 changes: 13 additions & 5 deletions cadasta/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
]

urlpatterns = [
url(r'^', include('core.urls', namespace='core')),
url(r'^account/', include('accounts.urls.default', namespace='account')),
url(r'^account/', include('allauth.urls')),
url('^', include('django.contrib.auth.urls')),
url(r'^',
include('core.urls',
namespace='core')),
url(r'^account/',
include('accounts.urls.default',
namespace='account')),
url(r'^account/',
include('allauth.urls')),
url('^',
include('django.contrib.auth.urls')),
url(r'^organizations/',
include('organization.urls.default.organizations',
namespace='organization')),
Expand All @@ -45,5 +51,7 @@
include('organization.urls.default.users',
namespace='user')),

url(r'^api/', include(api, namespace='api'))
url(r'^api/',
include(api,
namespace='api'))
]
15 changes: 15 additions & 0 deletions cadasta/core/templates/core/dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends "core/base.html" %}

{% block title %}Dashboard{% endblock %}

{% block content %}

<h1>Dashboard</h1>

<ul>
<li><a href="{% url 'organization:list' %}">Organization index</a></li>
<li><a href="{% url 'project:list' %}">Project index</a></li>
<li><a href="{% url 'user:list' %}">User index</a></li>
</ul>

{% endblock %}
File renamed without changes.
13 changes: 0 additions & 13 deletions cadasta/core/templates/dashboard.html

This file was deleted.

6 changes: 3 additions & 3 deletions cadasta/core/tests/test_urls.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from django.test import TestCase
from django.core.urlresolvers import reverse, resolve

from .. import views
from ..views import default


class CoreUrlTest(TestCase):
def test_index_page(self):
assert reverse('core:index') == '/'

resolved = resolve('/')
assert resolved.func.__name__ == views.IndexPage.__name__
assert resolved.func.__name__ == default.IndexPage.__name__

def test_dashboard(self):
assert reverse('core:dashboard') == '/dashboard/'

resolved = resolve('/dashboard/')
assert resolved.func.__name__ == views.Dashboard.__name__
assert resolved.func.__name__ == default.Dashboard.__name__
91 changes: 0 additions & 91 deletions cadasta/core/tests/test_views.py

This file was deleted.

50 changes: 50 additions & 0 deletions cadasta/core/tests/test_views_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from django.test import TestCase
from django.http import Http404

from rest_framework.exceptions import NotFound

from ..views.api import set_exception, eval_json


class ExceptionHandleTest(TestCase):
def test_set_exception_with_404(self):
exception = Http404("No Organization matches the given query.")

e = set_exception(exception)
assert type(e) == NotFound
assert str(e) == "Organization not found."

def test_set_exception_with_404_and_different_error(self):
exception = Http404("Error Message")

e = set_exception(exception)
assert type(e) == Http404
assert str(e) == "Error Message"

def test_set_exception_with_NotFound(self):
exception = NotFound("Error Message")

e = set_exception(exception)
assert type(e) == NotFound
assert str(e) == "Error Message"

def test_evaluate_json(self):
response_data = {
'contacts': [
'{"name": "This field is required.", "url": "\'blah\' is not a \'uri\'"}',
'{"name": "This field is required."}',
],
'field': "Something went wrong"
}

actual = eval_json(response_data)

expected = {
'contacts': [
{'name': "This field is required.", 'url': "\'blah\' is not a \'uri\'"},
{'name': "This field is required."},
],
'field': "Something went wrong"
}

assert actual == expected
Loading

0 comments on commit 8fc9517

Please sign in to comment.