Edit |
Archive
@@ -19,20 +25,47 @@
{{ object.name }}
-
Dashboard
- {% for prj in object.projects.all %}
-
{{ prj.name }}
- {% empty %}
-
You're ready to go
-
- Add new project
- Add members
-
-
- {% endfor %}
+ {% if object.projects.all %}
+
+
+
+ Project |
+ Country |
+ Last updated |
+
+
+
+ {% for prj in object.projects.all %}
+
+ {{ prj.name }} |
+ {{ prj.country }} |
+ {{ prj.last_updated }} |
+
+ {{ prj.name }}
+ {% empty %}
+
+ {% endfor %}
+
+
+ {% else %}
+
You're ready to go
+
You have successfully created your organization. What would you like to do next?
+
+ Add new project
+ Add members
+
+ {% endif %}
{{ object.description }}
+
+
Members
+ {% for user in object.users.all %}
+
{{ user.get_full_name }}
+ Username: {{ user.username }}
+
+ {% endfor %}
+
View all
diff --git a/cadasta/organization/templates/organization/organization_edit.html b/cadasta/organization/templates/organization/organization_edit.html
index 2bbc019a0..52d51d371 100644
--- a/cadasta/organization/templates/organization/organization_edit.html
+++ b/cadasta/organization/templates/organization/organization_edit.html
@@ -2,7 +2,7 @@
{% load widget_tweaks %}
-{% block title %} | {{ form.instance.name }} | Edit{% endblock %}
+{% block title %}Edit {{ form.instance.name }}{% endblock %}
{% block modals %}
diff --git a/cadasta/organization/templates/organization/organization_list.html b/cadasta/organization/templates/organization/organization_list.html
index bbfe39e98..6b0deea1f 100644
--- a/cadasta/organization/templates/organization/organization_list.html
+++ b/cadasta/organization/templates/organization/organization_list.html
@@ -2,7 +2,7 @@
{% load widget_tweaks %}
-{% block title %} | Organizations{% endblock %}
+{% block title %}Organizations{% endblock %}
{% block content %}
diff --git a/cadasta/organization/templates/organization/organization_members.html b/cadasta/organization/templates/organization/organization_members.html
new file mode 100644
index 000000000..cad5ad989
--- /dev/null
+++ b/cadasta/organization/templates/organization/organization_members.html
@@ -0,0 +1,47 @@
+{% extends "core/base.html" %}
+
+{% load widget_tweaks %}
+{% load staticfiles %}
+
+{% block title %}Members | {{ object.name }}{% endblock %}
+
+{% block content %}
+
+
+
+
{{ object.name }}
+
+
+
+
+
+
+
+
+
+ Member |
+ Username |
+ Email |
+ Last login |
+
+
+
+ {% for user in object.users.all %}
+
+ {{ user.get_full_name }} |
+ {{ user.username }} |
+ {{ user.email }} |
+ {{ user.last_login }} |
+
+ {% endfor %}
+
+
+
+{% endblock %}
diff --git a/cadasta/organization/templates/organization/organization_members_add.html b/cadasta/organization/templates/organization/organization_members_add.html
new file mode 100644
index 000000000..e02601824
--- /dev/null
+++ b/cadasta/organization/templates/organization/organization_members_add.html
@@ -0,0 +1,41 @@
+{% extends "organization/organization_members.html" %}
+
+{% load widget_tweaks %}
+
+{% block title %}Add member | {{ object.name }}{% endblock %}
+
+{% block modals %}
+
+
+
+{% endblock %}
diff --git a/cadasta/organization/templates/organization/organization_members_edit.html b/cadasta/organization/templates/organization/organization_members_edit.html
new file mode 100644
index 000000000..d6e67eb42
--- /dev/null
+++ b/cadasta/organization/templates/organization/organization_members_edit.html
@@ -0,0 +1,86 @@
+{% extends "core/base.html" %}
+
+{% load widget_tweaks %}
+{% load staticfiles %}
+
+{% block title %}Members | {{ organization.name }}{% endblock %}
+
+{% block content %}
+
+
+
+
{{ organization.name }}
+
+
+
+
+
+
Member: {{ object.username }}
+
+
+
+
+
+
+
+
+
+
+
Removing this member will remove the member's project permissions for this organization.
+
Are you sure you want to remove this member?
+
+
+
+
+
+
+{% endblock %}
diff --git a/cadasta/organization/templates/organization/project_dashboard.html b/cadasta/organization/templates/organization/project_dashboard.html
index eeb317a4c..6c6fb00f1 100644
--- a/cadasta/organization/templates/organization/project_dashboard.html
+++ b/cadasta/organization/templates/organization/project_dashboard.html
@@ -1,5 +1,7 @@
{% extends "core/base.html" %}
+{% block title %}{{ project.name }}{% endblock %}
+
{% load leaflet_tags %}
{% block extra_head %}
diff --git a/cadasta/organization/templates/organization/project_list.html b/cadasta/organization/templates/organization/project_list.html
index 9bd91baac..470374da4 100644
--- a/cadasta/organization/templates/organization/project_list.html
+++ b/cadasta/organization/templates/organization/project_list.html
@@ -1,5 +1,7 @@
{% extends "core/base.html" %}
+{% block title %}Projects{% endblock %}
+
{% block content %}
Projects
diff --git a/cadasta/organization/templates/organization/user_list.html b/cadasta/organization/templates/organization/user_list.html
index 3f722d689..86998b356 100644
--- a/cadasta/organization/templates/organization/user_list.html
+++ b/cadasta/organization/templates/organization/user_list.html
@@ -1,5 +1,7 @@
{% extends "core/base.html" %}
+{% block title %}Users{% endblock %}
+
{% block content %}
Users
diff --git a/cadasta/organization/tests/test_forms.py b/cadasta/organization/tests/test_forms.py
index 97ba696c4..719e36d0b 100644
--- a/cadasta/organization/tests/test_forms.py
+++ b/cadasta/organization/tests/test_forms.py
@@ -1,9 +1,12 @@
import json
from django.test import TestCase
+from pytest import raises
-from ..forms import OrganizationForm
-from ..models import Organization
-from .factories import OrganizationFactory
+from .. import forms
+from ..models import Organization, OrganizationRole, ProjectRole
+from .factories import OrganizationFactory, ProjectFactory
+
+from accounts.tests.factories import UserFactory
class OrganzationAddTest(TestCase):
@@ -14,14 +17,15 @@ def test_add_organization(self):
'urls': '',
'contacts': ''
}
- form = OrganizationForm(data)
+ form = forms.OrganizationForm(data, user=UserFactory.create())
form.save()
assert form.is_valid() is True
assert Organization.objects.count() == 1
org = Organization.objects.first()
- assert org.slug
+ assert org.slug == 'org'
+ assert OrganizationRole.objects.filter(organization=org).count() == 1
def test_add_organization_with_url(self):
data = {
@@ -30,7 +34,7 @@ def test_add_organization_with_url(self):
'urls': 'http://example.com',
'contacts': ''
}
- form = OrganizationForm(data)
+ form = forms.OrganizationForm(data, user=UserFactory.create())
form.save()
assert form.is_valid() is True
@@ -49,7 +53,7 @@ def test_add_organization_with_contact(self):
'tel': '555-5555'
}])
}
- form = OrganizationForm(data)
+ form = forms.OrganizationForm(data, user=UserFactory.create())
form.save()
assert form.is_valid() is True
@@ -70,7 +74,7 @@ def test_update_organization(self):
'urls': '',
'contacts': ''
}
- form = OrganizationForm(data, instance=org)
+ form = forms.OrganizationForm(data, instance=org)
form.save()
org.refresh_from_db()
@@ -79,3 +83,93 @@ def test_update_organization(self):
assert org.name == data['name']
assert org.description == data['description']
assert org.slug == 'some-org'
+
+
+class AddOrganizationMemberFormTest(TestCase):
+ def test_add_with_username(self):
+ org = OrganizationFactory.create()
+ user = UserFactory.create()
+
+ data = {'identifier': user.username}
+ form = forms.AddOrganizationMemberForm(data, organization=org)
+
+ form.save()
+
+ assert form.is_valid() is True
+ assert OrganizationRole.objects.filter(
+ organization=org, user=user).count() == 1
+
+ def test_add_with_email(self):
+ org = OrganizationFactory.create()
+ user = UserFactory.create()
+
+ data = {'identifier': user.email}
+ form = forms.AddOrganizationMemberForm(data, organization=org)
+
+ form.save()
+
+ assert form.is_valid() is True
+ assert OrganizationRole.objects.filter(
+ organization=org, user=user).count() == 1
+
+ def test_add_non_existing_user(self):
+ org = OrganizationFactory.create()
+
+ data = {'identifier': 'some-user'}
+ form = forms.AddOrganizationMemberForm(data, organization=org)
+
+ with raises(ValueError):
+ form.save()
+
+ assert form.is_valid() is False
+ assert OrganizationRole.objects.count() == 0
+
+
+class EditOrganizationMemberFormTest(TestCase):
+ def test_edit_org_role(self):
+ org = OrganizationFactory.create()
+ user = UserFactory.create()
+
+ data = {'org_role': 'A'}
+
+ org_role = OrganizationRole.objects.create(organization=org, user=user)
+ form = forms.EditOrganizationMemberForm(data, org, user)
+
+ form.save()
+ org_role.refresh_from_db()
+
+ assert form.is_valid() is True
+ assert org_role.admin is True
+
+ def test_edit_project_roles(self):
+ user = UserFactory.create()
+ org = OrganizationFactory.create()
+ prj_1 = ProjectFactory.create(organization=org)
+ prj_2 = ProjectFactory.create(organization=org)
+ prj_3 = ProjectFactory.create(organization=org)
+ prj_4 = ProjectFactory.create(organization=org)
+
+ org_role = OrganizationRole.objects.create(organization=org, user=user)
+ ProjectRole.objects.create(project=prj_4, user=user, role='PM')
+
+ data = {
+ 'org_role': 'M',
+ prj_1.id: 'DC',
+ prj_2.id: 'PU',
+ prj_3.id: 'Pb',
+ prj_4.id: 'Pb'
+ }
+
+ form = forms.EditOrganizationMemberForm(data, org, user)
+
+ form.save()
+ org_role.refresh_from_db()
+
+ assert form.is_valid() is True
+ assert org_role.admin is False
+ assert ProjectRole.objects.get(user=user, project=prj_1).role == 'DC'
+ assert ProjectRole.objects.get(user=user, project=prj_2).role == 'PU'
+ assert (ProjectRole.objects.filter(user=user, project=prj_3).exists()
+ is False)
+ assert (ProjectRole.objects.filter(user=user, project=prj_4).exists()
+ is False)
diff --git a/cadasta/organization/tests/test_models.py b/cadasta/organization/tests/test_models.py
index 8c49ebf15..3f2323fe8 100644
--- a/cadasta/organization/tests/test_models.py
+++ b/cadasta/organization/tests/test_models.py
@@ -126,7 +126,7 @@ def test_assign_new_manager(self):
user = UserFactory.create()
ProjectRole.objects.create(
- project=project, user=user, manager=True)
+ project=project, user=user, role='PM')
assert user.has_perm('project.edit', project) is True
def test_add_manager_role(self):
@@ -135,7 +135,7 @@ def test_add_manager_role(self):
assert user.has_perm('project.edit', project) is False
ProjectRole.objects.create(
- project=project, user=user, manager=True)
+ project=project, user=user, role='PM')
assert user.has_perm('project.edit', project) is True
def test_keep_manager_role(self):
@@ -143,7 +143,7 @@ def test_keep_manager_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, manager=True)
+ project=project, user=user, role='PM')
assert user.has_perm('project.edit', project) is True
role.manager = True
@@ -155,7 +155,7 @@ def test_keep_non_manager_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, manager=False)
+ project=project, user=user, role='PU')
assert user.has_perm('project.edit', project) is False
role.manager = False
@@ -167,10 +167,10 @@ def test_remove_manager_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, manager=True)
+ project=project, user=user, role='PM')
assert user.has_perm('project.edit', project) is True
- role.manager = False
+ role.role = 'PU'
role.save()
assert user.has_perm('project.edit', project) is False
@@ -179,7 +179,7 @@ def test_assign_new_collector(self):
user = UserFactory.create()
ProjectRole.objects.create(
- project=project, user=user, collector=True)
+ project=project, user=user, role='DC')
assert user.has_perm('project.resources.add', project) is True
def test_add_collector_role(self):
@@ -188,7 +188,7 @@ def test_add_collector_role(self):
assert user.has_perm('project.resources.add', project) is False
ProjectRole.objects.create(
- project=project, user=user, collector=True)
+ project=project, user=user, role='DC')
assert user.has_perm('project.resources.add', project) is True
def test_keep_collector_role(self):
@@ -196,10 +196,10 @@ def test_keep_collector_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, collector=True)
+ project=project, user=user, role='DC')
assert user.has_perm('project.resources.add', project) is True
- role.collector = True
+ role.role = 'DC'
role.save()
assert user.has_perm('project.resources.add', project) is True
@@ -208,10 +208,10 @@ def test_keep_non_collector_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, collector=False)
+ project=project, user=user, role='PU')
assert user.has_perm('project.resources.add', project) is False
- role.collector = False
+ role.role = 'PU'
role.save()
assert user.has_perm('project.resources.add', project) is False
@@ -220,9 +220,9 @@ def test_remove_collector_role(self):
user = UserFactory.create()
role = ProjectRole.objects.create(
- project=project, user=user, collector=True)
+ project=project, user=user, role='DC')
assert user.has_perm('project.resources.add', project) is True
- role.collector = False
+ role.role = 'PU'
role.save()
assert user.has_perm('project.resources.add', project) is False
diff --git a/cadasta/organization/tests/test_serializers.py b/cadasta/organization/tests/test_serializers.py
index 5cb6c8649..e899a7de6 100644
--- a/cadasta/organization/tests/test_serializers.py
+++ b/cadasta/organization/tests/test_serializers.py
@@ -4,6 +4,7 @@
from django.test import TestCase
from django.core import mail
from rest_framework.serializers import ValidationError
+from rest_framework.test import APIRequestFactory
from accounts.tests.factories import UserFactory
from .. import serializers
@@ -13,15 +14,27 @@
class OrganizationSerializerTest(TestCase):
def test_slug_field_is_set(self):
+ request = APIRequestFactory().post('/')
+ user = UserFactory.create()
+ setattr(request, 'user', user)
+
org_data = {
'name': 'Test Organization',
}
- serializer = serializers.OrganizationSerializer(data=org_data)
+
+ serializer = serializers.OrganizationSerializer(
+ data=org_data,
+ context={
+ 'request': request
+ }
+ )
serializer.is_valid(raise_exception=True)
serializer.save()
org_instance = serializer.instance
assert org_instance.slug == slugify(org_data['name'])
+ assert OrganizationRole.objects.filter(
+ organization=org_instance).count() == 1
def test_slug_field_is_unique(self):
OrganizationFactory.create(**{
@@ -84,7 +97,7 @@ def test_to_represenation(self):
)
assert serializer.data['username'] == user.username
assert serializer.data['email'] == user.email
- assert serializer.data['roles']['admin'] is False
+ assert serializer.data['role'] == 'User'
def test_list_to_representation(self):
users = UserFactory.create_batch(2)
@@ -108,9 +121,9 @@ def test_list_to_representation(self):
for u in serializer.data:
if u['username'] is org_admin.username:
- assert u['roles']['admin'] is True
+ assert u['role'] == 'Admin'
else:
- assert u['roles']['admin'] is False
+ assert u['role'] == 'User'
def test_set_roles_with_username(self):
user = UserFactory.create()
@@ -118,9 +131,7 @@ def test_set_roles_with_username(self):
data = {
'username': user.username,
- 'roles': {
- 'admin': True,
- }
+ 'role': 'Admin'
}
serializer = serializers.OrganizationUserSerializer(
@@ -135,7 +146,7 @@ def test_set_roles_with_username(self):
serializer.save()
role = OrganizationRole.objects.get(user=user, organization=org)
- assert role.admin == data['roles']['admin']
+ assert role.admin is True
assert len(mail.outbox) == 1
def test_set_roles_with_email(self):
@@ -144,9 +155,7 @@ def test_set_roles_with_email(self):
data = {
'username': user.email,
- 'roles': {
- 'admin': True,
- }
+ 'role': 'Admin'
}
serializer = serializers.OrganizationUserSerializer(
@@ -161,7 +170,7 @@ def test_set_roles_with_email(self):
serializer.save()
role = OrganizationRole.objects.get(user=user, organization=org)
- assert role.admin == data['roles']['admin']
+ assert role.admin is True
assert len(mail.outbox) == 1
def test_set_roles_for_user_that_does_not_exist(self):
@@ -169,9 +178,7 @@ def test_set_roles_for_user_that_does_not_exist(self):
data = {
'username': 'some-user',
- 'roles': {
- 'admin': True
- }
+ 'role': 'Admin'
}
serializer = serializers.OrganizationUserSerializer(
@@ -191,9 +198,7 @@ def test_update_roles_for_user(self):
org = OrganizationFactory.create(add_users=[user])
data = {
- 'roles': {
- 'admin': True,
- }
+ 'role': 'Admin'
}
serializer = serializers.OrganizationUserSerializer(
@@ -208,7 +213,7 @@ def test_update_roles_for_user(self):
serializer.save()
role = OrganizationRole.objects.get(user=user, organization=org)
- assert role.admin == data['roles']['admin']
+ assert role.admin is True
class ProjectUserSerializerTest(TestCase):
@@ -225,8 +230,7 @@ def test_to_represenation(self):
assert serializer.data['username'] == user.username
assert serializer.data['email'] == user.email
- assert serializer.data['roles']['manager'] is False
- assert serializer.data['roles']['collector'] is False
+ assert serializer.data['role'] == 'PU'
def test_list_to_representation(self):
users = UserFactory.create_batch(2)
@@ -235,7 +239,7 @@ def test_list_to_representation(self):
ProjectRole.objects.create(
user=prj_admin,
project=project,
- manager=True
+ role='PM'
)
serializer = serializers.ProjectUserSerializer(
@@ -250,9 +254,9 @@ def test_list_to_representation(self):
for u in serializer.data:
if u['username'] is prj_admin.username:
- assert u['roles']['manager'] is True
+ assert u['role'] == 'PM'
else:
- assert u['roles']['manager'] is False
+ assert u['role'] == 'PU'
def test_set_roles_for_existing_user(self):
user = UserFactory.create()
@@ -261,10 +265,7 @@ def test_set_roles_for_existing_user(self):
data = {
'username': user.username,
- 'roles': {
- 'manager': False,
- 'collector': True,
- }
+ 'role': 'DC'
}
serializer = serializers.ProjectUserSerializer(
@@ -275,8 +276,7 @@ def test_set_roles_for_existing_user(self):
serializer.save()
role = ProjectRole.objects.get(user=user, project=project)
- assert role.manager == data['roles']['manager']
- assert role.collector == data['roles']['collector']
+ assert role.role == data['role']
def test_set_roles_for_user_who_is_not_an_org_member(self):
user = UserFactory.create()
@@ -284,10 +284,7 @@ def test_set_roles_for_user_who_is_not_an_org_member(self):
data = {
'username': user.username,
- 'roles': {
- 'manager': False,
- 'collector': True,
- }
+ 'role': 'DC'
}
serializer = serializers.ProjectUserSerializer(
@@ -307,10 +304,7 @@ def test_set_roles_for_user_that_does_not_exist(self):
data = {
'username': 'some-user',
- 'roles': {
- 'manager': False,
- 'collector': True,
- }
+ 'role': 'DC'
}
serializer = serializers.ProjectUserSerializer(
@@ -330,9 +324,7 @@ def test_update_roles_for_user(self):
project = ProjectFactory.create(add_users=[user])
data = {
- 'roles': {
- 'manager': True,
- }
+ 'role': 'PM'
}
serializer = serializers.ProjectUserSerializer(
user,
@@ -346,8 +338,7 @@ def test_update_roles_for_user(self):
serializer.save()
role = ProjectRole.objects.get(user=user, project=project)
- assert role.manager == data['roles']['manager']
- assert role.collector is False
+ assert role.role == data['role']
class UserAdminSerializerTest(TestCase):
diff --git a/cadasta/organization/tests/test_api_urls.py b/cadasta/organization/tests/test_urls_api.py
similarity index 100%
rename from cadasta/organization/tests/test_api_urls.py
rename to cadasta/organization/tests/test_urls_api.py
diff --git a/cadasta/organization/tests/test_default_urls.py b/cadasta/organization/tests/test_urls_default.py
similarity index 69%
rename from cadasta/organization/tests/test_default_urls.py
rename to cadasta/organization/tests/test_urls_default.py
index e9bc5f31e..305bbf614 100644
--- a/cadasta/organization/tests/test_default_urls.py
+++ b/cadasta/organization/tests/test_urls_default.py
@@ -102,3 +102,48 @@ def test_project_edit(self):
assert resolved.func.__name__ == default.ProjectEdit.__name__
assert resolved.kwargs['organization'] == 'org-slug'
assert resolved.kwargs['project'] == 'proj-slug'
+
+
+class OrganizationMembersUrlsTest(TestCase):
+ def test_member_list(self):
+ url = reverse('organization:members', kwargs={'slug': 'org-slug'})
+ assert url == '/organizations/org-slug/members/'
+
+ resolved = resolve('/organizations/org-slug/members/')
+ assert resolved.func.__name__ == default.OrganizationMembers.__name__
+ assert resolved.kwargs['slug'] == 'org-slug'
+
+ def test_member_add(self):
+ url = reverse('organization:members_add', kwargs={'slug': 'org-slug'})
+ assert url == '/organizations/org-slug/members/add/'
+
+ resolved = resolve('/organizations/org-slug/members/add/')
+ assert (resolved.func.__name__ ==
+ default.OrganizationMembersAdd.__name__)
+ assert resolved.kwargs['slug'] == 'org-slug'
+
+ def test_member_edit(self):
+ url = reverse(
+ 'organization:members_edit',
+ kwargs={'slug': 'org-slug', 'username': 'some-user'}
+ )
+ assert url == '/organizations/org-slug/members/some-user/'
+
+ resolved = resolve('/organizations/org-slug/members/some-user/')
+ assert (resolved.func.__name__ ==
+ default.OrganizationMembersEdit.__name__)
+ assert resolved.kwargs['slug'] == 'org-slug'
+ assert resolved.kwargs['username'] == 'some-user'
+
+ def test_member_remove(self):
+ url = reverse(
+ 'organization:members_remove',
+ kwargs={'slug': 'org-slug', 'username': 'some-user'}
+ )
+ assert url == '/organizations/org-slug/members/some-user/remove/'
+
+ resolved = resolve('/organizations/org-slug/members/some-user/remove/')
+ assert (resolved.func.__name__ ==
+ default.OrganizationMembersRemove.__name__)
+ assert resolved.kwargs['slug'] == 'org-slug'
+ assert resolved.kwargs['username'] == 'some-user'
diff --git a/cadasta/organization/tests/test_api.py b/cadasta/organization/tests/test_views_api.py
similarity index 99%
rename from cadasta/organization/tests/test_api.py
rename to cadasta/organization/tests/test_views_api.py
index 8f73822b1..996c5ca92 100644
--- a/cadasta/organization/tests/test_api.py
+++ b/cadasta/organization/tests/test_views_api.py
@@ -973,11 +973,7 @@ def test_update_user(self):
user = UserFactory.create()
project = ProjectFactory.create(add_users=[user])
- data = {
- 'roles': {
- 'manager': True
- }
- }
+ data = {'role': 'PM'}
response = self._patch(
org=project.organization.slug,
@@ -988,17 +984,13 @@ def test_update_user(self):
assert response.status_code == 200
role = ProjectRole.objects.get(project=project, user=user)
- assert role.manager is True
+ assert role.role == 'PM'
def test_update_user_with_unauthorized_user(self):
user = UserFactory.create()
project = ProjectFactory.create(add_users=[user])
- data = {
- 'roles': {
- 'manager': True
- }
- }
+ data = {'role': 'PM'}
response = self._patch(
org=project.organization.slug,
@@ -1008,7 +1000,7 @@ def test_update_user_with_unauthorized_user(self):
assert response.status_code == 403
role = ProjectRole.objects.get(project=project, user=user)
- assert role.manager is False
+ assert role.role == 'PU'
def test_delete_user(self):
user = UserFactory.create()
diff --git a/cadasta/organization/tests/test_default.py b/cadasta/organization/tests/test_views_default.py
similarity index 58%
rename from cadasta/organization/tests/test_default.py
rename to cadasta/organization/tests/test_views_default.py
index 1dea7ba01..c3460353f 100644
--- a/cadasta/organization/tests/test_default.py
+++ b/cadasta/organization/tests/test_views_default.py
@@ -9,7 +9,7 @@
from accounts.tests.factories import UserFactory
from ..views import default
-from ..models import Organization
+from ..models import Organization, OrganizationRole
from .. import forms
from .factories import OrganizationFactory, ProjectFactory, clause
@@ -105,23 +105,23 @@ def test_post_with_authorized_user(self):
assert response.status_code == 302
assert '/organizations/{}/'.format(org.slug) in response['location']
- def test_get_with_unauthorized_user(self):
- user = UserFactory.create()
- setattr(self.request, 'user', user)
- response = self.view(self.request).render()
- content = response.content.decode('utf-8')
- print(content)
+ # def test_get_with_unauthorized_user(self):
+ # user = UserFactory.create()
+ # setattr(self.request, 'user', user)
+ # response = self.view(self.request).render()
+ # content = response.content.decode('utf-8')
- context = RequestContext(self.request)
- context['form'] = forms.OrganizationForm()
+ # context = RequestContext(self.request)
+ # context['form'] = forms.OrganizationForm()
- expected = render_to_string(
- 'organization/organization_add.html',
- context
- )
+ # expected = render_to_string(
+ # 'organization/organization_add.html',
+ # context
+ # )
+
+ # assert response.status_code == 200
+ # assert expected == content
- assert response.status_code == 200
- assert expected == content
class OrganizationDashboardTest(TestCase):
def setUp(self):
@@ -259,6 +259,205 @@ def test_archive_with_authorized_user(self):
assert self.org.archived is True
+class OrganizationMembersTest(TestCase):
+ def setUp(self):
+ self.view = default.OrganizationMembers.as_view()
+ self.request = HttpRequest()
+ setattr(self.request, 'method', 'GET')
+ setattr(self.request, 'user', AnonymousUser())
+
+ self.users = UserFactory.create_batch(2)
+ self.org = OrganizationFactory.create(add_users=self.users)
+
+ clauses = {
+ 'clause': [
+ clause('allow', ['org.list']),
+ clause('allow', ['org.*', 'org.*.*'], ['organization/*'])
+ ]
+ }
+ self.policy = Policy.objects.create(
+ name='allow',
+ body=json.dumps(clauses))
+
+ def test_get_with_authorized_user(self):
+ user = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+
+ response = self.view(self.request, slug=self.org.slug).render()
+ content = response.content.decode('utf-8')
+
+ context = RequestContext(self.request)
+ context['object'] = self.org
+
+ expected = render_to_string(
+ 'organization/organization_members.html',
+ context
+ )
+
+ assert response.status_code == 200
+ assert expected == content
+
+
+class OrganizationMembersAddTest(TestCase):
+ def setUp(self):
+ self.view = default.OrganizationMembersAdd.as_view()
+ self.request = HttpRequest()
+ setattr(self.request, 'method', 'GET')
+ setattr(self.request, 'user', AnonymousUser())
+
+ self.org = OrganizationFactory.create()
+
+ clauses = {
+ 'clause': [
+ clause('allow', ['org.list']),
+ clause('allow', ['org.*', 'org.*.*'], ['organization/*'])
+ ]
+ }
+ self.policy = Policy.objects.create(
+ name='allow',
+ body=json.dumps(clauses))
+
+ def test_get_with_authorized_user(self):
+ user = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+
+ response = self.view(self.request, slug=self.org.slug).render()
+ content = response.content.decode('utf-8')
+
+ context = RequestContext(self.request)
+ context['object'] = self.org
+ context['form'] = forms.AddOrganizationMemberForm()
+
+ expected = render_to_string(
+ 'organization/organization_members_add.html',
+ context
+ )
+
+ assert response.status_code == 200
+ assert expected == content
+
+ def test_post_with_authorized_user(self):
+ user = UserFactory.create()
+ user_to_add = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+ setattr(self.request, 'method', 'POST')
+ setattr(self.request, 'POST', {'identifier': user_to_add.username})
+
+ response = self.view(self.request, slug=self.org.slug)
+
+ assert response.status_code == 302
+ assert ('/organizations/{}/members/{}'.format(
+ self.org.slug, user_to_add.username)
+ in response['location'])
+ assert OrganizationRole.objects.filter(
+ organization=self.org, user=user_to_add).count() == 1
+
+
+class OrganizationMembersEditTest(TestCase):
+ def setUp(self):
+ self.view = default.OrganizationMembersEdit.as_view()
+ self.request = HttpRequest()
+ setattr(self.request, 'method', 'GET')
+ setattr(self.request, 'user', AnonymousUser())
+
+ self.member = UserFactory.create()
+ self.org = OrganizationFactory.create(add_users=[self.member])
+
+ clauses = {
+ 'clause': [
+ clause('allow', ['org.list']),
+ clause('allow', ['org.*', 'org.*.*'], ['organization/*'])
+ ]
+ }
+ self.policy = Policy.objects.create(
+ name='allow',
+ body=json.dumps(clauses))
+
+ def test_get_with_authorized_user(self):
+ user = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+
+ response = self.view(
+ self.request,
+ slug=self.org.slug,
+ username=self.member.username).render()
+ content = response.content.decode('utf-8')
+
+ context = RequestContext(self.request)
+ context['object'] = self.member
+ context['organization'] = self.org
+ context['form'] = forms.EditOrganizationMemberForm(None, self.org, self.member)
+
+ expected = render_to_string(
+ 'organization/organization_members_edit.html',
+ context
+ )
+
+ assert response.status_code == 200
+ assert expected == content
+
+ def test_post_with_authorized_user(self):
+ user = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+ setattr(self.request, 'method', 'POST')
+ setattr(self.request, 'POST', {'org_role': 'A'})
+
+ response = self.view(
+ self.request,
+ slug=self.org.slug,
+ username=self.member.username)
+
+ assert response.status_code == 302
+ assert ('/organizations/{}/members/'.format(self.org.slug)
+ in response['location'])
+ role = OrganizationRole.objects.get(organization=self.org,
+ user=self.member)
+ assert role.admin is True
+
+
+class OrganizationMembersRemoveTest(TestCase):
+ def setUp(self):
+ self.view = default.OrganizationMembersRemove.as_view()
+ self.request = HttpRequest()
+ setattr(self.request, 'method', 'GET')
+ setattr(self.request, 'user', AnonymousUser())
+
+ self.member = UserFactory.create()
+ self.org = OrganizationFactory.create(add_users=[self.member])
+
+ clauses = {
+ 'clause': [
+ clause('allow', ['org.list']),
+ clause('allow', ['org.*', 'org.*.*'], ['organization/*'])
+ ]
+ }
+ self.policy = Policy.objects.create(
+ name='allow',
+ body=json.dumps(clauses))
+
+ def test_get_with_authorized_user(self):
+ user = UserFactory.create()
+ assign_user_policies(user, self.policy)
+ setattr(self.request, 'user', user)
+
+ response = self.view(
+ self.request,
+ slug=self.org.slug,
+ username=self.member.username)
+
+ assert response.status_code == 302
+ assert ('/organizations/{}/members/'.format(self.org.slug)
+ in response['location'])
+ assert (OrganizationRole.objects.filter(organization=self.org,
+ user=self.member).exists() is
+ False)
+
+
class ProjectListTest(TestCase):
def setUp(self):
self.view = default.ProjectList.as_view()
@@ -279,7 +478,8 @@ def setUp(self):
self.projs += ProjectFactory.create_batch(2, organization=self.ok_org1)
self.projs += ProjectFactory.create_batch(2, organization=self.ok_org2)
ProjectFactory.create(
- name='Unauthorized project', project_slug='unauth-proj',
+ name='Unauthorized project',
+ project_slug='unauth-proj',
organization=self.ok_org2
)
ProjectFactory.create(
@@ -310,8 +510,8 @@ def test_get_with_user(self):
expected = render_to_string(
'organization/project_list.html',
{'object_list': self.projs,
- 'user': self.request.user,
- 'add_allowed': True})
+ 'add_allowed': True,
+ 'user': self.request.user})
assert response.status_code == 200
assert expected == content
diff --git a/cadasta/organization/urls/default/organizations.py b/cadasta/organization/urls/default/organizations.py
index 0f36260c2..459687e45 100644
--- a/cadasta/organization/urls/default/organizations.py
+++ b/cadasta/organization/urls/default/organizations.py
@@ -23,6 +23,9 @@
r'^(?P
[-\w]+)/archive/$',
default.OrganizationArchive.as_view(),
name='archive'),
+ #
+ # PROJECTS
+ #
url(
r'^(?P[-\w]+)/projects/(?P[-\w]+)/$',
@@ -31,5 +34,26 @@
url(
r'^(?P[-\w]+)/projects/(?P[-\w]+)/edit/$',
default.ProjectEdit.as_view(),
- name='project-edit')
+ name='project-edit'),
+
+ #
+ # MEMBERS
+ #
+
+ url(
+ r'^(?P[-\w]+)/members/$',
+ default.OrganizationMembers.as_view(),
+ name='members'),
+ url(
+ r'^(?P[-\w]+)/members/add/$',
+ default.OrganizationMembersAdd.as_view(),
+ name='members_add'),
+ url(
+ r'^(?P[-\w]+)/members/(?P[-\w]+)/$',
+ default.OrganizationMembersEdit.as_view(),
+ name='members_edit'),
+ url(
+ r'^(?P[-\w]+)/members/(?P[-\w]+)/remove/$',
+ default.OrganizationMembersRemove.as_view(),
+ name='members_remove'),
]
diff --git a/cadasta/organization/views/default.py b/cadasta/organization/views/default.py
index 9533674a6..b2f6249e6 100644
--- a/cadasta/organization/views/default.py
+++ b/cadasta/organization/views/default.py
@@ -1,6 +1,6 @@
from django.http import Http404
import django.views.generic as generic
-from django.shortcuts import redirect
+from django.shortcuts import redirect, get_object_or_404
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.text import slugify
@@ -10,7 +10,8 @@
from core.mixins import PermissionRequiredMixin
from accounts.models import User
-from ..models import Organization, Project
+
+from ..models import Organization, Project, OrganizationRole
from .. import forms
@@ -36,8 +37,13 @@ def get_success_url(self):
kwargs={'slug': self.object.slug}
)
+ def get_form_kwargs(self, *args, **kwargs):
+ kwargs = super(OrganizationAdd, self).get_form_kwargs(*args, **kwargs)
+ kwargs['user'] = self.request.user
+ return kwargs
+
-class OrganizationDashboard(PermissionRequiredMixin, generic.DetailView):
+class OrganizationDashboard(generic.DetailView):
model = Organization
template_name = 'organization/organization_dashboard.html'
permission_required = 'org.view'
@@ -74,6 +80,113 @@ def get_success_url(self):
)
+class OrganizationMembers(generic.DetailView):
+ model = Organization
+ template_name = 'organization/organization_members.html'
+ permission_required = 'org.users.list'
+
+
+class OrganizationObjectMixin:
+ def get_organization(self):
+ if not hasattr(self, 'org'):
+ self.org = get_object_or_404(Organization,
+ slug=self.kwargs['slug'])
+ return self.org
+
+
+class OrganizationMembersAdd(OrganizationObjectMixin, generic.CreateView):
+ model = OrganizationRole
+ form_class = forms.AddOrganizationMemberForm
+ template_name = 'organization/organization_members_add.html'
+ permission_required = 'org.users.add'
+
+ def get_context_data(self, *args, **kwargs):
+ context = super(OrganizationMembersAdd, self).get_context_data(
+ *args, **kwargs)
+ context['object'] = self.get_organization()
+ return context
+
+ def get_form_kwargs(self, *args, **kwargs):
+ kwargs = super().get_form_kwargs(*args, **kwargs)
+
+ if self.request.method == 'POST':
+ org = get_object_or_404(Organization, slug=self.kwargs['slug'])
+ kwargs['organization'] = org
+
+ return kwargs
+
+ def get_success_url(self):
+ return reverse(
+ 'organization:members_edit',
+ kwargs={'slug': self.object.organization.slug,
+ 'username': self.object.user.username}
+ )
+
+
+class OrganizationMembersEdit(OrganizationObjectMixin,
+ generic.edit.FormMixin,
+ generic.DetailView):
+ slug_field = 'username'
+ slug_url_kwarg = 'username'
+ template_name = 'organization/organization_members_edit.html'
+ form_class = forms.EditOrganizationMemberForm
+
+ def get_success_url(self):
+ return reverse(
+ 'organization:members',
+ kwargs={'slug': self.get_organization().slug}
+ )
+
+ def get_queryset(self):
+ return self.get_organization().users.all()
+
+ def get_form(self):
+ if self.request.method == 'POST':
+ return self.form_class(self.request.POST,
+ self.get_organization(),
+ self.get_object())
+ else:
+ return self.form_class(None,
+ self.get_organization(),
+ self.get_object())
+
+ def get_context_data(self, *args, **kwargs):
+ context = super(OrganizationMembersEdit, self).get_context_data(
+ *args, **kwargs)
+ context['organization'] = self.get_organization()
+ context['form'] = self.get_form()
+ return context
+
+ def post(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ form = self.get_form()
+ if form.is_valid():
+ return self.form_valid(form)
+ else:
+ return self.form_invalid(form)
+
+ def form_valid(self, form):
+ form.save()
+ return super(OrganizationMembersEdit, self).form_valid(form)
+
+
+class OrganizationMembersRemove(OrganizationObjectMixin, generic.DeleteView):
+ def get_object(self):
+ return OrganizationRole.objects.get(
+ organization__slug=self.kwargs['slug'],
+ user__username=self.kwargs['username'],
+ )
+
+ def get_success_url(self):
+ return reverse(
+ 'organization:members',
+ kwargs={'slug': self.get_organization().slug}
+ )
+
+ def get(self, *args, **kwargs):
+ return self.post(*args, **kwargs)
+
+
class UserList(PermissionRequiredMixin, generic.ListView):
model = User
template_name = 'organization/user_list.html'
@@ -218,6 +331,7 @@ def done(self, form_list, form_dict, **kwargs):
break
if not is_admin:
usernames.append(user.username)
+ print(form_data)
user_roles = [(k, form_data[2][k]) for k in usernames]
print('name:', name)
print('organization:', organization)
diff --git a/cadasta/templates/allauth/account/login.html b/cadasta/templates/allauth/account/login.html
index 41c095233..47f9503d9 100644
--- a/cadasta/templates/allauth/account/login.html
+++ b/cadasta/templates/allauth/account/login.html
@@ -45,6 +45,7 @@ {% trans "Sign in to your account" %}
{{ error|escape }}
{% endfor %}
+
{% render_field form.password class+="form-control input-lg" placeholder="" %}