diff --git a/dusken/admin.py b/dusken/admin.py index 28c672f..d1e4435 100644 --- a/dusken/admin.py +++ b/dusken/admin.py @@ -27,16 +27,13 @@ class MemberAdmin(admin.ModelAdmin): return self.readonly_fields + ('username', ) return self.readonly_fields - -class InstitutionAdmin(admin.ModelAdmin): - pass - admin.site.unregister(django.contrib.auth.models.Group) admin.site.unregister(User) + admin.site.register(Address) admin.site.register(Country) admin.site.register(Group) -admin.site.register(Institution, InstitutionAdmin) +admin.site.register(Institution) admin.site.register(Member, MemberAdmin) admin.site.register(MembershipType) admin.site.register(Membership) diff --git a/dusken/api/member.py b/dusken/api/member.py index ceb2022..65cb965 100644 --- a/dusken/api/member.py +++ b/dusken/api/member.py @@ -72,18 +72,36 @@ class MemberResource(ModelResource): """ Catches POST and PATCH requests and intercepts data. """ - if bundle.obj.user_ptr_id is not None: # happens only if user exists - for key, value in bundle.data.items(): - if key == 'username': - if value != bundle.obj.username: - # We can't change username. - raise ImmediateHttpResponse(HttpForbidden("You can't change your username.")) - return bundle + # Check if the user exists and return an error when attempting to change the username + if bundle.obj.user_ptr_id is not None and not bundle.data['username'] == bundle.obj.username: + raise ImmediateHttpResponse(HttpForbidden("You can't change your username.")) + return bundle def obj_update(self, bundle, request, **kwargs): if bundle.data.get('password') is not None: bundle.obj.set_password(bundle.data['password']) bundle.obj.save() + + if 'address' in bundle.data: + new_address = bundle.data.get('address') + address = bundle.obj.address + + if 'street_address' in new_address: + address.street_address = new_address['street_address'] + if 'city' in new_address: + address.city = new_address['city'] + if 'postal_code' in new_address: + address.postal_code = new_address['postal_code'] + if 'country' in new_address: + try: + country = Country.objects.get(name=new_address['country']) + except Country.DoesNotExist, e: + raise ImmediateHttpResponse(HttpForbidden('The country "{}" does not exist.'.format(new_address['country']))) + else: + address.country = country + + address.save() + return super(MemberResource, self).obj_update(bundle, request, **kwargs) def dehydrate(self, bundle): diff --git a/dusken/fixtures/address.json b/dusken/fixtures/address.json new file mode 100644 index 0000000..865b885 --- /dev/null +++ b/dusken/fixtures/address.json @@ -0,0 +1 @@ +[{"pk": 1, "model": "dusken.address", "fields": {"city": "Oslo", "updated": "2013-08-21T19:37:53.679Z", "created": "2013-08-21T19:37:53.679Z", "country": 1, "postal_code": "1023", "street_address": "Somestreet 1"}}, {"pk": 2, "model": "dusken.address", "fields": {"city": "Amsterdam", "updated": "2013-08-21T19:38:17.664Z", "created": "2013-08-21T19:38:17.664Z", "country": 2, "postal_code": "1432AD", "street_address": "Dutchroad 4"}}] \ No newline at end of file diff --git a/dusken/fixtures/auth.json b/dusken/fixtures/auth.json new file mode 100644 index 0000000..3fbb07b --- /dev/null +++ b/dusken/fixtures/auth.json @@ -0,0 +1 @@ +[{"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 6}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_country", "name": "Can add country", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_country", "name": "Can change country", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_country", "name": "Can delete country", "content_type": 8}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_address", "name": "Can add address", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_address", "name": "Can change address", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_address", "name": "Can delete address", "content_type": 9}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_institution", "name": "Can add institution", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_institution", "name": "Can change institution", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_institution", "name": "Can delete institution", "content_type": 10}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_placeofstudy", "name": "Can add place of study", "content_type": 11}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_placeofstudy", "name": "Can change place of study", "content_type": 11}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_placeofstudy", "name": "Can delete place of study", "content_type": 11}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_member", "name": "Can add user", "content_type": 12}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_member", "name": "Can change user", "content_type": 12}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_member", "name": "Can delete user", "content_type": 12}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_facebookauth", "name": "Can add facebook auth", "content_type": 13}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_facebookauth", "name": "Can change facebook auth", "content_type": 13}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_facebookauth", "name": "Can delete facebook auth", "content_type": 13}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_googleauth", "name": "Can add google auth", "content_type": 14}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_googleauth", "name": "Can change google auth", "content_type": 14}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_googleauth", "name": "Can delete google auth", "content_type": 14}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_extendedmemberdetail", "name": "Can add extended member detail", "content_type": 15}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_extendedmemberdetail", "name": "Can change extended member detail", "content_type": 15}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_extendedmemberdetail", "name": "Can delete extended member detail", "content_type": 15}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_paymenttype", "name": "Can add payment type", "content_type": 16}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_paymenttype", "name": "Can change payment type", "content_type": 16}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_paymenttype", "name": "Can delete payment type", "content_type": 16}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_payment", "name": "Can add payment", "content_type": 17}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_payment", "name": "Can change payment", "content_type": 17}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_payment", "name": "Can delete payment", "content_type": 17}}, {"pk": 52, "model": "auth.permission", "fields": {"codename": "add_membershiptype", "name": "Can add membership type", "content_type": 18}}, {"pk": 53, "model": "auth.permission", "fields": {"codename": "change_membershiptype", "name": "Can change membership type", "content_type": 18}}, {"pk": 54, "model": "auth.permission", "fields": {"codename": "delete_membershiptype", "name": "Can delete membership type", "content_type": 18}}, {"pk": 55, "model": "auth.permission", "fields": {"codename": "add_membership", "name": "Can add membership", "content_type": 19}}, {"pk": 56, "model": "auth.permission", "fields": {"codename": "change_membership", "name": "Can change membership", "content_type": 19}}, {"pk": 57, "model": "auth.permission", "fields": {"codename": "delete_membership", "name": "Can delete membership", "content_type": 19}}, {"pk": 58, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 20}}, {"pk": 59, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 20}}, {"pk": 60, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 20}}, {"pk": 61, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 21}}, {"pk": 62, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 21}}, {"pk": 63, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 21}}, {"pk": 64, "model": "auth.permission", "fields": {"codename": "add_apiaccess", "name": "Can add api access", "content_type": 22}}, {"pk": 65, "model": "auth.permission", "fields": {"codename": "change_apiaccess", "name": "Can change api access", "content_type": 22}}, {"pk": 66, "model": "auth.permission", "fields": {"codename": "delete_apiaccess", "name": "Can delete api access", "content_type": 22}}, {"pk": 67, "model": "auth.permission", "fields": {"codename": "add_apikey", "name": "Can add api key", "content_type": 23}}, {"pk": 68, "model": "auth.permission", "fields": {"codename": "change_apikey", "name": "Can change api key", "content_type": 23}}, {"pk": 69, "model": "auth.permission", "fields": {"codename": "delete_apikey", "name": "Can delete api key", "content_type": 23}}, {"pk": 1, "model": "auth.user", "fields": {"username": "mark", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": true, "last_login": "2013-08-21T19:53:07.653Z", "groups": [], "user_permissions": [], "password": "pbkdf2_sha256$10000$8NUVcwCrxbai$5gri/57kESD/t8ZhpZxueVGQcPCW8l3PSCjSuxDp4AI=", "email": "mark@thedutchies.com", "date_joined": "2013-08-21T19:53:07.653Z"}}] \ No newline at end of file diff --git a/dusken/fixtures/country.json b/dusken/fixtures/country.json new file mode 100644 index 0000000..cc3c1e8 --- /dev/null +++ b/dusken/fixtures/country.json @@ -0,0 +1 @@ +[{"pk": 1, "model": "dusken.country", "fields": {"updated": "2013-08-21T19:37:24.851Z", "name": "Norway", "created": "2013-08-21T19:37:24.851Z"}}, {"pk": 2, "model": "dusken.country", "fields": {"updated": "2013-08-21T19:37:31.577Z", "name": "Netherlands", "created": "2013-08-21T19:37:31.577Z"}}] \ No newline at end of file diff --git a/dusken/fixtures/institution.json b/dusken/fixtures/institution.json new file mode 100644 index 0000000..3d36b84 --- /dev/null +++ b/dusken/fixtures/institution.json @@ -0,0 +1 @@ +[{"pk": 1, "model": "dusken.institution", "fields": {"updated": "2013-08-21T19:38:45.577Z", "name": "EDB Long name", "short_name": "KAK-EDB", "created": "2013-08-21T19:38:45.577Z"}}] \ No newline at end of file diff --git a/dusken/tests/member.py b/dusken/tests/member.py index abcde07..588854f 100644 --- a/dusken/tests/member.py +++ b/dusken/tests/member.py @@ -1,7 +1,9 @@ import logging from support.test import ResourceTestCase -from dusken.models import Member +from dusken.models import Address, Country, Member + +from utils.tests import test_fixtures class MemberTestBase(ResourceTestCase): @@ -19,7 +21,7 @@ class MemberTestBase(ResourceTestCase): # URIs to the member api self.all_members_url = '/api/v1/member/' - self.member_url = self.all_members_url + '{}/'.format(self.member.pk) + self.member_url = self.all_members_url + '{}/' class MemberTest(MemberTestBase): @@ -49,7 +51,7 @@ class MemberTest(MemberTestBase): """ Tests that we can get a premade user correctly. """ - resp = self.api_client.get(self.member_url, format='json') + resp = self.api_client.get(self.member_url.format(self.member.pk), format='json') self.assertValidJSONResponse(resp) # Check if the returned data is correct: @@ -127,7 +129,7 @@ class MemberTest(MemberTestBase): 'phone_number' : 90541242 } - resp = self.api_client.patch(self.member_url, + resp = self.api_client.patch(self.member_url.format(self.member.pk), format='json', data=data) self.assertHttpAccepted(resp) @@ -146,7 +148,7 @@ class MemberTest(MemberTestBase): newusername = oldusername + 'lolzorz' data = { 'username' : newusername } - resp = self.api_client.patch(self.member_url, format='json', data=data) + resp = self.api_client.patch(self.member_url.format(self.member.pk), format='json', data=data) self.assertHttpForbidden(resp) try: @@ -161,20 +163,93 @@ class MemberTest(MemberTestBase): pass # ...the test. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -class MemberAdressTest(MemberTestBase): +class MemberAddressTest(MemberTestBase): - def test_member_update_address(self): + fixtures = test_fixtures() + + def setUp(self): + super(MemberAddressTest, self).setUp() + + self.user_id = 1 + + member = Member.objects.get(id=self.user_id) + member.address = Address.objects.get(id=1) + member.save() + + def test_member_address_update_street(self): data = { "address": { - "street" : "somestreet", - } + "street_address" : "somestreet 2", + } } - response = self.api_client.patch(self.member_url, - format='json', - data=data) + response = self.api_client.patch( + self.member_url.format(self.user_id), + format='json', + data=data) self.assertHttpAccepted(response) + self.assertEquals('somestreet 2', Member.objects.get(id=self.user_id).address.street_address) + + def test_member_address_update_city(self): + data = { + "address": { + "city": "Amsterdam" + } + } + + response = self.api_client.patch( + self.member_url.format(self.user_id), + format='json', + data=data) + + self.assertHttpAccepted(response) + self.assertEquals('Amsterdam', Member.objects.get(id=self.user_id).address.city) + + def test_member_address_update_postcode(self): + data = { + "address": { + "postal_code": "0977RT" + } + } + + response = self.api_client.patch( + self.member_url.format(self.user_id), + format='json', + data=data) + + self.assertHttpAccepted(response) + self.assertEquals('0977RT', Member.objects.get(id=self.user_id).address.postal_code) + + def test_member_address_update_country(self): + data = { + "address": { + "country": "Netherlands" + } + } + + response = self.api_client.patch( + self.member_url.format(self.user_id), + format='json', + data=data) + + self.assertHttpAccepted(response) + self.assertEquals( + Country.objects.get(name="Netherlands"), + Member.objects.get(id=self.user_id).address.country) + + def test_member_adress_update_unknown_country(self): + data = { + "address": { + "country": "unknown" + } + } + + response = self.api_client.patch( + self.member_url.format(self.user_id), + format='json', + data=data) + + self.assertHttpForbidden(response) + self.assertEquals('The country "unknown" does not exist.', response.content) - print response - print Member.objects.get(username="robert").address diff --git a/recreatedb.sh b/recreatedb.sh new file mode 100755 index 0000000..d192faa --- /dev/null +++ b/recreatedb.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +if [ -f dusken.db ]; then + echo 'Removing existing database...' + rm dusken.db +fi + +echo 'Synchronizing database...' +python manage.py syncdb --noinput > /dev/null +echo 'Migrating database...' +python manage.py migrate > /dev/null + +echo '' +echo 'Loading fixtures...' +echo ' - Auth' +python manage.py loaddata dusken/fixtures/auth.json > /dev/null +echo ' - Country' +python manage.py loaddata dusken/fixtures/country.json > /dev/null +echo ' - Address' +python manage.py loaddata dusken/fixtures/address.json > /dev/null +echo ' - Institution' +python manage.py loaddata dusken/fixtures/institution.json > /dev/null + +echo '' +echo 'Done.' +echo '' diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/models.py b/utils/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/utils/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/utils/tests.py b/utils/tests.py new file mode 100644 index 0000000..4a052e4 --- /dev/null +++ b/utils/tests.py @@ -0,0 +1,18 @@ +import os.path +from django.core.management import call_command + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +def test_fixtures(): + ''' Returns a list with the locations of all defined fixtures. ''' + return [os.path.join('dusken', 'fixtures', 'address.json'), + os.path.join('dusken', 'fixtures', 'country.json'), + os.path.join('dusken', 'fixtures', 'institution.json'), + ] + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +def load_test_fixtures(): + ''' Explicitly load all defined fixtures. This can be useful when + you only want to load the fixtures for some testcases, but not + for all tests in a test class.''' + for f in test_fixtures(): + call_command('loaddata', f, verbosity=0) diff --git a/utils/views.py b/utils/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/utils/views.py @@ -0,0 +1 @@ +# Create your views here.