Provide api calls for permitting helpdesk users to access user information by user...
authorSofia Papagiannaki <papagian@gmail.com>
Mon, 21 May 2012 12:27:40 +0000 (15:27 +0300)
committerSofia Papagiannaki <papagian@gmail.com>
Mon, 21 May 2012 12:27:40 +0000 (15:27 +0300)
Refs: #2414

13 files changed:
snf-astakos-app/astakos/im/api.py
snf-astakos-app/astakos/im/faults.py
snf-astakos-app/astakos/im/fixtures/groups.json
snf-astakos-app/astakos/im/management/commands/_common.py
snf-astakos-app/astakos/im/management/commands/addgroup.py
snf-astakos-app/astakos/im/management/commands/addgrouppermissions.py [new file with mode: 0644]
snf-astakos-app/astakos/im/management/commands/createuser.py
snf-astakos-app/astakos/im/management/commands/listgroups.py
snf-astakos-app/astakos/im/management/commands/listusers.py
snf-astakos-app/astakos/im/management/commands/modifyuser.py
snf-astakos-app/astakos/im/management/commands/removegrouppermissions.py [new file with mode: 0644]
snf-astakos-app/astakos/im/management/commands/showuser.py
snf-astakos-app/astakos/im/urls.py

index d47b8f3..98d2eb9 100644 (file)
@@ -45,13 +45,15 @@ from django.http import HttpResponse
 from django.utils import simplejson as json
 from django.core.urlresolvers import reverse
 
-from astakos.im.faults import BadRequest, Unauthorized, InternalServerError, Fault
+from astakos.im.faults import BadRequest, Unauthorized, InternalServerError, \
+Fault, ItemNotFound, Forbidden
 from astakos.im.models import AstakosUser
 from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED, COOKIE_NAME, \
 EMAILCHANGE_ENABLED
 from astakos.im.util import epoch
 
 logger = logging.getLogger(__name__)
+format = ('%a, %d %b %Y %H:%M:%S GMT')
 
 def render_fault(request, fault):
     if isinstance(fault, InternalServerError) and settings.DEBUG:
@@ -65,8 +67,10 @@ def render_fault(request, fault):
     response['Content-Length'] = len(response.content)
     return response
 
-def api_method(http_method=None, token_required=False, perms=[]):
+def api_method(http_method=None, token_required=False, perms=None):
     """Decorator function for views that implement an API method."""
+    if not perms:
+        perms = []
     
     def decorator(func):
         @wraps(func)
@@ -81,7 +85,7 @@ def api_method(http_method=None, token_required=False, perms=[]):
                     try:
                         user = AstakosUser.objects.get(auth_token=x_auth_token)
                         if not user.has_perms(perms):
-                            raise Unauthorized('Unauthorized request')
+                            raise Forbidden('Unauthorized request')
                     except AstakosUser.DoesNotExist, e:
                         raise Unauthorized('Invalid X-Auth-Token')
                     kwargs['user'] = user
@@ -221,46 +225,68 @@ def get_menu(request, with_extra_links=False, with_signout=True):
 
     return HttpResponse(content=data, mimetype=mimetype)
 
-@api_method(http_method='GET', token_required=True, perms=['astakos.im.can_find_userid'])
-def find_userid(request):
-    # Normal Response Codes: 204
+@api_method(http_method='GET', token_required=True, perms=['im.can_access_userinfo'])
+def get_user_by_email(request, user=None):
+    # Normal Response Codes: 200
     # Error Response Codes: internalServerError (500)
     #                       badRequest (400)
     #                       unauthorised (401)
-    email = request.GET.get('email')
+    #                       forbidden (403)
+    #                       itemNotFound (404)
+    email = request.GET.get('name')
     if not email:
         raise BadRequest('Email missing')
     try:
-        user = AstakosUser.objects.get(email = email, is_active=True)
+        user = AstakosUser.objects.get(email = email)
     except AstakosUser.DoesNotExist, e:
-        raise BadRequest('Invalid email')
+        raise ItemNotFound('Invalid email')
+    
+    if not user.is_active:
+        raise ItemNotFound('Inactive user')
     else:
         response = HttpResponse()
-        response.status=204
-        user_info = {'userid':user.username}
+        response.status=200
+        user_info = {'id':user.id,
+                     'username':user.username,
+                     'email':[user.email],
+                     'enabled':user.is_active,
+                     'name':user.realname,
+                     'auth_token_created':user.auth_token_created.strftime(format),
+                     'auth_token_expires':user.auth_token_expires.strftime(format),
+                     'has_credits':user.has_credits,
+                     'groups':[g.name for g in user.groups.all()],
+                     'user_permissions':[p.codename for p in user.user_permissions.all()],
+                     'group_permissions': list(user.get_group_permissions())}
         response.content = json.dumps(user_info)
         response['Content-Type'] = 'application/json; charset=UTF-8'
         response['Content-Length'] = len(response.content)
         return response
 
-@api_method(http_method='GET', token_required=True, perms=['astakos.im.can_find_email'])
-def find_email(request):
-    # Normal Response Codes: 204
+@api_method(http_method='GET', token_required=True, perms=['can_access_userinfo'])
+def get_user_by_username(request, user_id, user=None):
+    # Normal Response Codes: 200
     # Error Response Codes: internalServerError (500)
     #                       badRequest (400)
     #                       unauthorised (401)
-    userid = request.GET.get('userid')
-    if not userid:
-        raise BadRequest('Userid missing')
+    #                       forbidden (403)
+    #                       itemNotFound (404)
     try:
-        user = AstakosUser.objects.get(username = userid)
+        user = AstakosUser.objects.get(username = user_id)
     except AstakosUser.DoesNotExist, e:
-        raise BadRequest('Invalid userid')
+        raise ItemNotFound('Invalid userid')
     else:
         response = HttpResponse()
-        response.status=204
-        user_info = {'userid':user.email}
+        response.status=200
+        user_info = {'id':user.id,
+                     'username':user.username,
+                     'email':[user.email],
+                     'name':user.realname,
+                     'auth_token_created':user.auth_token_created.strftime(format),
+                     'auth_token_expires':user.auth_token_expires.strftime(format),
+                     'has_credits':user.has_credits,
+                     'enabled':user.is_active,
+                     'groups':[g.name for g in user.groups.all()]}
         response.content = json.dumps(user_info)
         response['Content-Type'] = 'application/json; charset=UTF-8'
         response['Content-Length'] = len(response.content)
-        return response
+        return response
\ No newline at end of file
index e5a5244..72408f1 100644 (file)
@@ -49,3 +49,9 @@ class Unauthorized(Fault):
 
 class InternalServerError(Fault):
     code = 500
+
+class Forbidden(Fault):
+    code = 403
+
+class ItemNotFound(Fault):
+    code = 404
\ No newline at end of file
index 472b56e..4b325cf 100644 (file)
         "fields": {
             "name": "shibboleth"
         }
+    },
+    {
+        "model": "auth.group",
+        "pk": 4,
+        "fields": {
+            "name": "helpdesk"
+        }
     }
 ]
index 73fe569..0771989 100644 (file)
 from datetime import datetime
 
 from django.utils.timesince import timesince, timeuntil
+from django.contrib.auth.models import Permission
+from django.contrib.contenttypes.models import ContentType
 
 from astakos.im.models import AstakosUser
 
+content_type = None
 
 def get_user(email_or_id, **kwargs):
     try:
@@ -59,3 +62,59 @@ def format_date(d):
         return timesince(d) + ' ago'
     else:
         return 'in ' + timeuntil(d)
+
+def get_astakosuser_content_type():
+    if content_type:
+        return content_type
+    
+    try:
+        return ContentType.objects.get(app_label='im',
+                                       model='astakosuser')
+    except:
+        return content_type
+    
+def add_user_permission(user, pname):
+    content_type = get_astakosuser_content_type()
+    if user.has_perm(pname):
+        return 0, None
+    p, created = Permission.objects.get_or_create(codename=pname,
+                                                  name=pname.capitalize(),
+                                                  content_type=content_type)
+    user.user_permissions.add(p)
+    return 1, created
+
+def add_group_permission(group, pname):
+    content_type = get_astakosuser_content_type()
+    if pname in [p.codename for p in group.permissions.all()]:
+        return 0, None
+    content_type = ContentType.objects.get(app_label='im',
+                                           model='astakosuser')
+    p, created = Permission.objects.get_or_create(codename=pname,
+                                                  name=pname.capitalize(),
+                                                  content_type=content_type)
+    group.permissions.add(p)
+    return 1, created
+
+def remove_user_permission(user, pname):
+    content_type = get_astakosuser_content_type()
+    if user.has_perm(pname):
+        return 0
+    try:
+        p = Permission.objects.get(codename=pname,
+                                    content_type=content_type)
+        user.user_permissions.remove(p)
+        return 1
+    except Permission.DoesNotExist, e:
+        return -1
+
+def remove_group_permission(group, pname):
+    content_type = get_astakosuser_content_type()
+    if pname not in [p.codename for p in group.permissions.all()]:
+        return 0
+    try:
+        p = Permission.objects.get(codename=pname,
+                                    content_type=content_type)
+        group.permissions.remove(p)
+        return 1
+    except Permission.DoesNotExist, e:
+        return -1
\ No newline at end of file
index b37f89f..25620da 100644 (file)
@@ -39,15 +39,16 @@ from time import time
 from os.path import abspath
 
 from django.core.management.base import BaseCommand, CommandError
-
 from django.contrib.auth.models import Group
 
+from ._common import add_group_permission
+
 class Command(BaseCommand):
-    args = "<name>"
+    args = "<groupname> [<permission> ...]"
     help = "Insert group"
     
     def handle(self, *args, **options):
-        if len(args) != 1:
+        if len(args) < 1:
             raise CommandError("Invalid number of arguments")
         
         name = args[0].decode('utf8')
@@ -58,6 +59,16 @@ class Command(BaseCommand):
         except Group.DoesNotExist, e:
             group = Group(name=name)
             group.save()
-        
-        msg = "Created group id %d" % (group.id,)
-        self.stdout.write(msg + '\n')
+            msg = "Created group id %d" % (group.id,)
+            self.stdout.write(msg + '\n')
+            try:
+                for pname in args[1:]:
+                    r, created = add_group_permission(group, pname)
+                    if created:
+                        self.stdout.write('Permission: %s created successfully\n' % pname)
+                    if r == 0:
+                        self.stdout.write('Group has already permission: %s\n' % pname)
+                    else:
+                        self.stdout.write('Permission: %s added successfully\n' % pname)
+            except Exception, e:
+                raise CommandError(e)
\ No newline at end of file
diff --git a/snf-astakos-app/astakos/im/management/commands/addgrouppermissions.py b/snf-astakos-app/astakos/im/management/commands/addgrouppermissions.py
new file mode 100644 (file)
index 0000000..6f6b9b9
--- /dev/null
@@ -0,0 +1,73 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+from optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import Group, Permission
+from django.contrib.contenttypes.models import ContentType
+from django.core.exceptions import ValidationError
+
+from astakos.im.models import AstakosUser
+from ._common import add_group_permission
+
+class Command(BaseCommand):
+    args = "<groupname> <permission> [<permissions> ...]"
+    help = "Add group permissions"
+    
+    def handle(self, *args, **options):
+        if len(args) < 2:
+            raise CommandError("Please provide a group name and at least one permission")
+        
+        group = None
+        try:
+            if args[0].isdigit():
+                group = Group.objects.get(id=args[0])
+            else:
+                group = Group.objects.get(name=args[0])
+        except Group.DoesNotExist, e:
+            raise CommandError("Invalid group")
+        
+        try:
+            content_type = ContentType.objects.get(app_label='im',
+                                                       model='astakosuser')
+            for pname in args[1:]:
+                r, created = add_group_permission(group, pname)
+                if created:
+                    self.stdout.write('Permission: %s created successfully\n' % pname)
+                if r == 0:
+                    self.stdout.write('Group has already permission: %s\n' % pname)
+                else:
+                    self.stdout.write('Permission: %s added successfully\n' % pname)
+        except Exception, e:
+            raise CommandError(e)
\ No newline at end of file
index 9c21447..3691f4a 100644 (file)
@@ -41,10 +41,14 @@ from uuid import uuid4
 from django.core.management.base import BaseCommand, CommandError
 from django.core.validators import validate_email
 from django.core.exceptions import ValidationError
+from django.contrib.auth.models import Group, Permission
+from django.contrib.contenttypes.models import ContentType
 
 from astakos.im.models import AstakosUser
 from astakos.im.util import reserved_email
 
+from ._common import add_user_permission
+
 class Command(BaseCommand):
     args = "<email> <first name> <last name> <affiliation>"
     help = "Create a user"
@@ -63,7 +67,13 @@ class Command(BaseCommand):
         make_option('--password',
             dest='password',
             metavar='PASSWORD',
-            help="Set user's password")
+            help="Set user's password"),
+        make_option('--add-group',
+            dest='add-group',
+            help="Add user group"),
+        make_option('--add-permission',
+            dest='add-permission',
+            help="Add user permission")
         )
     
     def handle(self, *args, **options):
@@ -108,3 +118,25 @@ class Command(BaseCommand):
             if options['password'] is None:
                 msg += " with password '%s'" % (password,)
             self.stdout.write(msg + '\n')
+            
+            groupname = options.get('add-group')
+            if groupname is not None:
+                try:
+                    group = Group.objects.get(name=groupname)
+                    user.groups.add(group)
+                    self.stdout.write('Group: %s added successfully\n' % groupname)
+                except Group.DoesNotExist, e:
+                    self.stdout.write('Group named %s does not exist\n' % groupname)
+            
+            pname = options.get('add-permission')
+            if pname is not None:
+                try:
+                    r, created = add_user_permission(user, pname)
+                    if created:
+                        self.stdout.write('Permission: %s created successfully\n' % pname)
+                    if r > 0:
+                        self.stdout.write('Permission: %s added successfully\n' % pname)
+                    elif r==0:
+                        self.stdout.write('User has already permission: %s\n' % pname)
+                except Exception, e:
+                    raise CommandError(e)
\ No newline at end of file
index 9559aaf..9846370 100644 (file)
@@ -58,8 +58,8 @@ class Command(BaseCommand):
         
         groups = Group.objects.all()
         
-        labels = ('id', 'name')
-        columns = (1, 2)
+        labels = ('id', 'name', 'permissions')
+        columns = (3, 12, 50)
         
         if not options['csv']:
             line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
@@ -68,7 +68,8 @@ class Command(BaseCommand):
             self.stdout.write(sep + '\n')
         
         for group in groups:
-            fields = (str(group.id), group.name)
+            fields = (str(group.id), group.name,
+                      ','.join(p.codename for p in group.permissions.all()))
             
             if options['csv']:
                 line = '|'.join(fields)
index 48e78b8..839689c 100644 (file)
@@ -64,8 +64,8 @@ class Command(BaseCommand):
         if options['pending']:
             users = users.filter(is_active=False)
         
-        labels = ('id', 'email', 'real name', 'affiliation', 'active', 'admin', 'provider')
-        columns = (3, 24, 24, 12, 6, 5, 12)
+        labels = ('id', 'email', 'real name', 'active', 'admin', 'provider', 'groups')
+        columns = (3, 24, 24, 6, 5, 12,  24)
         
         if not options['csv']:
             line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
@@ -77,8 +77,8 @@ class Command(BaseCommand):
             id = str(user.id)
             active = format_bool(user.is_active)
             admin = format_bool(user.is_superuser)
-            fields = (id, user.email, user.realname, user.affiliation, active,
-                      admin, user.provider)
+            fields = (id, user.email, user.realname, active, admin, user.provider,
+                      ','.join([g.name for g in user.groups.all()]))
             
             if options['csv']:
                 line = '|'.join(fields)
index d50995e..45a5a8b 100644 (file)
 from optparse import make_option
 
 from django.core.management.base import BaseCommand, CommandError
-from django.contrib.auth.models import Group
+from django.contrib.auth.models import Group, Permission
+from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 
 from astakos.im.models import AstakosUser
+from ._common import remove_user_permission, add_user_permission
 
 class Command(BaseCommand):
     args = "<user ID>"
@@ -87,6 +89,12 @@ class Command(BaseCommand):
         make_option('--delete-group',
             dest='delete-group',
             help="Delete user group"),
+        make_option('--add-permission',
+            dest='add-permission',
+            help="Add user permission"),
+        make_option('--delete-permission',
+            dest='delete-permission',
+            help="Delete user permission"),
         )
     
     def handle(self, *args, **options):
@@ -121,7 +129,7 @@ class Command(BaseCommand):
                 group = Group.objects.get(name=groupname)
                 user.groups.add(group)
             except Group.DoesNotExist, e:
-                raise CommandError("Group named %s does not exist." % groupname)
+                self.stdout.write("Group named %s does not exist\n" % groupname)
         
         groupname = options.get('delete-group')
         if groupname is not None:
@@ -129,7 +137,33 @@ class Command(BaseCommand):
                 group = Group.objects.get(name=groupname)
                 user.groups.remove(group)
             except Group.DoesNotExist, e:
-                raise CommandError("Group named %s does not exist." % groupname)
+                self.stdout.write("Group named %s does not exist\n" % groupname)
+        
+        pname = options.get('add-permission')
+        if pname is not None:
+            try:
+                r, created = add_user_permission(user, pname)
+                if created:
+                    self.stdout.write('Permission: %s created successfully\n' % pname)
+                if r > 0:
+                    self.stdout.write('Permission: %s added successfully\n' % pname)
+                elif r==0:
+                    self.stdout.write('User has already permission: %s\n' % pname)
+            except Exception, e:
+                raise CommandError(e)
+        
+        pname  = options.get('delete-permission')
+        if pname is not None and not user.has_perm(pname):
+            try:
+                r = remove_user_permission(user, pname)
+                if r < 0:
+                    self.stdout.write('Invalid permission codename: %s\n' % pname)
+                elif r == 0:
+                    self.stdout.write('User has not permission: %s\n' % pname)
+                elif r > 0:
+                    self.stdout.write('Permission: %s removed successfully\n' % pname)
+            except Exception, e:
+                raise CommandError(e)
         
         level = options.get('level')
         if level is not None:
diff --git a/snf-astakos-app/astakos/im/management/commands/removegrouppermissions.py b/snf-astakos-app/astakos/im/management/commands/removegrouppermissions.py
new file mode 100644 (file)
index 0000000..5ead6b0
--- /dev/null
@@ -0,0 +1,70 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+from optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import Group
+from django.core.exceptions import ValidationError
+
+from astakos.im.models import AstakosUser
+from ._common import remove_group_permission
+
+class Command(BaseCommand):
+    args = "<groupname> <permission> [<permissions> ...]"
+    help = "Remove group permissions"
+    
+    def handle(self, *args, **options):
+        if len(args) < 2:
+            raise CommandError("Please provide a group name and at least one permission")
+        
+        group = None
+        try:
+            if args[0].isdigit():
+                group = Group.objects.get(id=args[0])
+            else:
+                group = Group.objects.get(name=args[0])
+        except Group.DoesNotExist, e:
+            raise CommandError("Invalid group")
+        
+        try:
+            for pname in args[1:]:
+                r = remove_group_permission(group, pname)
+                if r < 0:
+                    self.stdout.write('Invalid permission codename: %s\n' % pname)
+                elif r == 0:
+                    self.stdout.write('Group has not permission: %s\n' % pname)
+                elif r > 0:
+                    self.stdout.write('Permission: %s removed successfully\n' % pname)
+        except Exception, e:
+            raise CommandError(e)
\ No newline at end of file
index d149a76..1609687 100644 (file)
@@ -67,7 +67,7 @@ class Command(BaseCommand):
                 'last login': format_date(user.last_login),
                 'date joined': format_date(user.date_joined),
                 'last update': format_date(user.updated),
-                'token': user.auth_token,
+                #'token': user.auth_token,
                 'token expiration': format_date(user.auth_token_expires),
                 'invitations': user.invitations,
                 'invitation level': user.level,
@@ -75,8 +75,11 @@ class Command(BaseCommand):
                 'verified': format_bool(user.is_verified),
                 'has_credits': format_bool(user.has_credits),
                 'groups': [elem.name for elem in user.groups.all()],
+                'permissions': [elem.codename for elem in user.user_permissions.all()],
+                'group_permissions': user.get_group_permissions(),
                 'third_party_identifier': user.third_party_identifier,
-                'email_verified': format_bool(user.email_verified)
+                'email_verified': format_bool(user.email_verified),
+                'username': user.username
             }
             if get_latest_terms():
                 has_signed_terms = user.signed_terms()
index 5317574..1b76b58 100644 (file)
@@ -98,6 +98,6 @@ urlpatterns += patterns('astakos.im.api',
     url(r'^authenticate/v2/?$', 'authenticate'),
     url(r'^get_services/?$', 'get_services'),
     url(r'^get_menu/?$', 'get_menu'),
-    url(r'^find_userid/?$', 'find_userid'),
-    url(r'^find_email/?$', 'find_email'),
+    url(r'^v2.0/users/?$', 'get_user_by_email'),
+    url(r'^v2.0/users/(?P<user_id>.+?)/?$', 'get_user_by_username'),
 )