From e85d9ca8d0508895fe69bc1204daec859cf14fd1 Mon Sep 17 00:00:00 2001 From: Kurt Grandis Date: Fri, 25 Mar 2016 09:36:55 -0400 Subject: [PATCH] First pass at making codebase PEP8 compliant. Mostly non-aggressive autopeping, linebreak fixes, and some minor delambdafication --- adl_lrs/forms.py | 24 +- adl_lrs/management/commands/clear_models.py | 89 +- adl_lrs/settings.py | 66 +- adl_lrs/urls.py | 62 +- adl_lrs/views.py | 82 +- fabfile.py | 31 +- lrs/__init__.py | 2 +- lrs/admin.py | 2 +- lrs/celery.py | 4 +- lrs/exceptions.py | 10 + lrs/managers/ActivityManager.py | 32 +- lrs/managers/ActivityProfileManager.py | 56 +- lrs/managers/ActivityStateManager.py | 30 +- lrs/managers/AgentProfileManager.py | 34 +- lrs/managers/StatementManager.py | 42 +- lrs/models.py | 127 +- lrs/tasks.py | 84 +- lrs/tests/ActivityManagerTests.py | 749 ++++--- lrs/tests/ActivityProfileTests.py | 236 +-- lrs/tests/ActivityStateTests.py | 174 +- lrs/tests/ActivityTests.py | 273 +-- lrs/tests/AgentManagerTests.py | 146 +- lrs/tests/AgentProfileTests.py | 117 +- lrs/tests/AgentTests.py | 30 +- lrs/tests/AttachmentAndSignedTests.py | 911 ++++---- lrs/tests/AuthTests.py | 895 ++++---- lrs/tests/OAuth2Tests.py | 221 +- lrs/tests/OAuthTests.py | 1416 ++++++------- lrs/tests/StatementFilterTests.py | 2003 +++++++++--------- lrs/tests/StatementManagerTests.py | 569 +++-- lrs/tests/StatementMoreTests.py | 550 +++-- lrs/tests/StatementTests.py | 1297 ++++++------ lrs/urls.py | 24 +- lrs/utils/StatementValidator.py | 1354 ++++++------ lrs/utils/XAPIVersionHeaderMiddleware.py | 3 +- lrs/utils/__init__.py | 21 +- lrs/utils/authorization.py | 134 +- lrs/utils/etag.py | 13 +- lrs/utils/jws.py | 39 +- lrs/utils/profile_decorator.py | 4 +- lrs/utils/req_parse.py | 58 +- lrs/utils/req_process.py | 100 +- lrs/utils/req_validate.py | 161 +- lrs/utils/retrieve_statement.py | 95 +- lrs/views.py | 155 +- oauth2_provider/provider/__init__.py | 1 - oauth2_provider/provider/compat/urls.py | 2 +- oauth2_provider/provider/forms.py | 1 + oauth2_provider/provider/oauth2/__init__.py | 2 +- oauth2_provider/provider/oauth2/backends.py | 5 +- oauth2_provider/provider/oauth2/forms.py | 21 +- oauth2_provider/provider/oauth2/managers.py | 1 + oauth2_provider/provider/oauth2/models.py | 9 +- oauth2_provider/provider/oauth2/tests.py | 23 +- oauth2_provider/provider/oauth2/urls.py | 26 +- oauth2_provider/provider/oauth2/views.py | 3 + oauth2_provider/provider/scope.py | 2 +- oauth2_provider/provider/sphinx.py | 2 + oauth2_provider/provider/tests/test_utils.py | 5 +- oauth2_provider/provider/utils.py | 3 +- oauth2_provider/provider/views.py | 37 +- oauth_provider/__init__.py | 1 - oauth_provider/admin.py | 2 +- oauth_provider/backends.py | 2 +- oauth_provider/compat.py | 6 +- oauth_provider/consts.py | 8 +- oauth_provider/decorators.py | 15 +- oauth_provider/forms.py | 26 +- oauth_provider/managers.py | 11 +- oauth_provider/models.py | 33 +- oauth_provider/runtests/manage.py | 5 +- oauth_provider/runtests/runtests.py | 1 + oauth_provider/runtests/settings.py | 4 +- oauth_provider/runtests/test_app/__init__.py | 2 +- oauth_provider/runtests/test_app/models.py | 1 + oauth_provider/runtests/urls.py | 11 +- oauth_provider/store/__init__.py | 3 +- oauth_provider/store/db.py | 2 + oauth_provider/tests/__init__.py | 2 +- oauth_provider/tests/auth.py | 20 +- oauth_provider/tests/compat.py | 3 +- oauth_provider/tests/decorators.py | 29 +- oauth_provider/tests/issues.py | 64 +- oauth_provider/tests/models.py | 2 +- oauth_provider/tests/protocol.py | 13 +- oauth_provider/tests/xauth.py | 9 +- oauth_provider/urls.py | 10 +- oauth_provider/utils.py | 42 +- oauth_provider/views.py | 37 +- requirements.txt | 2 +- 90 files changed, 6628 insertions(+), 6406 deletions(-) diff --git a/adl_lrs/forms.py b/adl_lrs/forms.py index 4ccdae7a..5780703f 100644 --- a/adl_lrs/forms.py +++ b/adl_lrs/forms.py @@ -1,16 +1,18 @@ import json from django import forms + class ValidatorForm(forms.Form): - jsondata = forms.CharField(label='Data', required=True, - widget=forms.Textarea(attrs={'cols':100, 'rows':20})) - + jsondata = forms.CharField(label='Data', required=True, + widget=forms.Textarea(attrs={'cols': 100, 'rows': 20})) + + class RegisterForm(forms.Form): username = forms.CharField(max_length=200, label='Name') email = forms.EmailField(max_length=200, label='Email') - password = forms.CharField(label='Password', - widget=forms.PasswordInput(render_value=False)) - password2 = forms.CharField(label='Password Again', + password = forms.CharField(label='Password', + widget=forms.PasswordInput(render_value=False)) + password2 = forms.CharField(label='Password Again', widget=forms.PasswordInput(render_value=False)) def clean(self): @@ -22,13 +24,15 @@ def clean(self): return cleaned raise forms.ValidationError("Passwords did not match") + class RegClientForm(forms.Form): name = forms.CharField(max_length=200, label='Name') - description = forms.CharField(label='Description', required=False, - widget=forms.Textarea(attrs={'cols':50, 'rows':10})) + description = forms.CharField(label='Description', required=False, + widget=forms.Textarea(attrs={'cols': 50, 'rows': 10})) rsa = forms.BooleanField(label='RSA Signature Method', required=False) secret = forms.CharField(max_length=1024, label='Public RSA Key', required=False, - widget=forms.Textarea(attrs={'cols':50, 'rows':10})) + widget=forms.Textarea(attrs={'cols': 50, 'rows': 10})) + class HookRegistrationForm(forms.Form): name = forms.CharField(max_length=50, label='Name', required=True) @@ -44,4 +48,4 @@ def clean(self): json.loads(json_filters) except Exception: raise forms.ValidationError("filters are not valid JSON") - return cleaned \ No newline at end of file + return cleaned diff --git a/adl_lrs/management/commands/clear_models.py b/adl_lrs/management/commands/clear_models.py index 123291cf..d792b3ca 100644 --- a/adl_lrs/management/commands/clear_models.py +++ b/adl_lrs/management/commands/clear_models.py @@ -6,48 +6,49 @@ from django.db.models import get_app, get_models from django.contrib.auth.models import User + class Command(BaseCommand): - help = 'Clears all data in the apps (does not clear users), clears cache and deletes any media files' - option_list = BaseCommand.option_list + ( - make_option( - '--sa', - dest = 'saveagents', - default = False, - help = 'Save the agents associated with the users\' emails', - metavar = 'SA' - ), - ) - - def handle(self, *args, **options): - # To preserve users' agents add -sa True when running command - sa = False - if options['saveagents']: - sa = True - - apps = [] - apps.append(get_app('lrs')) - apps.append(get_app('oauth_provider')) - apps.append(get_app('oauth2')) - - # Clear app(db) data - for app in apps: - for model in get_models(app): - if app.__name__.split('.')[0] == 'lrs' and model.__name__ == "Agent" and sa: - user_emails = ["mailto:" + s for s in User.objects.all().values_list('email', flat=True)] - model.objects.exclude(mbox__in=user_emails).delete() - self.stdout.write("Deleted all %s objects from - %s except for the Agents associated with LRS users\n" % (model.__name__, app.__name__.split('.')[0])) - else: - model.objects.all().delete() - self.stdout.write("Deleted all %s objects from - %s\n" % (model.__name__, app.__name__.split('.')[0])) - - # Clear cache data - cache.clear() - - # Clear media folders - for subdir, dirs, files in os.walk(settings.MEDIA_ROOT): - for dr in dirs: - for sd, ds, fs in os.walk(os.path.join(settings.MEDIA_ROOT, dr)): - for f in fs: - os.remove(os.path.join(sd, f)) - - self.stdout.write("Successfully cleared all data from the apps\n") \ No newline at end of file + help = 'Clears all data in the apps (does not clear users), clears cache and deletes any media files' + option_list = BaseCommand.option_list + ( + make_option( + '--sa', + dest='saveagents', + default=False, + help='Save the agents associated with the users\' emails', + metavar='SA' + ), + ) + + def handle(self, *args, **options): + # To preserve users' agents add -sa True when running command + sa = False + if options['saveagents']: + sa = True + + apps = [] + apps.append(get_app('lrs')) + apps.append(get_app('oauth_provider')) + apps.append(get_app('oauth2')) + + # Clear app(db) data + for app in apps: + for model in get_models(app): + if app.__name__.split('.')[0] == 'lrs' and model.__name__ == "Agent" and sa: + user_emails = ["mailto:" + s for s in User.objects.all().values_list('email', flat=True)] + model.objects.exclude(mbox__in=user_emails).delete() + self.stdout.write("Deleted all %s objects from - %s except for the Agents associated with LRS users\n" % (model.__name__, app.__name__.split('.')[0])) + else: + model.objects.all().delete() + self.stdout.write("Deleted all %s objects from - %s\n" % (model.__name__, app.__name__.split('.')[0])) + + # Clear cache data + cache.clear() + + # Clear media folders + for subdir, dirs, files in os.walk(settings.MEDIA_ROOT): + for dr in dirs: + for sd, ds, fs in os.walk(os.path.join(settings.MEDIA_ROOT, dr)): + for f in fs: + os.remove(os.path.join(sd, f)) + + self.stdout.write("Successfully cleared all data from the apps\n") diff --git a/adl_lrs/settings.py b/adl_lrs/settings.py index 8c7d0698..8de6f9dc 100644 --- a/adl_lrs/settings.py +++ b/adl_lrs/settings.py @@ -23,7 +23,7 @@ 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '', - } + } } # Local time zone for this installation. Choices can be found here: @@ -105,7 +105,7 @@ # OAuth1 callback views OAUTH_AUTHORIZE_VIEW = 'oauth_provider.views.authorize_client' OAUTH_CALLBACK_VIEW = 'oauth_provider.views.callback_view' -OAUTH_SIGNATURE_METHODS = ['plaintext','hmac-sha1','rsa-sha1'] +OAUTH_SIGNATURE_METHODS = ['plaintext', 'hmac-sha1', 'rsa-sha1'] OAUTH_REALM_KEY_NAME = '%s://%s/xAPI' % (SITE_SCHEME, SITE_DOMAIN) # THIS IS OAUTH2 STUFF @@ -120,15 +120,15 @@ # List STATEMENTS_WRITE and STATEMENTS_READ_MINE first so they get defaulted in oauth2/forms.py OAUTH_SCOPES = ( - (STATEMENTS_WRITE,'statements/write'), - (STATEMENTS_READ_MINE,'statements/read/mine'), - (STATEMENTS_READ,'statements/read'), - (STATE,'state'), - (DEFINE,'define'), - (PROFILE,'profile'), - (ALL_READ,'all/read'), - (ALL,'all') - ) + (STATEMENTS_WRITE, 'statements/write'), + (STATEMENTS_READ_MINE, 'statements/read/mine'), + (STATEMENTS_READ, 'statements/read'), + (STATE, 'state'), + (DEFINE, 'define'), + (PROFILE, 'profile'), + (ALL_READ, 'all/read'), + (ALL, 'all') +) SESSION_KEY = 'oauth2' @@ -149,10 +149,10 @@ 'LOCATION': 'cache_statement_list', 'TIMEOUT': 86400, }, - 'attachment_cache':{ - 'BACKEND':'django.core.cache.backends.db.DatabaseCache', - 'LOCATION':'attachment_cache', - 'TIMEOUT': 86400, + 'attachment_cache': { + 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', + 'LOCATION': 'attachment_cache', + 'TIMEOUT': 86400, }, } @@ -256,7 +256,7 @@ REQUEST_HANDLER_LOG_DIR = path.join(PROJECT_ROOT, 'logs/django_request.log') DEFAULT_LOG_DIR = path.join(PROJECT_ROOT, 'logs/lrs.log') -CELERY_TASKS_LOG_DIR = path.join(PROJECT_ROOT, 'logs/celery_tasks.log') +CELERY_TASKS_LOG_DIR = path.join(PROJECT_ROOT, 'logs/celery_tasks.log') CELERYD_HIJACK_ROOT_LOGGER = False @@ -280,29 +280,29 @@ }, 'handlers': { 'default': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': DEFAULT_LOG_DIR, - 'maxBytes': 1024*1024*5, # 5 MB + 'maxBytes': 1024 * 1024 * 5, # 5 MB 'backupCount': 5, - 'formatter':'standard', - }, + 'formatter': 'standard', + }, 'request_handler': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', - 'filename': REQUEST_HANDLER_LOG_DIR, - 'maxBytes': 1024*1024*5, # 5 MB - 'backupCount': 5, - 'formatter':'standard', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': REQUEST_HANDLER_LOG_DIR, + 'maxBytes': 1024 * 1024 * 5, # 5 MB + 'backupCount': 5, + 'formatter': 'standard', }, 'celery_handler': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': CELERY_TASKS_LOG_DIR, - 'maxBytes': 1024*1024*5, # 5 MB + 'maxBytes': 1024 * 1024 * 5, # 5 MB 'backupCount': 5, - 'formatter':'standard', - }, + 'formatter': 'standard', + }, }, 'loggers': { 'lrs': { @@ -319,6 +319,6 @@ 'handlers': ['celery_handler'], 'level': 'DEBUG', 'propagate': True - }, + }, } } diff --git a/adl_lrs/urls.py b/adl_lrs/urls.py index af43ce9a..93bd86d8 100644 --- a/adl_lrs/urls.py +++ b/adl_lrs/urls.py @@ -6,41 +6,41 @@ admin.autodiscover() urlpatterns = patterns('adl_lrs.views', - # for anyone trying to hit the xapi endpoints - url(r'^XAPI/', include('lrs.urls')), - url(r'^xapi/', include('lrs.urls')), - url(r'^xAPI/', include('lrs.urls')), + # for anyone trying to hit the xapi endpoints + url(r'^XAPI/', include('lrs.urls')), + url(r'^xapi/', include('lrs.urls')), + url(r'^xAPI/', include('lrs.urls')), - # start of non xapi endpoints - # comment the next line to disable the admin: - url(r'^admin/', include(admin.site.urls)), - url(r'^actexample1/$', 'actexample1'), - url(r'^actexample2/$', 'actexample2'), - url(r'^oauth2/', include('oauth2_provider.provider.oauth2.urls', namespace='oauth2')), - url(r'^$', 'home'), - url(r'^register', 'register'), - url(r'^regclient2', 'reg_client2'), - url(r'^regclient', 'reg_client'), - url(r'^me/statements', 'my_statements'), - url(r'^me/download/statements', 'my_download_statements'), - url(r'^me/activities/states', 'my_activity_states'), - url(r'^me/activities/state', 'my_activity_state'), - url(r'^me/apps', 'my_app_status'), - url(r'^me/tokens2', 'delete_token2'), - url(r'^me/tokens', 'delete_token'), - url(r'^me/clients', 'delete_client'), - url(r'^me', 'me'), - url(r'^statementvalidator', 'stmt_validator'), -) + # start of non xapi endpoints + # comment the next line to disable the admin: + url(r'^admin/', include(admin.site.urls)), + url(r'^actexample1/$', 'actexample1'), + url(r'^actexample2/$', 'actexample2'), + url(r'^oauth2/', include('oauth2_provider.provider.oauth2.urls', namespace='oauth2')), + url(r'^$', 'home'), + url(r'^register', 'register'), + url(r'^regclient2', 'reg_client2'), + url(r'^regclient', 'reg_client'), + url(r'^me/statements', 'my_statements'), + url(r'^me/download/statements', 'my_download_statements'), + url(r'^me/activities/states', 'my_activity_states'), + url(r'^me/activities/state', 'my_activity_state'), + url(r'^me/apps', 'my_app_status'), + url(r'^me/tokens2', 'delete_token2'), + url(r'^me/tokens', 'delete_token'), + url(r'^me/clients', 'delete_client'), + url(r'^me', 'me'), + url(r'^statementvalidator', 'stmt_validator'), + ) # Login and logout patterns urlpatterns += patterns('', - url(r'^accounts/login/$', 'django.contrib.auth.views.login', name="login"), - url(r'^accounts/logout/$', 'adl_lrs.views.logout_view', name="logout"), -) + url(r'^accounts/login/$', 'django.contrib.auth.views.login', name="login"), + url(r'^accounts/logout/$', 'adl_lrs.views.logout_view', name="logout"), + ) # Allows admins to view attachments in admin console if settings.DEBUG: - urlpatterns += patterns('adl_lrs.views', - url(r'^media/attachment_payloads/(?P.*)$', 'admin_attachments'), - ) \ No newline at end of file + urlpatterns += patterns('adl_lrs.views', + url(r'^media/attachment_payloads/(?P.*)$', 'admin_attachments'), + ) diff --git a/adl_lrs/views.py b/adl_lrs/views.py index 7abdc208..c4cd6c89 100644 --- a/adl_lrs/views.py +++ b/adl_lrs/views.py @@ -25,6 +25,7 @@ from oauth2_provider.provider.oauth2.forms import ClientForm from oauth2_provider.provider.oauth2.models import Client, AccessToken + @csrf_protect @require_http_methods(["GET"]) def home(request): @@ -37,7 +38,8 @@ def home(request): stats['activitycnt'] = Activity.objects.filter().count() form = RegisterForm() - return render_to_response('home.html', {'stats':stats, "form": form}, context_instance=context) + return render_to_response('home.html', {'stats': stats, "form": form}, context_instance=context) + @csrf_protect @require_http_methods(["POST", "GET"]) @@ -56,22 +58,27 @@ def stmt_validator(request): valid = validator.validate() except ParamError, e: clean_data = form.cleaned_data['jsondata'] - return render_to_response('validator.html', {"form": form, "error_message": e.message, "clean_data":clean_data}, - context_instance=context) + return render_to_response('validator.html', {"form": form, "error_message": e.message, "clean_data": clean_data}, + context_instance=context) else: clean_data = json.dumps(validator.data, indent=4, sort_keys=True) - return render_to_response('validator.html', {"form": form,"valid_message": valid, "clean_data":clean_data}, - context_instance=context) + return render_to_response('validator.html', {"form": form, "valid_message": valid, "clean_data": clean_data}, + context_instance=context) return render_to_response('validator.html', {"form": form}, context_instance=context) # Hosted example activites for the tests + + @require_http_methods(["GET"]) def actexample1(request): return render_to_response('actexample1.json', mimetype="application/json") + + @require_http_methods(["GET"]) def actexample2(request): return render_to_response('actexample2.json', mimetype="application/json") + @csrf_protect @require_http_methods(["POST", "GET"]) def register(request): @@ -85,7 +92,7 @@ def register(request): name = form.cleaned_data['username'] pword = form.cleaned_data['password'] email = form.cleaned_data['email'] - + # If username doesn't already exist if not User.objects.filter(username__exact=name).count(): # if email doesn't already exist @@ -93,11 +100,11 @@ def register(request): User.objects.create_user(name, email, pword) else: return render_to_response('register.html', {"form": form, "error_message": "Email %s is already registered." % email}, - context_instance=context) + context_instance=context) else: return render_to_response('register.html', {"form": form, "error_message": "User %s already exists." % name}, - context_instance=context) - + context_instance=context) + # If a user is already logged in, log them out if request.user.is_authenticated(): logout(request) @@ -108,6 +115,7 @@ def register(request): else: return render_to_response('register.html', {"form": form}, context_instance=context) + @login_required() @require_http_methods(["GET"]) def admin_attachments(request, path): @@ -129,6 +137,7 @@ def admin_attachments(request, path): response['Content-Disposition'] = 'attachment; filename="%s"' % path return response + @transaction.commit_on_success @login_required() @require_http_methods(["POST", "GET"]) @@ -148,16 +157,17 @@ def reg_client(request): client = Consumer.objects.get(name__exact=name) except Consumer.DoesNotExist: client = Consumer.objects.create(name=name, description=description, user=request.user, - status=ACCEPTED, secret=secret, rsa_signature=rsa_signature) + status=ACCEPTED, secret=secret, rsa_signature=rsa_signature) else: - return render_to_response('regclient.html', {"form": form, "error_message": "Client %s already exists." % name}, context_instance=RequestContext(request)) - + return render_to_response('regclient.html', {"form": form, "error_message": "Client %s already exists." % name}, context_instance=RequestContext(request)) + client.generate_random_codes() - d = {"name":client.name,"app_id":client.key, "secret":client.secret, "rsa":client.rsa_signature, "info_message": "Your Client Credentials"} + d = {"name": client.name, "app_id": client.key, "secret": client.secret, "rsa": client.rsa_signature, "info_message": "Your Client Credentials"} return render_to_response('reg_success.html', d, context_instance=RequestContext(request)) else: return render_to_response('regclient.html', {"form": form}, context_instance=RequestContext(request)) + @transaction.commit_on_success @login_required() @require_http_methods(["POST", "GET"]) @@ -167,23 +177,25 @@ def reg_client2(request): return render_to_response('regclient2.html', {"form": form}, context_instance=RequestContext(request)) elif request.method == 'POST': form = ClientForm(request.POST) - if form.is_valid(): + if form.is_valid(): client = form.save(commit=False) client.user = request.user client.save() - d = {"name":client.name,"app_id":client.client_id, "secret":client.client_secret, "info_message": "Your Client Credentials"} + d = {"name": client.name, "app_id": client.client_id, "secret": client.client_secret, "info_message": "Your Client Credentials"} return render_to_response('reg_success.html', d, context_instance=RequestContext(request)) else: return render_to_response('regclient2.html', {"form": form}, context_instance=RequestContext(request)) + @login_required() @require_http_methods(["GET"]) def my_statements(request, template="my_statements.html", page_template="my_statements_holder.html"): - context = {'statements': Statement.objects.filter(user=request.user).order_by('-timestamp'),'page_template': page_template} + context = {'statements': Statement.objects.filter(user=request.user).order_by('-timestamp'), 'page_template': page_template} if request.is_ajax(): template = page_template return render_to_response(template, context, context_instance=RequestContext(request)) + @login_required() @require_http_methods(["GET"]) def my_activity_states(request, template="my_activity_states.html", page_template="my_activity_states_holder.html"): @@ -195,11 +207,12 @@ def my_activity_states(request, template="my_activity_states.html", page_templat return HttpResponseBadRequest("More than one agent returned with email") context = {'activity_states': ActivityState.objects.filter(agent=ag).order_by('-updated', 'activity_id'), 'page_template': page_template} - + if request.is_ajax(): template = page_template return render_to_response(template, context, context_instance=RequestContext(request)) + @login_required() @require_http_methods(["GET"]) def my_activity_state(request): @@ -223,6 +236,7 @@ def my_activity_state(request): return HttpResponse(state.json_state, content_type=state.content_type, status=200) return HttpResponseBadRequest("Activity ID, State ID and are both required") + @transaction.commit_on_success @login_required() @require_http_methods(["GET"]) @@ -237,13 +251,14 @@ def me(request, template='me.html'): access_token_scopes.append((token, scopes)) context_dict = { - 'client_apps':client_apps, - 'access_tokens':access_tokens, - 'client_apps2': client_apps2, - 'access_tokens2':access_token_scopes - } + 'client_apps': client_apps, + 'access_tokens': access_tokens, + 'client_apps2': client_apps2, + 'access_tokens2': access_token_scopes + } return render_to_response(template, context_dict, context_instance=RequestContext(request)) + @login_required() @require_http_methods(["GET", "HEAD"]) def my_download_statements(request): @@ -254,6 +269,7 @@ def my_download_statements(request): response['Content-Length'] = len(result) return response + @transaction.commit_on_success @login_required() @require_http_methods(["GET", "POST"]) @@ -261,14 +277,15 @@ def my_app_status(request): try: name = request.GET['app_name'] status = request.GET['status'] - new_status = [s[0] for s in CONSUMER_STATES if s[1] == status][0] #should only be 1 + new_status = [s[0] for s in CONSUMER_STATES if s[1] == status][0] # should only be 1 client = Consumer.objects.get(name__exact=name, user=request.user) client.status = new_status client.save() - ret = {"app_name":client.name, "status":client.get_status_display()} + ret = {"app_name": client.name, "status": client.get_status_display()} return HttpResponse(json.dumps(ret), mimetype="application/json", status=200) except: - return HttpResponse(json.dumps({"error_message":"unable to fulfill request"}), mimetype="application/json", status=400) + return HttpResponse(json.dumps({"error_message": "unable to fulfill request"}), mimetype="application/json", status=400) + @transaction.commit_on_success @login_required() @@ -280,17 +297,18 @@ def delete_token(request): consumer_id = ids[1] ts = ids[2] token = Token.objects.get(user=request.user, - key__startswith=token_key, - consumer__id=consumer_id, - timestamp=ts, - token_type=Token.ACCESS, - is_approved=True) + key__startswith=token_key, + consumer__id=consumer_id, + timestamp=ts, + token_type=Token.ACCESS, + is_approved=True) token.is_approved = False token.save() return HttpResponse("", status=204) except: return HttpResponse("Unknown token", status=400) + @transaction.commit_on_success @login_required() @require_http_methods(["DELETE"]) @@ -306,13 +324,14 @@ def delete_token2(request): return HttpResponse(e.message, status=400) return HttpResponse("", status=204) + @transaction.commit_on_success @login_required() @require_http_methods(["DELETE"]) def delete_client(request): try: client_id = request.GET['id'] - client = Client.objects.get(user=request.user,client_id=client_id) + client = Client.objects.get(user=request.user, client_id=client_id) except: return HttpResponse("Unknown client", status=400) try: @@ -321,6 +340,7 @@ def delete_client(request): return HttpResponse(e.message, status=400) return HttpResponse("", status=204) + @login_required() @require_http_methods(["GET"]) def logout_view(request): diff --git a/fabfile.py b/fabfile.py index dc1fdbe7..22a80338 100644 --- a/fabfile.py +++ b/fabfile.py @@ -3,6 +3,7 @@ import linecache from fabric.api import local + def setup_env(): INSTALL_STEPS = ['virtualenv ../env;. ../env/bin/activate;pip install -r requirements.txt;deactivate'] for step in INSTALL_STEPS: @@ -17,10 +18,10 @@ def setup_env(): if not line_140 or line_140 == '\n': with open('../env/local/lib/python2.7/site-packages/django/utils/translation/trans_real.py', 'r') as f: data = f.readlines() - + data[139] = " if res is None:\n" data[140] = " return gettext_module.NullTranslations()\n" - + with open('../env/local/lib/python2.7/site-packages/django/utils/translation/trans_real.py', 'w') as f: data = f.writelines(data) @@ -31,15 +32,15 @@ def setup_lrs(): activity_profile = 'activity_profile' activity_state = 'activity_state' statement_attachments = 'attachment_payloads' - + # Add env packages and project to the path cwd = os.path.dirname(os.path.abspath(__file__)) - - if not cwd in sys.path: + + if cwd not in sys.path: sys.path.append(cwd) - + env_dir = os.path.join(cwd, '../env/lib/python2.7/site-packages') - if not env_dir in sys.path: + if env_dir not in sys.path: sys.path.append(env_dir) log_dir = os.path.join(cwd, '../logs') @@ -68,17 +69,17 @@ def setup_lrs(): adldir = settings.MEDIA_ROOT # Create media directories - if not os.path.exists(os.path.join(adldir,activity_profile)): - os.makedirs(os.path.join(adldir,activity_profile)) + if not os.path.exists(os.path.join(adldir, activity_profile)): + os.makedirs(os.path.join(adldir, activity_profile)) - if not os.path.exists(os.path.join(adldir,activity_state)): - os.makedirs(os.path.join(adldir,activity_state)) + if not os.path.exists(os.path.join(adldir, activity_state)): + os.makedirs(os.path.join(adldir, activity_state)) - if not os.path.exists(os.path.join(adldir,agent_profile)): - os.makedirs(os.path.join(adldir,agent_profile)) + if not os.path.exists(os.path.join(adldir, agent_profile)): + os.makedirs(os.path.join(adldir, agent_profile)) - if not os.path.exists(os.path.join(adldir,statement_attachments)): - os.makedirs(os.path.join(adldir,statement_attachments)) + if not os.path.exists(os.path.join(adldir, statement_attachments)): + os.makedirs(os.path.join(adldir, statement_attachments)) # Create cache tables and sync the db local('./manage.py createcachetable cache_statement_list') diff --git a/lrs/__init__.py b/lrs/__init__.py index 46faaf48..b64e43e8 100644 --- a/lrs/__init__.py +++ b/lrs/__init__.py @@ -2,4 +2,4 @@ # This will make sure the app is always imported when # Django starts so that shared_task will use this app. -from .celery import app as celery_app \ No newline at end of file +from .celery import app as celery_app diff --git a/lrs/admin.py b/lrs/admin.py index 0da9b35c..528b7ce7 100644 --- a/lrs/admin.py +++ b/lrs/admin.py @@ -1,3 +1,3 @@ from .utils import autoregister # Registers all models in lrs for admin -autoregister('lrs') \ No newline at end of file +autoregister('lrs') diff --git a/lrs/celery.py b/lrs/celery.py index 7f52af1c..cc81d0d4 100644 --- a/lrs/celery.py +++ b/lrs/celery.py @@ -10,8 +10,8 @@ from django.conf import settings app = Celery('lrs', - broker='amqp://:@localhost:5672/', - include=['lrs.tasks']) + broker='amqp://:@localhost:5672/', + include=['lrs.tasks']) # Using a string here means the worker will not have to # pickle the object when using Windows. diff --git a/lrs/exceptions.py b/lrs/exceptions.py index 2db5c1b8..4945a57d 100644 --- a/lrs/exceptions.py +++ b/lrs/exceptions.py @@ -1,32 +1,42 @@ class BadRequest(Exception): pass + class ParamError(BadRequest): pass + class Unauthorized(Exception): pass + class Forbidden(Exception): pass + class NotFound(Exception): pass + class IDNotFoundError(NotFound): pass + class Conflict(Exception): pass + class ParamConflict(Conflict): pass + class PreconditionFail(Exception): pass + class OauthUnauthorized(Exception): pass + class OauthBadRequest(BadRequest): pass diff --git a/lrs/managers/ActivityManager.py b/lrs/managers/ActivityManager.py index ac2779ad..fecbbfac 100644 --- a/lrs/managers/ActivityManager.py +++ b/lrs/managers/ActivityManager.py @@ -2,7 +2,9 @@ from ..models import Activity + class ActivityManager(): + def __init__(self, data, auth=None, define=True): self.auth = auth self.define_permission = define @@ -18,23 +20,23 @@ def create_activity_definition(self, act_def): self.Activity.activity_definition_extensions = act_def.get('extensions', {}) self.Activity.activity_definition_interactionType = interactionType - #Multiple choice and sequencing must have choices - if (interactionType == 'choice' or \ - interactionType == 'sequencing') and \ - ('choices' in act_def): + # Multiple choice and sequencing must have choices + if (interactionType == 'choice' or + interactionType == 'sequencing') and \ + ('choices' in act_def): self.Activity.activity_definition_choices = act_def['choices'] - #Matching must have both source and target + # Matching must have both source and target elif (interactionType == 'matching') and \ - ('source' in act_def and 'target' in act_def): - self.Activity.activity_definition_sources = act_def['source'] + ('source' in act_def and 'target' in act_def): + self.Activity.activity_definition_sources = act_def['source'] self.Activity.activity_definition_targets = act_def['target'] - #Performance must have steps + # Performance must have steps elif (interactionType == 'performance') and \ - ('steps' in act_def): + ('steps' in act_def): self.Activity.activity_definition_steps = act_def['steps'] - #Likert must have scale + # Likert must have scale elif (interactionType == 'likert') and \ - ('scale' in act_def): + ('scale' in act_def): self.Activity.activity_definition_scales = act_def['scale'] self.Activity.save() @@ -43,7 +45,7 @@ def update_activity_definition(self, act_def): if self.Activity.activity_definition_name: self.Activity.activity_definition_name = dict(self.Activity.activity_definition_name.items() + act_def['name'].items()) else: - self.Activity.activity_definition_name = act_def['name'] + self.Activity.activity_definition_name = act_def['name'] if 'description' in act_def: if self.Activity.activity_definition_description: @@ -63,7 +65,7 @@ def populate(self, the_object): can_define = True # If activity DNE and can define - create activity with auth try: - self.Activity, act_created = Activity.objects.get_or_create(activity_id=activity_id, authority=self.auth) + self.Activity, act_created = Activity.objects.get_or_create(activity_id=activity_id, authority=self.auth) except IntegrityError: self.Activity = Activity.objects.get(activity_id=activity_id, authority=self.auth) act_created = False @@ -82,7 +84,7 @@ def populate(self, the_object): if self.define_permission: # Act exists but it was created by someone who didn't have define permissions so it's up for grabs # for first user with define permission or... - # Act exists - if it has same auth set it, else do nothing + # Act exists - if it has same auth set it, else do nothing if (not act.authority) or \ (act.authority == self.auth) or \ (act.authority.objectType == 'Group' and self.auth in act.authority.member.all()) or \ @@ -100,4 +102,4 @@ def populate(self, the_object): self.update_activity_definition(activity_definition) # If there is an incoming definition for an activity and the activity didn't exist yet and the user can update create the definition elif activity_definition and can_define and act_created: - self.create_activity_definition(activity_definition) \ No newline at end of file + self.create_activity_definition(activity_definition) diff --git a/lrs/managers/ActivityProfileManager.py b/lrs/managers/ActivityProfileManager.py index 8186b32f..9e4eae77 100644 --- a/lrs/managers/ActivityProfileManager.py +++ b/lrs/managers/ActivityProfileManager.py @@ -9,30 +9,32 @@ from ..exceptions import IDNotFoundError, ParamError from ..utils import etag + class ActivityProfileManager(): + def save_non_json_profile(self, p, created, profile, request_dict): - #Save profile content type based on incoming content type header and create etag + # Save profile content type based on incoming content type header and create etag p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(profile.read()) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: p.updated = datetime.datetime.utcnow().replace(tzinfo=utc) - #Go to beginning of file + # Go to beginning of file profile.seek(0) - #Set filename with the activityID and profileID and save - fn = "%s_%s" % (p.activityId,request_dict.get('filename', p.id)) + # Set filename with the activityID and profileID and save + fn = "%s_%s" % (p.activityId, request_dict.get('filename', p.id)) p.profile.save(fn, profile) - + p.save() def post_profile(self, request_dict): # get/create profile - p, created = ActivityProfile.objects.get_or_create(activityId=request_dict['params']['activityId'], profileId=request_dict['params']['profileId']) - + p, created = ActivityProfile.objects.get_or_create(activityId=request_dict['params']['activityId'], profileId=request_dict['params']['profileId']) + if "application/json" not in request_dict['headers']['CONTENT_TYPE']: try: post_profile = ContentFile(request_dict['profile'].read()) @@ -40,7 +42,7 @@ def post_profile(self, request_dict): try: post_profile = ContentFile(request_dict['profile']) except: - post_profile = ContentFile(str(request_dict['profile'])) + post_profile = ContentFile(str(request_dict['profile'])) self.save_non_json_profile(p, created, post_profile, request_dict) else: post_profile = request_dict['profile'] @@ -49,7 +51,7 @@ def post_profile(self, request_dict): p.json_profile = post_profile p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(post_profile) - # If incoming profile is application/json and if a profile already existed with the same activityId and profileId + # If incoming profile is application/json and if a profile already existed with the same activityId and profileId else: orig_prof = json.loads(p.json_profile) post_profile = json.loads(request_dict['profile']) @@ -60,8 +62,8 @@ def post_profile(self, request_dict): merged = json.dumps(dict(orig_prof.items() + post_profile.items())) p.json_profile = merged p.etag = etag.create_tag(merged) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: @@ -69,9 +71,9 @@ def post_profile(self, request_dict): p.save() def put_profile(self, request_dict): - #Get the profile, or if not already created, create one - p,created = ActivityProfile.objects.get_or_create(profileId=request_dict['params']['profileId'],activityId=request_dict['params']['activityId']) - + # Get the profile, or if not already created, create one + p, created = ActivityProfile.objects.get_or_create(profileId=request_dict['params']['profileId'], activityId=request_dict['params']['activityId']) + # Profile being PUT is not json if "application/json" not in request_dict['headers']['CONTENT_TYPE']: try: @@ -84,15 +86,15 @@ def put_profile(self, request_dict): # If a profile already existed with the profileId and activityId if not created: - #If it already exists delete it - etag.check_preconditions(request_dict,p, required=True) + # If it already exists delete it + etag.check_preconditions(request_dict, p, required=True) if p.profile: try: p.profile.delete() except OSError: # probably was json before p.json_profile = {} - + self.save_non_json_profile(p, created, profile, request_dict) # Profile being PUT is json else: @@ -103,8 +105,8 @@ def put_profile(self, request_dict): p.json_profile = the_profile p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(the_profile) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: @@ -112,7 +114,7 @@ def put_profile(self, request_dict): p.save() def get_profile(self, profileId, activityId): - #Retrieve the profile with the given profileId and activity + # Retrieve the profile with the given profileId and activity try: return ActivityProfile.objects.get(profileId=profileId, activityId=activityId) except ActivityProfile.DoesNotExist: @@ -122,26 +124,26 @@ def get_profile(self, profileId, activityId): def get_profile_ids(self, activityId, since=None): ids = [] - #If there is a since param return all profileIds since then + # If there is a since param return all profileIds since then if since: try: # this expects iso6801 date/time format "2013-02-15T12:00:00+00:00" profs = ActivityProfile.objects.filter(updated__gte=since, activityId=activityId) except ValidationError: err_msg = 'Since field is not in correct format for retrieval of activity profile IDs' - raise ParamError(err_msg) + raise ParamError(err_msg) ids = [p.profileId for p in profs] else: - #Return all IDs of profiles associated with this activity b/c there is no since param + # Return all IDs of profiles associated with this activity b/c there is no since param ids = ActivityProfile.objects.filter(activityId=activityId).values_list('profileId', flat=True) return ids def delete_profile(self, request_dict): - #Get profile and delete it + # Get profile and delete it try: self.get_profile(request_dict['params']['profileId'], request_dict['params']['activityId']).delete() # we don't want it anyway except ActivityProfile.DoesNotExist: pass except IDNotFoundError: - pass \ No newline at end of file + pass diff --git a/lrs/managers/ActivityStateManager.py b/lrs/managers/ActivityStateManager.py index 859f05c6..5f62fc06 100644 --- a/lrs/managers/ActivityStateManager.py +++ b/lrs/managers/ActivityStateManager.py @@ -8,7 +8,9 @@ from ..exceptions import IDNotFoundError, ParamError from ..utils import etag + class ActivityStateManager(): + def __init__(self, agent): self.Agent = agent @@ -20,7 +22,7 @@ def save_non_json_state(self, s, state, request_dict): s.updated = request_dict['headers']['updated'] else: s.updated = datetime.datetime.utcnow().replace(tzinfo=utc) - + # Go to beginning of file state.seek(0) fn = "%s_%s_%s" % (s.agent_id, s.activity_id, request_dict.get('filename', s.id)) @@ -49,11 +51,11 @@ def post_state(self, request_dict): registration = request_dict['params'].get('registration', None) if registration: s, created = ActivityState.objects.get_or_create(state_id=request_dict['params']['stateId'], agent=self.Agent, - activity_id=request_dict['params']['activityId'], registration_id=request_dict['params']['registration']) + activity_id=request_dict['params']['activityId'], registration_id=request_dict['params']['registration']) else: s, created = ActivityState.objects.get_or_create(state_id=request_dict['params']['stateId'], agent=self.Agent, - activity_id=request_dict['params']['activityId']) - + activity_id=request_dict['params']['activityId']) + if "application/json" not in request_dict['headers']['CONTENT_TYPE']: try: post_state = ContentFile(request_dict['state'].read()) @@ -80,23 +82,23 @@ def post_state(self, request_dict): merged = json.dumps(dict(orig_state.items() + post_state.items())) s.json_state = merged s.etag = etag.create_tag(merged) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: s.updated = request_dict['headers']['updated'] else: s.updated = datetime.datetime.utcnow().replace(tzinfo=utc) s.save() - + def put_state(self, request_dict): registration = request_dict['params'].get('registration', None) if registration: s, created = ActivityState.objects.get_or_create(state_id=request_dict['params']['stateId'], agent=self.Agent, - activity_id=request_dict['params']['activityId'], registration_id=request_dict['params']['registration']) + activity_id=request_dict['params']['activityId'], registration_id=request_dict['params']['registration']) else: s, created = ActivityState.objects.get_or_create(state_id=request_dict['params']['stateId'], agent=self.Agent, - activity_id=request_dict['params']['activityId']) - + activity_id=request_dict['params']['activityId']) + if "application/json" not in request_dict['headers']['CONTENT_TYPE']: try: post_state = ContentFile(request_dict['state'].read()) @@ -105,7 +107,7 @@ def put_state(self, request_dict): post_state = ContentFile(request_dict['state']) except: post_state = ContentFile(str(request_dict['state'])) - + # If a state already existed with the profileId and activityId if not created: etag.check_preconditions(request_dict, s) @@ -125,7 +127,7 @@ def put_state(self, request_dict): s.content_type = request_dict['headers']['CONTENT_TYPE'] s.etag = etag.create_tag(the_state) - #Set updated + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: s.updated = request_dict['headers']['updated'] else: @@ -157,11 +159,11 @@ def delete_state(self, request_dict): if not state_id: states = self.get_state_set(activity_id, registration, None) for s in states: - s.delete() # bulk delete skips the custom delete function + s.delete() # bulk delete skips the custom delete function # Single delete else: self.get_state(activity_id, registration, state_id).delete() except ActivityState.DoesNotExist: pass except IDNotFoundError: - pass \ No newline at end of file + pass diff --git a/lrs/managers/AgentProfileManager.py b/lrs/managers/AgentProfileManager.py index 41a296b0..93867dba 100644 --- a/lrs/managers/AgentProfileManager.py +++ b/lrs/managers/AgentProfileManager.py @@ -9,14 +9,16 @@ from ..exceptions import IDNotFoundError, ParamError from ..utils import etag + class AgentProfileManager(): + def __init__(self, agent): - self.Agent = agent + self.Agent = agent def save_non_json_profile(self, p, profile, request_dict): p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(profile.read()) - + if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: @@ -26,10 +28,10 @@ def save_non_json_profile(self, p, profile, request_dict): fn = "%s_%s" % (p.agent_id, request_dict.get('filename', p.id)) p.profile.save(fn, profile) p.save() - + def post_profile(self, request_dict): # get/create profile - p, created = AgentProfile.objects.get_or_create(profileId=request_dict['params']['profileId'],agent=self.Agent) + p, created = AgentProfile.objects.get_or_create(profileId=request_dict['params']['profileId'], agent=self.Agent) if "application/json" not in request_dict['headers']['CONTENT_TYPE']: try: post_profile = ContentFile(request_dict['profile'].read()) @@ -37,7 +39,7 @@ def post_profile(self, request_dict): try: post_profile = ContentFile(request_dict['profile']) except: - post_profile = ContentFile(str(request_dict['profile'])) + post_profile = ContentFile(str(request_dict['profile'])) self.save_non_json_profile(p, post_profile, request_dict) else: post_profile = request_dict['profile'] @@ -46,7 +48,7 @@ def post_profile(self, request_dict): p.json_profile = post_profile p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(post_profile) - # If incoming profile is application/json and if a profile already existed with the same agent and profileId + # If incoming profile is application/json and if a profile already existed with the same agent and profileId else: orig_prof = json.loads(p.json_profile) post_profile = json.loads(post_profile) @@ -57,8 +59,8 @@ def post_profile(self, request_dict): merged = json.dumps(dict(orig_prof.items() + post_profile.items())) p.json_profile = merged p.etag = etag.create_tag(merged) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: @@ -67,7 +69,7 @@ def post_profile(self, request_dict): def put_profile(self, request_dict): # get/create profile - p, created = AgentProfile.objects.get_or_create(profileId=request_dict['params']['profileId'],agent=self.Agent) + p, created = AgentProfile.objects.get_or_create(profileId=request_dict['params']['profileId'], agent=self.Agent) # Profile being PUT is not json if "application/json" not in request_dict['headers']['CONTENT_TYPE']: @@ -81,7 +83,7 @@ def put_profile(self, request_dict): # If a profile already existed with the profileId and activityId if not created: - #If it already exists delete it + # If it already exists delete it etag.check_preconditions(request_dict, p, required=True) if p.profile: try: @@ -99,14 +101,14 @@ def put_profile(self, request_dict): p.json_profile = the_profile p.content_type = request_dict['headers']['CONTENT_TYPE'] p.etag = etag.create_tag(the_profile) - - #Set updated + + # Set updated if 'updated' in request_dict['headers'] and request_dict['headers']['updated']: p.updated = request_dict['headers']['updated'] else: p.updated = datetime.datetime.utcnow().replace(tzinfo=utc) p.save() - + def get_profile(self, profile_id): try: return self.Agent.agentprofile_set.get(profileId=profile_id) @@ -122,7 +124,7 @@ def get_profile_ids(self, since=None): profs = self.Agent.agentprofile_set.filter(updated__gt=since) except ValidationError: err_msg = 'Since field is not in correct format for retrieval of agent profiles' - raise ParamError(err_msg) + raise ParamError(err_msg) ids = [p.profileId for p in profs] else: ids = self.Agent.agentprofile_set.values_list('profileId', flat=True) @@ -133,6 +135,6 @@ def delete_profile(self, profileId): self.get_profile(profileId).delete() # we don't want it anyway except AgentProfile.DoesNotExist: - pass + pass except IDNotFoundError: - pass \ No newline at end of file + pass diff --git a/lrs/managers/StatementManager.py b/lrs/managers/StatementManager.py index 8f0108cb..d32dbaa5 100644 --- a/lrs/managers/StatementManager.py +++ b/lrs/managers/StatementManager.py @@ -2,11 +2,13 @@ from django.core.cache import get_cache from .ActivityManager import ActivityManager -from ..models import Verb, Statement, StatementAttachment, SubStatement, Agent +from ..models import Verb, Statement, StatementAttachment, SubStatement, Agent att_cache = get_cache('attachment_cache') + class StatementManager(): + def __init__(self, stmt_data, auth_info, payload_sha2s): # auth_info contains define, endpoint, user, and request authority if self.__class__.__name__ == 'StatementManager': @@ -33,7 +35,7 @@ def set_authority(self, auth_info, stmt_data): def build_context_activities(self, stmt, auth_info, con_act_data): for con_act_group in con_act_data.items(): - # Incoming contextActivities can either be a list or dict + # Incoming contextActivities can either be a list or dict if isinstance(con_act_group[1], list): for con_act in con_act_group[1]: act = ActivityManager(con_act, auth=auth_info['agent'], define=auth_info['define']).Activity @@ -45,7 +47,7 @@ def build_context_activities(self, stmt, auth_info, con_act_data): stmt.context_ca_category.add(act) else: stmt.context_ca_other.add(act) - else: + else: act = ActivityManager(con_act_group[1], auth=auth_info['agent'], define=auth_info['define']).Activity if con_act_group[0] == 'parent': stmt.context_ca_parent.add(act) @@ -59,17 +61,17 @@ def build_context_activities(self, stmt, auth_info, con_act_data): def build_substatement(self, auth_info, stmt_data): # Pop off any context activities - con_act_data = stmt_data.pop('context_contextActivities',{}) + con_act_data = stmt_data.pop('context_contextActivities', {}) # Delete objectType since it is not a field in the model del stmt_data['objectType'] - sub = SubStatement.objects.create(**stmt_data) + sub = SubStatement.objects.create(**stmt_data) if con_act_data: self.build_context_activities(sub, auth_info, con_act_data) return sub def build_statement(self, auth_info, stmt_data): # Pop off any context activities - con_act_data = stmt_data.pop('context_contextActivities',{}) + con_act_data = stmt_data.pop('context_contextActivities', {}) stmt_data['user'] = auth_info['user'] # Name of id field in models is statement_id if 'id' in stmt_data: @@ -84,10 +86,10 @@ def build_statement(self, auth_info, stmt_data): def build_result(self, stmt_data): if 'result' in stmt_data: result = stmt_data['result'] - for k,v in result.iteritems(): + for k, v in result.iteritems(): stmt_data['result_' + k] = v if 'result_score' in stmt_data: - for k,v in stmt_data['result_score'].iteritems(): + for k, v in stmt_data['result_score'].iteritems(): stmt_data['result_score_' + k] = v del stmt_data['result']['score'] del stmt_data['result_score'] @@ -116,7 +118,7 @@ def build_attachments(self, user_info, attachment_data, payload_sha2s): def build_context(self, stmt_data): if 'context' in stmt_data: context = stmt_data['context'] - for k,v in context.iteritems(): + for k, v in context.iteritems(): stmt_data['context_' + k] = v if 'context_instructor' in stmt_data: stmt_data['context_instructor'] = Agent.objects.retrieve_or_create(**stmt_data['context_instructor'])[0] @@ -125,7 +127,7 @@ def build_context(self, stmt_data): if 'context_statement' in stmt_data: stmt_data['context_statement'] = stmt_data['context_statement']['id'] del stmt_data['context'] - + def build_verb(self, stmt_data): incoming_verb = stmt_data['verb'] verb_id = incoming_verb['id'] @@ -134,7 +136,7 @@ def build_verb(self, stmt_data): # If existing, get existing keys existing_lang_maps = {} if not created and verb_object.display: - existing_lang_maps = verb_object.display + existing_lang_maps = verb_object.display # Save verb displays if 'display' in incoming_verb: @@ -144,12 +146,12 @@ def build_verb(self, stmt_data): def build_statement_object(self, auth_info, stmt_data): statement_object_data = stmt_data['object'] - valid_agent_objects = ['Agent', 'Group'] + valid_agent_objects = ['Agent', 'Group'] # If not specified, the object is assumed to be an activity - if not 'objectType' in statement_object_data or statement_object_data['objectType'] == 'Activity': + if 'objectType' not in statement_object_data or statement_object_data['objectType'] == 'Activity': statement_object_data['objectType'] = 'Activity' stmt_data['object_activity'] = ActivityManager(statement_object_data, auth=auth_info['agent'], - define=auth_info['define']).Activity + define=auth_info['define']).Activity elif statement_object_data['objectType'] in valid_agent_objects: stmt_data['object_agent'] = Agent.objects.retrieve_or_create(**statement_object_data)[0] elif statement_object_data['objectType'] == 'SubStatement': @@ -161,22 +163,24 @@ def build_statement_object(self, auth_info, stmt_data): def populate(self, auth_info, stmt_data, payload_sha2s): if self.__class__.__name__ == 'StatementManager': stmt_data['voided'] = False - + self.build_verb(stmt_data) self.build_statement_object(auth_info, stmt_data) stmt_data['actor'] = Agent.objects.retrieve_or_create(**stmt_data['actor'])[0] self.build_context(stmt_data) self.build_result(stmt_data) attachment_data = stmt_data.pop('attachments', None) - + if self.__class__.__name__ == 'StatementManager': - #Save statement/substatement + # Save statement/substatement self.model_object = self.build_statement(auth_info, stmt_data) else: self.model_object = self.build_substatement(auth_info, stmt_data) if attachment_data: self.build_attachments(auth_info, attachment_data, payload_sha2s) + class SubStatementManager(StatementManager): - def __init__(self, substmt_data, auth_info): - StatementManager.__init__(self, substmt_data, auth_info, None) \ No newline at end of file + + def __init__(self, substmt_data, auth_info): + StatementManager.__init__(self, substmt_data, auth_info, None) diff --git a/lrs/models.py b/lrs/models.py index 17b50524..e11e8e54 100644 --- a/lrs/models.py +++ b/lrs/models.py @@ -18,6 +18,7 @@ ACTIVITY_PROFILE_UPLOAD_TO = "activity_profile" STATEMENT_ATTACHMENT_UPLOAD_TO = "attachment_payloads" + class Verb(models.Model): verb_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True, unique=True) display = JSONField(default={}, blank=True) @@ -35,7 +36,7 @@ def get_display(self, lang=None): return self.verb_id if lang: return self.display[lang] - try: + try: return self.display['en-US'] except: try: @@ -47,10 +48,12 @@ def get_display(self, lang=None): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class AgentManager(models.Manager): + def retrieve(self, **kwargs): agent_ifps_can_only_be_one = ['mbox', 'mbox_sha1sum', 'account', 'openid'] - ifp_sent = [a for a in agent_ifps_can_only_be_one if kwargs.get(a, None) != None] + ifp_sent = [a for a in agent_ifps_can_only_be_one if kwargs.get(a, None) is not None] if ifp_sent: # Get IFP ifp = ifp_sent[0] @@ -74,7 +77,7 @@ def retrieve(self, **kwargs): def retrieve_or_create(self, **kwargs): agent_ifps_can_only_be_one = ['mbox', 'mbox_sha1sum', 'account', 'openid'] - ifp_sent = [a for a in agent_ifps_can_only_be_one if kwargs.get(a, None) != None] + ifp_sent = [a for a in agent_ifps_can_only_be_one if kwargs.get(a, None) is not None] is_group = kwargs.get('objectType', None) == "Group" has_member = False # Set member if incoming group @@ -110,7 +113,7 @@ def retrieve_or_create(self, **kwargs): except IntegrityError, ValidationError: # Try getting agent by IFP in ifp_dict agent = Agent.objects.filter(**ifp_dict)[0] - created = False + created = False # For identified groups with members if is_group and has_member: @@ -164,7 +167,7 @@ def retrieve_or_create_anonymous_group(self, member, kwargs): # If it is a newly created anonymous group, add the members if created: members = [self.retrieve_or_create(**a) for a in member] - agent.member.add(*(a for a, c in members)) + agent.member.add(*(a for a, c in members)) return agent, created def oauth_group(self, **kwargs): @@ -173,6 +176,8 @@ def oauth_group(self, **kwargs): return g, False except Agent.DoesNotExist: return Agent.objects.retrieve_or_create(**kwargs) + + class Agent(models.Model): objectType = models.CharField(max_length=6, blank=True, default="Agent") name = models.CharField(max_length=100, blank=True) @@ -204,7 +209,7 @@ def to_dict(self, format='exact'): ret['objectType'] = self.objectType # show members for groups if format isn't 'ids' # show members' ids for anon groups if format is 'ids' - if not format == 'ids' or not (set(['mbox','mbox_sha1sum','openid','account']) & set(ret.keys())): + if not format == 'ids' or not (set(['mbox', 'mbox_sha1sum', 'openid', 'account']) & set(ret.keys())): ret['member'] = [a.to_dict(format) for a in self.member.all()] if self.objectType and not format == 'ids': ret['objectType'] = self.objectType @@ -259,9 +264,10 @@ def get_user_from_oauth_group(self): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class Activity(models.Model): activity_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True, unique=True) - objectType = models.CharField(max_length=8,blank=True, default="Activity") + objectType = models.CharField(max_length=8, blank=True, default="Activity") activity_definition_name = JSONField(default={}, blank=True) activity_definition_description = JSONField(default={}, blank=True) activity_definition_type = models.CharField(max_length=MAX_URL_LENGTH, blank=True) @@ -289,7 +295,7 @@ def add_interaction_type(self, i_type, ret, lang): interactions = self.activity_definition_targets for i in interactions: i['description'] = get_lang(i['description'], lang) - ret['definition'][i_type].append(i) + ret['definition'][i_type].append(i) def to_dict(self, lang=None, format='exact'): ret = OrderedDict() @@ -337,11 +343,12 @@ def get_a_name(self): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class SubStatement(models.Model): object_agent = models.ForeignKey(Agent, related_name="object_of_substatement", on_delete=models.SET_NULL, null=True, db_index=True) object_activity = models.ForeignKey(Activity, related_name="object_of_substatement", on_delete=models.SET_NULL, null=True, db_index=True) object_statementref = models.CharField(max_length=40, blank=True, null=True) - actor = models.ForeignKey(Agent,related_name="actor_of_substatement", null=True, on_delete=models.SET_NULL) + actor = models.ForeignKey(Agent, related_name="actor_of_substatement", null=True, on_delete=models.SET_NULL) verb = models.ForeignKey(Verb, null=True, on_delete=models.SET_NULL) result_success = models.NullBooleanField() result_completion = models.NullBooleanField() @@ -354,15 +361,15 @@ class SubStatement(models.Model): result_score_max = models.FloatField(blank=True, null=True) result_extensions = JSONField(default={}, blank=True) timestamp = models.DateTimeField(blank=True, null=True, - default=lambda: datetime.utcnow().replace(tzinfo=utc).isoformat()) + default=lambda: datetime.utcnow().replace(tzinfo=utc).isoformat()) context_registration = models.CharField(max_length=40, blank=True, db_index=True) - context_instructor = models.ForeignKey(Agent,blank=True, null=True, on_delete=models.SET_NULL, - db_index=True, related_name='substatement_context_instructor') - context_team = models.ForeignKey(Agent,blank=True, null=True, on_delete=models.SET_NULL, - related_name="substatement_context_team") + context_instructor = models.ForeignKey(Agent, blank=True, null=True, on_delete=models.SET_NULL, + db_index=True, related_name='substatement_context_instructor') + context_team = models.ForeignKey(Agent, blank=True, null=True, on_delete=models.SET_NULL, + related_name="substatement_context_team") context_revision = models.TextField(blank=True) - context_platform = models.CharField(max_length=50,blank=True) - context_language = models.CharField(max_length=50,blank=True) + context_platform = models.CharField(max_length=50, blank=True) + context_language = models.CharField(max_length=50, blank=True) context_extensions = JSONField(default={}, blank=True) context_ca_parent = models.ManyToManyField(Activity, related_name="sub_context_ca_parent") context_ca_grouping = models.ManyToManyField(Activity, related_name="sub_context_ca_grouping") @@ -370,37 +377,37 @@ class SubStatement(models.Model): context_ca_other = models.ManyToManyField(Activity, related_name="sub_context_ca_other") # context also has a stmt field which is a statementref context_statement = models.CharField(max_length=40, blank=True) - + def to_dict(self, lang=None, format='exact'): ret = OrderedDict() ret['actor'] = self.actor.to_dict(format) ret['verb'] = self.verb.to_dict() - + if self.object_agent: ret['object'] = self.object_agent.to_dict(format) elif self.object_activity: ret['object'] = self.object_activity.to_dict(lang, format) else: ret['object'] = {'id': self.object_statementref, 'objectType': 'StatementRef'} - + ret['result'] = OrderedDict() - if self.result_success != None: + if self.result_success is not None: ret['result']['success'] = self.result_success - if self.result_completion != None: + if self.result_completion is not None: ret['result']['completion'] = self.result_completion if self.result_response: ret['result']['response'] = self.result_response if self.result_duration: ret['result']['duration'] = self.result_duration - + ret['result']['score'] = OrderedDict() - if not self.result_score_scaled is None: + if self.result_score_scaled is not None: ret['result']['score']['scaled'] = self.result_score_scaled - if not self.result_score_raw is None: + if self.result_score_raw is not None: ret['result']['score']['raw'] = self.result_score_raw - if not self.result_score_min is None: + if self.result_score_min is not None: ret['result']['score']['min'] = self.result_score_min - if not self.result_score_max is None: + if self.result_score_max is not None: ret['result']['score']['max'] = self.result_score_max # If there is no score, delete from dict if not ret['result']['score']: @@ -467,15 +474,16 @@ def get_object(self): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class Statement(models.Model): # If no statement_id is given, will create one automatically statement_id = UUIDField(version=1, db_index=True, unique=True) object_agent = models.ForeignKey(Agent, related_name="object_of_statement", null=True, on_delete=models.SET_NULL, db_index=True) object_activity = models.ForeignKey(Activity, related_name="object_of_statement", null=True, on_delete=models.SET_NULL, db_index=True) object_substatement = models.ForeignKey(SubStatement, related_name="object_of_statement", null=True, on_delete=models.SET_NULL) - object_statementref = models.CharField(max_length=40, blank=True, null=True, db_index=True) - actor = models.ForeignKey(Agent,related_name="actor_statement", db_index=True, null=True, - on_delete=models.SET_NULL) + object_statementref = models.CharField(max_length=40, blank=True, null=True, db_index=True) + actor = models.ForeignKey(Agent, related_name="actor_statement", db_index=True, null=True, + on_delete=models.SET_NULL) verb = models.ForeignKey(Verb, null=True, on_delete=models.SET_NULL) result_success = models.NullBooleanField() result_completion = models.NullBooleanField() @@ -490,17 +498,17 @@ class Statement(models.Model): # If no stored or timestamp given - will create automatically (only happens if using StatementManager directly) stored = models.DateTimeField(default=datetime.utcnow().replace(tzinfo=utc).isoformat(), db_index=True) timestamp = models.DateTimeField(default=datetime.utcnow().replace(tzinfo=utc).isoformat(), db_index=True) - authority = models.ForeignKey(Agent, blank=True,null=True,related_name="authority_statement", db_index=True, - on_delete=models.SET_NULL) + authority = models.ForeignKey(Agent, blank=True, null=True, related_name="authority_statement", db_index=True, + on_delete=models.SET_NULL) voided = models.NullBooleanField(default=False) context_registration = models.CharField(max_length=40, blank=True, db_index=True) - context_instructor = models.ForeignKey(Agent,blank=True, null=True, on_delete=models.SET_NULL, - db_index=True, related_name='statement_context_instructor') - context_team = models.ForeignKey(Agent,blank=True, null=True, on_delete=models.SET_NULL, - related_name="statement_context_team") + context_instructor = models.ForeignKey(Agent, blank=True, null=True, on_delete=models.SET_NULL, + db_index=True, related_name='statement_context_instructor') + context_team = models.ForeignKey(Agent, blank=True, null=True, on_delete=models.SET_NULL, + related_name="statement_context_team") context_revision = models.TextField(blank=True) - context_platform = models.CharField(max_length=50,blank=True) - context_language = models.CharField(max_length=50,blank=True) + context_platform = models.CharField(max_length=50, blank=True) + context_language = models.CharField(max_length=50, blank=True) context_extensions = JSONField(default={}, blank=True) context_ca_parent = models.ManyToManyField(Activity, related_name="stmt_context_ca_parent") context_ca_grouping = models.ManyToManyField(Activity, related_name="stmt_context_ca_grouping") @@ -512,7 +520,7 @@ class Statement(models.Model): # Used in views user = models.ForeignKey(User, null=True, blank=True, db_index=True, on_delete=models.SET_NULL) full_statement = JSONField() - + def to_dict(self, lang=None, format='exact'): ret = OrderedDict() if format == 'exact': @@ -527,7 +535,7 @@ def to_dict(self, lang=None, format='exact'): ret['timestamp'] = self.full_statement['timestamp'] ret['stored'] = self.full_statement['stored'] if 'authority' in self.full_statement: - ret['authority'] = self.full_statement['authority'] + ret['authority'] = self.full_statement['authority'] ret['version'] = self.full_statement['version'] if 'attachments' in self.full_statement: ret['attachments'] = self.full_statement['attachments'] @@ -537,7 +545,7 @@ def to_dict(self, lang=None, format='exact'): ret['verb'] = self.verb.to_dict() if self.object_agent: - ret['object'] = self.object_agent.to_dict(format) + ret['object'] = self.object_agent.to_dict(format) elif self.object_activity: ret['object'] = self.object_activity.to_dict(lang, format) elif self.object_substatement: @@ -546,9 +554,9 @@ def to_dict(self, lang=None, format='exact'): ret['object'] = {'id': self.object_statementref, 'objectType': 'StatementRef'} ret['result'] = OrderedDict() - if self.result_success != None: + if self.result_success is not None: ret['result']['success'] = self.result_success - if self.result_completion != None: + if self.result_completion is not None: ret['result']['completion'] = self.result_completion if self.result_response: ret['result']['response'] = self.result_response @@ -556,13 +564,13 @@ def to_dict(self, lang=None, format='exact'): ret['result']['duration'] = self.result_duration ret['result']['score'] = OrderedDict() - if not self.result_score_scaled is None: + if self.result_score_scaled is not None: ret['result']['score']['scaled'] = self.result_score_scaled - if not self.result_score_raw is None: + if self.result_score_raw is not None: ret['result']['score']['raw'] = self.result_score_raw - if not self.result_score_min is None: + if self.result_score_min is not None: ret['result']['score']['min'] = self.result_score_min - if not self.result_score_max is None: + if self.result_score_max is not None: ret['result']['score']['max'] = self.result_score_max # If there is no score, delete from dict if not ret['result']['score']: @@ -587,7 +595,7 @@ def to_dict(self, lang=None, format='exact'): ret['context']['language'] = self.context_language if self.context_statement: ret['context']['statement'] = {'id': self.context_statement, 'objectType': 'StatementRef'} - + ret['context']['contextActivities'] = OrderedDict() if self.context_ca_parent.all(): ret['context']['contextActivities']['parent'] = [cap.to_dict(lang, format) for cap in self.context_ca_parent.all()] @@ -606,9 +614,9 @@ def to_dict(self, lang=None, format='exact'): ret['timestamp'] = self.timestamp.isoformat() ret['stored'] = self.stored.isoformat() - if not self.authority is None: + if self.authority is not None: ret['authority'] = self.authority.to_dict(format) - ret['version'] = self.version + ret['version'] = self.version if self.stmt_attachments.all(): ret['attachments'] = [a.to_dict(lang) for a in self.stmt_attachments.all()] return ret @@ -630,7 +638,9 @@ def get_object(self): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class AttachmentFileSystemStorage(FileSystemStorage): + def get_available_name(self, name): return name @@ -639,7 +649,9 @@ def _save(self, name, content): # if the file exists, do not call the superclasses _save method return name # if the file is new, DO call it - return super(AttachmentFileSystemStorage, self)._save(name, content) + return super(AttachmentFileSystemStorage, self)._save(name, content) + + class StatementAttachment(models.Model): usageType = models.CharField(max_length=MAX_URL_LENGTH) contentType = models.CharField(max_length=128) @@ -669,6 +681,7 @@ def to_dict(self, lang=None): def __unicode__(self): return json.dumps(self.to_dict(), sort_keys=False) + class ActivityState(models.Model): state_id = models.CharField(max_length=MAX_URL_LENGTH) updated = models.DateTimeField(auto_now_add=True, blank=True, db_index=True) @@ -677,36 +690,38 @@ class ActivityState(models.Model): agent = models.ForeignKey(Agent) activity_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True) registration_id = models.CharField(max_length=40, db_index=True) - content_type = models.CharField(max_length=255,blank=True) - etag = models.CharField(max_length=50,blank=True) + content_type = models.CharField(max_length=255, blank=True) + etag = models.CharField(max_length=50, blank=True) def delete(self, *args, **kwargs): if self.state: self.state.delete() super(ActivityState, self).delete(*args, **kwargs) + class ActivityProfile(models.Model): profileId = models.CharField(max_length=MAX_URL_LENGTH, db_index=True) updated = models.DateTimeField(auto_now_add=True, blank=True, db_index=True) activityId = models.CharField(max_length=MAX_URL_LENGTH, db_index=True) profile = models.FileField(upload_to=ACTIVITY_PROFILE_UPLOAD_TO, null=True) json_profile = models.TextField(blank=True) - content_type = models.CharField(max_length=255,blank=True) - etag = models.CharField(max_length=50,blank=True) + content_type = models.CharField(max_length=255, blank=True) + etag = models.CharField(max_length=50, blank=True) def delete(self, *args, **kwargs): if self.profile: self.profile.delete() super(ActivityProfile, self).delete(*args, **kwargs) + class AgentProfile(models.Model): profileId = models.CharField(max_length=MAX_URL_LENGTH, db_index=True) updated = models.DateTimeField(auto_now_add=True, blank=True, db_index=True) agent = models.ForeignKey(Agent, db_index=True) profile = models.FileField(upload_to=AGENT_PROFILE_UPLOAD_TO, null=True) json_profile = models.TextField(blank=True) - content_type = models.CharField(max_length=255,blank=True) - etag = models.CharField(max_length=50,blank=True) + content_type = models.CharField(max_length=255, blank=True) + etag = models.CharField(max_length=50, blank=True) def delete(self, *args, **kwargs): if self.profile: diff --git a/lrs/tasks.py b/lrs/tasks.py index 29c0c78d..f0f6710c 100644 --- a/lrs/tasks.py +++ b/lrs/tasks.py @@ -17,21 +17,24 @@ celery_logger = get_task_logger('celery-task') + @shared_task def check_activity_metadata(stmts): from .models import Activity activity_ids = list(Activity.objects.filter(object_of_statement__statement_id__in=stmts).values_list('activity_id', flat=True).distinct()) [get_activity_metadata(a_id) for a_id in activity_ids] + @shared_task @transaction.commit_on_success def void_statements(stmts): - from .models import Statement + from .models import Statement try: Statement.objects.filter(statement_id__in=stmts).update(voided=True) except Exception, e: celery_logger.exception("Voiding Statement Error: " + e.message) + @shared_task def check_statement_hooks(stmt_ids): try: @@ -62,6 +65,7 @@ def check_statement_hooks(stmt_ids): except SoftTimeLimitExceeded: celery_logger.exception("Statement hook task timed out") + def parse_filter(filters, filterQ): from .models import Agent actorQ, verbQ, objectQ, filterQ = Q(), Q(), Q(), Q() @@ -97,6 +101,7 @@ def parse_filter(filters, filterQ): filterQ = filterQ & parse_related_filter(related, True) return filterQ + def parse_related_filter(related, or_operand): from .models import Agent innerQ = Q() @@ -131,47 +136,51 @@ def parse_related_filter(related, or_operand): else: return objectQ & innerQ + def set_object_activity_query(q, act_list, or_operand): if or_operand: - return q | (Q(object_activity__activity_id__in=act_list) \ - | Q(context_ca_parent__activity_id__in=act_list) \ - | Q(context_ca_grouping__activity_id__in=act_list) \ - | Q(context_ca_category__activity_id__in=act_list) \ - | Q(context_ca_other__activity_id__in=act_list) \ - | Q(object_substatement__object_activity__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_parent__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_grouping__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_category__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_other__activity_id__in=act_list)) - - return q & (Q(object_activity__activity_id__in=act_list) \ - | Q(context_ca_parent__activity_id__in=act_list) \ - | Q(context_ca_grouping__activity_id__in=act_list) \ - | Q(context_ca_category__activity_id__in=act_list) \ - | Q(context_ca_other__activity_id__in=act_list) \ - | Q(object_substatement__object_activity__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_parent__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_grouping__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_category__activity_id__in=act_list) \ - | Q(object_substatement__context_ca_other__activity_id__in=act_list)) + return q | (Q(object_activity__activity_id__in=act_list) | + Q(context_ca_parent__activity_id__in=act_list) | + Q(context_ca_grouping__activity_id__in=act_list) | + Q(context_ca_category__activity_id__in=act_list) | + Q(context_ca_other__activity_id__in=act_list) | + Q(object_substatement__object_activity__activity_id__in=act_list) | + Q(object_substatement__context_ca_parent__activity_id__in=act_list) | + Q(object_substatement__context_ca_grouping__activity_id__in=act_list) | + Q(object_substatement__context_ca_category__activity_id__in=act_list) | + Q(object_substatement__context_ca_other__activity_id__in=act_list)) + + return q & (Q(object_activity__activity_id__in=act_list) | + Q(context_ca_parent__activity_id__in=act_list) | + Q(context_ca_grouping__activity_id__in=act_list) | + Q(context_ca_category__activity_id__in=act_list) | + Q(context_ca_other__activity_id__in=act_list) | + Q(object_substatement__object_activity__activity_id__in=act_list) | + Q(object_substatement__context_ca_parent__activity_id__in=act_list) | + Q(object_substatement__context_ca_grouping__activity_id__in=act_list) | + Q(object_substatement__context_ca_category__activity_id__in=act_list) | + Q(object_substatement__context_ca_other__activity_id__in=act_list)) + def set_object_agent_query(q, agent, or_operand): if or_operand: - return q | (Q(actor=agent) | Q(object_agent=agent) | Q(authority=agent) \ - | Q(context_instructor=agent) | Q(context_team=agent) \ - | Q(object_substatement__actor=agent) \ - | Q(object_substatement__object_agent=agent) \ - | Q(object_substatement__context_instructor=agent) \ - | Q(object_substatement__context_team=agent)) - - return q & (Q(actor=agent) | Q(object_agent=agent) | Q(authority=agent) \ - | Q(context_instructor=agent) | Q(context_team=agent) \ - | Q(object_substatement__actor=agent) \ - | Q(object_substatement__object_agent=agent) \ - | Q(object_substatement__context_instructor=agent) \ - | Q(object_substatement__context_team=agent)) + return q | (Q(actor=agent) | Q(object_agent=agent) | Q(authority=agent) | + Q(context_instructor=agent) | Q(context_team=agent) | + Q(object_substatement__actor=agent) | + Q(object_substatement__object_agent=agent) | + Q(object_substatement__context_instructor=agent) | + Q(object_substatement__context_team=agent)) + + return q & (Q(actor=agent) | Q(object_agent=agent) | Q(authority=agent) | + Q(context_instructor=agent) | Q(context_team=agent) | + Q(object_substatement__actor=agent) | + Q(object_substatement__object_agent=agent) | + Q(object_substatement__context_instructor=agent) | + Q(object_substatement__context_team=agent)) # Retrieve JSON data from ID + + def get_activity_metadata(act_id): act_url_data = {} # See if id resolves @@ -205,6 +214,7 @@ def get_activity_metadata(act_id): if valid_url_data: update_activity_definition(fake_activity) + @transaction.commit_on_success def update_activity_definition(act): from .models import Activity @@ -229,8 +239,8 @@ def update_activity_definition(act): activity.activity_definition_extensions = act['definition'].get('extensions', {}) activity.activity_definition_crpanswers = act['definition'].get('correctResponsesPattern', {}) activity.activity_definition_choices = act['definition'].get('choices', {}) - activity.activity_definition_sources = act['definition'].get('source', {}) + activity.activity_definition_sources = act['definition'].get('source', {}) activity.activity_definition_targets = act['definition'].get('target', {}) activity.activity_definition_steps = act['definition'].get('steps', {}) activity.activity_definition_scales = act['definition'].get('scale', {}) - activity.save() \ No newline at end of file + activity.save() diff --git a/lrs/tests/ActivityManagerTests.py b/lrs/tests/ActivityManagerTests.py index d1e845ca..eb2d29c2 100644 --- a/lrs/tests/ActivityManagerTests.py +++ b/lrs/tests/ActivityManagerTests.py @@ -13,35 +13,37 @@ CURRENT_SITE = settings.SITE_SCHEME + '://' + Site.objects.get_current().domain + class ActivityManagerTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ - def setUp(self): + def setUp(self): self.username = "tester1" self.email = "test1@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) - #Called on all activity django models to see if they were created with the correct fields - def do_activity_model(self,realid,act_id, objType): + # Called on all activity django models to see if they were created with the correct fields + def do_activity_model(self, realid, act_id, objType): self.assertEqual(Activity.objects.filter(id=realid)[0].objectType, objType) self.assertEqual(Activity.objects.filter(id=realid)[0].activity_id, act_id) - #Called on all activity django models with definitions to see if they were created with the correct + # Called on all activity django models with definitions to see if they were created with the correct # fields def do_activity_definition_model(self, act, course, intType, moreInfo=""): self.assertEqual(act.activity_definition_type, course) self.assertEqual(act.activity_definition_interactionType, intType) self.assertEqual(act.activity_definition_moreInfo, moreInfo) - # Called on all activity django models with extensions to see if they were created with the correct + # Called on all activity django models with extensions to see if they were created with the correct # fields and values. All extensions are created with the same three values and keys def do_activity_definition_extensions_model(self, act, key1, key2, key3, value1, value2, value3): - #Create list comprehesions to easier assess keys and values + # Create list comprehesions to easier assess keys and values ext_keys = act.activity_definition_extensions.keys() ext_vals = act.activity_definition_extensions.values() @@ -52,77 +54,77 @@ def do_activity_definition_extensions_model(self, act, key1, key2, key3, value1, self.assertIn(value2, ext_vals) self.assertIn(value3, ext_vals) - #Called on all activity django models with a correctResponsePattern because of http://adlnet.gov/expapi/activities/cmi.interaction type - def do_activity_definition_correctResponsePattern_model(self, act, answers): + # Called on all activity django models with a correctResponsePattern because of http://adlnet.gov/expapi/activities/cmi.interaction type + def do_activity_definition_correctResponsePattern_model(self, act, answers): for answer in answers: - self.assertIn(answer,act.activity_definition_crpanswers) + self.assertIn(answer, act.activity_definition_crpanswers) - #Called on all activity django models with choices because of sequence and choice interactionType + # Called on all activity django models with choices because of sequence and choice interactionType def do_activity_definition_choices_model(self, act, clist, dlist): # Grab all lang map IDs in act def choice_ids = [v['id'] for v in act.activity_definition_choices] choice_descs = [v['description'] for v in act.activity_definition_choices] - + for c in clist: - self.assertIn(c,choice_ids) + self.assertIn(c, choice_ids) for d in dlist: self.assertIn(d, choice_descs) - #Called on all activity django models with scale because of likert interactionType + # Called on all activity django models with scale because of likert interactionType def do_activity_definition_likert_model(self, act, clist, dlist): - scale_ids = [v['id'] for v in act.activity_definition_scales] + scale_ids = [v['id'] for v in act.activity_definition_scales] scale_descs = [v['description'] for v in act.activity_definition_scales] for c in clist: - self.assertIn(c,scale_ids) + self.assertIn(c, scale_ids) for d in dlist: self.assertIn(d, scale_descs) - #Called on all activity django models with steps because of performance interactionType + # Called on all activity django models with steps because of performance interactionType def do_activity_definition_performance_model(self, act, slist, dlist): step_ids = [v['id'] for v in act.activity_definition_steps] step_descs = [v['description'] for v in act.activity_definition_steps] for s in slist: - self.assertIn(s,step_ids) + self.assertIn(s, step_ids) for d in dlist: self.assertIn(d, step_descs) - #Called on all activity django models with source and target because of matching interactionType + # Called on all activity django models with source and target because of matching interactionType def do_activity_definition_matching_model(self, act, source_id_list, source_desc_list, - target_id_list, target_desc_list): + target_id_list, target_desc_list): source_ids = [v['id'] for v in act.activity_definition_sources] source_descs = [v['description'] for v in act.activity_definition_sources] - + target_ids = [v['id'] for v in act.activity_definition_targets] target_descs = [v['description'] for v in act.activity_definition_targets] for s_id in source_id_list: - self.assertIn(s_id,source_ids) + self.assertIn(s_id, source_ids) for s_desc in source_desc_list: self.assertIn(s_desc, source_descs) for t_id in target_id_list: - self.assertIn(t_id,target_ids) + self.assertIn(t_id, target_ids) for t_desc in target_desc_list: - self.assertIn(t_desc, target_descs) + self.assertIn(t_desc, target_descs) # Test activity that doesn't have a def (populates everything from JSON) @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') def test_activity_no_def_json_metadata(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': CURRENT_SITE + '/actexample1/'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': CURRENT_SITE + '/actexample1/'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version="1.0.0") - + Authorization=self.auth, X_Experience_API_Version="1.0.0") + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -130,7 +132,7 @@ def test_activity_no_def_json_metadata(self): name_keys = act.activity_definition_name.keys() name_values = act.activity_definition_name.values() desc_keys = act.activity_definition_description.keys() - desc_values = act.activity_definition_description.values() + desc_values = act.activity_definition_description.values() self.assertIn('en-FR', name_keys) self.assertIn('Example Name', name_values) @@ -145,24 +147,24 @@ def test_activity_no_def_json_metadata(self): self.do_activity_model(act.id, CURRENT_SITE + '/actexample1/', 'Activity') @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') # Test that passing in the same info gets the same activity def test_activities_no_defs_json_metadata(self): st_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': CURRENT_SITE + '/actexample1/'}} - - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': CURRENT_SITE + '/actexample1/'}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': CURRENT_SITE + '/actexample1/'}} + + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': CURRENT_SITE + '/actexample1/'}} st_list.append(stmt1) st_list.append(stmt2) response = self.client.post(reverse(statements), json.dumps(st_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version="1.0.0") + Authorization=self.auth, X_Experience_API_Version="1.0.0") self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) @@ -174,15 +176,15 @@ def test_activities_no_defs_json_metadata(self): # Test activity that doesn't have a def with extensions (populates everything from XML) @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') def test_activity_no_def_json_metadata_extensions(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': CURRENT_SITE + '/actexample2/'}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': CURRENT_SITE + '/actexample2/'}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version="1.0.0") - + Authorization=self.auth, X_Experience_API_Version="1.0.0") + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -190,7 +192,7 @@ def test_activity_no_def_json_metadata_extensions(self): name_set = act.activity_definition_name desc_set = act.activity_definition_description - + self.assertEqual(name_set.keys()[0], 'en-US') self.assertEqual(name_set.values()[0], 'Example Name') @@ -198,21 +200,20 @@ def test_activity_no_def_json_metadata_extensions(self): self.assertEqual(desc_set.values()[0], 'Example Desc') self.do_activity_model(act.id, CURRENT_SITE + '/actexample2/', 'Activity') - self.do_activity_definition_extensions_model(act, 'ext:keya', 'ext:keyb', 'ext:keyc','first value', - 'second value', 'third value') - + self.do_activity_definition_extensions_model(act, 'ext:keya', 'ext:keyb', 'ext:keyc', 'first value', + 'second value', 'third value') # Test an activity that has a def, and the provided ID doesn't resolve # (should still use values from JSON) def test_activity_no_resolve(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', - 'id':'act://var/www/adllrs/activity/example.json','definition': {'name': {'en-CH':'testname'}, - 'description': {'en-US':'testdesc'}, 'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[]}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', + 'id': 'act://var/www/adllrs/activity/example.json', 'definition': {'name': {'en-CH': 'testname'}, + 'description': {'en-US': 'testdesc'}, 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': []}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -228,19 +229,19 @@ def test_activity_no_resolve(self): self.assertEqual(desc_set.keys()[0], 'en-US') self.assertEqual(desc_set.values()[0], 'testdesc') - self.do_activity_model(act.id, 'act://var/www/adllrs/activity/example.json', 'Activity') + self.do_activity_model(act.id, 'act://var/www/adllrs/activity/example.json', 'Activity') self.do_activity_definition_model(act, 'type:course', 'other') # Test an activity that has a def and the ID resolves (should use values from payload) def test_activity_id_resolve(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id': CURRENT_SITE + reverse(home), - 'definition': {'name': {'en-GB':'testname'},'description': {'en-GB':'testdesc1'}, - 'type': 'type:link','interactionType': 'other', 'correctResponsesPattern':[]}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': CURRENT_SITE + reverse(home), + 'definition': {'name': {'en-GB': 'testname'}, 'description': {'en-GB': 'testdesc1'}, + 'type': 'type:link', 'interactionType': 'other', 'correctResponsesPattern': []}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -249,14 +250,14 @@ def test_activity_id_resolve(self): name_set = act.activity_definition_name desc_set = act.activity_definition_description - + self.assertEqual(name_set.keys()[0], 'en-GB') self.assertEqual(name_set.values()[0], 'testname') self.assertEqual(desc_set.keys()[0], 'en-GB') self.assertEqual(desc_set.values()[0], 'testdesc1') - self.do_activity_model(act.id, CURRENT_SITE + reverse(home), 'Activity') + self.do_activity_model(act.id, CURRENT_SITE + reverse(home), 'Activity') self.do_activity_definition_model(act, 'type:link', 'other') # Throws exception because incoming data is not JSON @@ -264,35 +265,35 @@ def test_activity_not_json(self): stmt1 = "This string should throw exception since it's not JSON" response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Could not parse request body, no value for: This string should throw exception since it's not JSON") - #Test activity where given URL isn't IRI + # Test activity where given URL isn't IRI def test_activity_invalid_activity_id(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'id': 'foo', - 'objectType':'Activity','definition': {'name': {'en-GB':'testname'}, - 'description': {'en-GB':'testdesc'}, 'type': 'type:link','interactionType': 'other'}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'id': 'foo', + 'objectType': 'Activity', 'definition': {'name': {'en-GB': 'testname'}, + 'description': {'en-GB': 'testdesc'}, 'type': 'type:link', 'interactionType': 'other'}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Activity id with value foo was not a valid IRI') - #Test activity with definition - must retrieve activity object in order to test definition from DB + # Test activity with definition - must retrieve activity object in order to test definition from DB def test_activity_definition(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'id':'act:fooc', - 'definition': {'name': {'en-GB':'testname'},'description': {'en-US':'testdesc'}, - 'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[]}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'id': 'act:fooc', + 'definition': {'name': {'en-GB': 'testname'}, 'description': {'en-US': 'testdesc'}, + 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': []}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -301,28 +302,28 @@ def test_activity_definition(self): name_set = act.activity_definition_name desc_set = act.activity_definition_description - + self.assertEqual(name_set.keys()[0], 'en-GB') self.assertEqual(name_set.values()[0], 'testname') self.assertEqual(desc_set.keys()[0], 'en-US') self.assertEqual(desc_set.values()[0], 'testdesc') - self.do_activity_model(act.id,'act:fooc', 'Activity') + self.do_activity_model(act.id, 'act:fooc', 'Activity') self.do_activity_definition_model(act, 'type:course', 'other') # Test activity with definition that contains extensions - need to retrieve activity and activity definition objects # in order to test extenstions def test_activity_definition_extensions(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:food', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-CH':'testdesc2'}, - 'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[], 'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:food', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-CH': 'testdesc2'}, + 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': [], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -338,22 +339,22 @@ def test_activity_definition_extensions(self): self.assertEqual(desc_set.keys()[0], 'en-CH') self.assertEqual(desc_set.values()[0], 'testdesc2') - self.do_activity_model(act.id,'act:food', 'Activity') - self.do_activity_definition_model(act, 'type:course','other') + self.do_activity_model(act.id, 'act:food', 'Activity') + self.do_activity_definition_model(act, 'type:course', 'other') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') def test_multiple_names_and_descs(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:food', - 'definition': {'name': {'en-FR':'testname2','en-US': 'testnameEN'},'description': {'en-CH':'testdesc2', - 'en-GB': 'testdescGB'},'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[], 'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:food', + 'definition': {'name': {'en-FR': 'testname2', 'en-US': 'testnameEN'}, 'description': {'en-CH': 'testdesc2', + 'en-GB': 'testdescGB'}, 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': [], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -372,42 +373,41 @@ def test_multiple_names_and_descs(self): self.assertEqual(desc_set.keys()[1], 'en-CH') self.assertEqual(desc_set.values()[1], 'testdesc2') - self.do_activity_model(act.id,'act:food', 'Activity') + self.do_activity_model(act.id, 'act:food', 'Activity') self.do_activity_definition_model(act, 'type:course', 'other') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2','value3') - + 'value1', 'value2', 'value3') - #Test activity with definition given wrong interactionType (won't create one) + # Test activity with definition given wrong interactionType (won't create one) def test_activity_definition_wrong_interactionType(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', - 'id':'http://facebook.com','definition': {'name': {'en-US':'testname2'}, - 'description': {'en-GB':'testdesc2'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'intType2', 'correctResponsesPattern': 'response', - 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', + 'id': 'http://facebook.com', 'definition': {'name': {'en-US': 'testname2'}, + 'description': {'en-GB': 'testdesc2'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'intType2', 'correctResponsesPattern': 'response', + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Activity definition interactionType intType2 is not valid') - - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and true-false interactionType + + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and true-false interactionType def test_activity_definition_cmiInteraction_true_false(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fooe', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'true-false', - 'correctResponsesPattern': ['true'] ,'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', - 'ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fooe', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'true-false', + 'correctResponsesPattern': ['true'], 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', + 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -420,34 +420,34 @@ def test_activity_definition_cmiInteraction_true_false(self): self.assertEqual(name_set.values()[0], 'testname2') self.assertEqual(desc_set.keys()[0], 'en-US') - self.assertEqual(desc_set.values()[0], 'testdesc2') + self.assertEqual(desc_set.values()[0], 'testdesc2') - self.do_activity_model(act.id,'act:fooe', 'Activity') + self.do_activity_model(act.id, 'act:fooe', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'true-false') + 'true-false') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1','value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['true']) - - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and multiple choice interactionType - def test_activity_definition_cmiInteraction_multiple_choice(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:foof', - 'definition': {'name': {'en-US':'testname1'},'description': {'en-US':'testdesc1'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'choice', - 'correctResponsesPattern': ['golf', 'tetris'],'choices':[{'id': 'golf', - 'description': {'en-US':'Golf Example', 'en-GB': 'GOLF'}},{'id': 'tetris', - 'description':{'en-US': 'Tetris Example', 'en-GB': 'TETRIS'}}, {'id':'facebook', - 'description':{'en-US':'Facebook App', 'en-GB': 'FACEBOOK'}},{'id':'scrabble', - 'description': {'en-US': 'Scrabble Example', 'en-GB': 'SCRABBLE'}}],'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and multiple choice interactionType + def test_activity_definition_cmiInteraction_multiple_choice(self): + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foof', + 'definition': {'name': {'en-US': 'testname1'}, 'description': {'en-US': 'testdesc1'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'choice', + 'correctResponsesPattern': ['golf', 'tetris'], 'choices': [{'id': 'golf', + 'description': {'en-US': 'Golf Example', 'en-GB': 'GOLF'}}, {'id': 'tetris', + 'description': {'en-US': 'Tetris Example', 'en-GB': 'TETRIS'}}, {'id': 'facebook', + 'description': {'en-US': 'Facebook App', 'en-GB': 'FACEBOOK'}}, {'id': 'scrabble', + 'description': {'en-US': 'Scrabble Example', 'en-GB': 'SCRABBLE'}}], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -462,33 +462,33 @@ def test_activity_definition_cmiInteraction_multiple_choice(self): self.assertEqual(desc_set.keys()[0], 'en-US') self.assertEqual(desc_set.values()[0], 'testdesc1') - self.do_activity_model(act.id,'act:foof', 'Activity') + self.do_activity_model(act.id, 'act:foof', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', 'choice') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['golf', 'tetris']) - - #Check model choice values + + # Check model choice values clist = ['golf', 'tetris', 'facebook', 'scrabble'] dlist = [{'en-GB': 'GOLF', 'en-US': 'Golf Example'}, {'en-GB': 'TETRIS', 'en-US': 'Tetris Example'}, - {'en-GB': 'FACEBOOK', 'en-US': 'Facebook App'}, {'en-GB': 'SCRABBLE', 'en-US': 'Scrabble Example'}] + {'en-GB': 'FACEBOOK', 'en-US': 'Facebook App'}, {'en-GB': 'SCRABBLE', 'en-US': 'Scrabble Example'}] - self.do_activity_definition_choices_model(act, clist, dlist) - - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and multiple choice but missing choices + self.do_activity_definition_choices_model(act, clist, dlist) + + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and multiple choice but missing choices def test_activity_definition_cmiInteraction_multiple_choice_no_choices(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', - 'id':'http://wikipedia.org','definition': {'name': {'en-US':'testname2'}, - 'description': {'en-US':'testdesc2'},'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'choice','correctResponsesPattern': ['golf', 'tetris'], - 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', + 'id': 'http://wikipedia.org', 'definition': {'name': {'en-US': 'testname2'}, + 'description': {'en-US': 'testdesc2'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'choice', 'correctResponsesPattern': ['golf', 'tetris'], + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -504,31 +504,31 @@ def test_activity_definition_cmiInteraction_multiple_choice_no_choices(self): self.assertEqual(desc_set.keys()[0], 'en-US') self.assertEqual(desc_set.values()[0], 'testdesc2') - self.do_activity_model(act.id,'http://wikipedia.org', 'Activity') + self.do_activity_model(act.id, 'http://wikipedia.org', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'choice') + 'choice') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['golf', 'tetris']) self.assertEqual(act.activity_definition_choices, {}) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and fill in interactionType + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and fill in interactionType def test_activity_definition_cmiInteraction_fill_in(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:foog', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'fill-in', - 'correctResponsesPattern': ['Fill in answer'],'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foog', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'fill-in', + 'correctResponsesPattern': ['Fill in answer'], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -543,29 +543,29 @@ def test_activity_definition_cmiInteraction_fill_in(self): self.assertEqual(desc_set.keys()[0], 'en-FR') self.assertEqual(desc_set.values()[0], 'testdesc2') - self.do_activity_model(act.id,'act:foog', 'Activity') + self.do_activity_model(act.id, 'act:foog', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'fill-in') + 'fill-in') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['Fill in answer']) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and long fill in interactionType + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and long fill in interactionType def test_activity_definition_cmiInteraction_long_fill_in(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fooh', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'fill-in', - 'correctResponsesPattern': ['Long fill in answer'],'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fooh', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'fill-in', + 'correctResponsesPattern': ['Long fill in answer'], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -583,28 +583,28 @@ def test_activity_definition_cmiInteraction_long_fill_in(self): self.do_activity_model(act.id, 'act:fooh', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'fill-in') + 'fill-in') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['Long fill in answer']) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and likert interactionType - def test_activity_definition_cmiInteraction_likert(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fooi', - 'definition': {'name': {'en-CH':'testname2'},'description': {'en-CH':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'likert', - 'correctResponsesPattern': ['likert_3'],'scale':[{'id': 'likert_0', - 'description': {'en-US':'Its OK', 'en-GB': 'Tis OK'}},{'id': 'likert_1', - 'description':{'en-US': 'Its Pretty Cool', 'en-GB':'Tis Pretty Cool'}}, {'id':'likert_2', - 'description':{'en-US':'Its Cool Cool', 'en-GB':'Tis Cool Cool'}}, - {'id':'likert_3', 'description': {'en-US': 'Its Gonna Change the World'}}]}}}) + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and likert interactionType + def test_activity_definition_cmiInteraction_likert(self): + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fooi', + 'definition': {'name': {'en-CH': 'testname2'}, 'description': {'en-CH': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'likert', + 'correctResponsesPattern': ['likert_3'], 'scale': [{'id': 'likert_0', + 'description': {'en-US': 'Its OK', 'en-GB': 'Tis OK'}}, {'id': 'likert_1', + 'description': {'en-US': 'Its Pretty Cool', 'en-GB': 'Tis Pretty Cool'}}, {'id': 'likert_2', + 'description': {'en-US': 'Its Cool Cool', 'en-GB': 'Tis Cool Cool'}}, + {'id': 'likert_3', 'description': {'en-US': 'Its Gonna Change the World'}}]}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -623,32 +623,32 @@ def test_activity_definition_cmiInteraction_likert(self): self.do_activity_model(act.id, 'act:fooi', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'likert') + 'likert') self.do_activity_definition_correctResponsePattern_model(act, ['likert_3']) - #Check model choice values + # Check model choice values clist = ['likert_0', 'likert_1', 'likert_2', 'likert_3'] - dlist = [{'en-GB': 'Tis OK', 'en-US': 'Its OK'},{'en-GB': 'Tis Pretty Cool', 'en-US': 'Its Pretty Cool'}, + dlist = [{'en-GB': 'Tis OK', 'en-US': 'Its OK'}, {'en-GB': 'Tis Pretty Cool', 'en-US': 'Its Pretty Cool'}, {'en-GB': 'Tis Cool Cool', 'en-US': 'Its Cool Cool'}, {'en-US': 'Its Gonna Change the World'}] - + self.do_activity_definition_likert_model(act, clist, dlist) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and matching interactionType - def test_activity_definition_cmiInteraction_matching(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fooj', - 'definition': {'name': {'en-CH':'testname2'},'description': {'en-CH':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'matching', - 'correctResponsesPattern': ['lou.3,tom.2,andy.1'],'source':[{'id': 'lou', - 'description': {'en-US':'Lou', 'it': 'Luigi'}},{'id': 'tom','description':{'en-US': 'Tom', 'it':'Tim'}}, - {'id':'andy', 'description':{'en-US':'Andy'}}],'target':[{'id':'1', - 'description':{'en-US': 'SCORM Engine'}},{'id':'2','description':{'en-US': 'Pure-sewage'}}, - {'id':'3', 'description':{'en-US': 'SCORM Cloud', 'en-CH': 'cloud'}}]}}}) + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and matching interactionType + def test_activity_definition_cmiInteraction_matching(self): + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fooj', + 'definition': {'name': {'en-CH': 'testname2'}, 'description': {'en-CH': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'matching', + 'correctResponsesPattern': ['lou.3,tom.2,andy.1'], 'source': [{'id': 'lou', + 'description': {'en-US': 'Lou', 'it': 'Luigi'}}, {'id': 'tom', 'description': {'en-US': 'Tom', 'it': 'Tim'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}], 'target': [{'id': '1', + 'description': {'en-US': 'SCORM Engine'}}, {'id': '2', 'description': {'en-US': 'Pure-sewage'}}, + {'id': '3', 'description': {'en-US': 'SCORM Cloud', 'en-CH': 'cloud'}}]}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -667,34 +667,34 @@ def test_activity_definition_cmiInteraction_matching(self): self.do_activity_model(act.id, 'act:fooj', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'matching') + 'matching') self.do_activity_definition_correctResponsePattern_model(act, ['lou.3,tom.2,andy.1']) - #Check model choice values + # Check model choice values source_id_list = ['lou', 'tom', 'andy'] source_desc_list = [{'en-US': 'Lou', 'it': 'Luigi'}, {'en-US': 'Tom', 'it': 'Tim'}, {'en-US': 'Andy'}] - target_id_list = ['1','2','3'] - target_desc_list = [{"en-US": "SCORM Engine"},{"en-US": "Pure-sewage"}, + target_id_list = ['1', '2', '3'] + target_desc_list = [{"en-US": "SCORM Engine"}, {"en-US": "Pure-sewage"}, {'en-US': 'SCORM Cloud', 'en-CH': 'cloud'}] self.do_activity_definition_matching_model(act, source_id_list, source_desc_list, - target_id_list, target_desc_list) - - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and performance interactionType - def test_activity_definition_cmiInteraction_performance(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fook', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'performance', - 'correctResponsesPattern': ['pong.1,dg.10,lunch.4'],'steps':[{'id': 'pong', - 'description': {'en-US':'Net pong matches won', 'en-GB': 'won'}},{'id': 'dg', - 'description':{'en-US': 'Strokes over par in disc golf at Liberty'}}, - {'id':'lunch', 'description':{'en-US':'Lunch having been eaten'}}]}}}) + target_id_list, target_desc_list) + + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and performance interactionType + def test_activity_definition_cmiInteraction_performance(self): + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fook', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'performance', + 'correctResponsesPattern': ['pong.1,dg.10,lunch.4'], 'steps': [{'id': 'pong', + 'description': {'en-US': 'Net pong matches won', 'en-GB': 'won'}}, {'id': 'dg', + 'description': {'en-US': 'Strokes over par in disc golf at Liberty'}}, + {'id': 'lunch', 'description': {'en-US': 'Lunch having been eaten'}}]}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) @@ -703,42 +703,42 @@ def test_activity_definition_cmiInteraction_performance(self): name_set = act.activity_definition_name desc_set = act.activity_definition_description - + self.assertEqual(name_set.keys()[0], 'en-US') self.assertEqual(name_set.values()[0], 'testname2') self.assertEqual(desc_set.keys()[0], 'en-US') - self.assertEqual(desc_set.values()[0], 'testdesc2') + self.assertEqual(desc_set.values()[0], 'testdesc2') self.do_activity_model(act.id, 'act:fook', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'performance') + 'performance') self.do_activity_definition_correctResponsePattern_model(act, ['pong.1,dg.10,lunch.4']) - #Check model choice values + # Check model choice values slist = ['pong', 'dg', 'lunch'] dlist = [{'en-GB': 'won', 'en-US': 'Net pong matches won'}, {'en-US': 'Strokes over par in disc golf at Liberty'}, - {'en-US': 'Lunch having been eaten'}] - + {'en-US': 'Lunch having been eaten'}] + self.do_activity_definition_performance_model(act, slist, dlist) # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and sequencing interactionType - def test_activity_definition_cmiInteraction_sequencing(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:fool', - 'definition': {'name': {'en-GB':'testname2'},'description': {'en-GB':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'sequencing', - 'correctResponsesPattern': ['lou,tom,andy,aaron'],'choices':[{'id': 'lou', - 'description': {'en-US':'Lou'}},{'id': 'tom','description':{'en-US': 'Tom'}}, - {'id':'andy', 'description':{'en-US':'Andy'}},{'id':'aaron', - 'description':{'en-US':'Aaron', 'en-GB': 'Erin'}}]}}}) + def test_activity_definition_cmiInteraction_sequencing(self): + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:fool', + 'definition': {'name': {'en-GB': 'testname2'}, 'description': {'en-GB': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'sequencing', + 'correctResponsesPattern': ['lou,tom,andy,aaron'], 'choices': [{'id': 'lou', + 'description': {'en-US': 'Lou'}}, {'id': 'tom', 'description': {'en-US': 'Tom'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}, {'id': 'aaron', + 'description': {'en-US': 'Aaron', 'en-GB': 'Erin'}}]}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -758,23 +758,23 @@ def test_activity_definition_cmiInteraction_sequencing(self): self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', 'sequencing') self.do_activity_definition_correctResponsePattern_model(act, ['lou,tom,andy,aaron']) - #Check model choice values + # Check model choice values clist = ['lou', 'tom', 'andy', 'aaron'] - dlist = [{"en-US": "Lou"},{"en-US": "Tom"},{"en-US": "Andy"}, {'en-GB': 'Erin', 'en-US': 'Aaron'}] + dlist = [{"en-US": "Lou"}, {"en-US": "Tom"}, {"en-US": "Andy"}, {'en-GB': 'Erin', 'en-US': 'Aaron'}] self.do_activity_definition_choices_model(act, clist, dlist) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and numeric interactionType + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and numeric interactionType def test_activity_definition_cmiInteraction_numeric(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:foom', - 'definition': {'name': {'en-CH':'testname2'},'description': {'en-CH':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'numeric','correctResponsesPattern': ['4'], - 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foom', + 'definition': {'name': {'en-CH': 'testname2'}, 'description': {'en-CH': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'numeric', 'correctResponsesPattern': ['4'], + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -792,26 +792,26 @@ def test_activity_definition_cmiInteraction_numeric(self): self.do_activity_model(act.id, 'act:foom', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'numeric') + 'numeric') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['4']) - #Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and other interactionType + # Test activity with definition that is http://adlnet.gov/expapi/activities/cmi.interaction and other interactionType def test_activity_definition_cmiInteraction_other(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id': 'act:foon', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other', - 'correctResponsesPattern': ['(35.937432,-86.868896)'],'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foon', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', + 'correctResponsesPattern': ['(35.937432,-86.868896)'], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -829,38 +829,38 @@ def test_activity_definition_cmiInteraction_other(self): self.do_activity_model(act.id, 'act:foon', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + 'other') self.do_activity_definition_extensions_model(act, 'ext:key1', 'ext:key2', 'ext:key3', - 'value1', 'value2', 'value3') + 'value1', 'value2', 'value3') self.do_activity_definition_correctResponsePattern_model(act, ['(35.937432,-86.868896)']) # Should be the same, no auth required def test_multiple_activities(self): stmt_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob'}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob'}} - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob'}} + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob'}} - stmt3 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob'}} + stmt3 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob'}} - stmt4 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foon'}} + stmt4 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foon'}} stmt_list.append(stmt1) stmt_list.append(stmt2) stmt_list.append(stmt3) stmt_list.append(stmt4) response = self.client.post(reverse(statements), json.dumps(stmt_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) @@ -879,16 +879,16 @@ def test_multiple_activities(self): self.assertNotEqual(act1.id, act4.id) def test_language_map_description_name(self): - stmt1 = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id': 'act:foz', - 'definition': {'name': {'en-US':'actname'},'description': {'en-US':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other', - 'correctResponsesPattern': ['(35,-86)']}}}) + stmt1 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foz', + 'definition': {'name': {'en-US': 'actname'}, 'description': {'en-US': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', + 'correctResponsesPattern': ['(35,-86)']}}}) response = self.client.post(reverse(statements), stmt1, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) @@ -905,32 +905,32 @@ def test_language_map_description_name(self): self.do_activity_model(act.id, 'act:foz', 'Activity') self.do_activity_definition_model(act, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + 'other') def test_multiple_activities_update_name(self): stmt_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-US':'actname'},'description': {'en-US':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} - - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-US':'actname2'},'description': {'en-US':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-US': 'actname'}, 'description': {'en-US': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} + + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-US': 'actname2'}, 'description': {'en-US': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} stmt_list.append(stmt1) stmt_list.append(stmt2) response = self.client.post(reverse(statements), json.dumps(stmt_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) st1 = Statement.objects.get(statement_id=st_ids[0]) - st2 = Statement.objects.get(statement_id=st_ids[1]) + st2 = Statement.objects.get(statement_id=st_ids[1]) act1 = Activity.objects.get(id=st1.object_activity.id) act2 = Activity.objects.get(id=st2.object_activity.id) @@ -938,57 +938,56 @@ def test_multiple_activities_update_name(self): name_set1 = act1.activity_definition_name desc_set1 = act1.activity_definition_description - + self.assertEqual(name_set1.keys()[0], 'en-US') self.assertEqual(name_set1.values()[0], 'actname2') self.assertEqual(desc_set1.keys()[0], 'en-US') - self.assertEqual(desc_set1.values()[0], 'actdesc') - + self.assertEqual(desc_set1.values()[0], 'actdesc') self.do_activity_definition_model(act1, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + 'other') self.do_activity_model(act2.id, 'act:foob', 'Activity') name_set2 = act2.activity_definition_name desc_set2 = act2.activity_definition_description - + self.assertEqual(name_set2.keys()[0], 'en-US') self.assertEqual(name_set2.values()[0], 'actname2') self.assertEqual(desc_set2.keys()[0], 'en-US') - self.assertEqual(desc_set2.values()[0], 'actdesc') + self.assertEqual(desc_set2.values()[0], 'actdesc') self.do_activity_definition_model(act2, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + 'other') self.assertEqual(act1, act2) - + def test_multiple_activities_update_desc(self): stmt_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foobe', - 'definition':{'name': {'en-US':'actname'},'description': {'en-US':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} - - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foobe', - 'definition':{'name': {'en-US':'actname'},'description': {'en-US':'actdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobe', + 'definition': {'name': {'en-US': 'actname'}, 'description': {'en-US': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} + + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobe', + 'definition': {'name': {'en-US': 'actname'}, 'description': {'en-US': 'actdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} stmt_list.append(stmt1) stmt_list.append(stmt2) response = self.client.post(reverse(statements), json.dumps(stmt_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) st1 = Statement.objects.get(statement_id=st_ids[0]) - st2 = Statement.objects.get(statement_id=st_ids[1]) + st2 = Statement.objects.get(statement_id=st_ids[1]) act1 = Activity.objects.get(id=st1.object_activity.id) act2 = Activity.objects.get(id=st2.object_activity.id) @@ -996,7 +995,7 @@ def test_multiple_activities_update_desc(self): name_set1 = act1.activity_definition_name desc_set1 = act1.activity_definition_description - + self.assertEqual(name_set1.keys()[0], 'en-US') self.assertEqual(name_set1.values()[0], 'actname') @@ -1013,35 +1012,35 @@ def test_multiple_activities_update_desc(self): self.assertEqual(name_set2.values()[0], 'actname') self.assertEqual(desc_set2.keys()[0], 'en-US') - self.assertEqual(desc_set2.values()[0], 'actdesc2') + self.assertEqual(desc_set2.values()[0], 'actdesc2') self.do_activity_definition_model(act2, 'http://adlnet.gov/expapi/activities/cmi.interaction', 'other') self.assertEqual(act1, act2) def test_multiple_activities_update_both(self): stmt_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-CH':'actname'},'description': {'en-FR':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} - - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-CH':'actname2'},'description': {'en-FR':'actdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-CH': 'actname'}, 'description': {'en-FR': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} + + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-CH': 'actname2'}, 'description': {'en-FR': 'actdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} stmt_list.append(stmt1) stmt_list.append(stmt2) response = self.client.post(reverse(statements), json.dumps(stmt_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) st1 = Statement.objects.get(statement_id=st_ids[0]) - st2 = Statement.objects.get(statement_id=st_ids[1]) + st2 = Statement.objects.get(statement_id=st_ids[1]) act1 = Activity.objects.get(id=st1.object_activity.id) act2 = Activity.objects.get(id=st2.object_activity.id) @@ -1049,7 +1048,7 @@ def test_multiple_activities_update_both(self): name_set1 = act1.activity_definition_name desc_set1 = act1.activity_definition_description - + self.assertEqual(name_set1.keys()[0], 'en-CH') self.assertEqual(name_set1.values()[0], 'actname2') @@ -1062,37 +1061,37 @@ def test_multiple_activities_update_both(self): name_set2 = act2.activity_definition_name desc_set2 = act2.activity_definition_description - + self.assertEqual(name_set2.keys()[0], 'en-CH') self.assertEqual(name_set2.values()[0], 'actname2') self.assertEqual(desc_set2.keys()[0], 'en-FR') - self.assertEqual(desc_set2.values()[0], 'actdesc2') - self.do_activity_definition_model(act2,'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + self.assertEqual(desc_set2.values()[0], 'actdesc2') + self.do_activity_definition_model(act2, 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'other') self.assertEqual(act1, act2) def test_multiple_activities_update_both_and_add(self): stmt_list = [] - stmt1 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-CH':'actname'},'description': {'en-FR':'actdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} - - stmt2 = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType':'Activity', 'id': 'act:foob', - 'definition':{'name': {'en-CH':'actname2', 'en-US': 'altname'},'description': {'en-FR':'actdesc2', 'en-GB': 'altdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other','correctResponsesPattern': ['(35,-86)']}}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-CH': 'actname'}, 'description': {'en-FR': 'actdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} + + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foob', + 'definition': {'name': {'en-CH': 'actname2', 'en-US': 'altname'}, 'description': {'en-FR': 'actdesc2', 'en-GB': 'altdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', 'correctResponsesPattern': ['(35,-86)']}}} stmt_list.append(stmt1) stmt_list.append(stmt2) response = self.client.post(reverse(statements), json.dumps(stmt_list), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) st_ids = json.loads(response.content) st1 = Statement.objects.get(statement_id=st_ids[0]) @@ -1106,7 +1105,7 @@ def test_multiple_activities_update_both_and_add(self): name_set1 = act1.activity_definition_name desc_set1 = act1.activity_definition_description - + self.assertEqual(name_set1.keys()[1], 'en-CH') self.assertEqual(name_set1.values()[1], 'actname2') self.assertEqual(name_set1.keys()[0], 'en-US') @@ -1118,4 +1117,4 @@ def test_multiple_activities_update_both_and_add(self): self.assertEqual(desc_set1.values()[0], 'altdesc') self.do_activity_definition_model(act1, 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'other') + 'other') diff --git a/lrs/tests/ActivityProfileTests.py b/lrs/tests/ActivityProfileTests.py index a291d79a..712d20f7 100644 --- a/lrs/tests/ActivityProfileTests.py +++ b/lrs/tests/ActivityProfileTests.py @@ -10,6 +10,7 @@ from lrs import models, views from adl_lrs.views import register + class ActivityProfileTests(TestCase): test_activityId1 = 'act:act-1' test_activityId2 = 'act:act-2' @@ -30,80 +31,79 @@ def setUp(self): self.email = "test@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username, 'email': self.email,'password':self.password,'password2':self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': self.username, 'email': self.email, 'password': self.password, 'password2': self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams1 = {"profileId": self.testprofileId1, "activityId": self.test_activityId1} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - self.testprofile1 = {"test":"put profile 1","obj":{"activity":"test"}} - self.put1 = self.client.put(path, json.dumps(self.testprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + self.testprofile1 = {"test": "put profile 1", "obj": {"activity": "test"}} + self.put1 = self.client.put(path, json.dumps(self.testprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.testparams2 = {"profileId": self.testprofileId2, "activityId": self.test_activityId2} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams2)) - self.testprofile2 = {"test":"put profile 2","obj":{"activity":"test"}} - self.put2 = self.client.put(path, json.dumps(self.testprofile2), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.testprofile2 = {"test": "put profile 2", "obj": {"activity": "test"}} + self.put2 = self.client.put(path, json.dumps(self.testprofile2), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams3 = {"profileId": self.testprofileId3, "activityId": self.test_activityId3} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams3)) - self.testprofile3 = {"test":"put profile 3","obj":{"activity":"test"}} - self.put3 = self.client.put(path, json.dumps(self.testprofile3), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.testprofile3 = {"test": "put profile 3", "obj": {"activity": "test"}} + self.put3 = self.client.put(path, json.dumps(self.testprofile3), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams4 = {"profileId": self.otherprofileId1, "activityId": self.other_activityId} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams4)) - self.otherprofile1 = {"test":"put profile other","obj":{"activity":"other"}} - self.put4 = self.client.put(path, json.dumps(self.otherprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.otherprofile1 = {"test": "put profile other", "obj": {"activity": "other"}} + self.put4 = self.client.put(path, json.dumps(self.otherprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams5 = {"profileId": self.otherprofileId1, "activityId": self.test_activityId1} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams5)) - self.anotherprofile1 = {"test":"put another profile 1","obj":{"activity":"other"}} - self.put5 = self.client.put(path, json.dumps(self.anotherprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.anotherprofile1 = {"test": "put another profile 1", "obj": {"activity": "other"}} + self.put5 = self.client.put(path, json.dumps(self.anotherprofile1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - def tearDown(self): self.client.delete(reverse(views.activity_profile), self.testparams1, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.client.delete(reverse(views.activity_profile), self.testparams2, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.client.delete(reverse(views.activity_profile), self.testparams3, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.client.delete(reverse(views.activity_profile), self.testparams4, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.client.delete(reverse(views.activity_profile), self.testparams5, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + self.client.delete(reverse(views.activity_profile), self.testparams4, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.client.delete(reverse(views.activity_profile), self.testparams5, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + def test_put(self): - #Test the puts + # Test the puts self.assertEqual(self.put1.status_code, 204) self.assertEqual(self.put2.status_code, 204) - + self.assertEqual(self.put3.status_code, 204) - + self.assertEqual(self.put4.status_code, 204) - + self.assertEqual(self.put5.status_code, 204) - #Make sure profiles have correct activities + # Make sure profiles have correct activities self.assertEqual(models.ActivityProfile.objects.filter(profileId=self.testprofileId1)[0].activityId, self.test_activityId1) self.assertEqual(models.ActivityProfile.objects.filter(profileId=self.testprofileId2)[0].activityId, self.test_activityId2) self.assertEqual(models.ActivityProfile.objects.filter(profileId=self.testprofileId3)[0].activityId, self.test_activityId3) def test_put_no_params(self): - put = self.client.put(reverse(views.activity_profile) ,content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + put = self.client.put(reverse(views.activity_profile), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEquals(put.content, 'Error -- activity_profile - method = PUT, but activityId parameter missing..') def test_put_no_activityId(self): - put = self.client.put(reverse(views.activity_profile), {'profileId':'10'},content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + put = self.client.put(reverse(views.activity_profile), {'profileId': '10'}, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEquals(put.content, 'Error -- activity_profile - method = PUT, but activityId parameter missing..') def test_put_no_profileId(self): - testparams = {'activityId':'act:act:act'} + testparams = {'activityId': 'act:act:act'} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(testparams)) put = self.client.put(path, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEquals(put.content, 'Error -- activity_profile - method = PUT, but profileId parameter missing..') def test_put_etag_missing_on_change(self): path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/o etag header","obj":{"activity":"test"}} + profile = {"test": "error - trying to put new profile w/o etag header", "obj": {"activity": "test"}} response = self.client.put(path, profile, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 409) self.assertIn('If-Match and If-None-Match headers were missing', response.content) - + r = self.client.get(reverse(views.activity_profile), self.testparams1, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) robj = ast.literal_eval(r.content) @@ -112,7 +112,7 @@ def test_put_etag_missing_on_change(self): def test_put_etag_right_on_change(self): path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"good - trying to put new profile w/ etag header","obj":{"activity":"act:test"}} + profile = {"test": "good - trying to put new profile w/ etag header", "obj": {"activity": "act:test"}} thehash = '"%s"' % hashlib.sha1(json.dumps(self.testprofile1)).hexdigest() response = self.client.put(path, json.dumps(profile), content_type=self.content_type, If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -122,7 +122,7 @@ def test_put_etag_right_on_change(self): def test_put_etag_wrong_on_change(self): path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/ wrong etag value","obj":{"activity":"act:test"}} + profile = {"test": "error - trying to put new profile w/ wrong etag value", "obj": {"activity": "act:test"}} thehash = '"%s"' % hashlib.sha1('%s' % 'wrong hash').hexdigest() response = self.client.put(path, profile, content_type=self.content_type, If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 412) @@ -137,7 +137,7 @@ def test_put_etag_wrong_on_change(self): def test_put_etag_if_none_match_good(self): params = {"profileId": 'http://etag.nomatch.good', "activityId": self.test_activityId1} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - profile = {"test":"good - trying to put new profile w/ if none match etag header","obj":{"activity":"act:test"}} + profile = {"test": "good - trying to put new profile w/ if none match etag header", "obj": {"activity": "act:test"}} response = self.client.put(path, json.dumps(profile), content_type=self.content_type, if_none_match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) r = self.client.get(reverse(views.activity_profile), params, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) @@ -150,7 +150,7 @@ def test_put_etag_if_none_match_good(self): def test_put_etag_if_none_match_bad(self): path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/ if none match etag but one exists","obj":{"activity":"act:test"}} + profile = {"test": "error - trying to put new profile w/ if none match etag but one exists", "obj": {"activity": "act:test"}} response = self.client.put(path, profile, content_type=self.content_type, If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 412) self.assertEqual(response.content, 'Resource detected') @@ -160,9 +160,9 @@ def test_put_etag_if_none_match_bad(self): robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], self.testprofile1['test']) self.assertEqual(robj['obj']['activity'], self.testprofile1['obj']['activity']) - + def test_get_activity_only(self): - response = self.client.get(reverse(views.activity_profile), {'activityId':self.test_activityId2}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'activityId': self.test_activityId2}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 200) self.assertContains(response, self.testprofileId2) @@ -171,69 +171,69 @@ def test_get_activity_only(self): self.client.delete(reverse(views.activity_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_get_activity_profileId(self): - response = self.client.get(reverse(views.activity_profile), {'activityId':self.test_activityId1,'profileId':self.testprofileId1}, - X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'activityId': self.test_activityId1, 'profileId': self.testprofileId1}, + X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 200) robj = ast.literal_eval(response.content) self.assertEqual(robj['test'], self.testprofile1['test']) self.assertEqual(robj['obj']['activity'], self.testprofile1['obj']['activity']) resp_hash = hashlib.sha1(response.content).hexdigest() - self.assertEqual(response['etag'], '"%s"' % resp_hash) + self.assertEqual(response['etag'], '"%s"' % resp_hash) params = {'activityId': self.test_activityId1, 'profileId': self.testprofileId1} self.client.delete(reverse(views.activity_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + def test_get_activity_profileId_no_auth(self): - response = self.client.get(reverse(views.activity_profile), {'activityId':self.test_activityId1,'profileId':self.testprofileId1}, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(views.activity_profile), {'activityId': self.test_activityId1, 'profileId': self.testprofileId1}, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) def test_get_activity_profileId_activity_dne(self): - response = self.client.get(reverse(views.activity_profile), {'activityId':'http://actID','profileId':self.testprofileId1}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'activityId': 'http://actID', 'profileId': self.testprofileId1}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 404) - + def test_get_activity_since_tz(self): actid = "test:activity" profid = "test://test/tz" - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id': actid}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': actid}}) st_post = self.client.post(reverse(views.statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) params = {"profileId": profid, "activityId": actid} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - prof = {"test":"timezone since","obj":{"activity":"other"}} + prof = {"test": "timezone since", "obj": {"activity": "other"}} r = self.client.put(path, json.dumps(prof), content_type=self.content_type, updated="2012-11-11T12:00:00+00:00", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) since = "2012-11-11T12:00:00-02:00" - response = self.client.get(reverse(views.activity_profile), {'activityId': actid,'since':since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'activityId': actid, 'since': since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 200) self.assertNotIn(profid, response.content) - + params = {"activityId": actid, "profileId": profid} self.client.delete(reverse(views.activity_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_get_activity_bad_since(self): actid = "test:activity" profid = "test://test/tz" - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id': actid}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': actid}}) st_post = self.client.post(reverse(views.statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) params = {"profileId": profid, "activityId": actid} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - prof = {"test":"timezone since","obj":{"activity":"other"}} + prof = {"test": "timezone since", "obj": {"activity": "other"}} r = self.client.put(path, json.dumps(prof), content_type=self.content_type, updated="2012-11-11T12:00:00+00:00", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) since = "2012-11-1112:00:00-02:00" - response = self.client.get(reverse(views.activity_profile), {'activityId': actid,'since':since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'activityId': actid, 'since': since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Since parameter was not a valid ISO8601 timestamp") - + params = {"activityId": actid, "profileId": profid} self.client.delete(reverse(views.activity_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -244,65 +244,65 @@ def test_get_no_activityId_with_profileId(self): def test_get_no_activityId_with_since(self): since = "2012-07-01T13:30:00+04:00" - response = self.client.get(reverse(views.activity_profile), {'since':since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + response = self.client.get(reverse(views.activity_profile), {'since': since}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Error -- activity_profile - method = GET, but activityId parameter missing..') - + def test_delete(self): - response = self.client.delete(reverse(views.activity_profile), {'activityId':self.other_activityId, 'profileId':self.otherprofileId1}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.delete(reverse(views.activity_profile), {'activityId': self.other_activityId, 'profileId': self.otherprofileId1}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) - self.assertEqual(response.content, '') + self.assertEqual(response.content, '') def test_cors_put(self): profileid = 'http://test.cors.put' activityid = 'act:test_cors_put-activity' - + testparams1 = {"profileId": profileid, "activityId": activityid} - content = {"test":"put profile 1","obj":{"activity":"act:test"}} - params = "profileId=%s&activityId=%s&Authorization=%s&content=%s&X-Experience-API-Version=1.0" % (profileid, activityid,self.auth,content) - - path = path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode({"method":"PUT"})) - - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id': activityid}}) + content = {"test": "put profile 1", "obj": {"activity": "act:test"}} + params = "profileId=%s&activityId=%s&Authorization=%s&content=%s&X-Experience-API-Version=1.0" % (profileid, activityid, self.auth, content) + + path = path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode({"method": "PUT"})) + + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': activityid}}) st_post = self.client.post(reverse(views.statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) thedata = urllib.quote_plus(params) put1 = self.client.post(path, thedata, content_type="application/x-www-form-urlencoded") - self.assertEqual(put1.status_code, 204) + self.assertEqual(put1.status_code, 204) get1 = self.client.get(reverse(views.activity_profile), testparams1, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get1.status_code, 200) - + import ast c = ast.literal_eval(get1.content) - self.assertEqual(c['test'], content['test']) + self.assertEqual(c['test'], content['test']) self.client.delete(reverse(views.activity_profile), testparams1, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_cors_put_etag(self): pid = 'http://ie.cors.etag/test' aid = 'act:ie.cors.etag/test' - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id': aid}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': aid}}) st_post = self.client.post(reverse(views.statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(self.testparams1)) - tp = {"test":"put example profile for test_cors_put_etag","obj":{"activity":"this should be replaced -- ie cors post/put"}} + tp = {"test": "put example profile for test_cors_put_etag", "obj": {"activity": "this should be replaced -- ie cors post/put"}} thehash = '"%s"' % hashlib.sha1(json.dumps(self.testprofile1)).hexdigest() put1 = self.client.put(path, tp, content_type=self.content_type, If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) - path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode({"method":"PUT"})) - - content = {"test":"good - trying to put new profile w/ etag header - IE cors","obj":{"activity":"test IE cors etag"}} + path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode({"method": "PUT"})) + + content = {"test": "good - trying to put new profile w/ etag header - IE cors", "obj": {"activity": "test IE cors etag"}} thehash = '"%s"' % hashlib.sha1('%s' % tp).hexdigest() thedata = "profileId=%s&activityId=%s&If-Match=%s&Authorization=%s&Content-Type=application/x-www-form-urlencoded&content=%s&X-Experience-API-Version=1.0.0" % (pid, aid, thehash, self.auth, content) response = self.client.post(path, thedata, content_type="application/x-www-form-urlencoded") - + self.assertEqual(response.status_code, 204) r = self.client.get(reverse(views.activity_profile), {'activityId': aid, 'profileId': pid}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) @@ -315,11 +315,11 @@ def test_cors_put_etag(self): def test_tetris_snafu(self): params = {"profileId": "http://test.tetris/", "activityId": "act:tetris.snafu"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - profile = {"test":"put profile 1","obj":{"activity":"test"}} + profile = {"test": "put profile 1", "obj": {"activity": "test"}} - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id': "act:tetris.snafu"}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': "act:tetris.snafu"}}) st_post = self.client.post(reverse(views.statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) @@ -329,30 +329,30 @@ def test_tetris_snafu(self): self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], self.content_type) self.assertIn("\"", r.content) - - self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_post_new_profile(self): params = {"profileId": "prof:test_post_new_profile", "activityId": "act:test.post.new.prof"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - prof = {"test":"post new profile","obj":{"activity":"act:test.post.new.prof"}} - - post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + prof = {"test": "post new profile", "obj": {"activity": "act:test.post.new.prof"}} + + post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(ast.literal_eval(get.content), prof) self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) - self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_post_blank_profile(self): params = {"profileId": "prof:test_post_new_profile", "activityId": "act:test.post.new.prof"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) prof = "" - - post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + + post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(post.status_code, 400) self.assertEqual(post.content, 'No body in request') @@ -360,10 +360,10 @@ def test_post_blank_profile(self): # params = {"profileId": "prof:test_post_update_profile", "activityId": "act:test.post.update.prof"} # path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) # prof = {"test":"post updated profile","obj":{"activity":"act:test.post.update.prof"}} - + # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 204) - + # get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(get.status_code, 200) # what = ast.literal_eval(get.content) @@ -374,7 +374,7 @@ def test_post_blank_profile(self): # params = {"profileId": "prof:test_post_update_profile", "activityId": "act:test.post.update.prof"} # path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) # prof = {"obj":{"activity":"act:test.post.update.prof_changed", "new":"thing"}, "added":"yes"} - + # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 204) @@ -395,25 +395,25 @@ def test_post_blank_profile(self): def test_post_and_put_profile(self): params = {"profileId": "prof:test_post_and_put_profile", "activityId": "act:test.post.put.prof"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - prof = {"test":"post and put profile","obj":{"activity":"act:test.post.put.prof"}} - - post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + prof = {"test": "post and put profile", "obj": {"activity": "act:test.post.put.prof"}} + + post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(ast.literal_eval(get.content), prof) self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) params = {"profileId": "prof:test_post_and_put_profile", "activityId": "act:test.post.put.prof"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - prof = {"wipe":"new data"} + prof = {"wipe": "new data"} thehash = get.get('etag') - - put = self.client.put(path, json.dumps(prof), content_type="application/json", If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + put = self.client.put(path, json.dumps(prof), content_type="application/json", If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(ast.literal_eval(get.content), prof) etag = '"%s"' % hashlib.sha1(get.content).hexdigest() @@ -422,7 +422,7 @@ def test_post_and_put_profile(self): # params = {"profileId": "prof:test_post_and_put_profile", "activityId": "act:test.post.put.prof"} # path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) # prof = {"test":"post updated profile","obj":{"activity":"act:test.post.update.prof_changed", "new":"thing"}, "added":"yes"} - + # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 409) @@ -439,22 +439,22 @@ def test_post_and_put_profile(self): # self.assertEqual(ret_json['obj']['new'], prof['obj']['new']) # self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) - self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_put_wrong_activityId(self): - params = {'activityId':'foo','profileId':'10'} + params = {'activityId': 'foo', 'profileId': '10'} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - + put = self.client.put(path, '{"test":"body"}', content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEquals(put.content, 'activityId param for activity profile with value foo was not a valid IRI') def test_current_tetris(self): - params = {"profileId":"profile:highscores","activityId":"act:adlnet.gov/JsTetris_TCAPI"} + params = {"profileId": "profile:highscores", "activityId": "act:adlnet.gov/JsTetris_TCAPI"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - + put = self.client.put(path, '[{"actor":{"name":"tom","mbox":"mailto:tom@tom.com"},"score":802335,"date":"2013-07-26T13:42:13.465Z"},{"actor":{"name":"tom","mbox":"mailto:tom@tom.com"},"score":159482,"date":"2013-07-26T13:49:14.011Z"},{"actor":{"name":"lou","mbox":"mailto:l@l.com"},"score":86690,"date":"2013-07-26T13:27:29.083Z"},{"actor":{"name":"tom","mbox":"mailto:tom@tom.com"},"score":15504,"date":"2013-07-26T13:27:30.763Z"},{"actor":{"name":"tom","mbox":"mailto:tom@tom.com"},"score":1982,"date":"2013-07-26T13:29:46.067Z"},{"actor":{"name":"unknown","mbox":"mailto:unknown@example.com"},"score":348,"date":"2013-07-26T13:51:08.043Z"}]', content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put.status_code, 204) - + theget = self.client.get(path, Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(theget['ETag'], '"d4827d99a5cc3510d3847baa341ba5a3b477fdfc"') @@ -463,11 +463,11 @@ def test_json_merge(self): params = {"profileId": "prof:test_json_merge", "activityId": "act:test.json.merge.prof"} path = '%s?%s' % (reverse(views.activity_profile), urllib.urlencode(params)) - - post = self.client.post(path, prof, content_type="application/json", If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + post = self.client.post(path, prof, content_type="application/json", If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) returned = json.loads(get.content) sent = json.loads(prof) @@ -480,10 +480,10 @@ def test_json_merge(self): sent['test']['result'] = True sent['test']['attempt'] = sent['test']['attempt'] + 1 prof = json.dumps(sent) - post = self.client.post(path, prof, content_type="application/json", If_Match=etag, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + post = self.client.post(path, prof, content_type="application/json", If_Match=etag, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) returned = json.loads(get.content) sent = json.loads(prof) @@ -491,4 +491,4 @@ def test_json_merge(self): self.assertEqual(returned['test']['attempt'], sent['test']['attempt']) self.assertEqual(returned['test']['result'], sent['test']['result']) etag = '"%s"' % hashlib.sha1(get.content).hexdigest() - self.assertEqual(get.get('etag'), etag) \ No newline at end of file + self.assertEqual(get.get('etag'), etag) diff --git a/lrs/tests/ActivityStateTests.py b/lrs/tests/ActivityStateTests.py index e86c53a5..20e55d22 100644 --- a/lrs/tests/ActivityStateTests.py +++ b/lrs/tests/ActivityStateTests.py @@ -11,7 +11,8 @@ from django.core.urlresolvers import reverse from adl_lrs.views import register -from ..views import activity_state +from ..views import activity_state + class ActivityStateTests(TestCase): url = reverse(activity_state) @@ -32,31 +33,30 @@ def setUpClass(cls): def setUp(self): self.username = "test" - self.email = "test@example.com" + self.email = "test@example.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username,'email': self.email,'password':self.password,'password2':self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) - + form = {'username': self.username, 'email': self.email, 'password': self.password, 'password2': self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams1 = {"stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams1)) - self.teststate1 = {"test":"put activity state 1","obj":{"agent":"test"}} + self.teststate1 = {"test": "put activity state 1", "obj": {"agent": "test"}} self.put1 = self.client.put(path, json.dumps(self.teststate1), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams2 = {"stateId": self.stateId2, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams2)) - self.teststate2 = {"test":"put activity state 2","obj":{"agent":"test"}} + self.teststate2 = {"test": "put activity state 2", "obj": {"agent": "test"}} self.put2 = self.client.put(path, json.dumps(self.teststate2), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams3 = {"stateId": self.stateId3, "activityId": self.activityId2, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams3)) - self.teststate3 = {"test":"put activity state 3","obj":{"agent":"test"}} + self.teststate3 = {"test": "put activity state 3", "obj": {"agent": "test"}} self.put3 = self.client.put(path, json.dumps(self.teststate3), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams4 = {"stateId": self.stateId4, "activityId": self.activityId2, "agent": self.otheragent} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams4)) - self.teststate4 = {"test":"put activity state 4","obj":{"agent":"other"}} + self.teststate4 = {"test": "put activity state 4", "obj": {"agent": "other"}} self.put4 = self.client.put(path, json.dumps(self.teststate4), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def tearDown(self): @@ -85,33 +85,32 @@ def test_put(self): self.assertEqual(self.put4.status_code, 204) self.assertEqual(self.put4.content, '') - + def test_put_no_existing_activity(self): testparams = {"stateId": self.stateId3, "activityId": "http://foobar", "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparams)) - teststate = {"test":"put activity state","obj":{"agent":"test"}} + teststate = {"test": "put activity state", "obj": {"agent": "test"}} put = self.client.put(path, teststate, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put.status_code, 204) self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - def test_put_with_registration(self): testparamsregid = {"registration": "not-uuid", "stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsregid)) - teststateregid = {"test":"put activity state w/ registration","obj":{"agent":"test"}} + teststateregid = {"test": "put activity state w/ registration", "obj": {"agent": "test"}} put1 = self.client.put(path, teststateregid, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 400) testparamsregid = {"registration": self.registration, "stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsregid)) - teststateregid = {"test":"put activity state w/ registration","obj":{"agent":"test"}} + teststateregid = {"test": "put activity state w/ registration", "obj": {"agent": "test"}} put1 = self.client.put(path, teststateregid, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + # also testing get w/ registration id r = self.client.get(self.url, testparamsregid, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) @@ -119,7 +118,7 @@ def test_put_with_registration(self): self.assertEqual(robj['test'], teststateregid['test']) self.assertEqual(robj['obj']['agent'], teststateregid['obj']['agent']) self.assertEqual(r['etag'], '"%s"' % hashlib.sha1(r.content).hexdigest()) - + # and tests delete w/ registration id del_r = self.client.delete(self.url, testparamsregid, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(del_r.status_code, 204) @@ -127,13 +126,13 @@ def test_put_with_registration(self): def test_put_without_auth(self): testparamsregid = {"registration": self.registration, "stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsregid)) - teststateregid = {"test":"put activity state w/ registration","obj":{"agent":"test"}} + teststateregid = {"test": "put activity state w/ registration", "obj": {"agent": "test"}} put1 = self.client.put(path, teststateregid, content_type=self.content_type, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 400) def test_put_etag_conflict_if_none_match(self): - teststateetaginm = {"test":"etag conflict - if none match *","obj":{"agent":"test"}} + teststateetaginm = {"test": "etag conflict - if none match *", "obj": {"agent": "test"}} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams1)) r = self.client.put(path, teststateetaginm, content_type=self.content_type, If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 412) @@ -147,7 +146,7 @@ def test_put_etag_conflict_if_none_match(self): self.assertEqual(r['etag'], '"%s"' % hashlib.sha1(r.content).hexdigest()) def test_put_etag_conflict_if_match(self): - teststateetagim = {"test":"etag conflict - if match wrong hash","obj":{"agent":"test"}} + teststateetagim = {"test": "etag conflict - if match wrong hash", "obj": {"agent": "test"}} new_etag = '"%s"' % hashlib.sha1('wrong etag value').hexdigest() path = '%s?%s' % (self.url, urllib.urlencode(self.testparams1)) r = self.client.put(path, teststateetagim, content_type=self.content_type, If_Match=new_etag, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -162,7 +161,7 @@ def test_put_etag_conflict_if_match(self): self.assertEqual(r['etag'], '"%s"' % hashlib.sha1(r.content).hexdigest()) def test_put_etag_no_conflict_if_match(self): - teststateetagim = {"test":"etag no conflict - if match good hash","obj":{"agent":"test"}} + teststateetagim = {"test": "etag no conflict - if match good hash", "obj": {"agent": "test"}} new_etag = '"%s"' % hashlib.sha1(json.dumps(self.teststate1)).hexdigest() path = '%s?%s' % (self.url, urllib.urlencode(self.testparams1)) r = self.client.put(path, teststateetagim, content_type=self.content_type, If_Match=new_etag, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -174,17 +173,17 @@ def test_put_etag_no_conflict_if_match(self): robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststateetagim['test']) self.assertEqual(robj['obj']['agent'], teststateetagim['obj']['agent']) - self.assertEqual(r['etag'], '"%s"' % hashlib.sha1(r.content).hexdigest()) + self.assertEqual(r['etag'], '"%s"' % hashlib.sha1(r.content).hexdigest()) def test_put_etag_missing_on_change(self): teststateetagim = {'test': 'etag no need for etag', 'obj': {'agent': 'test'}} path = '%s?%s' % (self.url, urllib.urlencode(self.testparams1)) r = self.client.put(path, teststateetagim, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) - + r = self.client.get(self.url, self.testparams1, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststateetagim['test']) self.assertEqual(robj['obj']['agent'], self.teststate1['obj']['agent']) @@ -193,27 +192,25 @@ def test_put_etag_missing_on_change(self): def test_put_without_activityid(self): testparamsbad = {"stateId": "bad_state", "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsbad)) - teststatebad = {"test":"put activity state BAD no activity id","obj":{"agent":"test"}} + teststatebad = {"test": "put activity state BAD no activity id", "obj": {"agent": "test"}} put1 = self.client.put(path, teststatebad, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 400) self.assertIn('activityId parameter is missing', put1.content) - def test_put_without_agent(self): testparamsbad = {"stateId": "bad_state", "activityId": self.activityId} path = '%s?%s' % (self.url, urllib.urlencode(testparamsbad)) - teststatebad = {"test":"put activity state BAD no agent","obj":{"agent":"none"}} + teststatebad = {"test": "put activity state BAD no agent", "obj": {"agent": "none"}} put1 = self.client.put(path, teststatebad, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 400) self.assertIn('agent parameter is missing', put1.content) - def test_put_without_stateid(self): testparamsbad = {"activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsbad)) - teststatebad = {"test":"put activity state BAD no state id","obj":{"agent":"test"}} + teststatebad = {"test": "put activity state BAD no state id", "obj": {"agent": "test"}} put1 = self.client.put(path, teststatebad, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 400) @@ -225,8 +222,8 @@ def test_get(self): email = "other@example.com" password = "test" auth = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) - form = {'username':username,'email': email,'password':password,'password2':password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': username, 'email': email, 'password': password, 'password2': password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) r = self.client.get(self.url, self.testparams1, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) @@ -241,7 +238,7 @@ def test_get(self): self.assertEqual(robj2['test'], self.teststate2['test']) self.assertEqual(robj2['obj']['agent'], self.teststate2['obj']['agent']) self.assertEqual(r2['etag'], '"%s"' % hashlib.sha1(r2.content).hexdigest()) - + r3 = self.client.get(self.url, self.testparams3, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r3.status_code, 200) robj3 = ast.literal_eval(r3.content) @@ -264,7 +261,6 @@ def test_get_no_existing_id(self): r = self.client.get(self.url, testparams, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 404) - def test_get_ids(self): params = {"activityId": self.activityId, "agent": self.testagent} r = self.client.get(self.url, params, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) @@ -274,21 +270,20 @@ def test_get_ids(self): self.assertNotIn(self.stateId3, r.content) self.assertNotIn(self.stateId4, r.content) - def test_get_with_since(self): state_id = "old_state_test" testparamssince = {"stateId": state_id, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince)) - teststatesince = {"test":"get w/ since","obj":{"agent":"test"}} + teststatesince = {"test": "get w/ since", "obj": {"agent": "test"}} updated = "2012-06-12T12:00:00Z" put1 = self.client.put(path, teststatesince, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamssince, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststatesince['test']) self.assertEqual(robj['obj']['agent'], teststatesince['obj']['agent']) @@ -305,21 +300,21 @@ def test_get_with_since(self): self.assertNotIn(self.stateId4, r.content) self.client.delete(self.url, testparamssince, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + def test_get_with_since_tz(self): state_id = "old_state_test" testparamssince = {"stateId": state_id, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince)) - teststatesince = {"test":"get w/ since","obj":{"agent":"test"}} + teststatesince = {"test": "get w/ since", "obj": {"agent": "test"}} updated = "2012-06-12:T12:00:00Z" put1 = self.client.put(path, teststatesince, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamssince, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststatesince['test']) self.assertEqual(robj['obj']['agent'], teststatesince['obj']['agent']) @@ -328,16 +323,16 @@ def test_get_with_since_tz(self): state_id2 = "new_tz_state_test" testparamssince2 = {"stateId": state_id2, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince2)) - teststatesince2 = {"test":"get w/ since TZ","obj":{"agent":"test"}} - updated_tz = "2012-07-01T13:30:00+04:00" + teststatesince2 = {"test": "get w/ since TZ", "obj": {"agent": "test"}} + updated_tz = "2012-07-01T13:30:00+04:00" put2 = self.client.put(path, teststatesince2, content_type=self.content_type, updated=updated_tz, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put2.status_code, 204) self.assertEqual(put2.content, '') - + r2 = self.client.get(self.url, testparamssince2, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r2.status_code, 200) - + robj2 = ast.literal_eval(r2.content) self.assertEqual(robj2['test'], teststatesince2['test']) self.assertEqual(robj2['obj']['agent'], teststatesince2['obj']['agent']) @@ -362,16 +357,16 @@ def test_get_with_since_and_regid(self): state_id = "old_state_test_no_reg" testparamssince = {"stateId": state_id, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince)) - teststatesince = {"test":"get w/ since","obj":{"agent":"test","stateId":state_id}} + teststatesince = {"test": "get w/ since", "obj": {"agent": "test", "stateId": state_id}} updated = "2012-06-12:T12:00:00Z" put1 = self.client.put(path, teststatesince, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamssince, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststatesince['test']) self.assertEqual(robj['obj']['agent'], teststatesince['obj']['agent']) @@ -380,9 +375,9 @@ def test_get_with_since_and_regid(self): # create old state w/ registration id regid = str(uuid.uuid1()) state_id2 = "old_state_test_w_reg" - testparamssince2 = {"registration": regid, "activityId": self.activityId, "agent": self.testagent, "stateId":state_id2} + testparamssince2 = {"registration": regid, "activityId": self.activityId, "agent": self.testagent, "stateId": state_id2} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince2)) - teststatesince2 = {"test":"get w/ since and registration","obj":{"agent":"test","stateId":state_id2}} + teststatesince2 = {"test": "get w/ since and registration", "obj": {"agent": "test", "stateId": state_id2}} put2 = self.client.put(path, teststatesince2, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put2.status_code, 204) @@ -390,7 +385,7 @@ def test_get_with_since_and_regid(self): r2 = self.client.get(self.url, testparamssince2, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r2.status_code, 200) - + robj2 = ast.literal_eval(r2.content) self.assertEqual(robj2['test'], teststatesince2['test']) self.assertEqual(robj2['obj']['agent'], teststatesince2['obj']['agent']) @@ -398,9 +393,9 @@ def test_get_with_since_and_regid(self): # create new state w/ registration id state_id3 = "old_state_test_w_new_reg" - testparamssince3 = {"registration": regid, "activityId": self.activityId, "agent": self.testagent, "stateId":state_id3} + testparamssince3 = {"registration": regid, "activityId": self.activityId, "agent": self.testagent, "stateId": state_id3} path = '%s?%s' % (self.url, urllib.urlencode(testparamssince3)) - teststatesince3 = {"test":"get w/ since and registration","obj":{"agent":"test","stateId":state_id3}} + teststatesince3 = {"test": "get w/ since and registration", "obj": {"agent": "test", "stateId": state_id3}} put3 = self.client.put(path, teststatesince3, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put3.status_code, 204) @@ -408,7 +403,7 @@ def test_get_with_since_and_regid(self): r3 = self.client.get(self.url, testparamssince3, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r3.status_code, 200) - + robj3 = ast.literal_eval(r3.content) self.assertEqual(robj3['test'], teststatesince3['test']) self.assertEqual(robj3['obj']['agent'], teststatesince3['obj']['agent']) @@ -436,12 +431,11 @@ def test_get_with_since_and_regid(self): self.assertNotIn(self.stateId2, r.content) self.assertNotIn(self.stateId3, r.content) self.assertNotIn(self.stateId4, r.content) - + self.client.delete(self.url, testparamssince, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.client.delete(self.url, testparamssince2, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.client.delete(self.url, testparamssince3, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - def test_get_without_activityid(self): params = {"stateId": self.stateId, "agent": self.testagent} r = self.client.get(self.url, params, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) @@ -459,9 +453,9 @@ def test_get_invalid_agent_structure(self): r = self.client.get(self.url, params, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 400) self.assertIn('agent param for activity state is not valid', r.content) - + def test_get_invalid_agent(self): - params = {"stateId": self.stateId, "activityId": self.activityId, "agent": {"mbox":"blahagent"}} + params = {"stateId": self.stateId, "activityId": self.activityId, "agent": {"mbox": "blahagent"}} r = self.client.get(self.url, params, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 400) self.assertIn('agent param for activity state is not valid', r.content) @@ -475,12 +469,12 @@ def test_get_invalid_activityid(self): def test_delete_without_activityid(self): testparamsregid = {"registration": self.registration, "stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsregid)) - teststateregid = {"test":"delete activity state w/o activityid","obj":{"agent":"test"}} + teststateregid = {"test": "delete activity state w/o activityid", "obj": {"agent": "test"}} put1 = self.client.put(path, teststateregid, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamsregid, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) robj = ast.literal_eval(r.content) @@ -496,16 +490,15 @@ def test_delete_without_activityid(self): del_r = self.client.delete(self.url, testparamsregid, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(del_r.status_code, 204) - def test_delete_without_agent(self): testparamsregid = {"registration": self.registration, "stateId": self.stateId, "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsregid)) - teststateregid = {"test":"delete activity state w/o agent","obj":{"agent":"test"}} + teststateregid = {"test": "delete activity state w/o agent", "obj": {"agent": "test"}} put1 = self.client.put(path, teststateregid, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamsregid, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) robj = ast.literal_eval(r.content) @@ -520,19 +513,18 @@ def test_delete_without_agent(self): del_r = self.client.delete(self.url, testparamsregid, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(del_r.status_code, 204) - def test_delete_set(self): testparamsdelset1 = {"registration": self.registration, "stateId": "del_state_set_1", "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsdelset1)) - teststatedelset1 = {"test":"delete set #1","obj":{"agent":"test"}} + teststatedelset1 = {"test": "delete set #1", "obj": {"agent": "test"}} put1 = self.client.put(path, teststatedelset1, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamsdelset1, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], teststatedelset1['test']) self.assertEqual(robj['obj']['agent'], teststatedelset1['obj']['agent']) @@ -540,15 +532,15 @@ def test_delete_set(self): testparamsdelset2 = {"registration": self.registration, "stateId": "del_state_set_2", "activityId": self.activityId, "agent": self.testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparamsdelset2)) - teststatedelset2 = {"test":"delete set #2","obj":{"agent":"test"}} + teststatedelset2 = {"test": "delete set #2", "obj": {"agent": "test"}} put1 = self.client.put(path, teststatedelset2, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') - + r = self.client.get(self.url, testparamsdelset2, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) - + robj2 = ast.literal_eval(r.content) self.assertEqual(robj2['test'], teststatedelset2['test']) self.assertEqual(robj2['obj']['agent'], teststatedelset2['obj']['agent']) @@ -570,19 +562,19 @@ def test_ie_cors_put_delete(self): email = "anothertest@example.com" password = "test" auth = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) - form = {'username':username,'email': email,'password':password,'password2':password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': username, 'email': email, 'password': password, 'password2': password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) testagent = '{"name":"another test","mbox":"mailto:anothertest@example.com"}' sid = "test_ie_cors_put_delete_set_1" - path = '%s?%s' % (self.url, urllib.urlencode({"method":"PUT"})) - - content = {"test":"test_ie_cors_put_delete","obj":{"actor":"another test"}} + path = '%s?%s' % (self.url, urllib.urlencode({"method": "PUT"})) + + content = {"test": "test_ie_cors_put_delete", "obj": {"actor": "another test"}} param = "stateId=%s&activityId=%s&agent=%s&content=%s&Content-Type=application/x-www-form-urlencoded&Authorization=%s&X-Experience-API-Version=1.0.0" % (sid, self.activityId, - testagent, content, auth) + testagent, content, auth) put1 = self.client.post(path, param, content_type='application/x-www-form-urlencoded') - + self.assertEqual(put1.status_code, 204) self.assertEqual(put1.content, '') @@ -593,9 +585,9 @@ def test_ie_cors_put_delete(self): self.assertEqual(c['test'], content['test']) self.assertEqual(r['etag'], '"%s"' % hashlib.sha1('%s' % content).hexdigest()) - - dparam = "agent=%s&activityId=%s&Authorization=%s&Content-Type=application/x-www-form-urlencoded&X-Experience-API-Version=1.0.0" % (testagent,self.activityId,auth) - path = '%s?%s' % (self.url, urllib.urlencode({"method":"DELETE"})) + + dparam = "agent=%s&activityId=%s&Authorization=%s&Content-Type=application/x-www-form-urlencoded&X-Experience-API-Version=1.0.0" % (testagent, self.activityId, auth) + path = '%s?%s' % (self.url, urllib.urlencode({"method": "DELETE"})) f_r = self.client.post(path, dparam, content_type='application/x-www-form-urlencoded') self.assertEqual(f_r.status_code, 204) @@ -604,23 +596,23 @@ def test_agent_is_group(self): email = "the.group@example.com" password = "test" auth = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) - form = {'username':username,'email': email,'password':password,'password2':password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': username, 'email': email, 'password': password, 'password2': password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) ot = "Group" name = "the group" mbox = "mailto:the.group@example.com" - members = [{"name":"agent1","mbox":"mailto:agent1@example.com"}, - {"name":"agent2","mbox":"mailto:agent2@example.com"}] - testagent = json.dumps({"objectType":ot, "name":name, "mbox":mbox,"member":members}) + members = [{"name": "agent1", "mbox": "mailto:agent1@example.com"}, + {"name": "agent2", "mbox": "mailto:agent2@example.com"}] + testagent = json.dumps({"objectType": ot, "name": name, "mbox": mbox, "member": members}) testparams1 = {"stateId": "group.state.id", "activityId": self.activityId, "agent": testagent} path = '%s?%s' % (self.url, urllib.urlencode(testparams1)) - teststate1 = {"test":"put activity state using group as agent","obj":{"agent":"group of 2 agents"}} + teststate1 = {"test": "put activity state using group as agent", "obj": {"agent": "group of 2 agents"}} put1 = self.client.put(path, teststate1, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) - get1 = self.client.get(self.url, {"stateId":"group.state.id", "activityId": self.activityId, "agent":testagent}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=auth) + get1 = self.client.get(self.url, {"stateId": "group.state.id", "activityId": self.activityId, "agent": testagent}, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=auth) self.assertEqual(get1.status_code, 200) robj = ast.literal_eval(get1.content) self.assertEqual(robj['test'], teststate1['test']) @@ -628,12 +620,12 @@ def test_agent_is_group(self): self.assertEqual(get1['etag'], '"%s"' % hashlib.sha1(get1.content).hexdigest()) delr = self.client.delete(self.url, testparams1, Authorization=auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(delr.status_code, 204) + self.assertEqual(delr.status_code, 204) def test_post_new_state(self): param = {"stateId": "test:postnewstate", "activityId": "act:test/post.new.state", "agent": '{"mbox":"mailto:testagent@example.com"}'} path = '%s?%s' % (self.url, urllib.urlencode(param)) - state = {"post":"testing new state", "obj":{"f1":"v1","f2":"v2"}} + state = {"post": "testing new state", "obj": {"f1": "v1", "f2": "v2"}} r = self.client.post(path, json.dumps(state), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) @@ -656,7 +648,7 @@ def test_post_blank_state(self): def test_post_update_state(self): param = {"stateId": "test:postupdatestate", "activityId": "act:test/post.update.state", "agent": '{"mbox":"mailto:test@example.com"}'} path = '%s?%s' % (self.url, urllib.urlencode(param)) - state = {"field1":"value1", "obj":{"ofield1":"oval1","ofield2":"oval2"}} + state = {"field1": "value1", "obj": {"ofield1": "oval1", "ofield2": "oval2"}} r = self.client.post(path, json.dumps(state), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) @@ -665,7 +657,7 @@ def test_post_update_state(self): self.assertEqual(r.status_code, 200) self.assertEqual(ast.literal_eval(r.content), state) - state2 = {"field_xtra":"xtra val", "obj":"ha, not a obj"} + state2 = {"field_xtra": "xtra val", "obj": "ha, not a obj"} r = self.client.post(path, json.dumps(state2), content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) @@ -689,4 +681,4 @@ def test_nonjson_put_state(self): r = self.client.get(path, Authorization=self.auth, X_Experience_API_Version="1.0.1") self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], "text/plain") - self.assertEqual(r.content, state) \ No newline at end of file + self.assertEqual(r.content, state) diff --git a/lrs/tests/ActivityTests.py b/lrs/tests/ActivityTests.py index c87d3b54..7fe20536 100644 --- a/lrs/tests/ActivityTests.py +++ b/lrs/tests/ActivityTests.py @@ -8,7 +8,9 @@ from ..views import statements, activities from adl_lrs.views import register + class ActivityTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -18,38 +20,38 @@ def setUp(self): self.email = "test@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username, 'email': self.email,'password':self.password,'password2':self.password} - self.client.post(reverse(register),form, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': self.username, 'email': self.email, 'password': self.password, 'password2': self.password} + self.client.post(reverse(register), form, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_get(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id':'act:foobar'}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar'}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId':'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('act:foobar', rsp) self.assertIn('Activity', rsp) - self.assertIn('objectType', rsp) + self.assertIn('objectType', rsp) self.assertIn('content-length', response._headers) def test_get_not_exist(self): activity_id = "this:does_not_exist" - response = self.client.get(reverse(activities), {'activityId':activity_id}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': activity_id}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 404) self.assertEqual(response.content, 'No activity found with ID this:does_not_exist') def test_get_not_array(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id':'act:foobar'}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar'}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId':'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('content-length', response._headers) @@ -58,28 +60,28 @@ def test_get_not_array(self): self.assertEqual('act:foobar', rsp_obj['id']) def test_head(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType':'Activity', 'id':'act:foobar'}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar'}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.head(reverse(activities), {'activityId':'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.head(reverse(activities), {'activityId': 'act:foobar'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, '') self.assertIn('content-length', response._headers) def test_get_def(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar1', - 'definition': {'name': {'en-US':'testname', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc', 'en-GB': 'altdesc'}, - 'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar1', + 'definition': {'name': {'en-US': 'testname', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc', 'en-GB': 'altdesc'}, + 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': []}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId':'act:foobar1'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar1'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('act:foobar1', rsp) @@ -90,16 +92,16 @@ def test_get_def(self): self.assertEqual(len(rsp_dict['definition']['description'].keys()), 2) def test_get_ext(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar2', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'type:course','interactionType': 'other', 'correctResponsesPattern':[], - 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar2', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'type:course', 'interactionType': 'other', 'correctResponsesPattern': [], + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId':'act:foobar2'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar2'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('act:foobar2', rsp) @@ -114,21 +116,21 @@ def test_get_ext(self): self.assertIn('value2', rsp) def test_get_crp_multiple_choice(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar3', - 'definition': {'name': {'en-FR':'testname2'}, - 'description': {'en-FR':'testdesc2', 'en-CH': 'altdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'choice', - 'correctResponsesPattern': ['golf', 'tetris'],'choices':[{'id': 'golf', - 'description': {'en-US':'Golf Example', 'en-GB':'alt golf'}},{'id': 'tetris', - 'description':{'en-US': 'Tetris Example'}}, {'id':'facebook', - 'description':{'en-US':'Facebook App'}},{'id':'scrabble', - 'description': {'en-US': 'Scrabble Example'}}]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar3', + 'definition': {'name': {'en-FR': 'testname2'}, + 'description': {'en-FR': 'testdesc2', 'en-CH': 'altdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'choice', + 'correctResponsesPattern': ['golf', 'tetris'], 'choices': [{'id': 'golf', + 'description': {'en-US': 'Golf Example', 'en-GB': 'alt golf'}}, {'id': 'tetris', + 'description': {'en-US': 'Tetris Example'}}, {'id': 'facebook', + 'description': {'en-US': 'Facebook App'}}, {'id': 'scrabble', + 'description': {'en-US': 'Scrabble Example'}}]}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - - response = self.client.get(reverse(activities), {'activityId':'act:foobar3'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + response = self.client.get(reverse(activities), {'activityId': 'act:foobar3'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -148,14 +150,14 @@ def test_get_crp_multiple_choice(self): self.assertEqual(len(rsp_dict['definition']['choices'][3]['description'].keys()), 1) def test_get_crp_true_false(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar4', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'true-false','correctResponsesPattern': ['true']}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar4', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'true-false', 'correctResponsesPattern': ['true']}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - + response = self.client.get(reverse(activities), {'activityId': 'act:foobar4'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content @@ -170,16 +172,16 @@ def test_get_crp_true_false(self): self.assertIn('true', rsp) def test_get_crp_fill_in(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar5', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'fill-in', - 'correctResponsesPattern': ['Fill in answer']}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar5', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'fill-in', + 'correctResponsesPattern': ['Fill in answer']}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId': 'act:foobar5'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar5'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -193,16 +195,16 @@ def test_get_crp_fill_in(self): self.assertIn('Fill in answer', rsp) def test_get_crp_long_fill_in(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar6', - 'definition': {'name': {'en-FR':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'fill-in', - 'correctResponsesPattern': ['Long fill in answer']}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar6', + 'definition': {'name': {'en-FR': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'fill-in', + 'correctResponsesPattern': ['Long fill in answer']}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId': 'act:foobar6'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar6'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content @@ -217,19 +219,19 @@ def test_get_crp_long_fill_in(self): self.assertIn('Long fill in answer', rsp) def test_get_crp_likert(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar7', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'likert','correctResponsesPattern': ['likert_3'], - 'scale':[{'id': 'likert_0', 'description': {'en-US':'Its OK'}},{'id': 'likert_1', - 'description':{'en-US': 'Its Pretty Cool'}}, {'id':'likert_2', - 'description':{'en-US':'Its Cool Cool'}},{'id':'likert_3', - 'description': {'en-US': 'Its Gonna Change the World'}}]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar7', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'likert', 'correctResponsesPattern': ['likert_3'], + 'scale': [{'id': 'likert_0', 'description': {'en-US': 'Its OK'}}, {'id': 'likert_1', + 'description': {'en-US': 'Its Pretty Cool'}}, {'id': 'likert_2', + 'description': {'en-US': 'Its Cool Cool'}}, {'id': 'likert_3', + 'description': {'en-US': 'Its Gonna Change the World'}}]}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId': 'act:foobar7'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar7'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -245,27 +247,27 @@ def test_get_crp_likert(self): self.assertIn('likert_1', rsp) def test_get_crp_matching(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar8', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-FR':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'matching', - 'correctResponsesPattern': ['lou.3,tom.2,andy.1'],'source':[{'id': 'lou', - 'description': {'en-US':'Lou'}},{'id': 'tom','description':{'en-US': 'Tom'}}, - {'id':'andy', 'description':{'en-US':'Andy'}}],'target':[{'id':'1', - 'description':{'en-US': 'SCORM Engine'}},{'id':'2','description':{'en-US': 'Pure-sewage'}}, - {'id':'3', 'description':{'en-US': 'SCORM Cloud'}}]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar8', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-FR': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'matching', + 'correctResponsesPattern': ['lou.3,tom.2,andy.1'], 'source': [{'id': 'lou', + 'description': {'en-US': 'Lou'}}, {'id': 'tom', 'description': {'en-US': 'Tom'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}], 'target': [{'id': '1', + 'description': {'en-US': 'SCORM Engine'}}, {'id': '2', 'description': {'en-US': 'Pure-sewage'}}, + {'id': '3', 'description': {'en-US': 'SCORM Cloud'}}]}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - - response = self.client.get(reverse(activities), {'activityId': 'act:foobar8'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + response = self.client.get(reverse(activities), {'activityId': 'act:foobar8'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('act:foobar8', rsp) self.assertIn('http://adlnet.gov/expapi/activities/cmi.interaction', rsp) self.assertIn('matching', rsp) self.assertIn('en-FR', rsp) - self.assertIn('en-US', rsp) + self.assertIn('en-US', rsp) self.assertIn('testname2', rsp) self.assertIn('testdesc2', rsp) self.assertIn('correctResponsesPattern', rsp) @@ -274,21 +276,21 @@ def test_get_crp_matching(self): self.assertIn('target', rsp) def test_get_crp_performance(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar9', - 'definition': {'name': {'en-US':'testname2', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc2'},'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'performance', - 'correctResponsesPattern': ['pong.1,dg.10,lunch.4'],'steps':[{'id': 'pong', - 'description': {'en-US':'Net pong matches won'}},{'id': 'dg', - 'description':{'en-US': 'Strokes over par in disc golf at Liberty'}}, - {'id':'lunch', 'description':{'en-US':'Lunch having been eaten', - 'en-FR': 'altlunch'}}]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar9', + 'definition': {'name': {'en-US': 'testname2', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc2'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'performance', + 'correctResponsesPattern': ['pong.1,dg.10,lunch.4'], 'steps': [{'id': 'pong', + 'description': {'en-US': 'Net pong matches won'}}, {'id': 'dg', + 'description': {'en-US': 'Strokes over par in disc golf at Liberty'}}, + {'id': 'lunch', 'description': {'en-US': 'Lunch having been eaten', + 'en-FR': 'altlunch'}}]}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - - response = self.client.get(reverse(activities), {'activityId': 'act:foobar9'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + response = self.client.get(reverse(activities), {'activityId': 'act:foobar9'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) self.assertIn('act:foobar9', rsp) @@ -307,18 +309,18 @@ def test_get_crp_performance(self): self.assertEqual(len(rsp_dict['definition']['steps'][2]['description'].keys()), 2) def test_get_crp_sequencing(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar10', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'sequencing', - 'correctResponsesPattern': ['lou,tom,andy,aaron'],'choices':[{'id': 'lou', - 'description': {'en-US':'Lou'}},{'id': 'tom','description':{'en-US': 'Tom'}}, - {'id':'andy', 'description':{'en-US':'Andy'}},{'id':'aaron', 'description':{'en-US':'Aaron'}}]}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar10', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'sequencing', + 'correctResponsesPattern': ['lou,tom,andy,aaron'], 'choices': [{'id': 'lou', + 'description': {'en-US': 'Lou'}}, {'id': 'tom', 'description': {'en-US': 'Tom'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}, {'id': 'aaron', 'description': {'en-US': 'Aaron'}}]}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId': 'act:foobar10'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar10'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -326,23 +328,23 @@ def test_get_crp_sequencing(self): self.assertIn('http://adlnet.gov/expapi/activities/cmi.interaction', rsp) self.assertIn('sequencing', rsp) self.assertIn('choices', rsp) - self.assertIn('en-US', rsp) + self.assertIn('en-US', rsp) self.assertIn('testname2', rsp) self.assertIn('testdesc2', rsp) self.assertIn('correctResponsesPattern', rsp) self.assertIn('lou,tom,andy,aaron', rsp) def test_get_crp_numeric(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id':'act:foobar11', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'numeric','correctResponsesPattern': ['4'], - 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar11', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'numeric', 'correctResponsesPattern': ['4'], + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - response = self.client.get(reverse(activities), {'activityId': 'act:foobar11'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(activities), {'activityId': 'act:foobar11'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -350,7 +352,7 @@ def test_get_crp_numeric(self): self.assertIn('http://adlnet.gov/expapi/activities/cmi.interaction', rsp) self.assertIn('numeric', rsp) self.assertIn('4', rsp) - self.assertIn('en-US', rsp) + self.assertIn('en-US', rsp) self.assertIn('testname2', rsp) self.assertIn('testdesc2', rsp) self.assertIn('correctResponsesPattern', rsp) @@ -360,19 +362,19 @@ def test_get_crp_numeric(self): self.assertIn('key2', rsp) self.assertIn('value2', rsp) self.assertIn('key3', rsp) - self.assertIn('value3', rsp) + self.assertIn('value3', rsp) def test_get_crp_other(self): - st = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{'objectType': 'Activity', 'id': 'act:foobar12', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'other', - 'correctResponsesPattern': ['(35.937432,-86.868896)']}}}) + st = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {'objectType': 'Activity', 'id': 'act:foobar12', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'other', + 'correctResponsesPattern': ['(35.937432,-86.868896)']}}}) st_post = self.client.post(reverse(statements), st, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(st_post.status_code, 200) - - response = self.client.get(reverse(activities), {'activityId': 'act:foobar12'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + response = self.client.get(reverse(activities), {'activityId': 'act:foobar12'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) rsp = response.content self.assertEqual(response.status_code, 200) @@ -380,12 +382,11 @@ def test_get_crp_other(self): self.assertIn('http://adlnet.gov/expapi/activities/cmi.interaction', rsp) self.assertIn('other', rsp) self.assertIn('(35.937432,-86.868896)', rsp) - self.assertIn('en-US', rsp) + self.assertIn('en-US', rsp) self.assertIn('testname2', rsp) self.assertIn('testdesc2', rsp) self.assertIn('correctResponsesPattern', rsp) - def test_get_wrong_activity(self): response = self.client.get(reverse(activities), {'activityId': 'act:act:foo'}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 404) @@ -397,18 +398,18 @@ def test_head_wrong_activity(self): def test_get_no_activity(self): response = self.client.get(reverse(activities), Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) - + def test_post(self): - response = self.client.post(reverse(activities), {'activityId':'act:my_activity'}, - content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.post(reverse(activities), {'activityId': 'act:my_activity'}, + content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 405) def test_delete(self): - response = self.client.delete(reverse(activities), {'activityId':'act:my_activity'}, - content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.delete(reverse(activities), {'activityId': 'act:my_activity'}, + content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 405) def test_put(self): - response = self.client.put(reverse(activities), {'activityId':'act:my_activity'}, - content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(response.status_code, 405) \ No newline at end of file + response = self.client.put(reverse(activities), {'activityId': 'act:my_activity'}, + content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 405) diff --git a/lrs/tests/AgentManagerTests.py b/lrs/tests/AgentManagerTests.py index e569a170..8a19365e 100644 --- a/lrs/tests/AgentManagerTests.py +++ b/lrs/tests/AgentManagerTests.py @@ -10,7 +10,9 @@ from ..views import statements from adl_lrs.views import register + class AgentManagerTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -20,34 +22,34 @@ def setUp(self): self.email = "test1@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) def test_agent_mbox_create(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bob@example.com"}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bob@example.com"}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) - st_id = json.loads(response.content) + st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) bob = st.actor self.assertEquals(bob.objectType, "Agent") self.assertFalse(bob.name) def test_agent_mbox_sha1sum_create(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox_sha1sum":hashlib.sha1("mailto:bob@example.com").hexdigest()}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox_sha1sum": hashlib.sha1("mailto:bob@example.com").hexdigest()}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) - st_id = json.loads(response.content) + st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) bob = st.actor @@ -57,26 +59,26 @@ def test_agent_mbox_sha1sum_create(self): self.assertFalse(bob.mbox) def test_agent_bogus_mbox_sha1sum_create(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox_sha1sum":"notarealsum"}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox_sha1sum": "notarealsum"}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "mbox_sha1sum value [notarealsum] is not a valid sha1sum") def test_agent_openID_create(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "openid":"http://bob.openid.com"}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "openid": "http://bob.openid.com"}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - st_id = json.loads(response.content) + st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) bob = st.actor @@ -87,15 +89,15 @@ def test_agent_openID_create(self): self.assertFalse(bob.mbox_sha1sum) def test_agent_account_create(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "account":{"homePage": "http://www.adlnet.gov", "name":"freakshow"}}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "account": {"homePage": "http://www.adlnet.gov", "name": "freakshow"}}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) - st_id = json.loads(response.content) + st_id = json.loads(response.content) st = Statement.objects.get(statement_id=st_id[0]) bob = st.actor @@ -110,7 +112,7 @@ def test_agent_kwargs_basic(self): ot = "Agent" name = "bob bobson" mbox = "mailto:bobbobson@example.com" - kwargs = {"objectType":ot,"name":name,"mbox":mbox} + kwargs = {"objectType": ot, "name": name, "mbox": mbox} bob, created = Agent.objects.retrieve_or_create(**kwargs) self.assertTrue(created) bob.save() @@ -129,11 +131,11 @@ def test_agent_kwargs_basic(self): bob3.save() self.assertNotEqual(bob.pk, bob3.pk) - def test_agent_kwargs_basic_account(self): + def test_agent_kwargs_basic_account(self): ot = "Agent" name = "bob bobson" - account = {"homePage":"http://www.adlnet.gov","name":"freakshow"} - kwargs = {"objectType":ot,"name":name,"account":account} + account = {"homePage": "http://www.adlnet.gov", "name": "freakshow"} + kwargs = {"objectType": ot, "name": name, "account": account} bob, created = Agent.objects.retrieve_or_create(**kwargs) self.assertTrue(created) self.assertEquals(bob.objectType, ot) @@ -144,24 +146,24 @@ def test_agent_kwargs_basic_account(self): def test_group_kwargs(self): ot = "Agent" name = "bob bobson" - kwargs = {"objectType":ot,"name":name, "mbox": "mailto:bob@example.com"} + kwargs = {"objectType": ot, "name": name, "mbox": "mailto:bob@example.com"} bob, created = Agent.objects.retrieve_or_create(**kwargs) ot = "Agent" name = "john johnson" - kwargs = {"objectType":ot,"name":name, "mbox": "mailto:john@example.com"} + kwargs = {"objectType": ot, "name": name, "mbox": "mailto:john@example.com"} john, created = Agent.objects.retrieve_or_create(**kwargs) - + ot = "Group" - members = [{"name":"bob bobson","mbox":"mailto:bob@example.com"}, - {"name":"john johnson","mbox":"mailto:john@example.com"}] - - kwargs = {"objectType":ot, "member": members} + members = [{"name": "bob bobson", "mbox": "mailto:bob@example.com"}, + {"name": "john johnson", "mbox": "mailto:john@example.com"}] + + kwargs = {"objectType": ot, "member": members} gr, created = Agent.objects.retrieve_or_create(**kwargs) # Already created from above self.assertTrue(created) - kwargs1 = {"objectType":ot, "member": members, "name": "my group"} + kwargs1 = {"objectType": ot, "member": members, "name": "my group"} gr1, created = Agent.objects.retrieve_or_create(**kwargs1) # creates another one b/c of adding a name self.assertTrue(created) @@ -172,24 +174,24 @@ def test_group_kwargs(self): self.assertEquals(len(agents.filter(objectType='Agent')), 2) def test_agent_json_no_ids(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "name":"freakshow"}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "freakshow"}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'One and only one of mbox, mbox_sha1sum, openid, account may be supplied with an Agent') def test_agent_json_many_ids(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bob@example.com", "openid":"bob.bobson.openid.org"}, - "verb":{"id": "http://example.com/verbs/passed"}, - "object": {'id': 'act://blah.com'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bob@example.com", "openid": "bob.bobson.openid.org"}, + "verb": {"id": "http://example.com/verbs/passed"}, + "object": {'id': 'act://blah.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'One and only one of mbox, mbox_sha1sum, openid, account may be supplied with an Agent') @@ -197,9 +199,9 @@ def test_group(self): ot = "Group" name = "the group" mbox = "mailto:the.group@example.com" - members = [{"name":"agent1","mbox":"mailto:agent1@example.com"}, - {"name":"agent2","mbox":"mailto:agent2@example.com"}] - kwargs = {"objectType":ot, "name":name, "mbox":mbox,"member":members} + members = [{"name": "agent1", "mbox": "mailto:agent1@example.com"}, + {"name": "agent2", "mbox": "mailto:agent2@example.com"}] + kwargs = {"objectType": ot, "name": name, "mbox": mbox, "member": members} g, created = Agent.objects.retrieve_or_create(**kwargs) self.assertTrue(created) self.assertEquals(g.name, name) @@ -209,8 +211,8 @@ def test_group(self): self.assertIn('agent1', mems) self.assertIn('agent2', mems) gr_dict = g.to_dict() - self.assertEquals(gr_dict['objectType'],'Group') - + self.assertEquals(gr_dict['objectType'], 'Group') + for member in gr_dict['member']: self.assertEquals(member['objectType'], 'Agent') if member['name'] == 'agent1': @@ -222,9 +224,9 @@ def test_group_from_agent_object(self): ot = "Group" name = "the group" mbox = "mailto:the.group@example.com" - members = [{"name":"agent1","mbox":"mailto:agent1@example.com"}, - {"name":"agent2","mbox":"mailto:agent2@example.com"}] - kwargs = {"objectType":ot, "name":name, "mbox":mbox,"member":members} + members = [{"name": "agent1", "mbox": "mailto:agent1@example.com"}, + {"name": "agent2", "mbox": "mailto:agent2@example.com"}] + kwargs = {"objectType": ot, "name": name, "mbox": mbox, "member": members} g = Agent.objects.retrieve_or_create(**kwargs)[0] self.assertEquals(g.name, name) self.assertEquals(g.mbox, mbox) @@ -237,9 +239,9 @@ def test_group_from_agent_string(self): ot = "Group" name = "the group" mbox = "mailto:the.group@example.com" - members = [{"name":"agent1","mbox":"mailto:agent1@example.com"}, - {"name":"agent2","mbox":"mailto:agent2@example.com"}] - kwargs = {"objectType":ot, "name":name, "mbox":mbox,"member":members} + members = [{"name": "agent1", "mbox": "mailto:agent1@example.com"}, + {"name": "agent2", "mbox": "mailto:agent2@example.com"}] + kwargs = {"objectType": ot, "name": name, "mbox": mbox, "member": members} g = Agent.objects.retrieve_or_create(**kwargs)[0] self.assertEquals(g.name, name) self.assertEquals(g.mbox, mbox) @@ -252,7 +254,7 @@ def test_agent_format(self): ot_s = "Agent" name_s = "superman" mbox_s = "mailto:superman@example.com" - kwargs_s = {"objectType":ot_s,"name":name_s,"mbox":mbox_s} + kwargs_s = {"objectType": ot_s, "name": name_s, "mbox": mbox_s} clark, created = Agent.objects.retrieve_or_create(**kwargs_s) self.assertTrue(created) clark.save() @@ -273,7 +275,7 @@ def test_agent_format(self): ot_ww = "Agent" name_ww = "wonder woman" mbox_sha1sum_ww = hashlib.sha1("mailto:wonderwoman@example.com").hexdigest() - kwargs_ww = {"objectType":ot_ww,"name":name_ww,"mbox_sha1sum":mbox_sha1sum_ww} + kwargs_ww = {"objectType": ot_ww, "name": name_ww, "mbox_sha1sum": mbox_sha1sum_ww} diana, created = Agent.objects.retrieve_or_create(**kwargs_ww) self.assertTrue(created) diana.save() @@ -295,7 +297,7 @@ def test_agent_format(self): ot_b = "Agent" name_b = "batman" openid_b = "id:batman" - kwargs_b = {"objectType":ot_b,"name":name_b,"openid":openid_b} + kwargs_b = {"objectType": ot_b, "name": name_b, "openid": openid_b} bruce, created = Agent.objects.retrieve_or_create(**kwargs_b) self.assertTrue(created) bruce.save() @@ -317,8 +319,8 @@ def test_agent_format(self): ot_f = "Agent" name_f = "the flash" - account_f = {"homePage":"http://ultrasecret.justiceleague.com/accounts/", "name":"theflash"} - kwargs_f = {"objectType":ot_f,"name":name_f,"account":account_f} + account_f = {"homePage": "http://ultrasecret.justiceleague.com/accounts/", "name": "theflash"} + kwargs_f = {"objectType": ot_f, "name": name_f, "account": account_f} barry, created = Agent.objects.retrieve_or_create(**kwargs_f) self.assertTrue(created) barry.save() @@ -345,7 +347,7 @@ def test_agent_format(self): ot_j = "Group" name_j = "Justice League" mbox_j = "mailto:justiceleague@example.com" - kwargs_j = {"objectType":ot_j,"name":name_j,"mbox":mbox_j, "member":[kwargs_s,kwargs_ww,kwargs_f,kwargs_b]} + kwargs_j = {"objectType": ot_j, "name": name_j, "mbox": mbox_j, "member": [kwargs_s, kwargs_ww, kwargs_f, kwargs_b]} justiceleague, created = Agent.objects.retrieve_or_create(**kwargs_j) self.assertTrue(created) justiceleague.save() @@ -363,12 +365,12 @@ def test_agent_format(self): self.assertFalse('name' in str(justiceleague_ids), "name was found in agent json") self.assertEquals(justiceleague_ids['mbox'], mbox_j) - badguy_ds = {"objectType":"Agent", "mbox":"mailto:darkseid@example.com", "name":"Darkseid"} - badguy_m = {"objectType":"Agent", "mbox":"mailto:mantis@example.com", "name":"Mantis"} + badguy_ds = {"objectType": "Agent", "mbox": "mailto:darkseid@example.com", "name": "Darkseid"} + badguy_m = {"objectType": "Agent", "mbox": "mailto:mantis@example.com", "name": "Mantis"} ot_bg = "Group" members_bg = [badguy_ds, badguy_m] - kwargs_bg = {"objectType":ot_bg,"member":members_bg} + kwargs_bg = {"objectType": ot_bg, "member": members_bg} badguys, created = Agent.objects.retrieve_or_create(**kwargs_bg) self.assertTrue(created) badguys.save() diff --git a/lrs/tests/AgentProfileTests.py b/lrs/tests/AgentProfileTests.py index 8244c0c2..0ef2ef0e 100644 --- a/lrs/tests/AgentProfileTests.py +++ b/lrs/tests/AgentProfileTests.py @@ -11,6 +11,7 @@ from ..views import agent_profile from adl_lrs.views import register + class AgentProfileTests(TestCase): testagent = '{"mbox":"mailto:test@example.com"}' otheragent = '{"mbox":"mailto:other@example.com"}' @@ -29,27 +30,27 @@ def setUp(self): self.email = "test@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username, 'email': self.email,'password':self.password,'password2':self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) - + form = {'username': self.username, 'email': self.email, 'password': self.password, 'password2': self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) + self.testparams1 = {"profileId": self.testprofileId1, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams1)) - self.testprofile1 = {"test":"put profile 1","obj":{"agent":"test"}} + self.testprofile1 = {"test": "put profile 1", "obj": {"agent": "test"}} self.put1 = self.client.put(path, self.testprofile1, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams2 = {"profileId": self.testprofileId2, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams2)) - self.testprofile2 = {"test":"put profile 2","obj":{"agent":"test"}} + self.testprofile2 = {"test": "put profile 2", "obj": {"agent": "test"}} self.put2 = self.client.put(path, self.testprofile2, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams3 = {"profileId": self.testprofileId3, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams3)) - self.testprofile3 = {"test":"put profile 3","obj":{"agent":"test"}} + self.testprofile3 = {"test": "put profile 3", "obj": {"agent": "test"}} self.put3 = self.client.put(path, self.testprofile3, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.testparams4 = {"profileId": self.otherprofileId1, "agent": self.otheragent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams4)) - self.otherprofile1 = {"test":"put profile 1","obj":{"agent":"other"}} + self.otherprofile1 = {"test": "put profile 1", "obj": {"agent": "other"}} self.put4 = self.client.put(path, self.otherprofile1, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def tearDown(self): @@ -80,12 +81,12 @@ def test_put(self): def test_put_etag_missing_on_change(self): path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/o etag header","obj":{"agent":"test"}} + profile = {"test": "error - trying to put new profile w/o etag header", "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 409) self.assertIn('If-Match and If-None-Match headers were missing', response.content) - + r = self.client.get(reverse(agent_profile), self.testparams1, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) robj = ast.literal_eval(r.content) @@ -94,7 +95,7 @@ def test_put_etag_missing_on_change(self): def test_put_etag_right_on_change(self): path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"good - trying to put new profile w/ etag header","obj":{"agent":"test"}} + profile = {"test": "good - trying to put new profile w/ etag header", "obj": {"agent": "test"}} thehash = '"%s"' % hashlib.sha1('%s' % self.testprofile1).hexdigest() response = self.client.put(path, profile, content_type=self.content_type, If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -108,7 +109,7 @@ def test_put_etag_right_on_change(self): def test_put_etag_wrong_on_change(self): path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/ wrong etag value","obj":{"agent":"test"}} + profile = {"test": "error - trying to put new profile w/ wrong etag value", "obj": {"agent": "test"}} thehash = '"%s"' % hashlib.sha1('%s' % 'wrong hash').hexdigest() response = self.client.put(path, profile, content_type=self.content_type, If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 412) @@ -123,7 +124,7 @@ def test_put_etag_wrong_on_change(self): def test_put_etag_if_none_match_good(self): params = {"profileId": 'http://etag.nomatch.good', "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - profile = {"test":"good - trying to put new profile w/ if none match etag header","obj":{"agent":"test"}} + profile = {"test": "good - trying to put new profile w/ if none match etag header", "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -139,7 +140,7 @@ def test_put_etag_if_none_match_good(self): def test_put_etag_if_none_match_bad(self): path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(self.testparams1)) - profile = {"test":"error - trying to put new profile w/ if none match etag but one exists","obj":{"agent":"test"}} + profile = {"test": "error - trying to put new profile w/ if none match etag but one exists", "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, If_None_Match='*', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 412) @@ -155,16 +156,16 @@ def test_get_invalid_agent_structure(self): r = self.client.get(reverse(agent_profile), {"profileId": self.testprofileId1, "agent": "wrong"}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertEqual(r.content, "agent param for agent profile is not valid") - + def test_get_invalid_agent(self): - r = self.client.get(reverse(agent_profile), {"profileId": self.testprofileId1, "agent": {"mbox":"foo"}}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + r = self.client.get(reverse(agent_profile), {"profileId": self.testprofileId1, "agent": {"mbox": "foo"}}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertEqual(r.content, "agent param for agent profile is not valid") def test_get(self): r = self.client.get(reverse(agent_profile), self.testparams1, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - + robj = ast.literal_eval(r.content) self.assertEqual(robj['test'], self.testprofile1['test']) self.assertEqual(robj['obj']['agent'], self.testprofile1['obj']['agent']) @@ -176,7 +177,7 @@ def test_get(self): self.assertEqual(robj2['test'], self.testprofile2['test']) self.assertEqual(robj2['obj']['agent'], self.testprofile2['obj']['agent']) self.assertEqual(r2['etag'], '"%s"' % hashlib.sha1('%s' % self.testprofile2).hexdigest()) - + r3 = self.client.get(reverse(agent_profile), self.testparams3, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r3.status_code, 200) robj3 = ast.literal_eval(r3.content) @@ -195,7 +196,7 @@ def test_get_no_params(self): r = self.client.get(reverse(agent_profile), Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertIn('agent parameter missing', r.content) - + def test_get_no_agent(self): params = {"profileId": self.testprofileId1} r = self.client.get(reverse(agent_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -206,12 +207,12 @@ def test_get_no_profileId(self): params = {"agent": self.testagent} r = self.client.get(reverse(agent_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - + def test_delete(self): prof_id = "http://deleteme" params = {"profileId": prof_id, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - profile = {"test":"delete profile","obj":{"agent":"test"}} + profile = {"test": "delete profile", "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -233,7 +234,7 @@ def test_get_agent_since(self): params = {"profileId": prof_id, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - profile = {"test1":"agent profile since time: %s" % updated,"obj":{"agent":"test"}} + profile = {"test1": "agent profile since time: %s" % updated, "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -244,7 +245,7 @@ def test_get_agent_since(self): self.assertEqual(robj['obj']['agent'], profile['obj']['agent']) since = "2012-07-01T12:00:00Z" - params2 = {"agent": self.testagent, "since":since} + params2 = {"agent": self.testagent, "since": since} r2 = self.client.get(reverse(agent_profile), params2, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertNotIn(prof_id, r2.content) @@ -256,7 +257,7 @@ def test_get_agent_since_tz(self): params = {"profileId": prof_id, "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - profile = {"test2":"agent profile since time: %s" % updated,"obj":{"agent":"test"}} + profile = {"test2": "agent profile since time: %s" % updated, "obj": {"agent": "test"}} response = self.client.put(path, profile, content_type=self.content_type, updated=updated, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) r = self.client.get(reverse(agent_profile), params, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -266,12 +267,12 @@ def test_get_agent_since_tz(self): self.assertEqual(robj['obj']['agent'], profile['obj']['agent']) prof_id2 = "http://newprofile/timezone" - updated2 = "2012-07-01T08:30:00-04:00" + updated2 = "2012-07-01T08:30:00-04:00" params2 = {"profileId": prof_id2, "agent": self.testagent} path2 = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params2)) - profile2 = {"test3":"agent profile since time: %s" % updated2,"obj":{"agent":"test"}} + profile2 = {"test3": "agent profile since time: %s" % updated2, "obj": {"agent": "test"}} response = self.client.put(path2, profile2, content_type=self.content_type, updated=updated2, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) @@ -283,7 +284,7 @@ def test_get_agent_since_tz(self): since = "2012-07-01T12:00:00Z" - par = {"agent": self.testagent, "since":since} + par = {"agent": self.testagent, "since": since} r = self.client.get(reverse(agent_profile), par, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertNotIn(prof_id, r.content) @@ -294,8 +295,8 @@ def test_get_agent_since_tz(self): def test_post_put_delete(self): prof_id = "http://deleteme.too" - path = '%s?%s' % (reverse(agent_profile), urllib.urlencode({"method":"PUT"})) - content = {"test":"delete profile","obj":{"actor":"test", "testcase":"ie cors post for put and delete"}} + path = '%s?%s' % (reverse(agent_profile), urllib.urlencode({"method": "PUT"})) + content = {"test": "delete profile", "obj": {"actor": "test", "testcase": "ie cors post for put and delete"}} thedata = "profileId=%s&agent=%s&content=%s&Authorization=%s&Content-Type=application/json&X-Experience-API-Version=1.0.0" % (prof_id, self.testagent, content, self.auth) response = self.client.post(path, thedata, content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 204) @@ -304,9 +305,9 @@ def test_post_put_delete(self): import ast c = ast.literal_eval(r.content) self.assertEqual(c['test'], content['test']) - + thedata = "profileId=%s&agent=%s&Authorization=%s&X-Experience-API-Version=1.0" % (prof_id, self.testagent, self.auth) - path = '%s?%s' % (reverse(agent_profile), urllib.urlencode({"method":"DELETE"})) + path = '%s?%s' % (reverse(agent_profile), urllib.urlencode({"method": "DELETE"})) r = self.client.post(path, thedata, content_type="application/x-www-form-urlencoded", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) @@ -317,13 +318,13 @@ def test_group_as_agent(self): ot = "Group" name = "the group APT" mbox = "mailto:the.groupAPT@example.com" - members = [{"name":"agentA","mbox":"mailto:agentA@example.com"}, - {"name":"agentB","mbox":"mailto:agentB@example.com"}] - testagent = json.dumps({"objectType":ot, "name":name, "mbox":mbox,"member":members}) + members = [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, + {"name": "agentB", "mbox": "mailto:agentB@example.com"}] + testagent = json.dumps({"objectType": ot, "name": name, "mbox": mbox, "member": members}) testprofileId = "http://profile.test.id/group.as.agent/" testparams1 = {"profileId": testprofileId, "agent": testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(testparams1)) - testprofile = {"test":"put profile - group as agent","obj":{"agent":"group"}} + testprofile = {"test": "put profile - group as agent", "obj": {"agent": "group"}} put1 = self.client.put(path, testprofile, content_type=self.content_type, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put1.status_code, 204) @@ -339,24 +340,24 @@ def test_group_as_agent(self): def test_post_new_profile(self): params = {"profileId": "prof:test_post_new_profile", "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - prof = {"test":"post new profile","obj":{"agent":"mailto:test@example.com"}} - - post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + prof = {"test": "post new profile", "obj": {"agent": "mailto:test@example.com"}} + + post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(ast.literal_eval(get.content), prof) self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) - self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) def test_post_blank_profile(self): params = {"profileId": "prof:test_post_new_profile", "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) prof = "" - - post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + + post = self.client.post(path, prof, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(post.status_code, 400) self.assertEqual(post.content, 'No body in request') @@ -364,10 +365,10 @@ def test_post_blank_profile(self): # params = {"profileId": "prof:test_post_update_profile", "agent": self.testagent} # path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) # prof = {"test":"post updated profile","obj":{"agent":"mailto:test@example.com"}} - + # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 204) - + # get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(get.status_code, 200) # self.assertEqual(json.loads(get.content), prof) @@ -380,7 +381,7 @@ def test_post_blank_profile(self): # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 409) - + # post = self.client.post(path, json.dumps(prof), content_type="application/json",If_Match=etag, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 204) @@ -398,25 +399,25 @@ def test_post_blank_profile(self): def test_post_and_put_profile(self): params = {"profileId": "prof:test_post_and_put_profile", "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - prof = {"test":"post and put profile","obj":{"agent":"mailto:test@example.com"}} - - post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + prof = {"test": "post and put profile", "obj": {"agent": "mailto:test@example.com"}} + + post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(json.loads(get.content), prof) self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) params = {"profileId": "prof:test_post_and_put_profile", "agent": self.testagent} path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) - prof = {"wipe":"new data"} + prof = {"wipe": "new data"} thehash = get.get('etag') - - put = self.client.put(path, json.dumps(prof), content_type="application/json", If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + put = self.client.put(path, json.dumps(prof), content_type="application/json", If_Match=thehash, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put.status_code, 204) - - get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + + get = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) self.assertEqual(json.loads(get.content), prof) etag = '"%s"' % hashlib.sha1(get.content).hexdigest() @@ -425,7 +426,7 @@ def test_post_and_put_profile(self): # params = {"profileId": "prof:test_post_and_put_profile", "agent": self.testagent} # path = '%s?%s' % (reverse(agent_profile), urllib.urlencode(params)) # prof = {"test":"post updated profile","obj":{"agent":"mailto:test@example.com", "new":"thing"}, "added":"yes"} - + # post = self.client.post(path, json.dumps(prof), content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) # self.assertEqual(post.status_code, 409) @@ -442,4 +443,4 @@ def test_post_and_put_profile(self): # self.assertEqual(ret_json['obj']['new'], prof['obj']['new']) # self.assertEqual(get.get('etag'), '"%s"' % hashlib.sha1(get.content).hexdigest()) - self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) \ No newline at end of file + self.client.delete(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) diff --git a/lrs/tests/AgentTests.py b/lrs/tests/AgentTests.py index feb7a8aa..673f189e 100644 --- a/lrs/tests/AgentTests.py +++ b/lrs/tests/AgentTests.py @@ -9,7 +9,9 @@ from ..models import Agent from adl_lrs.views import register + class AgentTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -19,19 +21,19 @@ def setUp(self): self.password = "test" self.email = "test@example.com" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username,'password':self.password,'password2':self.password, 'email':self.email} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {'username': self.username, 'password': self.password, 'password2': self.password, 'email': self.email} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) def test_get_no_agents(self): - agent = json.dumps({"name":"me","mbox":"mailto:me@example.com"}) - response = self.client.get(reverse(agents), {'agent':agent}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + agent = json.dumps({"name": "me", "mbox": "mailto:me@example.com"}) + response = self.client.get(reverse(agents), {'agent': agent}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 404) self.assertEqual(response.content, "Error with Agent. The agent partial did not match any agents on record") def test_get(self): - a = json.dumps({"name":"me","mbox":"mailto:me@example.com"}) + a = json.dumps({"name": "me", "mbox": "mailto:me@example.com"}) Agent.objects.retrieve_or_create(**json.loads(a)) - response = self.client.get(reverse(agents), {'agent':a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.get(reverse(agents), {'agent': a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) r_data = json.loads(response.content) self.assertTrue(isinstance(r_data['mbox'], list)) self.assertTrue(isinstance(r_data['name'], list)) @@ -41,23 +43,23 @@ def test_get(self): self.assertIn('content-length', response._headers) def test_get_no_existing_agent(self): - a = json.dumps({"mbox":"mailto:fail@fail.com"}) - response = self.client.get(reverse(agents), {'agent':a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + a = json.dumps({"mbox": "mailto:fail@fail.com"}) + response = self.client.get(reverse(agents), {'agent': a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.content, 'Error with Agent. The agent partial did not match any agents on record') self.assertEqual(response.status_code, 404) def test_head(self): - a = json.dumps({"name":"me","mbox":"mailto:me@example.com"}) + a = json.dumps({"name": "me", "mbox": "mailto:me@example.com"}) Agent.objects.retrieve_or_create(**json.loads(a)) - response = self.client.head(reverse(agents), {'agent':a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.head(reverse(agents), {'agent': a}, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.content, '') self.assertIn('content-length', response._headers) def test_get_no_agent(self): response = self.client.get(reverse(agents), Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) - + def test_post(self): - agent = json.dumps({"name":"me","mbox":"mailto:me@example.com"}) - response = self.client.post(reverse(agents), {'agent':agent},content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(response.status_code, 405) \ No newline at end of file + agent = json.dumps({"name": "me", "mbox": "mailto:me@example.com"}) + response = self.client.post(reverse(agents), {'agent': agent}, content_type='application/x-www-form-urlencoded', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 405) diff --git a/lrs/tests/AttachmentAndSignedTests.py b/lrs/tests/AttachmentAndSignedTests.py index 2f3475b0..006703ea 100644 --- a/lrs/tests/AttachmentAndSignedTests.py +++ b/lrs/tests/AttachmentAndSignedTests.py @@ -22,7 +22,9 @@ from ..utils.jws import JWS from adl_lrs.views import register + class AttachmentAndSignedTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -32,19 +34,19 @@ def setUp(self): self.email = "test1@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.username2 = "tester2" self.email2 = "test2@tester.com" self.password2 = "test2" self.auth2 = "Basic %s" % base64.b64encode("%s:%s" % (self.username2, self.password2)) - form2 = {"username":self.username2, "email":self.email2,"password":self.password2,"password2":self.password2} - self.client.post(reverse(register),form2, X_Experience_API_Version=settings.XAPI_VERSION) + form2 = {"username": self.username2, "email": self.email2, "password": self.password2, "password2": self.password2} + self.client.post(reverse(register), form2, X_Experience_API_Version=settings.XAPI_VERSION) self.firstTime = str(datetime.utcnow().replace(tzinfo=utc).isoformat()) self.guid1 = str(uuid.uuid1()) - + def tearDown(self): attach_folder_path = os.path.join(settings.MEDIA_ROOT, "attachment_payloads") for the_file in os.listdir(attach_folder_path): @@ -53,23 +55,24 @@ def tearDown(self): os.unlink(file_path) except Exception, e: raise e + def test_multipart(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') textdata.add_header('X-Experience-API-Hash', txtsha) @@ -77,52 +80,52 @@ def test_multipart(self): message.attach(textdata) r = self.client.post(reverse(statements), message.as_string(), - content_type='multipart/mixed; boundary=myboundary', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type='multipart/mixed; boundary=myboundary', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) def test_multiple_stmt_multipart(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test2", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]} - ] + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test2", + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]} + ] message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt[0]['attachments'][0]["sha2"] = str(txtsha) - + txt2 = u"This is second attachment." txtsha2 = hashlib.sha256(txt2).hexdigest() stmt[1]['attachments'][0]['sha2'] = str(txtsha2) stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') textdata2 = MIMEText(txt2, 'plain', 'utf-8') - + textdata.add_header('X-Experience-API-Hash', txtsha) textdata2.add_header('X-Experience-API-Hash', txtsha2) message.attach(stmtdata) message.attach(textdata) message.attach(textdata2) - + r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) returned_ids = json.loads(r.content) stmt_id1 = returned_ids[0] @@ -134,49 +137,48 @@ def test_multiple_stmt_multipart(self): self.assertEqual(len(stmts), 2) self.assertEqual(len(attachments), 2) - self.assertEqual(saved_stmt1.stmt_attachments.all()[0].payload.read(), base64.b64encode("howdy.. this is a text attachment")) self.assertEqual(saved_stmt2.stmt_attachments.all()[0].payload.read(), base64.b64encode("This is second attachment.")) def test_multiple_stmt_multipart_same_attachment(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} - ] + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} + ] message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() - stmt[0]['attachments'][0]["sha2"] = str(txtsha) + stmt[0]['attachments'][0]["sha2"] = str(txtsha) stmt[1]['attachments'][0]['sha2'] = str(txtsha) stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') - + textdata.add_header('X-Experience-API-Hash', txtsha) message.attach(stmtdata) message.attach(textdata) - + r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - + returned_ids = json.loads(r.content) stmt_id1 = returned_ids[0] stmt_id2 = returned_ids[1] @@ -191,42 +193,42 @@ def test_multiple_stmt_multipart_same_attachment(self): self.assertEqual(saved_stmt2.stmt_attachments.all()[0].payload.read(), base64.b64encode("howdy.. this is a text attachment")) def test_multiple_stmt_multipart_one_attachment_one_fileurl(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://my/file/url"}]}] + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]}] message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() - stmt[0]['attachments'][0]["sha2"] = str(txtsha) + stmt[0]['attachments'][0]["sha2"] = str(txtsha) stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') - + textdata.add_header('X-Experience-API-Hash', txtsha) message.attach(stmtdata) message.attach(textdata) - + r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - + returned_ids = json.loads(r.content) stmt_id1 = returned_ids[0] stmt_id2 = returned_ids[1] @@ -241,45 +243,45 @@ def test_multiple_stmt_multipart_one_attachment_one_fileurl(self): self.assertEqual(saved_stmt2.stmt_attachments.all()[0].fileUrl, "http://my/file/url") def test_multiple_stmt_multipart_multiple_attachments_each(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test11", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)11"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)11"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, {"usageType": "http://example.com/attachment-usage/test12", - "display": {"en-US": "A test attachment12"}, - "description": {"en-US": "A test attachment (description)12"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test21", - "display": {"en-US": "A test attachment21"}, - "description": {"en-US": "A test attachment (description)21"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}, - {"usageType": "http://example.com/attachment-usage/test22", - "display": {"en-US": "A test attachment22"}, - "description": {"en-US": "A test attachment (description)22"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]} - ] + "display": {"en-US": "A test attachment12"}, + "description": {"en-US": "A test attachment (description)12"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test21", + "display": {"en-US": "A test attachment21"}, + "description": {"en-US": "A test attachment (description)21"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}, + {"usageType": "http://example.com/attachment-usage/test22", + "display": {"en-US": "A test attachment22"}, + "description": {"en-US": "A test attachment (description)22"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]} + ] message = MIMEMultipart(boundary="myboundary") txt11 = u"This is a text attachment11" txtsha11 = hashlib.sha256(txt11).hexdigest() stmt[0]['attachments'][0]["sha2"] = str(txtsha11) - + txt12 = u"This is a text attachment12" txtsha12 = hashlib.sha256(txt12).hexdigest() stmt[0]['attachments'][1]['sha2'] = str(txtsha12) @@ -297,7 +299,7 @@ def test_multiple_stmt_multipart_multiple_attachments_each(self): textdata12 = MIMEText(txt12, 'plain', 'utf-8') textdata21 = MIMEText(txt21, 'plain', 'utf-8') textdata22 = MIMEText(txt22, 'plain', 'utf-8') - + textdata11.add_header('X-Experience-API-Hash', txtsha11) textdata12.add_header('X-Experience-API-Hash', txtsha12) textdata21.add_header('X-Experience-API-Hash', txtsha21) @@ -308,11 +310,11 @@ def test_multiple_stmt_multipart_multiple_attachments_each(self): message.attach(textdata12) message.attach(textdata21) message.attach(textdata22) - + r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - + returned_ids = json.loads(r.content) stmt_id1 = returned_ids[0] stmt_id2 = returned_ids[1] @@ -324,24 +326,24 @@ def test_multiple_stmt_multipart_multiple_attachments_each(self): self.assertEqual(len(stmts), 2) self.assertEqual(len(attachments), 4) - stmt1_contents = ["This is a text attachment11","This is a text attachment12"] - stmt2_contents = ["This is a text attachment21","This is a text attachment22"] + stmt1_contents = ["This is a text attachment11", "This is a text attachment12"] + stmt2_contents = ["This is a text attachment21", "This is a text attachment22"] self.assertIn(base64.b64decode(saved_stmt1.stmt_attachments.all()[0].payload.read()), stmt1_contents) self.assertIn(base64.b64decode(saved_stmt1.stmt_attachments.all()[1].payload.read()), stmt1_contents) self.assertIn(base64.b64decode(saved_stmt2.stmt_attachments.all()[0].payload.read()), stmt2_contents) self.assertIn(base64.b64decode(saved_stmt2.stmt_attachments.all()[1].payload.read()), stmt2_contents) def test_multipart_wrong_sha(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" @@ -349,7 +351,7 @@ def test_multipart_wrong_sha(self): wrongtxt = u"blahblahblah this is wrong" wrongsha = hashlib.sha256(wrongtxt).hexdigest() stmt['attachments'][0]["sha2"] = str(wrongsha) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') textdata.add_header('X-Experience-API-Hash', txtsha) @@ -357,34 +359,34 @@ def test_multipart_wrong_sha(self): message.attach(textdata) r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertIn("Could not find attachment payload with sha", r.content) def test_multiple_multipart(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "sha2":""}]} + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + txt2 = u"this is second attachment" txtsha2 = hashlib.sha256(txt2).hexdigest() stmt['attachments'][1]["sha2"] = str(txtsha2) @@ -399,32 +401,32 @@ def test_multiple_multipart(self): message.attach(textdata2) r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) def test_multiple_multipart_wrong(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "sha2":""}]} + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + txt2 = u"this is second attachment" txtsha2 = hashlib.sha256(txt2).hexdigest() wrongtxt = u"this is some wrong text" @@ -441,70 +443,69 @@ def test_multiple_multipart_wrong(self): message.attach(textdata2) r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertIn("Could not find attachment payload with sha", r.content) def test_app_json_multipart(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - def test_app_json_multipart_wrong_fields(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "bad": "foo", - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "bad": "foo", + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Invalid field(s) found in Attachment - bad') def test_app_json_multipart_one_fileURL(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]}, - {"actor":{"mbox":"mailto:tom1@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads1"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - ] - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]}, + {"actor": {"mbox": "mailto:tom1@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads1"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + ] + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) returned_ids = json.loads(response.content) @@ -522,131 +523,131 @@ def test_app_json_multipart_one_fileURL(self): def tyler_attachment_snafu(self): stmt = { - "actor": { - "mbox": "mailto:tyler.mulligan.ctr@adlnet.gov", - "name": "Tyler", - "objectType": "Agent" - }, - "verb": { - "id": "http://example.com/verbs/answered", - "display": { - "en-US": "answered" + "actor": { + "mbox": "mailto:tyler.mulligan.ctr@adlnet.gov", + "name": "Tyler", + "objectType": "Agent" + }, + "verb": { + "id": "http://example.com/verbs/answered", + "display": { + "en-US": "answered" + } + }, + "object": { + "id": "http://adlnet.gov/expapi/activities/example", + "definition": { + "name": { + "en-US": "Example Activity" + }, + "description": { + "en-US": "Example activity description" } }, - "object": { - "id": "http://adlnet.gov/expapi/activities/example", - "definition": { - "name": { - "en-US": "Example Activity" - }, - "description": { - "en-US": "Example activity description" - } + "objectType": "Activity" + }, + "attachments": [ + { + "usageType": "http://cool.com/cool/cool", + "display": { + "en-US": "My attachment" }, - "objectType": "Activity" - }, - "attachments": [ - { - "usageType": "http://cool.com/cool/cool", - "display": { - "en-US": "My attachment" - }, - "contentType": "image/jpeg", - "length": 12345, - "sha2": "f522a694d7fc5c38d7c604f63c87c9f74dcd002e" - } - ] - } + "contentType": "image/jpeg", + "length": 12345, + "sha2": "f522a694d7fc5c38d7c604f63c87c9f74dcd002e" + } + ] + } response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Missing X-Experience-API-Hash field in header") def test_app_json_multipart_no_fileUrl(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27}]} - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27}]} + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('Attachment sha2 is required when no fileUrl is given', response.content) def test_multiple_app_json_multipart_no_fileUrl(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://some/url"}, + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://some/url"}, {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "fileUrl":""}]} + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "fileUrl": ""}]} response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('Attachments fileUrl with value was not a valid IRI', response.content) def test_multipart_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') textdata.add_header('X-Experience-API-Hash', txtsha) message.attach(stmtdata) message.attach(textdata) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.put(path, message.as_string(), content_type="multipart/mixed", Authorization=self.auth, - X_Experience_API_Version=settings.XAPI_VERSION) + X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) def test_multipart_wrong_sha_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" @@ -654,46 +655,46 @@ def test_multipart_wrong_sha_put(self): wrongtxt = u"blahblahblah this is wrong" wrongsha = hashlib.sha256(wrongtxt).hexdigest() stmt['attachments'][0]["sha2"] = str(wrongsha) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) textdata = MIMEText(txt, 'plain', 'utf-8') textdata.add_header('X-Experience-API-Hash', txtsha) message.attach(stmtdata) message.attach(textdata) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.put(path, message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertIn("Could not find attachment payload with sha", r.content) def test_multiple_multipart_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "sha2":""}]} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + txt2 = u"this is second attachment" txtsha2 = hashlib.sha256(txt2).hexdigest() stmt['attachments'][1]["sha2"] = str(txtsha2) @@ -707,37 +708,37 @@ def test_multiple_multipart_put(self): message.attach(textdata) message.attach(textdata2) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - r = self.client.put(path, message.as_string(), content_type="multipart/mixed" , Authorization=self.auth, - X_Experience_API_Version=settings.XAPI_VERSION) + r = self.client.put(path, message.as_string(), content_type="multipart/mixed", Authorization=self.auth, + X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 204) def test_multiple_multipart_put_wrong_attachment(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "sha2":""}]} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt = u"howdy.. this is a text attachment" txtsha = hashlib.sha256(txt).hexdigest() stmt['attachments'][0]["sha2"] = str(txtsha) - + txt2 = u"this is second attachment" txtsha2 = hashlib.sha256(txt2).hexdigest() wrongtxt = u"this is some wrong text" @@ -753,139 +754,137 @@ def test_multiple_multipart_put_wrong_attachment(self): message.attach(textdata) message.attach(textdata2) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.put(path, message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertIn("Could not find attachment payload with sha", r.content) def test_app_json_multipart_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - - param = {"statementId":stmt_id} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + + param = {"statementId": stmt_id} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) def test_app_json_multipart_not_array(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": "wrong"} - - param = {"statementId":stmt_id} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": "wrong"} + + param = {"statementId": stmt_id} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Attachments is not a properly formatted array') def test_app_json_multipart_no_fileUrl_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27}]} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27}]} - param = {"statementId":stmt_id} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": stmt_id} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) - self.assertIn( 'Attachment sha2 is required when no fileUrl is given', response.content) + self.assertIn('Attachment sha2 is required when no fileUrl is given', response.content) def test_app_json_invalid_fileUrl(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "blah"}]} - - param = {"statementId":stmt_id} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "blah"}]} + + param = {"statementId": stmt_id} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('Attachments fileUrl with value blah was not a valid IRI', response.content) - - def test_multiple_app_json_multipart_no_fileUrl_put(self): stmt_id = str(uuid.uuid1()) - stmt = {"id":stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://some/url"}, - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment2"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 28, - "fileUrl":""}]} - - param = {"statementId":stmt_id} + stmt = {"id": stmt_id, + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://some/url"}, + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment2"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 28, + "fileUrl": ""}]} + + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('Attachments fileUrl with value was not a valid IRI', response.content) def test_multipart_non_text_file(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test picture"}, - "description": {"en-US": "A test picture (description)"}, - "contentType": "image/png", - "length": 27, - "sha2":""}]} + "display": {"en-US": "A test picture"}, + "description": {"en-US": "A test picture (description)"}, + "contentType": "image/png", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") - img_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'adl_lrs','static','img', 'example.png')) + img_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'adl_lrs', 'static', 'img', 'example.png')) img = open(img_path, 'rb') img_data = img.read() img.close() imgsha = hashlib.sha256(img_data).hexdigest() stmt['attachments'][0]["sha2"] = str(imgsha) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) imgdata = MIMEImage(img_data) @@ -894,11 +893,11 @@ def test_multipart_non_text_file(self): message.attach(imgdata) r = self.client.post(reverse(statements), message.as_string(), - content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - - param= {"attachments":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + + param = {"attachments": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'multipart/mixed; boundary=======ADL_LRS======') @@ -909,7 +908,7 @@ def test_multipart_non_text_file(self): parts = [] for part in msg.walk(): parts.append(part) - + self.assertEqual(parts[1]['Content-Type'], "application/json") self.assertTrue(isinstance(json.loads(parts[1].get_payload()), dict)) # MIMEImage automatically b64 encodes data to be transfered @@ -924,23 +923,23 @@ def test_example_signed_statement(self): payload = base64.urlsafe_b64decode(fixpad(encodedpayload)) stmt = json.loads(exstmt) - + jwso = JWS(header, payload) thejws = jwso.create(privatekey) - self.assertEqual(thejws,sig) + self.assertEqual(thejws, sig) message = MIMEMultipart() stmt['attachments'][0]["sha2"] = jwso.sha2(thejws) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) jwsdata = MIMEApplication(thejws, _subtype="octet-stream") jwsdata.add_header('X-Experience-API-Hash', jwso.sha2(thejws)) message.attach(stmtdata) message.attach(jwsdata) - + r = self.client.post(reverse(statements), message.as_string(), - content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) def test_example_signed_statement_bad(self): @@ -949,23 +948,23 @@ def test_example_signed_statement_bad(self): stmt = json.loads(exstmt) stmt['actor'] = {"mbox": "mailto:sneaky@example.com", "name": "Cheater", "objectType": "Agent"} - + jwso = JWS(header, payload) thejws = jwso.create(privatekey) - self.assertEqual(thejws,sig) + self.assertEqual(thejws, sig) message = MIMEMultipart() stmt['attachments'][0]["sha2"] = jwso.sha2(thejws) - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) jwsdata = MIMEApplication(thejws, _subtype="octet-stream") jwsdata.add_header('X-Experience-API-Hash', jwso.sha2(thejws)) message.attach(stmtdata) message.attach(jwsdata) - + r = self.client.post(reverse(statements), message.as_string(), - content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 400) self.assertEqual(r.content, 'The JSON Web Signature is not valid') @@ -975,31 +974,33 @@ def test_example_signed_statements(self): stmt1 = json.loads(exstmt) - stmt2 = {"actor": {"mbox" : "mailto:otherguy@example.com"}, - "verb" : {"id":"http://verbs.com/did"}, - "object" : {"id":"act:stuff"} } + stmt2 = {"actor": {"mbox": "mailto:otherguy@example.com"}, + "verb": {"id": "http://verbs.com/did"}, + "object": {"id": "act:stuff"}} stmt = [stmt1, stmt2] - + jwso = JWS(header, payload) thejws = jwso.create(privatekey) - self.assertEqual(thejws,sig) + self.assertEqual(thejws, sig) message = MIMEMultipart() stmt1['attachments'][0]["sha2"] = jwso.sha2() - + stmtdata = MIMEApplication(json.dumps(stmt), _subtype="json", _encoder=json.JSONEncoder) jwsdata = MIMEApplication(thejws, _subtype="octet-stream") jwsdata.add_header('X-Experience-API-Hash', jwso.sha2(thejws)) message.attach(stmtdata) message.attach(jwsdata) - + r = self.client.post(reverse(statements), message.as_string(), - content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type='multipart/mixed', Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) -fixpad = lambda s: s if len(s) % 4 == 0 else s + '=' * (4 - (len(s) % 4)) + +def fixpad(s): + return s if len(s) % 4 == 0 else s + '=' * (4 - (len(s) % 4)) exstmt = """{ "version": "1.0.0", @@ -1059,4 +1060,4 @@ def test_example_signed_statements(self): lBRK8g7ZncekbGW3aRLVGVOxClnLLTzwOlamBKOUm8V6XxsMHQ6TE2D+fKJoNUY1 2HGpk+FWwy2D1hRGuoUCQAXfaLSxtaWdPtlZTPVueF7ZikQDsVg+vtTFgpuHloR2 6EVc1RbHHZm32yvGDY8IkcoMfJQqLONDdLfS/05yoNU= ------END RSA PRIVATE KEY-----""" \ No newline at end of file +-----END RSA PRIVATE KEY-----""" diff --git a/lrs/tests/AuthTests.py b/lrs/tests/AuthTests.py index f41049f5..6b8939fe 100644 --- a/lrs/tests/AuthTests.py +++ b/lrs/tests/AuthTests.py @@ -15,8 +15,10 @@ from ..utils import retrieve_statement from adl_lrs.views import register + class AuthTests(TestCase): # Want to test no auth, so have to disable both auths + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -27,21 +29,21 @@ def setUp(self): if settings.OAUTH_ENABLED: settings.OAUTH_ENABLED = False - - self.auth = "Basic %s" % base64.b64encode("%s:%s" % ('','')) + + self.auth = "Basic %s" % base64.b64encode("%s:%s" % ('', '')) self.guid1 = str(uuid.uuid1()) self.guid2 = str(uuid.uuid1()) - self.guid3 = str(uuid.uuid1()) + self.guid3 = str(uuid.uuid1()) self.guid4 = str(uuid.uuid1()) self.guid5 = str(uuid.uuid1()) self.guid6 = str(uuid.uuid1()) self.guid7 = str(uuid.uuid1()) self.guid8 = str(uuid.uuid1()) - self.guid9 = str(uuid.uuid1()) + self.guid9 = str(uuid.uuid1()) self.guid10 = str(uuid.uuid1()) self.cguid1 = str(uuid.uuid1()) - self.cguid2 = str(uuid.uuid1()) + self.cguid2 = str(uuid.uuid1()) self.cguid3 = str(uuid.uuid1()) self.cguid4 = str(uuid.uuid1()) self.cguid5 = str(uuid.uuid1()) @@ -49,181 +51,175 @@ def setUp(self): self.cguid7 = str(uuid.uuid1()) self.cguid8 = str(uuid.uuid1()) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) exist_stmt_response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(exist_stmt_response.status_code, 200) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(exist_stmt_response.status_code, 200) self.exist_stmt_id = json.loads(exist_stmt_response.content)[0] self.firstTime = str(datetime.utcnow().replace(tzinfo=utc).isoformat()) - self.existStmt1 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": self.cguid1, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}}) - - self.existStmt2 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@t.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname3", "en-GB": "altname"}, - "description": {"en-US":"testdesc3","en-GB":"altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key11": "value11", "ext:key22": "value22","ext:key33": "value33"}}}, - "result": {"score":{"scaled":.75}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid2, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey11": "cval11", - "ext:ckey22": "cval22"}}}) - - self.existStmt3 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:act:foogals", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key111": "value111", "ext:key222": "value222","ext:key333": "value333"}}}, - "result": {"score":{"scaled":.79}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid3, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US", - "instructor":{"objectType": "Agent", "name":"bob", "mbox":"mailto:bob@bob.com"}, - "extensions":{"ext:ckey111": "cval111","ext:ckey222": "cval222"}}}) - - self.existStmt4 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogal", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key111": "value111", "ext:key222": "value222","ext:key333": "value333"}}}, - "result": {"score":{"scaled":.79}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid4, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US","instructor":{"name":"bill", "mbox":"mailto:bill@bill.com"}, - "extensions":{"ext:ckey111": "cval111","ext:ckey222": "cval222"}}}) - - self.existStmt5 = json.dumps({"object":{"objectType":"Agent","name":"jon","mbox":"mailto:jon@jon.com"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt6 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity"},"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}}) - - self.existStmt7 = json.dumps({"object": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "verb": {"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt8 = json.dumps({"object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}, - "verb": {"id": "http://example.com/verbs/missed","display": {"en-US":"missed"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt9 = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:sub@sub.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:ss@ss.com"},"verb": {"id":"nested:verb/url/nested"}, - "object": {"objectType":"Activity", "id":"act:testex.com"}, "result":{"completion": True, "success": True, - "response": "kicked"}, "context":{"registration": self.cguid6, - "contextActivities": {"other": {"id": "act:NewActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:k1": "v1", "ext:k2": "v2"}}}}) - - self.existStmt10 = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:ref@ref.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"StatementRef", - "id":str(self.exist_stmt_id)}}) + self.existStmt1 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": self.cguid1, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}}) + + self.existStmt2 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@t.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname3", "en-GB": "altname"}, + "description": {"en-US": "testdesc3", "en-GB": "altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key11": "value11", "ext:key22": "value22", "ext:key33": "value33"}}}, + "result": {"score": {"scaled": .75}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid2, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey11": "cval11", + "ext:ckey22": "cval22"}}}) + + self.existStmt3 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:act:foogals", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key111": "value111", "ext:key222": "value222", "ext:key333": "value333"}}}, + "result": {"score": {"scaled": .79}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid3, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", + "instructor": {"objectType": "Agent", "name": "bob", "mbox": "mailto:bob@bob.com"}, + "extensions": {"ext:ckey111": "cval111", "ext:ckey222": "cval222"}}}) + + self.existStmt4 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogal", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key111": "value111", "ext:key222": "value222", "ext:key333": "value333"}}}, + "result": {"score": {"scaled": .79}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid4, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", "instructor": {"name": "bill", "mbox": "mailto:bill@bill.com"}, + "extensions": {"ext:ckey111": "cval111", "ext:ckey222": "cval222"}}}) + + self.existStmt5 = json.dumps({"object": {"objectType": "Agent", "name": "jon", "mbox": "mailto:jon@jon.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt6 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity"}, "verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}}) + + self.existStmt7 = json.dumps({"object": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt8 = json.dumps({"object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}, + "verb": {"id": "http://example.com/verbs/missed", "display": {"en-US": "missed"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt9 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:sub@sub.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:ss@ss.com"}, "verb": {"id": "nested:verb/url/nested"}, + "object": {"objectType": "Activity", "id": "act:testex.com"}, "result": {"completion": True, "success": True, + "response": "kicked"}, "context": {"registration": self.cguid6, + "contextActivities": {"other": {"id": "act:NewActivityID"}}, "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:k1": "v1", "ext:k2": "v2"}}}}) + + self.existStmt10 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:ref@ref.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, "object": {"objectType": "StatementRef", + "id": str(self.exist_stmt_id)}}) # Put statements - param = {"statementId":self.guid1} + param = {"statementId": self.guid1} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt1 - self.putresponse1 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse1 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse1.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid1).update(stored=time) - - param = {"statementId":self.guid3} + param = {"statementId": self.guid3} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt3 - self.putresponse3 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse3 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse3.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid3).update(stored=time) - - param = {"statementId":self.guid4} + param = {"statementId": self.guid4} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt4 - self.putresponse4 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse4 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse4.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid4).update(stored=time) - self.secondTime = str((datetime.utcnow()+timedelta(seconds=4)).replace(tzinfo=utc).isoformat()) - - param = {"statementId":self.guid2} + self.secondTime = str((datetime.utcnow() + timedelta(seconds=4)).replace(tzinfo=utc).isoformat()) + + param = {"statementId": self.guid2} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt2 - self.putresponse2 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse2 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse2.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=6)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=6)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid2).update(stored=time) - - param = {"statementId":self.guid5} + param = {"statementId": self.guid5} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt5 - self.putresponse5 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse5 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse5.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid5).update(stored=time) - - param = {"statementId":self.guid6} + param = {"statementId": self.guid6} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt6 - self.putresponse6 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse6 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse6.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid6).update(stored=time) - - param = {"statementId":self.guid7} + param = {"statementId": self.guid7} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt7 - self.putresponse7 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt_payload = self.existStmt7 + self.putresponse7 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse7.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid7).update(stored=time) - - param = {"statementId":self.guid8} + param = {"statementId": self.guid8} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt8 - self.putresponse8 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt_payload = self.existStmt8 + self.putresponse8 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse8.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid8).update(stored=time) - + param = {"statementId": self.guid9} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt9 - self.putresponse9 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt_payload = self.existStmt9 + self.putresponse9 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse9.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid9).update(stored=time) param = {"statementId": self.guid10} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt10 - self.putresponse10 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt_payload = self.existStmt10 + self.putresponse10 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse10.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid10).update(stored=time) def tearDown(self): @@ -234,17 +230,17 @@ def tearDown(self): def test_post_with_no_valid_params(self): # Error will be thrown in statements class - resp = self.client.post(reverse(statements), {"feet":"yes","hands": {"id":"http://example.com/test_post"}}, - Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.post(reverse(statements), {"feet": "yes", "hands": {"id": "http://example.com/test_post"}}, + Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 400) def test_post(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) act = Activity.objects.get(activity_id="act:test_post") @@ -253,29 +249,29 @@ def test_post(self): self.assertEqual(agent.name, "bob") def test_post_stmt_ref_no_existing_stmt(self): - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:ref@ref.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"StatementRef", - "id":"12345678-1234-5678-1234-567812345678"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:ref@ref.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, "object": {"objectType": "StatementRef", + "id": "12345678-1234-5678-1234-567812345678"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) def test_post_with_actor(self): - stmt = json.dumps({"actor":{"mbox":"mailto:mr.t@example.com"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:i.pity.the.fool"}}) - - response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({"actor": {"mbox": "mailto:mr.t@example.com"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:i.pity.the.fool"}}) + + response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) Agent.objects.get(mbox="mailto:mr.t@example.com") def test_list_post(self): - stmts = json.dumps([{"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_list_post"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/failed","display": {"en-GB":"failed"}}, - "object": {"id":"act:test_list_post1"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_list_post"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/failed", "display": {"en-GB": "failed"}}, + "object": {"id": "act:test_list_post1"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) activity1 = Activity.objects.get(activity_id="act:test_list_post") activity2 = Activity.objects.get(activity_id="act:test_list_post1") @@ -289,7 +285,7 @@ def test_list_post(self): self.assertEqual(response.status_code, 200) self.assertEqual(stmt1.verb.verb_id, "http://example.com/verbs/passed") self.assertEqual(stmt2.verb.verb_id, "http://example.com/verbs/failed") - + self.assertEqual(lang_map1.keys()[0], "en-US") self.assertEqual(lang_map1.values()[0], "passed") self.assertEqual(lang_map2.keys()[0], "en-GB") @@ -298,12 +294,12 @@ def test_list_post(self): def test_put(self): guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) - putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 204) stmt = Statement.objects.get(statement_id=guid) @@ -311,7 +307,7 @@ def test_put(self): self.assertEqual(act.activity_id, "act:test_put") self.assertEqual(stmt.actor.mbox, "mailto:t@t.com") - + self.assertEqual(stmt.verb.verb_id, "http://example.com/verbs/passed") def test_put_with_substatement(self): @@ -320,32 +316,32 @@ def test_put_with_substatement(self): param = {"statementId": st_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:sass@sass.com"}, - "verb": {"id":"verb:verb/url/tested"}, "object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:ss@ss.com"},"verb": {"id":"verb:verb/url/nested"}, - "object": {"objectType":"Activity", "id":"act:testex.com"}, "result":{"completion": True, "success": True, - "response": "kicked"}, "context":{"registration": con_guid, - "contextActivities": {"other": {"id": "act:NewActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:k1": "v1", "ext:k2": "v2"}}}}) - + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:sass@sass.com"}, + "verb": {"id": "verb:verb/url/tested"}, "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:ss@ss.com"}, "verb": {"id": "verb:verb/url/nested"}, + "object": {"objectType": "Activity", "id": "act:testex.com"}, "result": {"completion": True, "success": True, + "response": "kicked"}, "context": {"registration": con_guid, + "contextActivities": {"other": {"id": "act:NewActivityID"}}, "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:k1": "v1", "ext:k2": "v2"}}}}) + response = self.client.put(path, stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(get_response.status_code, 200) rsp = get_response.content - self.assertIn("objectType",rsp) + self.assertIn("objectType", rsp) self.assertIn("SubStatement", rsp) - self.assertIn("actor",rsp) - self.assertIn("mailto:ss@ss.com",rsp) - self.assertIn("verb",rsp) + self.assertIn("actor", rsp) + self.assertIn("mailto:ss@ss.com", rsp) + self.assertIn("verb", rsp) self.assertIn("verb:verb/url/nested", rsp) self.assertIn("Activity", rsp) self.assertIn("act:testex.com", rsp) self.assertIn("result", rsp) - self.assertIn("completion",rsp) + self.assertIn("completion", rsp) self.assertIn("success", rsp) self.assertIn("response", rsp) self.assertIn("kicked", rsp) @@ -363,67 +359,67 @@ def test_put_with_substatement(self): self.assertIn("ext:k1", rsp) self.assertIn("v1", rsp) self.assertIn("ext:k2", rsp) - self.assertIn("v2", rsp) + self.assertIn("v2", rsp) def test_no_content_put(self): guid = str(uuid.uuid1()) - - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt = json.dumps({}) - putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 400) def test_existing_stmtID_put_put(self): guid = str(uuid.uuid1()) - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - exist_stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:activity"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) - first_put = self.client.put(path, exist_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + exist_stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:activity"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) + first_put = self.client.put(path, exist_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(first_put.status_code, 204) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object":{"id":"act:test_existing_put"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) - putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_existing_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) + putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 409) def test_existing_stmtID_put_post(self): guid = str(uuid.uuid1()) - exist_stmt = json.dumps({"id": guid, "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:activity"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) - post = self.client.post(reverse(statements), exist_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + exist_stmt = json.dumps({"id": guid, "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:activity"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) + post = self.client.post(reverse(statements), exist_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 200) - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object":{"id":"act:test_existing_put"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_existing_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) - putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 409) - def test_missing_stmtID_put(self): - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) - response = self.client.put(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + def test_missing_stmtID_put(self): + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) + response = self.client.put(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn(response.content, "Error -- statements - method = PUT, but no statementId parameter or ID given in statement") def test_get(self): - param = {"statementId":self.guid1} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": self.guid1} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) getResponse = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(getResponse.status_code, 200) rsp = getResponse.content self.assertIn(self.guid1, rsp) def test_get_no_existing_ID(self): - param = {"statementId":"aaaaaa"} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": "aaaaaa"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) getResponse = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(getResponse.status_code, 404) @@ -432,26 +428,26 @@ def test_get_no_statementid(self): self.assertEqual(getResponse.status_code, 200) jsn = json.loads(getResponse.content) self.assertEqual(len(jsn["statements"]), 11) - + # Sever activities are PUT-contextActivites create 3 more def test_number_of_activities(self): acts = len(Activity.objects.all()) self.assertEqual(9, acts) def test_update_activity_correct_auth(self): - stmt = json.dumps({"verb": {"id":"verb:verb/url/changed-act"},"actor":{"objectType":"Agent", "mbox":"mailto:l@l.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, - "type": "http://adlnet.gov/expapi/activities/cmi.interaction","interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": self.cguid8, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}}) + stmt = json.dumps({"verb": {"id": "verb:verb/url/changed-act"}, "actor": {"objectType": "Agent", "mbox": "mailto:l@l.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, + "type": "http://adlnet.gov/expapi/activities/cmi.interaction", "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": self.cguid8, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}}) post_response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post_response.status_code, 200) act = Activity.objects.get(activity_id="act:foogie") @@ -471,11 +467,11 @@ def test_update_activity_correct_auth(self): def test_cors_post_put(self): st_id = str(uuid.uuid1()) - content = {"verb":{"id":"verb:verb/url"}, "actor":{"objectType":"Agent", "mbox": "mailto:r@r.com"}, - "object": {"id":"act:test_cors_post_put"}} - + content = {"verb": {"id": "verb:verb/url"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"id": "act:test_cors_post_put"}} + bdy = "statementId=%s&content=%s&Content-Type=application/json&X-Experience-API-Version=1.0.0" % (st_id, content) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"method":"PUT"})) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"method": "PUT"})) response = self.client.post(path, bdy, content_type="application/x-www-form-urlencoded", Authorization=self.auth) self.assertEqual(response.status_code, 204) @@ -483,26 +479,26 @@ def test_cors_post_put(self): self.assertEqual(act.activity_id, "act:test_cors_post_put") def test_issue_put(self): - stmt_id = "33f60b35-e1b2-4ddc-9c6f-7b3f65244430" - stmt = json.dumps({"verb":{"id":"verb:verb/iri"},"object":{"id":"act:scorm.com/JsTetris_TCAPI","definition":{"type":"type:media", - "name":{"en-US":"Js Tetris - Tin Can Prototype"},"description":{"en-US":"A game of tetris."}}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"6b1091be-2833-4886-b4a6-59e5e0b3c3f4"}, - "actor":{"mbox":"mailto:tom.creighton.ctr@adlnet.gov","name":"Tom Creighton"}}) - - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) - put_stmt = self.client.put(path, stmt, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION,Authorization=self.auth) - self.assertEqual(put_stmt.status_code, 204) + stmt_id = "33f60b35-e1b2-4ddc-9c6f-7b3f65244430" + stmt = json.dumps({"verb": {"id": "verb:verb/iri"}, "object": {"id": "act:scorm.com/JsTetris_TCAPI", "definition": {"type": "type:media", + "name": {"en-US": "Js Tetris - Tin Can Prototype"}, "description": {"en-US": "A game of tetris."}}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "6b1091be-2833-4886-b4a6-59e5e0b3c3f4"}, + "actor": {"mbox": "mailto:tom.creighton.ctr@adlnet.gov", "name": "Tom Creighton"}}) + + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) + put_stmt = self.client.put(path, stmt, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) + self.assertEqual(put_stmt.status_code, 204) def test_post_with_group(self): ot = "Group" name = "the group ST" mbox = "mailto:the.groupST@example.com" - stmt = json.dumps({"actor":{"objectType":ot, "name":name, "mbox":mbox,"member":[{"name":"agentA","mbox":"mailto:agentA@example.com"}, - {"name":"agentB","mbox":"mailto:agentB@example.com"}]},"verb":{"id": "http://verb/iri/created", "display":{"en-US":"created"}}, - "object": {"id":"act:i.pity.the.fool"}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({"actor": {"objectType": ot, "name": name, "mbox": mbox, "member": [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, + {"name": "agentB", "mbox": "mailto:agentB@example.com"}]}, "verb": {"id": "http://verb/iri/created", "display": {"en-US": "created"}}, + "object": {"id": "act:i.pity.the.fool"}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) g = Agent.objects.get(mbox="mailto:the.groupST@example.com") self.assertEquals(g.name, name) @@ -514,73 +510,73 @@ def test_post_with_group(self): def test_issue_put_no_version_header(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244431' - stmt = json.dumps({"verb":"verb:completed","object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt = json.dumps({"verb": "verb:completed", "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth) self.assertEqual(put_stmt.status_code, 400) def test_issue_put_wrong_version_header(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244432' - stmt = json.dumps({"verb":"verb:completed","object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) - put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="0.90") + stmt = json.dumps({"verb": "verb:completed", "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) + put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="0.90") self.assertEqual(put_stmt.status_code, 400) # Use this test to make sure stmts are being returned correctly with all data - doesn't check timestamp and stored fields def test_all_fields_activity_as_object(self): nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) + self.assertEqual(put_sub_stmt.status_code, 204) stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"uniqueName"}}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created", "en-GB":"made"}}, - "object": {"objectType": "Activity", "id":"http:adlnet.gov/my/Activity/URL", - "definition": {"name": {"en-US":"actName", "en-GB": "anotherActName"}, - "description": {"en-US":"This is my activity description.", "en-GB": "This is another activity description."}, - "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "choice", - "correctResponsesPattern": ["golf", "tetris"], - "choices":[{"id": "golf", "description": {"en-US":"Golf Example", "en-GB": "GOLF"}}, - {"id": "tetris","description":{"en-US": "Tetris Example", "en-GB": "TETRIS"}}, - {"id":"facebook", "description":{"en-US":"Facebook App", "en-GB": "FACEBOOK"}}, - {"id":"scrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": True, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}, - "grouping":{"id":"http://groupingID"} }, - "revision": "Spelling error in choices.", "platform":"Platform is web browser.","language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "uniqueName"}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created", "en-GB": "made"}}, + "object": {"objectType": "Activity", "id": "http:adlnet.gov/my/Activity/URL", + "definition": {"name": {"en-US": "actName", "en-GB": "anotherActName"}, + "description": {"en-US": "This is my activity description.", "en-GB": "This is another activity description."}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "choice", + "correctResponsesPattern": ["golf", "tetris"], + "choices": [{"id": "golf", "description": {"en-US": "Golf Example", "en-GB": "GOLF"}}, + {"id": "tetris", "description": {"en-US": "Tetris Example", "en-GB": "TETRIS"}}, + {"id": "facebook", "description": {"en-US": "Facebook App", "en-GB": "FACEBOOK"}}, + {"id": "scrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": True, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}, + "grouping": {"id": "http://groupingID"}}, + "revision": "Spelling error in choices.", "platform": "Platform is web browser.", "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['actor']['objectType'], 'Agent') @@ -616,35 +612,34 @@ def test_all_fields_activity_as_object(self): # Use this test to make sure stmts are being returned correctly with all data - doesn't check timestamp, stored fields def test_all_fields_agent_as_object(self): nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) - + self.assertEqual(put_sub_stmt.status_code, 204) stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - msha = hashlib.sha1("tom@example.com").hexdigest() - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"louUniqueName"}}, - "verb":{"id": "http://example.com/verbs/helped","display": {"en-US":"helped", "en-GB":"assisted"}}, - "object": {"objectType":"Agent","name": "Tom Creighton","mbox_sha1sum":msha}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": True, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, - "language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) - + msha = hashlib.sha1("tom@example.com").hexdigest() + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "louUniqueName"}}, + "verb": {"id": "http://example.com/verbs/helped", "display": {"en-US": "helped", "en-GB": "assisted"}}, + "object": {"objectType": "Agent", "name": "Tom Creighton", "mbox_sha1sum": msha}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": True, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, + "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) + put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['actor']['objectType'], 'Agent') @@ -681,64 +676,62 @@ def test_all_fields_agent_as_object(self): # Use this test to make sure stmts are being returned correctly with all data - doesn't check timestamps or stored fields def test_all_fields_substatement_as_object(self): nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincannest@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed", "en-GB":"graded"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincannest@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed", "en-GB": "graded"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) - + self.assertEqual(put_sub_stmt.status_code, 204) nested_sub_st_id = str(uuid.uuid1()) - nest_sub_param = {"statementId":nested_sub_st_id} - nest_sub_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_sub_param)) - nested_sub_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincannestsub@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/verb","display": {"en-US":"verb", "en-GB":"altVerb"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplenestedsubstatement"}}) + nest_sub_param = {"statementId": nested_sub_st_id} + nest_sub_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_sub_param)) + nested_sub_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincannestsub@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/verb", "display": {"en-US": "verb", "en-GB": "altVerb"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplenestedsubstatement"}}) put_nest_sub_stmt = self.client.put(nest_sub_path, nested_sub_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_nest_sub_stmt.status_code, 204) - stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - sub_context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + sub_context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"louUniqueName"}}, - "verb":{"id": "http://example.com/verbs/said","display": {"en-US":"said", "en-GB":"talked"}}, - "object": {"objectType": "SubStatement", "actor":{"objectType":"Agent","name":"Tom Creighton","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed", "en-GB": "Graded"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement", - 'definition': {'name': {'en-US':'SubStatement name'}, - 'description': {'en-US':'SubStatement description'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'matching', - 'correctResponsesPattern': ['lou.3,tom.2,andy.1'],'source':[{'id': 'lou', - 'description': {'en-US':'Lou', 'it': 'Luigi'}},{'id': 'tom','description':{'en-US': 'Tom', 'it':'Tim'}}, - {'id':'andy', 'description':{'en-US':'Andy'}}],'target':[{'id':'1', - 'description':{'en-US': 'ADL LRS'}},{'id':'2','description':{'en-US': 'lrs'}}, - {'id':'3', 'description':{'en-US': 'the adl lrs', 'en-CH': 'the lrs'}}]}}, - "result": {"score":{"scaled":.50, "raw": 50, "min":1, "max":51}, "completion": True, - "success": True, "response": "Poorly done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey11": "resultValue11", "ext:resultKey22":"resultValue22"}}, - "context":{"registration": sub_context_id, - "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test/nest"}}, - "language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_sub_st_id)}, - "extensions":{"ext:contextKey11": "contextVal11","ext:contextKey22": "contextVal22"}}}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": True, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, - "language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) + + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "louUniqueName"}}, + "verb": {"id": "http://example.com/verbs/said", "display": {"en-US": "said", "en-GB": "talked"}}, + "object": {"objectType": "SubStatement", "actor": {"objectType": "Agent", "name": "Tom Creighton", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed", "en-GB": "Graded"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement", + 'definition': {'name': {'en-US': 'SubStatement name'}, + 'description': {'en-US': 'SubStatement description'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'matching', + 'correctResponsesPattern': ['lou.3,tom.2,andy.1'], 'source': [{'id': 'lou', + 'description': {'en-US': 'Lou', 'it': 'Luigi'}}, {'id': 'tom', 'description': {'en-US': 'Tom', 'it': 'Tim'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}], 'target': [{'id': '1', + 'description': {'en-US': 'ADL LRS'}}, {'id': '2', 'description': {'en-US': 'lrs'}}, + {'id': '3', 'description': {'en-US': 'the adl lrs', 'en-CH': 'the lrs'}}]}}, + "result": {"score": {"scaled": .50, "raw": 50, "min": 1, "max": 51}, "completion": True, + "success": True, "response": "Poorly done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey11": "resultValue11", "ext:resultKey22": "resultValue22"}}, + "context": {"registration": sub_context_id, + "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test/nest"}}, + "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_sub_st_id)}, + "extensions": {"ext:contextKey11": "contextVal11", "ext:contextKey22": "contextVal22"}}}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": True, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, + "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['actor']['objectType'], 'Agent') @@ -749,11 +742,11 @@ def test_all_fields_substatement_as_object(self): self.assertEqual(the_returned['verb']['id'], 'http://example.com/verbs/said') self.assertEqual(the_returned['verb']['display']['en-GB'], 'talked') self.assertEqual(the_returned['verb']['display']['en-US'], 'said') - + self.assertEqual(the_returned['object']['actor']['objectType'], 'Agent') self.assertEqual(the_returned['object']['actor']['name'], 'Tom Creighton') self.assertEqual(the_returned['object']['actor']['mbox'], 'mailto:tom@adlnet.gov') - + self.assertEqual(the_returned['object']['context']['registration'], sub_context_id) self.assertEqual(the_returned['object']['context']['language'], 'en-US') self.assertEqual(the_returned['object']['context']['statement']['id'], str(nested_sub_st_id)) @@ -789,7 +782,7 @@ def test_all_fields_substatement_as_object(self): self.assertIn('the lrs', target_str) self.assertIn('the adl lrs', target_str) self.assertIn('3', target_str) - + self.assertEqual(the_returned['object']['objectType'], 'SubStatement') self.assertEqual(the_returned['object']['result']['completion'], True) @@ -802,7 +795,7 @@ def test_all_fields_substatement_as_object(self): self.assertEqual(the_returned['object']['result']['score']['raw'], 50) self.assertEqual(the_returned['object']['result']['score']['scaled'], 0.5) self.assertEqual(the_returned['object']['result']['success'], True) - + self.assertEqual(the_returned['object']['verb']['id'], 'http://example.com/verbs/assess') self.assertEqual(the_returned['object']['verb']['display']['en-GB'], 'Graded') self.assertEqual(the_returned['object']['verb']['display']['en-US'], 'assessed') @@ -825,40 +818,40 @@ def test_all_fields_substatement_as_object(self): self.assertEqual(the_returned['context']['registration'], context_id) self.assertEqual(the_returned['context']['statement']['id'], nested_st_id) self.assertEqual(the_returned['context']['statement']['objectType'], 'StatementRef') - + # Third stmt in list is missing actor - should throw error and perform cascading delete on first three statements def test_post_list_rollback(self): cguid1 = str(uuid.uuid1()) - stmts = json.dumps([{"verb":{"id": "http://example.com/verbs/wrong-failed","display": {"en-US":"wrong-failed"}},"object": {"id":"act:test_wrong_list_post2"}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"},"result": {"score":{"scaled":.99}, "completion": True, "success": True, "response": "wrong", - "extensions":{"ext:resultwrongkey1": "value1", "ext:resultwrongkey2":"value2"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}}, - "object": {"objectType": "Activity", "id":"act:test_wrong_list_post", - "definition": {"name": {"en-US":"wrongactName", "en-GB": "anotherActName"}, - "description": {"en-US":"This is my activity description.", "en-GB": "This is another activity description."}, - "type": "http://adlnet.gov/expapi/activities/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "choice", - "correctResponsesPattern": ["wronggolf", "wrongtetris"], - "choices":[{"id": "wronggolf", "description": {"en-US":"Golf Example", "en-GB": "GOLF"}}, - {"id": "wrongtetris","description":{"en-US": "Tetris Example", "en-GB": "TETRIS"}}, - {"id":"wrongfacebook", "description":{"en-US":"Facebook App", "en-GB": "FACEBOOK"}}, - {"id":"wrongscrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], - "extensions": {"ext:wrongkey1": "wrongvalue1", "ext:wrongkey2": "wrongvalue2","ext:wrongkey3": "wrongvalue3"}}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/wrong-passed","display": {"en-US":"wrong-passed"}},"object": {"id":"act:test_wrong_list_post1"}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"},"context":{"registration": cguid1, "contextActivities": {"other": {"id": "act:wrongActivityID2"}}, - "revision": "wrong", "platform":"wrong","language": "en-US", "extensions":{"ext:wrongkey1": "wrongval1", - "ext:wrongkey2": "wrongval2"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}},"object": {"id":"act:test_wrong_list_post2"}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}},"object": {"id":"act:test_wrong_list_post4"}, "actor":{"objectType":"Agent", "mbox":"wrong-t@t.com"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"verb": {"id": "http://example.com/verbs/wrong-failed", "display": {"en-US": "wrong-failed"}}, "object": {"id": "act:test_wrong_list_post2"}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}, "result": {"score": {"scaled": .99}, "completion": True, "success": True, "response": "wrong", + "extensions": {"ext:resultwrongkey1": "value1", "ext:resultwrongkey2": "value2"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, + "object": {"objectType": "Activity", "id": "act:test_wrong_list_post", + "definition": {"name": {"en-US": "wrongactName", "en-GB": "anotherActName"}, + "description": {"en-US": "This is my activity description.", "en-GB": "This is another activity description."}, + "type": "http://adlnet.gov/expapi/activities/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "choice", + "correctResponsesPattern": ["wronggolf", "wrongtetris"], + "choices":[{"id": "wronggolf", "description": {"en-US": "Golf Example", "en-GB": "GOLF"}}, + {"id": "wrongtetris", "description": {"en-US": "Tetris Example", "en-GB": "TETRIS"}}, + {"id": "wrongfacebook", "description": {"en-US": "Facebook App", "en-GB": "FACEBOOK"}}, + {"id": "wrongscrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], + "extensions": {"ext:wrongkey1": "wrongvalue1", "ext:wrongkey2": "wrongvalue2", "ext:wrongkey3": "wrongvalue3"}}}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/wrong-passed", "display": {"en-US": "wrong-passed"}}, "object": {"id": "act:test_wrong_list_post1"}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}, "context": {"registration": cguid1, "contextActivities": {"other": {"id": "act:wrongActivityID2"}}, + "revision": "wrong", "platform": "wrong", "language": "en-US", "extensions": {"ext:wrongkey1": "wrongval1", + "ext:wrongkey2": "wrongval2"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, "object": {"id": "act:test_wrong_list_post2"}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, "object": {"id": "act:test_wrong_list_post4"}, "actor": {"objectType": "Agent", "mbox": "wrong-t@t.com"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) - + verbs = Verb.objects.filter(verb_id__contains='wrong') - + activities = Activity.objects.filter(activity_id__contains='test_wrong_list_post') stmts = Statement.objects.all() @@ -870,25 +863,25 @@ def test_post_list_rollback(self): self.assertEqual(len(activities), 0) def test_post_list_rollback_part_2(self): - stmts = json.dumps([{"object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}, - "verb": {"id": "http://example.com/verbs/wrong","display": {"en-US":"wrong"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}, - {"verb":{"id": "http://example.com/verbs/created"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"]}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}, + "verb": {"id": "http://example.com/verbs/wrong", "display": {"en-US": "wrong"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}, + {"verb": {"id": "http://example.com/verbs/created"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"]}}, + "actor":{"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) created_verbs = Verb.objects.filter(verb_id__contains='http://example.com/verbs/created') wrong_verbs = Verb.objects.filter(verb_id__contains='http://example.com/verbs/wrong') - + activities = Activity.objects.filter(activity_id='act:foogie') - + stmts = Statement.objects.all() wrong_agent = Agent.objects.filter(mbox='mailto:wrong-t@t.com') @@ -901,7 +894,7 @@ def test_post_list_rollback_part_2(self): self.assertEqual(len(wrong_verbs), 0) self.assertEqual(len(activities), 1) - + self.assertEqual(len(stmts), 11) self.assertEqual(len(wrong_agent), 0) @@ -910,12 +903,12 @@ def test_post_list_rollback_part_2(self): self.assertEqual(len(auth_agent), 0) def test_post_list_rollback_with_void(self): - stmts = json.dumps([{"actor":{"objectType":"Agent","mbox":"mailto:only-s@s.com"}, - "object": {"objectType":"StatementRef","id":str(self.exist_stmt_id)}, - "verb": {"id": "http://adlnet.gov/expapi/verbs/voided","display": {"en-US":"voided"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) + stmts = json.dumps([{"actor": {"objectType": "Agent", "mbox": "mailto:only-s@s.com"}, + "object": {"objectType": "StatementRef", "id": str(self.exist_stmt_id)}, + "verb": {"id": "http://adlnet.gov/expapi/verbs/voided", "display": {"en-US": "voided"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) @@ -931,26 +924,26 @@ def test_post_list_rollback_with_void(self): def test_post_list_rollback_with_subs(self): sub_context_id = str(uuid.uuid1()) - stmts = json.dumps([{"actor":{"objectType":"Agent","mbox":"mailto:wrong-s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong","display": {"en-US":"wrong"}}, - "object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}}, - {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong-next","display": {"en-US":"wrong-next"}}, - "object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:wrong-ss@ss.com"},"verb": {"id":"http://example.com/verbs/wrong-sub"}, - "object": {"objectType":"Activity", "id":"act:wrong-testex.com"}, "result":{"completion": True, "success": True, - "response": "sub-wrong-kicked"}, "context":{"registration": sub_context_id, - "contextActivities": {"other": {"id": "act:sub-wrong-ActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"actor": {"objectType": "Agent", "mbox": "mailto:wrong-s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong", "display": {"en-US": "wrong"}}, + "object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}}, + {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong-next", "display": {"en-US": "wrong-next"}}, + "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-ss@ss.com"}, "verb": {"id": "http://example.com/verbs/wrong-sub"}, + "object": {"objectType": "Activity", "id": "act:wrong-testex.com"}, "result": {"completion": True, "success": True, + "response": "sub-wrong-kicked"}, "context": {"registration": sub_context_id, + "contextActivities": {"other": {"id": "act:sub-wrong-ActivityID"}}, "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) s_agent = Agent.objects.filter(mbox="mailto:wrong-s@s.com") ss_agent = Agent.objects.filter(mbox="mailto:wrong-ss@ss.com") - john_agent = Agent.objects.filter(mbox="mailto:john@john.com") + john_agent = Agent.objects.filter(mbox="mailto:john@john.com") subs = SubStatement.objects.all() wrong_verb = Verb.objects.filter(verb_id__contains="wrong") activities = Activity.objects.filter(activity_id__contains="wrong") @@ -970,22 +963,22 @@ def test_activity_definition_change(self): email_1 = "test1@tester.com" password_1 = "test" auth_1 = "Basic %s" % base64.b64encode("%s:%s" % (username_1, password_1)) - form_1 = {"username":username_1, "email":email_1,"password":password_1,"password2":password_1} - response_1 = self.client.post(reverse(register),form_1, X_Experience_API_Version=settings.XAPI_VERSION) + form_1 = {"username": username_1, "email": email_1, "password": password_1, "password2": password_1} + response_1 = self.client.post(reverse(register), form_1, X_Experience_API_Version=settings.XAPI_VERSION) username_2 = "tester2" email_2 = "test2@tester.com" password_2 = "test2" auth_2 = "Basic %s" % base64.b64encode("%s:%s" % (username_2, password_2)) - form_2 = {"username":username_2, "email":email_2,"password":password_2,"password2":password_2} - response_2 = self.client.post(reverse(register),form_2, X_Experience_API_Version=settings.XAPI_VERSION) + form_2 = {"username": username_2, "email": email_2, "password": password_2, "password2": password_2} + response_2 = self.client.post(reverse(register), form_2, X_Experience_API_Version=settings.XAPI_VERSION) # Should have no definition - stmt_1 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity_change"}, - "verb":{"id": "http://example.com/verbs/created", "display": {"en-US":"created"}}}) + stmt_1 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity_change"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}}) response_1 = self.client.post(reverse(statements), stmt_1, content_type="application/json", - Authorization=auth_1, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_1, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_1.status_code, 200) user1_agent = Agent.objects.get(mbox="mailto:test1@tester.com") act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() @@ -996,11 +989,11 @@ def test_activity_definition_change(self): self.assertEqual(acts, 1) # Does not update existing activity - stmt_2 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity_change", "definition":{"name":{"en-US": "fail_test"}}}, - "verb":{"id": "http://example.com/verbs/created", "display": {"en-US":"created"}}}) + stmt_2 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity_change", "definition": {"name": {"en-US": "fail_test"}}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}}) response_2 = self.client.post(reverse(statements), stmt_2, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) user2_agent = Agent.objects.get(mbox="mailto:test2@tester.com") self.assertEqual(response_2.status_code, 200) with self.assertRaises(Activity.DoesNotExist): @@ -1013,7 +1006,7 @@ def test_activity_definition_change(self): # Should not update activity response_3 = self.client.post(reverse(statements), stmt_1, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_3.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() self.assertEqual(act["id"], "act:test_activity_change") @@ -1023,45 +1016,45 @@ def test_activity_definition_change(self): self.assertEqual(acts, 1) # Should have new definition since user is owner - stmt_3 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity_change", "definition":{"name":{"en-US": "foo"}}}, - "verb":{"id": "http://example.com/verbs/created", "display": {"en-US":"created"}}}) + stmt_3 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity_change", "definition": {"name": {"en-US": "foo"}}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}}) response_4 = self.client.post(reverse(statements), stmt_3, content_type="application/json", - Authorization=auth_1, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_1, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_4.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change", authority=user1_agent).to_dict() self.assertEqual(act["id"], "act:test_activity_change") - self.assertEqual(act["definition"], {"name":{"en-US": "foo"}}) + self.assertEqual(act["definition"], {"name": {"en-US": "foo"}}) # Should still have definition from above response_5 = self.client.post(reverse(statements), stmt_3, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_5.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() self.assertEqual(act["id"], "act:test_activity_change") - self.assertEqual(act["definition"], {"name":{"en-US": "foo"}}) + self.assertEqual(act["definition"], {"name": {"en-US": "foo"}}) acts = Activity.objects.filter(activity_id="act:test_activity_change").count() self.assertEqual(acts, 1) # Should still have definition from above - stmt_4 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity_change", "definition":{"name":{"en-US": "bar"}}}, - "verb":{"id": "http://example.com/verbs/created", "display": {"en-US":"created"}}}) + stmt_4 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity_change", "definition": {"name": {"en-US": "bar"}}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}}) response_6 = self.client.post(reverse(statements), stmt_4, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_6.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() self.assertEqual(act["id"], "act:test_activity_change") - self.assertEqual(act["definition"], {"name":{"en-US": "foo"}}) + self.assertEqual(act["definition"], {"name": {"en-US": "foo"}}) acts = Activity.objects.filter(activity_id="act:test_activity_change").count() self.assertEqual(acts, 1) # Should still have definition from above - stmt_5 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity_change", "definition":{"name":{"fr": "bar"}}}, - "verb":{"id": "http://example.com/verbs/created", "display": {"en-US":"created"}}}) + stmt_5 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity_change", "definition": {"name": {"fr": "bar"}}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}}) response_7 = self.client.post(reverse(statements), stmt_5, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_7.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() self.assertEqual(act["id"], "act:test_activity_change") @@ -1071,7 +1064,7 @@ def test_activity_definition_change(self): # Should still have definition from above response_8 = self.client.post(reverse(statements), stmt_1, content_type="application/json", - Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=auth_2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response_8.status_code, 200) act = Activity.objects.get(activity_id="act:test_activity_change").to_dict() self.assertEqual(act["id"], "act:test_activity_change") @@ -1080,33 +1073,33 @@ def test_activity_definition_change(self): self.assertEqual(acts, 1) # Check canonical of last stmt returned from query to make sure it contains the definition - param = {"agent":{"mbox":"mailto:max@max.com"}, "format":"canonical", "activity":"act:test_activity_change"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:max@max.com"}, "format": "canonical", "activity": "act:test_activity_change"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=auth_1) self.assertEqual(r.status_code, 200) first_stmt = json.loads(r.content)["statements"][0] - self.assertEqual(first_stmt["object"]["definition"], {"name":{"en-US": "foo"}}) + self.assertEqual(first_stmt["object"]["definition"], {"name": {"en-US": "foo"}}) def test_post_with_non_oauth_not_existing_group(self): ot = "Group" name = "the group ST" mbox = "mailto:the.groupST@example.com" - stmt = json.dumps({"actor":{"name":"agentA","mbox":"mailto:agentA@example.com"},"verb":{"id": "http://verb/iri/joined", "display":{"en-US":"joined"}}, - "object": {"id":"act:i.pity.the.fool"}, "authority": {"objectType":ot, "name":name, "mbox":mbox,"member":[{"name":"agentA","mbox":"mailto:agentA@example.com"},{"name":"agentB","mbox":"mailto:agentB@example.com"}]}}) + stmt = json.dumps({"actor": {"name": "agentA", "mbox": "mailto:agentA@example.com"}, "verb": {"id": "http://verb/iri/joined", "display": {"en-US": "joined"}}, + "object": {"id": "act:i.pity.the.fool"}, "authority": {"objectType": ot, "name": name, "mbox": mbox, "member": [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, {"name": "agentB", "mbox": "mailto:agentB@example.com"}]}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) def test_post_with_non_oauth_existing_group(self): ot = "Group" name = "the group ST" mbox = "mailto:the.groupST@example.com" - group = {"objectType":ot, "name":name, "mbox":mbox,"member":[{"name":"agentA","mbox":"mailto:agentA@example.com"},{"name":"agentB","mbox":"mailto:agentB@example.com"}]} + group = {"objectType": ot, "name": name, "mbox": mbox, "member": [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, {"name": "agentB", "mbox": "mailto:agentB@example.com"}]} Agent.objects.retrieve_or_create(**group) - stmt = json.dumps({"actor":{"name":"agentA","mbox":"mailto:agentA@example.com"},"verb":{"id": "http://verb/iri/joined", "display":{"en-US":"joined"}}, - "object": {"id":"act:i.pity.the.fool"}, "authority": {"objectType":ot, "name":name, "mbox":mbox,"member":[{"name":"agentA","mbox":"mailto:agentA@example.com"},{"name":"agentB","mbox":"mailto:agentB@example.com"}]}}) - + stmt = json.dumps({"actor": {"name": "agentA", "mbox": "mailto:agentA@example.com"}, "verb": {"id": "http://verb/iri/joined", "display": {"en-US": "joined"}}, + "object": {"id": "act:i.pity.the.fool"}, "authority": {"objectType": ot, "name": name, "mbox": mbox, "member": [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, {"name": "agentB", "mbox": "mailto:agentB@example.com"}]}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(response.status_code, 400) \ No newline at end of file + self.assertEqual(response.status_code, 400) diff --git a/lrs/tests/OAuth2Tests.py b/lrs/tests/OAuth2Tests.py index 91c286ac..0ac357c2 100644 --- a/lrs/tests/OAuth2Tests.py +++ b/lrs/tests/OAuth2Tests.py @@ -23,7 +23,9 @@ DEFAULT_SCOPE = "%s %s" % (constants.SCOPES[0][1], constants.SCOPES[1][1]) + class OAuth2Tests(TestCase): + @classmethod def setUpClass(cls): print "\n%s-%s" % (__name__, cls.__name__) @@ -219,7 +221,7 @@ class AccessTokenTest(OAuth2Tests): fixtures = ['test_oauth2.json'] def get_user_auth(self): - return "Basic %s" % base64.b64encode("%s:%s" % ("test-user-1", "test")) + return "Basic %s" % base64.b64encode("%s:%s" % ("test-user-1", "test")) def test_access_token_get_expire_delta_value(self): user = self.get_user() @@ -255,7 +257,6 @@ def test_fetching_access_token_with_invalid_grant(self): self.assertEqual(400, response.status_code, response.content) self.assertEqual('invalid_grant', json.loads(response.content)['error']) - def _login_authorize_get_token(self, scope=DEFAULT_SCOPE, cid=2): required_props = ['access_token', 'token_type'] @@ -278,21 +279,20 @@ def _login_authorize_get_token(self, scope=DEFAULT_SCOPE, cid=2): for prop in required_props: self.assertIn(prop, token, "Access token response missing " - "required property: %s" % prop) + "required property: %s" % prop) return token def test_get_statements_user_submitted(self): token = self._login_authorize_get_token() - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - stmt_get = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization="Bearer " + token['access_token'], content_type="application/json") self.assertEqual(stmt_get.status_code, 200) stmts = json.loads(stmt_get.content)['statements'] @@ -301,11 +301,11 @@ def test_get_statements_user_submitted(self): def test_get_statements_oauth_submitted(self): token = self._login_authorize_get_token() - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_get = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization="Bearer " + token['access_token'], content_type="application/json") @@ -316,18 +316,18 @@ def test_get_statements_oauth_submitted(self): def test_get_statements_mix_submitted(self): token = self._login_authorize_get_token() - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_get = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization="Bearer " + token['access_token'], content_type="application/json") @@ -344,141 +344,141 @@ def test_put_statements(self): token = self._login_authorize_get_token(scope=constants.SCOPES[0][1]) put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"act:test_put"}}) - param = {"statementId":put_guid} + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "act:test_put"}}) + param = {"statementId": put_guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(resp.status_code, 204) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(resp.status_code, 204) def test_post_statements(self): token = self._login_authorize_get_token() - stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}} + stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}} stmt_json = json.dumps(stmt) - + post = self.client.post('/XAPI/statements/', data=stmt_json, content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 200) def test_write_statements_wrong_scope(self): token = self._login_authorize_get_token(scope=constants.SCOPES[2][1]) - stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}} + stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}} stmt_json = json.dumps(stmt) - + post = self.client.post('/XAPI/statements/', data=stmt_json, content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 403) def test_complex_statement_get(self): token = self._login_authorize_get_token() - stmt_data = [{"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_complex_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}}, - {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}}] + stmt_data = [{"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_complex_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}}, + {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}}] stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"activity":"act:test_complex_get"} + param = {"activity": "act:test_complex_get"} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) - resp = self.client.get(path,Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.get(path, Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmts = json.loads(resp.content)['statements'] self.assertEqual(len(stmts), 1) def test_define(self): stmt = { - "actor":{ - "objectType": "Agent", - "mbox":"mailto:t@t.com", - "name":"bob" - }, - "verb":{ - "id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"} - }, - "object":{ - "id":"act:test_define", - 'definition': { - 'name': {'en-US':'testname'}, - 'description': {'en-US':'testdesc'}, - 'type': 'type:course' - } + "actor": { + "objectType": "Agent", + "mbox": "mailto:t@t.com", + "name": "bob" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + }, + "object": { + "id": "act:test_define", + 'definition': { + 'name': {'en-US': 'testname'}, + 'description': {'en-US': 'testdesc'}, + 'type': 'type:course' } } + } stmt_post = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) token = self._login_authorize_get_token() stmt2 = { - "actor":{ - "objectType": "Agent", - "mbox":"mailto:t@t.com", - "name":"bob" - }, - "verb":{ - "id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"} - }, - "object":{ - "id":"act:test_define", - 'definition': { - 'name': {'en-US':'testname differ'}, - 'description': {'en-US':'testdesc differ'}, - 'type': 'type:course' - } + "actor": { + "objectType": "Agent", + "mbox": "mailto:t@t.com", + "name": "bob" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + }, + "object": { + "id": "act:test_define", + 'definition': { + 'name': {'en-US': 'testname differ'}, + 'description': {'en-US': 'testdesc differ'}, + 'type': 'type:course' } } + } # Doesn't have define permission stmt_post2 = self.client.post(reverse(statements), json.dumps(stmt2), content_type="application/json", - Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post2.status_code, 200) acts = Activity.objects.filter(activity_id="act:test_define") self.assertEqual(len(acts), 1) stmt_post = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.get_user_auth(), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) token2 = self._login_authorize_get_token(scope="%s %s" % (constants.SCOPES[0][1], constants.SCOPES[4][1]), cid=1) stmt3 = { - "actor":{ - "objectType": "Agent", - "mbox":"mailto:t@t.com", - "name":"bob" - }, - "verb":{ - "id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"} - }, - "object":{ - "id":"act:test_define", - 'definition': { - 'name': {'en-US':'testname i define!'}, - 'description': {'en-US':'testdesc i define!'}, - 'type': 'type:course' - } + "actor": { + "objectType": "Agent", + "mbox": "mailto:t@t.com", + "name": "bob" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + }, + "object": { + "id": "act:test_define", + 'definition': { + 'name': {'en-US': 'testname i define!'}, + 'description': {'en-US': 'testdesc i define!'}, + 'type': 'type:course' } } + } # Has define perission stmt_post3 = self.client.post(reverse(statements), json.dumps(stmt3), content_type="application/json", - Authorization="Bearer " + token2['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Bearer " + token2['access_token'], X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post3.status_code, 200) act_names = Activity.objects.filter(activity_id="act:test_define").values_list('activity_definition_name', flat=True) act_descs = Activity.objects.filter(activity_id="act:test_define").values_list('activity_definition_description', flat=True) @@ -507,7 +507,7 @@ def test_fetching_access_token_with_invalid_grant_type(self): self.assertEqual(400, response.status_code) self.assertEqual('unsupported_grant_type', json.loads(response.content)['error'], - response.content) + response.content) def test_fetching_single_access_token(self): constants.SINGLE_ACCESS_TOKEN = True @@ -587,11 +587,11 @@ def test_refreshing_an_access_token(self): self.assertEqual(400, response.status_code) self.assertEqual('invalid_grant', json.loads(response.content)['error'], - response.content) + response.content) def test_password_grant_public(self): c = self.get_client() - c.client_type = 1 # public + c.client_type = 1 # public c.save() response = self.client.post(self.access_token_url(), { @@ -610,7 +610,7 @@ def test_password_grant_public(self): def test_password_grant_confidential(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -626,7 +626,7 @@ def test_password_grant_confidential(self): def test_password_grant_confidential_no_secret(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -640,7 +640,7 @@ def test_password_grant_confidential_no_secret(self): def test_password_grant_invalid_password_public(self): c = self.get_client() - c.client_type = 1 # public + c.client_type = 1 # public c.save() response = self.client.post(self.access_token_url(), { @@ -655,7 +655,7 @@ def test_password_grant_invalid_password_public(self): def test_password_grant_invalid_password_confidential(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -701,7 +701,7 @@ def test_access_token_backend(self): backend = AccessTokenBackend() token = AccessToken.objects.create(user=user, client=client) authenticated = backend.authenticate(access_token=token.token, - client=client) + client=client) self.assertIsNotNone(authenticated) @@ -729,10 +729,12 @@ def test_access_token_enforces_SSL(self): self.assertEqual(400, response.status_code) self.assertTrue("A secure connection is required." in response.content) + class ClientFormTest(TestCase): + def test_client_form(self): form = ClientForm({'name': 'TestName', 'url': 'http://127.0.0.1:8000', - 'redirect_uri': 'http://localhost:8000/'}) + 'redirect_uri': 'http://localhost:8000/'}) self.assertFalse(form.is_valid()) @@ -744,10 +746,11 @@ def test_client_form(self): self.assertTrue(form.is_valid()) form.save() + class DeleteExpiredTest(OAuth2Tests): fixtures = ['test_oauth2'] - def setUp(self): + def setUp(self): self._delete_expired = constants.DELETE_EXPIRED constants.DELETE_EXPIRED = True @@ -797,7 +800,7 @@ def test_clear_expired(self): 'grant_type': 'refresh_token', 'refresh_token': token['refresh_token'], 'client_id': self.get_client().client_id, - 'client_secret': self.get_client().client_secret, + 'client_secret': self.get_client().client_secret, }) self.assertEqual(200, response.status_code) token = json.loads(response.content) @@ -810,4 +813,4 @@ def test_clear_expired(self): self.assertFalse(AccessToken.objects.filter(token=access_token) .exists()) self.assertFalse(RefreshToken.objects.filter(token=refresh_token) - .exists()) \ No newline at end of file + .exists()) diff --git a/lrs/tests/OAuthTests.py b/lrs/tests/OAuthTests.py index 637ea031..519074ec 100644 --- a/lrs/tests/OAuthTests.py +++ b/lrs/tests/OAuthTests.py @@ -27,7 +27,9 @@ AUTHORIZATION_ENDPOINT = TEST_SERVER + "/XAPI/OAuth/authorize" TOKEN_ENDPOINT = TEST_SERVER + "/XAPI/OAuth/token" + class OAuthTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -40,36 +42,35 @@ def setUp(self): self.user = User.objects.create_user('jane', 'jane@example.com', 'toto') self.client.login(username='jane', password='toto') - #Register a consumer + # Register a consumer self.name = "test jane client" self.desc = "test jane client desc" - form = {"name":self.name, "description":self.desc} - self.client.post(reverse(reg_client),form) + form = {"name": self.name, "description": self.desc} + self.client.post(reverse(reg_client), form) self.consumer = Consumer.objects.get(name=self.name) self.name2jane = "test jane client2" self.desc2jane = "test jane client desc2" - form2jane = {"name":self.name2jane, "description":self.desc2jane} - self.client.post(reverse(reg_client),form2jane) + form2jane = {"name": self.name2jane, "description": self.desc2jane} + self.client.post(reverse(reg_client), form2jane) self.consumer2jane = Consumer.objects.get(name=self.name2jane) - self.client.logout() - self.jane_auth = "Basic %s" % base64.b64encode("%s:%s" % ('jane','toto')) + self.jane_auth = "Basic %s" % base64.b64encode("%s:%s" % ('jane', 'toto')) # Create a user self.user2 = User.objects.create_user('dick', 'dick@example.com', 'lassie') self.client.login(username='dick', password='lassie') - #Register a client + # Register a client self.name2 = "test client2" self.desc2 = "test desc2" - form2 = {"name":self.name2, "description":self.desc2} - self.client.post(reverse(reg_client),form2) + form2 = {"name": self.name2, "description": self.desc2} + self.client.post(reverse(reg_client), form2) self.consumer2 = Consumer.objects.get(name=self.name2) self.client.logout() - self.dick_auth = "Basic %s" % base64.b64encode("%s:%s" % ('dick','lassie')) - + self.dick_auth = "Basic %s" % base64.b64encode("%s:%s" % ('dick', 'lassie')) + def tearDown(self): if settings.OAUTH_ENABLED: settings.OAUTH_ENABLED = False @@ -88,7 +89,7 @@ def tearDown(self): raise e def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_type='qs', change_scope=[], - request_nonce='', access_nonce='', resource_nonce='', consumer=None): + request_nonce='', access_nonce='', resource_nonce='', consumer=None): # ============= INITIATE ============= if not request_nonce: @@ -98,12 +99,12 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty consumer = self.consumer oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"%s\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (consumer.key,str(int(time.time())), request_nonce) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"%s\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (consumer.key, str(int(time.time())), request_nonce) # Add non oauth parameters appropriately request_token_params = {} @@ -129,29 +130,29 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty for p in oauth_header_request_token_params_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # Make oauth request depending on where the parameters are if param_type == 'qs': oauth_request = oauth.Request.from_consumer_and_token(consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) else: oauth_request = oauth.Request.from_consumer_and_token(consumer, token=None, http_method='POST', - http_url=request_token_path, parameters=dict(oauth_header_request_token_params_dict.items()+request_token_params.items())) + http_url=request_token_path, parameters=dict(oauth_header_request_token_params_dict.items() + request_token_params.items())) # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + # Send request depending on the parameters if param_type == 'qs': request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) else: request_resp = self.client.post(request_token_path, Authorization=oauth_header_request_token_params, data=request_token_params, - content_type="application/x-www-form-urlencoded") + content_type="application/x-www-form-urlencoded") # Get request token (will be only token for that user) self.assertEqual(request_resp.status_code, 200) @@ -162,23 +163,22 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty request_token = Token.objects.get(secret=token_secret) # ============= END INITIATE ============= - # ============= AUTHORIZE ============= # Create authorize path, must have oauth_token param authorize_param = {'oauth_token': request_token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) # Try to hit auth path, made to login auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(request_token.key, auth_resp['Location']) + self.assertIn(request_token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(request_token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + # Get the form, set required fields auth_form = auth_resp.context['form'] data = auth_form.initial @@ -202,7 +202,6 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty self.assertEqual(request_token_after_auth.is_approved, True) # ============= END AUTHORIZE ============= - # ============= ACCESS TOKEN ============= if not access_nonce: access_nonce = "access_nonce" @@ -217,17 +216,17 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty "oauth_version=\"1.0\","\ "oauth_verifier=\"%s\"" % (consumer.key, request_token_after_auth.key, str(int(time.time())), access_nonce, request_token_after_auth.verifier) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_access_token_params.split(",") oauth_header_access_params_dict = {} for p in param_list: item = p.split("=") oauth_header_access_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_access_params_dict['OAuth realm'] oauth_request = oauth.Request.from_token_and_callback(request_token_after_auth, http_method='GET', - http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) + http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) # Create signature and add it to the headers signature_method = oauth.SignatureMethod_HMAC_SHA1() @@ -258,19 +257,19 @@ def oauth_handshake(self, scope=True, scope_type=None, parameters=None, param_ty return oauth_header_resource_params, access_token def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_type='qs', change_scope=[], - request_nonce='', access_nonce='', resource_nonce=''): + request_nonce='', access_nonce='', resource_nonce=''): # ============= INITIATE ============= if not request_nonce: request_nonce = "request_nonce2" oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"%s\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer2.key,str(int(time.time())), request_nonce) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"%s\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer2.key, str(int(time.time())), request_nonce) # Add non oauth parameters appropriately request_token_params = {} @@ -294,28 +293,27 @@ def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_t for p in oauth_header_request_token_params_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] if param_type == 'qs': oauth_request = oauth.Request.from_consumer_and_token(self.consumer2, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) else: oauth_request = oauth.Request.from_consumer_and_token(self.consumer2, token=None, http_method='POST', - http_url=request_token_path, parameters=dict(oauth_header_request_token_params_dict.items()+request_token_params.items())) + http_url=request_token_path, parameters=dict(oauth_header_request_token_params_dict.items() + request_token_params.items())) - # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer2, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + if param_type == 'qs': request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) else: request_resp = self.client.post(request_token_path, Authorization=oauth_header_request_token_params, data=request_token_params, - content_type="application/x-www-form-urlencoded") + content_type="application/x-www-form-urlencoded") self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -324,21 +322,20 @@ def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_t request_token = Token.objects.get(consumer=self.consumer2) # ============= END INITIATE ============= - # ============= AUTHORIZE ============= authorize_param = {'oauth_token': request_token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(request_token.key, auth_resp['Location']) + self.assertIn(request_token.key, auth_resp['Location']) self.client.login(username='dick', password='lassie') self.assertEqual(request_token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + auth_form = auth_resp.context['form'] data = auth_form.initial data['authorize_access'] = 1 @@ -358,7 +355,6 @@ def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_t self.assertEqual(request_token_after_auth.is_approved, True) # ============= END AUTHORIZE ============= - # ============= ACCESS TOKEN ============= if not access_nonce: access_nonce = "access_nonce2" @@ -372,17 +368,17 @@ def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_t "oauth_version=\"1.0\","\ "oauth_verifier=\"%s\"" % (self.consumer2.key, request_token_after_auth.key, str(int(time.time())), access_nonce, request_token_after_auth.verifier) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_access_token_params.split(",") oauth_header_access_params_dict = {} for p in param_list: item = p.split("=") oauth_header_access_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_access_params_dict['OAuth realm'] oauth_request = oauth.Request.from_token_and_callback(request_token_after_auth, http_method='GET', - http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) + http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) # Create signature and add it to the headers signature_method = oauth.SignatureMethod_HMAC_SHA1() @@ -414,12 +410,12 @@ def oauth_handshake2(self, scope=True, scope_type=None, parameters=None, param_t def test_request_token_missing_headers(self): # Missing signature method oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) - + "oauth_consumer_key=\"%s\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) + # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") oauth_header_request_token_params_dict = {} @@ -429,13 +425,13 @@ def test_request_token_missing_headers(self): # Create OAuth request and signature oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) - + # Append signature to string headers oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + resp = self.client.get(INITIATE_ENDPOINT) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid request parameters.') @@ -443,15 +439,15 @@ def test_request_token_missing_headers(self): def test_request_token_unsupported_headers(self): # Rogue oauth param added oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "this_is_not_good=\"blah\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) - - # Make string params into dictionary for from_consumer_and_token function + "oauth_consumer_key=\"%s\","\ + "this_is_not_good=\"blah\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) + + # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") oauth_header_request_token_params_dict = {} for p in request_token_param_list: @@ -460,13 +456,13 @@ def test_request_token_unsupported_headers(self): # Create oauth request and signature oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) - - # Append signature + + # Append signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + resp = self.client.get(INITIATE_ENDPOINT) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid request parameters.') @@ -474,15 +470,15 @@ def test_request_token_unsupported_headers(self): def test_request_token_duplicated_headers(self): # Duplicate signature_method oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) - - # Make string params into dictionary for from_consumer_and_token function + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) + + # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") oauth_header_request_token_params_dict = {} for p in request_token_param_list: @@ -490,13 +486,13 @@ def test_request_token_duplicated_headers(self): oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) - + # Append signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + resp = self.client.get(INITIATE_ENDPOINT) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid request parameters.') @@ -504,14 +500,14 @@ def test_request_token_duplicated_headers(self): def test_request_token_unsupported_signature_method(self): # Add unsupported signature method oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"unsupported\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) - - # Make string params into dictionary for from_consumer_and_token function + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"unsupported\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) + + # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") oauth_header_request_token_params_dict = {} for p in request_token_param_list: @@ -519,13 +515,13 @@ def test_request_token_unsupported_signature_method(self): oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) - + # Append signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + resp = self.client.get(INITIATE_ENDPOINT) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid request parameters.') @@ -533,14 +529,14 @@ def test_request_token_unsupported_signature_method(self): def test_request_token_invalid_consumer_credentials(self): # Non existent consumer key oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"unsupported\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % ("aaaaaaaaaaaaaa",str(int(time.time()))) - - # Make string params into dictionary for from_consumer_and_token function + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"unsupported\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % ("aaaaaaaaaaaaaa", str(int(time.time()))) + + # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") oauth_header_request_token_params_dict = {} for p in request_token_param_list: @@ -548,13 +544,13 @@ def test_request_token_invalid_consumer_credentials(self): oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) - + # Append signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + resp = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params) self.assertEqual(resp.status_code, 401) self.assertEqual(resp.content, 'Invalid consumer.') @@ -562,16 +558,16 @@ def test_request_token_invalid_consumer_credentials(self): def test_request_token_unknown_scope(self): # passing scope as form param instead of in query string in this instance - scope DNE form_data = { - 'scope':'DNE', + 'scope': 'DNE', } oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") @@ -581,31 +577,31 @@ def test_request_token_unknown_scope(self): oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items()+form_data.items())) + http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items() + form_data.items())) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) # Add signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params, data=form_data, - content_type="x-www-form-urlencoded") + content_type="x-www-form-urlencoded") self.assertEqual(request_resp.status_code, 400) self.assertEqual(request_resp.content, 'Could not verify OAuth request.') def test_request_token_wrong_scope(self): # passing scope as form param instead of in query string in this instance form_data = { - 'scope':'all', + 'scope': 'all', } oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") @@ -618,18 +614,18 @@ def test_request_token_wrong_scope(self): del oauth_header_request_token_params_dict['OAuth realm'] oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items()+form_data.items())) + http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items() + form_data.items())) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) # Add signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - - #Change form scope from what oauth_request was made with + + # Change form scope from what oauth_request was made with form_data['scope'] = 'profile' request_resp = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params, data=form_data, - content_type="x-www-form-urlencoded") + content_type="x-www-form-urlencoded") self.assertEqual(request_resp.status_code, 400) self.assertEqual(request_resp.content, 'Could not verify OAuth request.') @@ -638,12 +634,12 @@ def test_request_token_same_nonce_and_time(self): # Header params we're passing in now_time = str(int(time.time())) oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, now_time) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, now_time) # Make string params into dictionary for from_consumer_and_token function request_token_param_list = oauth_header_request_token_params.split(",") @@ -651,19 +647,19 @@ def test_request_token_same_nonce_and_time(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) - + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) # ======================================== @@ -671,12 +667,12 @@ def test_request_token_same_nonce_and_time(self): # Try to create another request token with the same nonce # Header params we're passing in oauth_header_request_token_params2 = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, now_time) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, now_time) # Make string params into dictionary for from_consumer_and_token function request_token_param_list2 = oauth_header_request_token_params2.split(",") @@ -684,31 +680,31 @@ def test_request_token_same_nonce_and_time(self): for p in request_token_param_list2: item = p.split("=") oauth_header_request_token_params_dict2[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict2['OAuth realm'] # add scope to the existing params oauth_request2 = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict2) - + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict2) + # create signature and add it to the header params signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, None) oauth_header_request_token_params2 = oauth_header_request_token_params2 + ",oauth_signature=%s" % signature2 - + request_resp2 = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params2) self.assertEqual(request_resp2.status_code, 400) def test_request_token_no_scope(self): # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -716,19 +712,19 @@ def test_request_token_no_scope(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) - + http_url=INITIATE_ENDPOINT, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + # Should still give request_token even w/o scope sent request_resp = self.client.get(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) @@ -739,18 +735,18 @@ def test_request_token_no_scope(self): def test_request_token_scope_in_form(self): # passing scope as form param instead of in query string in this instance form_data = { - 'scope':'all', - 'consumer_name':'new_client' + 'scope': 'all', + 'consumer_name': 'new_client' } # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -758,21 +754,21 @@ def test_request_token_scope_in_form(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='POST', - http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items()+form_data.items())) + http_url=INITIATE_ENDPOINT, parameters=dict(oauth_header_request_token_params_dict.items() + form_data.items())) # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + # By default django's test client POSTs as multipart. We want form request_resp = self.client.post(INITIATE_ENDPOINT, Authorization=oauth_header_request_token_params, data=form_data, - content_type="application/x-www-form-urlencoded") + content_type="application/x-www-form-urlencoded") self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) self.assertIn('oauth_token', request_resp.content) @@ -781,18 +777,18 @@ def test_request_token_scope_in_form(self): def test_request_token_scope_in_qs(self): # Set scope and consumer_name in param param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -800,19 +796,19 @@ def test_request_token_scope_in_qs(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -821,18 +817,18 @@ def test_request_token_scope_in_qs(self): def test_request_token_plaintext(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -840,19 +836,19 @@ def test_request_token_plaintext(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -880,19 +876,19 @@ def test_request_token_rsa_sha1(self): self.consumer.save() param = { - 'scope':'all', - 'consumer_name':'new_client' - } + 'scope': 'all', + 'consumer_name': 'new_client' + } request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"RSA-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"RSA-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -900,14 +896,14 @@ def test_request_token_rsa_sha1(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = SignatureMethod_RSA_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) @@ -944,26 +940,26 @@ def test_request_token_rsa_sha1_full_workflow(self): Lw03eHTNQghS0A== -----END PRIVATE KEY-----""" - form = {"name":name, "description":desc, "rsa": True, "secret":rsa_key} - my_reg_client = self.client.post(reverse(reg_client),form) + form = {"name": name, "description": desc, "rsa": True, "secret": rsa_key} + my_reg_client = self.client.post(reverse(reg_client), form) self.assertEqual(my_reg_client.status_code, 200) consumer = Consumer.objects.get(name=name) self.client.logout() param = { - 'scope':'all', - 'consumer_name': name - } + 'scope': 'all', + 'consumer_name': name + } request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"RSA-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/token_ready\"" % (consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"RSA-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/token_ready\"" % (consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -971,14 +967,14 @@ def test_request_token_rsa_sha1_full_workflow(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = SignatureMethod_RSA_SHA1() signature = signature_method.sign(oauth_request, consumer, None) @@ -995,19 +991,19 @@ def test_request_token_rsa_sha1_full_workflow(self): # ============= AUTHORIZE ============= # Create authorize path, must have oauth_token param authorize_param = {'oauth_token': request_token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(authorize_param)) # Try to hit auth path, made to login auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(request_token.key, auth_resp['Location']) + self.assertIn(request_token.key, auth_resp['Location']) self.client.login(username='mike', password='dino') self.assertEqual(request_token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + # Get the form, set required fields auth_form = auth_resp.context['form'] data = auth_form.initial @@ -1037,17 +1033,17 @@ def test_request_token_rsa_sha1_full_workflow(self): "oauth_version=\"1.0\","\ "oauth_verifier=\"%s\"" % (consumer.key, request_token_after_auth.key, str(int(time.time())), "access_nonce", request_token_after_auth.verifier) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_access_token_params.split(",") oauth_header_access_params_dict = {} for p in param_list: item = p.split("=") oauth_header_access_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_access_params_dict['OAuth realm'] oauth_request = oauth.Request.from_token_and_callback(request_token_after_auth, http_method='GET', - http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) + http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) # Create signature and add it to the headers signature_method = SignatureMethod_RSA_SHA1() @@ -1072,19 +1068,19 @@ def test_request_token_rsa_sha1_full_workflow(self): "oauth_nonce=\"%s\","\ "oauth_version=\"1.0\"" % (consumer.key, access_token.key, str(int(time.time())), "resource_nonce") - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: item = p.split("=") oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_resource_params_dict['OAuth realm'] path = TEST_SERVER + "/XAPI/statements" oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) # Create signature and add it to the headers signature_method = SignatureMethod_RSA_SHA1() @@ -1115,19 +1111,19 @@ def test_request_token_rsa_sha1_wrong_key(self): self.consumer.save() param = { - 'scope':'all', - 'consumer_name':'new_client' - } + 'scope': 'all', + 'consumer_name': 'new_client' + } request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"RSA-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"RSA-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1135,7 +1131,7 @@ def test_request_token_rsa_sha1_wrong_key(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # create signature and add it to the header params oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % "badsignature" @@ -1144,18 +1140,18 @@ def test_request_token_rsa_sha1_wrong_key(self): def test_request_token_wrong_oauth_version(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in - wrong oauth_version oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.1\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.1\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1163,36 +1159,36 @@ def test_request_token_wrong_oauth_version(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 400) def test_request_token_wrong_signature(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.1\","\ - "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.1\","\ + "oauth_callback=\"http://example.com/request_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1200,28 +1196,28 @@ def test_request_token_wrong_signature(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # create signature and add it to the header params - adding wrong signature oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % "wrongsignature" - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 400) self.assertEqual(request_resp.content, 'Could not verify OAuth request.') def test_auth_correct(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1229,19 +1225,19 @@ def test_auth_correct(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1252,18 +1248,18 @@ def test_auth_correct(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + auth_form = auth_resp.context['form'] data = auth_form.initial data['authorize_access'] = 1 @@ -1276,22 +1272,22 @@ def test_auth_correct(self): self.assertIn('oauth_token=', auth_post['Location']) access_token = Token.objects.get(consumer=self.consumer) self.assertIn(access_token.key, auth_post['Location']) - self.assertEqual(access_token.is_approved, True) + self.assertEqual(access_token.is_approved, True) def test_auth_scope_up(self): param = { - 'scope':'statements/read', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'statements/read', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1299,19 +1295,19 @@ def test_auth_scope_up(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1322,18 +1318,18 @@ def test_auth_scope_up(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + # Increase power of scope here - not allowed auth_form = auth_resp.context['form'] data = auth_form.initial @@ -1347,18 +1343,18 @@ def test_auth_scope_up(self): def test_auth_wrong_auth(self): param = { - 'scope':'statements/read', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'statements/read', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1366,19 +1362,19 @@ def test_auth_wrong_auth(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1389,34 +1385,34 @@ def test_auth_wrong_auth(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) self.assertIn(token.key, auth_resp['Location']) - # Login with wrong user the client is associated with + # Login with wrong user the client is associated with self.client.login(username='dick', password='lassie') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 403) # Show return/display OAuth authorized view + self.assertEqual(auth_resp.status_code, 403) # Show return/display OAuth authorized view self.assertEqual(auth_resp.content, 'Invalid user for this client.') def test_auth_no_scope_chosen(self): param = { - 'scope':'statements/read', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'statements/read', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1424,19 +1420,19 @@ def test_auth_no_scope_chosen(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1447,18 +1443,18 @@ def test_auth_no_scope_chosen(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + # User must select at least one scope auth_form = auth_resp.context['form'] data = auth_form.initial @@ -1472,18 +1468,18 @@ def test_auth_no_scope_chosen(self): def test_access_token_invalid_token(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"requestnonce\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"requestnonce\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1491,19 +1487,19 @@ def test_access_token_invalid_token(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1514,18 +1510,18 @@ def test_access_token_invalid_token(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + auth_form = auth_resp.context['form'] data = auth_form.initial data['authorize_access'] = 1 @@ -1552,26 +1548,26 @@ def test_access_token_invalid_token(self): "oauth_timestamp=\"%s\","\ "oauth_nonce=\"accessnonce\","\ "oauth_version=\"1.0\","\ - "oauth_verifier=\"%s\"" % (self.consumer.key,token.key,self.consumer.secret,token.secret,str(int(time.time())),token.verifier) + "oauth_verifier=\"%s\"" % (self.consumer.key, token.key, self.consumer.secret, token.secret, str(int(time.time())), token.verifier) access_resp = self.client.get(TOKEN_ENDPOINT, Authorization=oauth_header_access_params) self.assertEqual(access_resp.status_code, 401) self.assertEqual(access_resp.content, "Request Token not approved by the user.") - + def test_access_token_access_resources(self): param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"PLAINTEXT\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"12345678\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"PLAINTEXT\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"12345678\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1579,19 +1575,19 @@ def test_access_token_access_resources(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_PLAINTEXT() signature = signature_method.sign(oauth_request, self.consumer, None) oauth_header_request_token_params = oauth_header_request_token_params + ",oauth_signature=%s" % signature - + request_resp = self.client.get(request_token_path, Authorization=oauth_header_request_token_params) self.assertEqual(request_resp.status_code, 200) self.assertIn('oauth_token_secret', request_resp.content) @@ -1602,18 +1598,18 @@ def test_access_token_access_resources(self): # Test AUTHORIZE param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + auth_form = auth_resp.context['form'] data = auth_form.initial data['authorize_access'] = 1 @@ -1638,7 +1634,7 @@ def test_access_token_access_resources(self): "oauth_timestamp=\"%s\","\ "oauth_nonce=\"87654321\","\ "oauth_version=\"1.0\","\ - "oauth_verifier=\"%s\"" % (self.consumer.key,token.key,self.consumer.secret,request_token.secret,str(int(time.time())),request_token.verifier) + "oauth_verifier=\"%s\"" % (self.consumer.key, token.key, self.consumer.secret, request_token.secret, str(int(time.time())), request_token.verifier) access_resp = self.client.get(TOKEN_ENDPOINT, Authorization=oauth_header_access_params) self.assertEqual(access_resp.status_code, 200) @@ -1657,19 +1653,19 @@ def test_access_token_access_resources(self): "oauth_nonce=\"accessresourcenonce\","\ "oauth_version=\"1.0\"" % (self.consumer.key, access_token.key, str(int(time.time()))) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: item = p.split("=") oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_resource_params_dict['OAuth realm'] path = TEST_SERVER + "/XAPI/statements" oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) # Create signature and add it to the headers signature_method = oauth.SignatureMethod_HMAC_SHA1() @@ -1683,18 +1679,18 @@ def test_unicode(self): # All client requests have the auth as unicode # ============= INITIATE ============= param = { - 'scope':'all', - 'consumer_name':'new_client' - } - request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) + 'scope': 'all', + 'consumer_name': 'new_client' + } + request_token_path = "%s?%s" % (INITIATE_ENDPOINT, urllib.urlencode(param)) # Header params we're passing in oauth_header_request_token_params = "OAuth realm=\"test\","\ - "oauth_consumer_key=\"%s\","\ - "oauth_signature_method=\"HMAC-SHA1\","\ - "oauth_timestamp=\"%s\","\ - "oauth_nonce=\"12345678\","\ - "oauth_version=\"1.0\","\ - "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key,str(int(time.time()))) + "oauth_consumer_key=\"%s\","\ + "oauth_signature_method=\"HMAC-SHA1\","\ + "oauth_timestamp=\"%s\","\ + "oauth_nonce=\"12345678\","\ + "oauth_version=\"1.0\","\ + "oauth_callback=\"http://example.com/access_token_ready\"" % (self.consumer.key, str(int(time.time()))) # Make the params into a dict to pass into from_consumer_and_token request_token_param_list = oauth_header_request_token_params.split(",") @@ -1702,14 +1698,14 @@ def test_unicode(self): for p in request_token_param_list: item = p.split("=") oauth_header_request_token_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # get_oauth_request in views ignores realm, must remove so not input to from_token_and_callback del oauth_header_request_token_params_dict['OAuth realm'] # add scope to the existing params oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=None, http_method='GET', - http_url=request_token_path, parameters=oauth_header_request_token_params_dict) - + http_url=request_token_path, parameters=oauth_header_request_token_params_dict) + # create signature and add it to the header params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, None) @@ -1725,18 +1721,18 @@ def test_unicode(self): # ============= AUTHORIZE ============= param = {'oauth_token': token.key} - authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) + authorize_path = "%s?%s" % (AUTHORIZATION_ENDPOINT, urllib.urlencode(param)) auth_resp = self.client.get(authorize_path) self.assertEqual(auth_resp.status_code, 302) self.assertIn('http://testserver/accounts/login?next=/XAPI/OAuth/authorize%3F', auth_resp['Location']) - self.assertIn(token.key, auth_resp['Location']) + self.assertIn(token.key, auth_resp['Location']) self.client.login(username='jane', password='toto') self.assertEqual(token.is_approved, False) # After being redirected to login and logging in again, try get again auth_resp = self.client.get(authorize_path) - self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view - + self.assertEqual(auth_resp.status_code, 200) # Show return/display OAuth authorized view + auth_form = auth_resp.context['form'] data = auth_form.initial data['authorize_access'] = 1 @@ -1760,19 +1756,19 @@ def test_unicode(self): "oauth_timestamp=\"%s\","\ "oauth_nonce=\"87654321\","\ "oauth_version=\"1.0\","\ - "oauth_verifier=\"%s\"" % (self.consumer.key,token.key,str(int(time.time())),request_token.verifier) + "oauth_verifier=\"%s\"" % (self.consumer.key, token.key, str(int(time.time())), request_token.verifier) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_access_params.split(",") oauth_header_access_params_dict = {} for p in param_list: item = p.split("=") oauth_header_access_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_access_params_dict['OAuth realm'] oauth_request = oauth.Request.from_token_and_callback(request_token, http_method='GET', - http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) + http_url=TOKEN_ENDPOINT, parameters=oauth_header_access_params_dict) # Create signature and add it to the headers signature_method = oauth.SignatureMethod_HMAC_SHA1() @@ -1796,19 +1792,19 @@ def test_unicode(self): "oauth_nonce=\"accessresourcenonce\","\ "oauth_version=\"1.0\"" % (self.consumer.key, access_token.key, str(int(time.time()))) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: item = p.split("=") oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_resource_params_dict['OAuth realm'] path = TEST_SERVER + "/XAPI/statements" oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) # Create signature and add it to the headers signature_method = oauth.SignatureMethod_HMAC_SHA1() @@ -1824,15 +1820,15 @@ def test_oauth_disabled(self): settings.OAUTH_ENABLED = False put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"act:test_put"}}) - param = {"statementId":put_guid} + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "act:test_put"}}) + param = {"statementId": put_guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) - + oauth_header_resource_params, access_token = self.oauth_handshake() - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -1842,8 +1838,8 @@ def test_oauth_disabled(self): del oauth_header_resource_params_dict['OAuth realm'] oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) - + http_url=path, parameters=oauth_header_resource_params_dict) + # build signature and add to the params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) @@ -1851,23 +1847,23 @@ def test_oauth_disabled(self): # Put statements resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, "OAuth is not enabled. To enable, set the OAUTH_ENABLED flag to true in settings") def test_stmt_put(self): # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"act:test_put"}}) - param = {"statementId":put_guid} + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "act:test_put"}}) + param = {"statementId": put_guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) - + # Get oauth header params and access token oauth_header_resource_params, access_token = self.oauth_handshake() - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -1878,8 +1874,8 @@ def test_stmt_put(self): # Create oauth request to PUT the stmt oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) - + http_url=path, parameters=oauth_header_resource_params_dict) + # build signature and add to the params signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) @@ -1887,19 +1883,19 @@ def test_stmt_put(self): # Put statements resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) def test_stmt_post_no_scope(self): - stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}} + stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}} stmt_json = json.dumps(stmt) # Don't send scope so it defaults to statements/write and statements/read/mine oauth_header_resource_params, access_token = self.oauth_handshake(scope=False) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -1910,29 +1906,29 @@ def test_stmt_post_no_scope(self): # Create oauth_request and apply signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='POST', - http_url='http://testserver/XAPI/statements/', parameters=oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements/', parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) - oauth_header_resource_params += ',oauth_signature="%s"' % signature + oauth_header_resource_params += ',oauth_signature="%s"' % signature post = self.client.post('/XAPI/statements/', data=stmt_json, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 200) def test_stmt_simple_get(self): guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_simple_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_simple_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake() - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -1943,7 +1939,7 @@ def test_stmt_simple_get(self): # Create oauth request and apply signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature @@ -1954,19 +1950,19 @@ def test_stmt_simple_get(self): self.assertIn(guid, rsp) def test_stmt_complex_get(self): - stmt_data = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_complex_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_complex_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"activity":"act:test_complex_get"} + param = {"activity": "act:test_complex_get"} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake() - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -1977,29 +1973,29 @@ def test_stmt_complex_get(self): # Create oauth request and apply signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - resp = self.client.get(path,Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.get(path, Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) def test_stmt_get_then_wrong_scope(self): guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_simple_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_simple_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - - param = {"statementId":guid} + + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake(scope_type="statements/read profile") - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2010,21 +2006,21 @@ def test_stmt_get_then_wrong_scope(self): # Create oauth request and add signature to get statements oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - resp = self.client.get(path,Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.get(path, Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) rsp = resp.content self.assertIn(guid, rsp) # ============================================= # Test POST (not allowed) - post_stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}} + post_stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}} post_stmt_json = json.dumps(post_stmt) # Use same oauth headers, change the nonce @@ -2032,17 +2028,17 @@ def test_stmt_get_then_wrong_scope(self): # create another oauth request oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='POST', - http_url='http://testserver/XAPI/statements/', parameters=oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements/', parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, access_token) # Replace old signature and add the new one - oauth_header_resource_params = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) + oauth_header_resource_params = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) # replace headers with the nonce you added in dict - oauth_header_resource_params = oauth_header_resource_params.replace('oauth_nonce="resource_nonce"','oauth_nonce="another_nonce"') + oauth_header_resource_params = oauth_header_resource_params.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="another_nonce"') post = self.client.post('/XAPI/statements/', data=post_stmt_json, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 403) self.assertEqual(post.content, 'Incorrect permissions to POST at /statements') @@ -2054,12 +2050,12 @@ def test_activity_state_put_then_wrong_scope(self): activity = Activity(activity_id=activityId) activity.save() testparams = {"stateId": stateId, "activityId": activityId, "agent": testagent} - teststate = {"test":"put activity state 1"} + teststate = {"test": "put activity state 1"} path = '%s?%s' % (url, urllib.urlencode(testparams)) oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='state') - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2070,26 +2066,26 @@ def test_activity_state_put_then_wrong_scope(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature put = self.client.put(path, data=teststate, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put.status_code, 204) # ========================================================== # Set up for Get guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_simple_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_simple_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) # Use same oauth_headers as before and change the nonce @@ -2097,34 +2093,34 @@ def test_activity_state_put_then_wrong_scope(self): # create another oauth request oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method.sign(oauth_request, self.consumer, access_token) # Replace old signature with the new one - oauth_header_resource_params_new = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) + oauth_header_resource_params_new = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) # replace headers with the nonce you added in dict - new_oauth_headers = oauth_header_resource_params_new.replace('oauth_nonce="resource_nonce"','oauth_nonce="differ_nonce"') - + new_oauth_headers = oauth_header_resource_params_new.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="differ_nonce"') + get = self.client.get(path, content_type="application/json", - Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 403) self.assertEqual(get.content, 'Incorrect permissions to GET at /statements') def stmt_get_then_wrong_profile_scope(self): guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_simple_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_simple_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake(scope_type="statements/read") - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2135,51 +2131,51 @@ def stmt_get_then_wrong_profile_scope(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - resp = self.client.get(path,Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.get(path, Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) rsp = resp.content self.assertIn(guid, rsp) # =================================================================== url = 'http://testserver/XAPI/agents/profile' - params = {"agent": {"mbox":"mailto:test@example.com"}} - path = "%s?%s" %(url, urllib.urlencode(params)) + params = {"agent": {"mbox": "mailto:test@example.com"}} + path = "%s?%s" % (url, urllib.urlencode(params)) # Use same oauth header, change nonce oauth_header_resource_params_dict['oauth_nonce'] = 'differ_nonce' # create another oauth request oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request, self.consumer, access_token) # Replace signature with new one - new_sig_params = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2 ) + new_sig_params = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) # replace headers with the nonce you added in dict - new_oauth_headers = new_sig_params.replace('oauth_nonce="resource_nonce"','oauth_nonce="differ_nonce"') - + new_oauth_headers = new_sig_params.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="differ_nonce"') + r = self.client.get(path, Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 403) def test_consumer_state(self): - stmt_data = {"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_complex_get"}, "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_complex_get"}, "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"object":{"objectType": "Activity", "id":"act:test_complex_get"}} + param = {"object": {"objectType": "Activity", "id": "act:test_complex_get"}} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake() - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2190,7 +2186,7 @@ def test_consumer_state(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature @@ -2200,7 +2196,7 @@ def test_consumer_state(self): consumer.status = 4 consumer.save() - resp = self.client.get(path,Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.get(path, Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 401) self.assertEqual(resp.content, 'Invalid Consumer.') @@ -2211,25 +2207,25 @@ def test_simple_stmt_get_mine_only(self): email = "test1@tester.com" password = "test" auth = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) - form = {"username":username, "email":email,"password":password,"password2":password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": username, "email": email, "password": password, "password2": password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.client.logout() - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) put_resp = self.client.put(path, stmt, content_type="application/json", Authorization=auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_resp.status_code, 204) - - param = {"statementId":guid} + + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) # ==================================================== oauth_header_resource_params, access_token = self.oauth_handshake(scope_type="statements/read/mine") - # From_token_and_callback takes a dictionary + # From_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2240,7 +2236,7 @@ def test_simple_stmt_get_mine_only(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature @@ -2255,32 +2251,32 @@ def test_simple_stmt_get_mine_only(self): oauth_group = Agent.objects.get(member__in=[oauth_agent1, oauth_agent2]) guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"act:test_put"}, "authority":oauth_group.to_dict()} - + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "act:test_put"}, "authority": oauth_group.to_dict()} + settings.ALLOW_EMPTY_HTTP_AUTH = True stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization="Basic %s" % base64.b64encode("%s:%s" % ('','')), X_Experience_API_Version=settings.XAPI_VERSION) + Authorization="Basic %s" % base64.b64encode("%s:%s" % ('', '')), X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) - # Use same oauth headers but replace the nonce + # Use same oauth headers but replace the nonce oauth_header_resource_params_dict['oauth_nonce'] = 'get_differ_nonce' # Create another oauth request, replace the signature with new one and change the nonce oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, access_token) sig = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) - new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"','oauth_nonce="get_differ_nonce"') + new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="get_differ_nonce"') get = self.client.get(path, content_type="application/json", - Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 200) settings.ALLOW_EMPTY_HTTP_AUTH = False @@ -2290,26 +2286,26 @@ def test_complex_stmt_get_mine_only(self): email = "test1@tester.com" password = "test" auth = "Basic %s" % base64.b64encode("%s:%s" % (username, password)) - form = {"username":username, "email":email,"password":password,"password2":password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": username, "email": email, "password": password, "password2": password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.client.logout() # Put statement - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) put_response = self.client.put(path, stmt, content_type="application/json", Authorization=auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_response.status_code, 204) # ============================================= - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % ('http://testserver/XAPI/statements', urllib.urlencode(param)) oauth_header_resource_params, access_token = self.oauth_handshake(scope_type="statements/read/mine") - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2320,7 +2316,7 @@ def test_complex_stmt_get_mine_only(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature @@ -2330,20 +2326,20 @@ def test_complex_stmt_get_mine_only(self): # ==================================================== # Should return 0 statements since the only statement is not this user's - # Use same oauth headers but replace the nonce + # Use same oauth headers but replace the nonce oauth_header_resource_params_dict['oauth_nonce'] = 'differ_nonce' - + # Create another oauth request and add the signature oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url='http://testserver/XAPI/statements', parameters=oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements', parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, access_token) sig = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) - new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"','oauth_nonce="differ_nonce"') + new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="differ_nonce"') # Get statements get = self.client.get('http://testserver/XAPI/statements', content_type="application/json", - Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) get_content = json.loads(get.content) self.assertEqual(get.status_code, 200) self.assertEqual(len(get_content['statements']), 0) @@ -2356,29 +2352,28 @@ def test_complex_stmt_get_mine_only(self): oauth_group = Agent.objects.get(member__in=[oauth_agent1, oauth_agent2]) guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"act:test_put"}, "authority":oauth_group.to_dict()} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "act:test_put"}, "authority": oauth_group.to_dict()} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - # Use same headers, change nonce oauth_header_resource_params_dict['oauth_nonce'] = 'get_differ_nonce' - # Create oauth request and add signature + # Create oauth request and add signature oauth_request3 = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url='http://testserver/XAPI/statements', parameters=oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements', parameters=oauth_header_resource_params_dict) signature_method3 = oauth.SignatureMethod_HMAC_SHA1() signature3 = signature_method3.sign(oauth_request3, self.consumer, access_token) sig2 = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature3) - new_oauth_headers2 = sig2.replace('oauth_nonce="resource_nonce"','oauth_nonce="get_differ_nonce"') + new_oauth_headers2 = sig2.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="get_differ_nonce"') # Get statements get2 = self.client.get('http://testserver/XAPI/statements', content_type="application/json", - Authorization=new_oauth_headers2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=new_oauth_headers2, X_Experience_API_Version=settings.XAPI_VERSION) get_content2 = json.loads(get2.content) self.assertEqual(get2.status_code, 200) @@ -2394,12 +2389,12 @@ def test_state_wrong_auth(self): activity = Activity(activity_id=activityId) activity.save() testparams = {"stateId": stateId, "activityId": activityId, "agent": testagent} - teststate = {"test":"put activity state 1"} + teststate = {"test": "put activity state 1"} path = '%s?%s' % (url, urllib.urlencode(testparams)) oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='state') - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2410,14 +2405,14 @@ def test_state_wrong_auth(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature put = self.client.put(path, data=teststate, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put.status_code, 404) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(put.status_code, 404) self.assertEqual(put.content, "Agent in state cannot be found to match user in authorization") def test_profile_wrong_auth(self): @@ -2431,7 +2426,7 @@ def test_profile_wrong_auth(self): oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='profile') - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2439,46 +2434,46 @@ def test_profile_wrong_auth(self): oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') # from_request ignores realm, must remove so not input to from_token_and_callback del oauth_header_resource_params_dict['OAuth realm'] - + # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature get = self.client.get(path, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(get.status_code, 403) self.assertEqual(get.content, "Authorization doesn't match agent in profile") def test_define_scope_activity(self): url = 'http://testserver/XAPI/statements' guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", - "mbox":"mailto:bob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"}},"object": {"id":"test://test/define/scope"}, - "authority":{"objectType":"Agent", "mbox":"mailto:jane@example.com"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", + "mbox": "mailto:bob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"}}, "object": {"id": "test://test/define/scope"}, + "authority": {"objectType": "Agent", "mbox": "mailto:jane@example.com"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bill@bill.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"test://test/define/scope", - 'definition': {'name': {'en-US':'testname', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc', 'en-GB': 'altdesc'},'type': 'type:course', - 'interactionType': 'other', 'correctResponsesPattern':[]}}}) - - param = {"statementId":put_guid} + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bill@bill.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "test://test/define/scope", + 'definition': {'name': {'en-US': 'testname', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc', 'en-GB': 'altdesc'}, 'type': 'type:course', + 'interactionType': 'other', 'correctResponsesPattern': []}}}) + + param = {"statementId": put_guid} path = "%s?%s" % (url, urllib.urlencode(param)) - + # START PUT STMT oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='statements/write statements/read') - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2489,14 +2484,14 @@ def test_define_scope_activity(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - + # Put statements - does not have define scope, therefore it cannot update the activity resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) acts = Activity.objects.all() @@ -2504,19 +2499,19 @@ def test_define_scope_activity(self): # ========================================================== # START GET STMT - get_params = {"activity":"test://test/define/scope"} - path = "%s?%s" % (url, urllib.urlencode(get_params)) + get_params = {"activity": "test://test/define/scope"} + path = "%s?%s" % (url, urllib.urlencode(get_params)) # User same oauth headers, change nonce oauth_header_resource_params_dict['oauth_nonce'] = 'get_differ_nonce' # Create oauth request and add signature oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, access_token) sig = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) - new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"','oauth_nonce="get_differ_nonce"') + new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="get_differ_nonce"') get_resp = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=new_oauth_headers) self.assertEqual(get_resp.status_code, 200) @@ -2526,37 +2521,37 @@ def test_define_scope_activity(self): # ========================================================== # START OF POST WITH ANOTHER HANDSHAKE - post_stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:dom@dom.com", "name":"dom"}, - "verb":{"id": "http://example.com/verbs/tested","display": {"en-US":"tested"}}, - "object": {"id":"test://test/define/scope", - 'definition': {'name': {'en-US':'definename', 'en-GB': 'definealtname'}, - 'description': {'en-US':'definedesc', 'en-GB': 'definealtdesc'},'type': 'type:course', - 'interactionType': 'other', 'correctResponsesPattern':[]}}} + post_stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:dom@dom.com", "name": "dom"}, + "verb": {"id": "http://example.com/verbs/tested", "display": {"en-US": "tested"}}, + "object": {"id": "test://test/define/scope", + 'definition': {'name': {'en-US': 'definename', 'en-GB': 'definealtname'}, + 'description': {'en-US': 'definedesc', 'en-GB': 'definealtdesc'}, 'type': 'type:course', + 'interactionType': 'other', 'correctResponsesPattern': []}}} stmt_json = json.dumps(post_stmt) post_oauth_header_resource_params, post_access_token = self.oauth_handshake2(scope_type='define statements/write') - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary post_param_list = post_oauth_header_resource_params.split(",") post_oauth_header_resource_params_dict = {} for p in post_param_list: item = p.split("=") post_oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del post_oauth_header_resource_params_dict['OAuth realm'] - + # Create oauth request and add signature post_oauth_request = oauth.Request.from_token_and_callback(post_access_token, http_method='POST', - http_url='http://testserver/XAPI/statements/', - parameters=post_oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements/', + parameters=post_oauth_header_resource_params_dict) post_signature_method = oauth.SignatureMethod_HMAC_SHA1() post_signature = post_signature_method.sign(post_oauth_request, self.consumer2, post_access_token) - post_oauth_header_resource_params += ',oauth_signature="%s"' % post_signature + post_oauth_header_resource_params += ',oauth_signature="%s"' % post_signature # Even though dick has define scope, he didn't create the activity so he can't update it post = self.client.post('/XAPI/statements/', data=stmt_json, content_type="application/json", - Authorization=post_oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=post_oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 200) acts = Activity.objects.all() self.assertEqual(len(acts), 1) @@ -2565,28 +2560,27 @@ def test_define_scope_activity(self): def test_define_scope_agent(self): url = 'http://testserver/XAPI/statements' guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", - "mbox":"mailto:bob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/helped", - "display": {"en-US":"helped"}},"object": {"objectType":"Agent", "mbox":"mailto:tim@tim.com", - "name":"tim"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", + "mbox": "mailto:bob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/helped", + "display": {"en-US": "helped"}}, "object": {"objectType": "Agent", "mbox": "mailto:tim@tim.com", + "name": "tim"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) - # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bill@bill.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/talked","display": {"en-US":"talked"}}, - "object": {"objectType":"Agent", "mbox":"mailto:tim@tim.com","name":"tim timson"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bill@bill.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/talked", "display": {"en-US": "talked"}}, + "object": {"objectType": "Agent", "mbox": "mailto:tim@tim.com", "name": "tim timson"}}) - param = {"statementId":put_guid} + param = {"statementId": put_guid} path = "%s?%s" % (url, urllib.urlencode(param)) - + # START PUT STMT oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='statements/write statements/read') - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2597,14 +2591,14 @@ def test_define_scope_agent(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature # Put statements resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) agents = Agent.objects.all().values_list('name', flat=True) # Jane, Anonymous agent for account, Group for jane and account, bill, bob, tim and tim timson should be same (no update to tim) @@ -2614,22 +2608,22 @@ def test_define_scope_agent(self): # ================================================= # START GET STMT - get_params = {"agent":{"objectType": "Agent", "mbox":"mailto:tim@tim.com"}, "related_agents":True} - path = "%s?%s" % (url, urllib.urlencode(get_params)) + get_params = {"agent": {"objectType": "Agent", "mbox": "mailto:tim@tim.com"}, "related_agents": True} + path = "%s?%s" % (url, urllib.urlencode(get_params)) # Use same oauth headers, replace nonce oauth_header_resource_params_dict['oauth_nonce'] = 'get_differ_nonce' # Create oauth request and add signature oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='GET', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer, access_token) sig = oauth_header_resource_params.replace('"%s"' % signature, '"%s"' % signature2) - new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"','oauth_nonce="get_differ_nonce"') + new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="get_differ_nonce"') get_resp = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, - Authorization=new_oauth_headers) + Authorization=new_oauth_headers) self.assertEqual(get_resp.status_code, 200) content = json.loads(get_resp.content) # Should be two since querying by tim email. @@ -2640,45 +2634,45 @@ def test_define_scope_agent(self): # START OF POST WITH ANOTHER HANDSHAKE # Anonymous group that will make 2 canonical agents ot = "Group" - members = [{"name":"john doe","mbox":"mailto:jd@example.com"}, - {"name":"jan doe","mbox":"mailto:jandoe@example.com"}] - kwargs = {"objectType":ot, "member": members, "name": "doe group"} + members = [{"name": "john doe", "mbox": "mailto:jd@example.com"}, + {"name": "jan doe", "mbox": "mailto:jandoe@example.com"}] + kwargs = {"objectType": ot, "member": members, "name": "doe group"} global_group, created = Agent.objects.retrieve_or_create(**kwargs) # Anonymous group that will retrieve two agents and create one more canonical agents - members = [{"name":"john doe","mbox":"mailto:jd@example.com"}, - {"name":"jan doe","mbox":"mailto:jandoe@example.com"}, - {"name":"dave doe", "mbox":"mailto:dd@example.com"}] - kwargs1 = {"objectType":ot, "member": members, "name": "doe group"} - - post_stmt = {"actor":{"objectType": "Agent", "mbox":"mailto:dom@dom.com", "name":"dom"}, - "verb":{"id": "http://example.com/verbs/assisted","display": {"en-US":"assisted"}}, - "object": kwargs1} + members = [{"name": "john doe", "mbox": "mailto:jd@example.com"}, + {"name": "jan doe", "mbox": "mailto:jandoe@example.com"}, + {"name": "dave doe", "mbox": "mailto:dd@example.com"}] + kwargs1 = {"objectType": ot, "member": members, "name": "doe group"} + + post_stmt = {"actor": {"objectType": "Agent", "mbox": "mailto:dom@dom.com", "name": "dom"}, + "verb": {"id": "http://example.com/verbs/assisted", "display": {"en-US": "assisted"}}, + "object": kwargs1} stmt_json = json.dumps(post_stmt) post_oauth_header_resource_params, post_access_token = self.oauth_handshake2(scope_type='statements/write statements/read') - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary post_param_list = post_oauth_header_resource_params.split(",") post_oauth_header_resource_params_dict = {} for p in post_param_list: item = p.split("=") post_oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del post_oauth_header_resource_params_dict['OAuth realm'] - + # Create oauth request and add signature post_oauth_request = oauth.Request.from_token_and_callback(post_access_token, http_method='POST', - http_url='http://testserver/XAPI/statements/', - parameters=post_oauth_header_resource_params_dict) + http_url='http://testserver/XAPI/statements/', + parameters=post_oauth_header_resource_params_dict) post_signature_method = oauth.SignatureMethod_HMAC_SHA1() post_signature = post_signature_method.sign(post_oauth_request, self.consumer2, - post_access_token) - post_oauth_header_resource_params += ',oauth_signature="%s"' % post_signature - + post_access_token) + post_oauth_header_resource_params += ',oauth_signature="%s"' % post_signature + post = self.client.post('/XAPI/statements/', data=stmt_json, content_type="application/json", - Authorization=post_oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=post_oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post.status_code, 200) agents = Agent.objects.all().values_list('name', flat=True) # 2 oauth group objects and 2 anon account agents for oauth, all of these agents since created with member or manually, 2 agents for @@ -2691,7 +2685,7 @@ def test_define_scope_agent(self): self.assertIn('tim', agents) self.assertIn('jan doe', agents) self.assertIn('john doe', agents) - self.assertIn('dave doe', agents) + self.assertIn('dave doe', agents) self.assertIn('jane', agents) self.assertIn('dick', agents) self.assertIn('doe group', agents) @@ -2699,74 +2693,74 @@ def test_define_scope_agent(self): def test_default_scope_multiple_requests(self): oauth_header_resource_params, access_token = self.oauth_handshake(scope=False) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) - # from_token_and_callback takes a dictionary + # from_token_and_callback takes a dictionary post_param_list = oauth_header_resource_params.split(",") post_oauth_header_resource_params_dict = {} for p in post_param_list: item = p.split("=") post_oauth_header_resource_params_dict[str(item[0]).strip()] = str(item[1]).strip('"') - + # from_request ignores realm, must remove so not input to from_token_and_callback del post_oauth_header_resource_params_dict['OAuth realm'] - + # Create oauth request and add signature post_oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='POST', - http_url=TEST_SERVER + '/XAPI/statements/', parameters=post_oauth_header_resource_params_dict) + http_url=TEST_SERVER + '/XAPI/statements/', parameters=post_oauth_header_resource_params_dict) post_signature_method = oauth.SignatureMethod_HMAC_SHA1() post_signature = post_signature_method.sign(post_oauth_request, self.consumer, access_token) - oauth_header_resource_params += ',oauth_signature="%s"' % post_signature - + oauth_header_resource_params += ',oauth_signature="%s"' % post_signature + post = self.client.post(TEST_SERVER + '/XAPI/statements/', data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(post.status_code, 200) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(post.status_code, 200) # ==================================================== - stmt2 = json.dumps({"verb":{"id": "http://example.com/verbs/failed","display": {"en-US":"failed"}}, - "object": {"id":"act:test_post"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt2 = json.dumps({"verb": {"id": "http://example.com/verbs/failed", "display": {"en-US": "failed"}}, + "object": {"id": "act:test_post"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) # Use same oauth headers, replace nonce post_oauth_header_resource_params_dict['oauth_nonce'] = 'post_differ_nonce' # Create oauth request and add signature post_oauth_request2 = oauth.Request.from_token_and_callback(access_token, http_method='POST', - http_url=TEST_SERVER + '/XAPI/statements/', parameters=post_oauth_header_resource_params_dict) + http_url=TEST_SERVER + '/XAPI/statements/', parameters=post_oauth_header_resource_params_dict) post_signature_method2 = oauth.SignatureMethod_HMAC_SHA1() post_signature2 = post_signature_method2.sign(post_oauth_request2, self.consumer, access_token) sig = oauth_header_resource_params.replace('"%s"' % post_signature, '"%s"' % post_signature2) - new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"','oauth_nonce="post_differ_nonce"') + new_oauth_headers = sig.replace('oauth_nonce="resource_nonce"', 'oauth_nonce="post_differ_nonce"') resp = self.client.post(TEST_SERVER + '/XAPI/statements/', data=stmt2, content_type="application/json", - Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=new_oauth_headers, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) def test_update_activity_with_oauth_containing_user(self): url = 'http://testserver/XAPI/statements' guid = str(uuid.uuid1()) - stmt_data = {"id":guid,"actor":{"objectType": "Agent", - "mbox":"mailto:bob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"}},"object": {"id":"test://test/define/scope"}} + stmt_data = {"id": guid, "actor": {"objectType": "Agent", + "mbox": "mailto:bob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"}}, "object": {"id": "test://test/define/scope"}} stmt_post = self.client.post(reverse(statements), json.dumps(stmt_data), content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bill@bill.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"test://test/define/scope", - 'definition': {'name': {'en-US':'testname', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc', 'en-GB': 'altdesc'},'type': 'type:course', - 'interactionType': 'other', 'correctResponsesPattern':[]}}}) - - param = {"statementId":put_guid} + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bill@bill.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "test://test/define/scope", + 'definition': {'name': {'en-US': 'testname', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc', 'en-GB': 'altdesc'}, 'type': 'type:course', + 'interactionType': 'other', 'correctResponsesPattern': []}}}) + + param = {"statementId": put_guid} path = "%s?%s" % (url, urllib.urlencode(param)) - + # START PUT STMT oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='statements/write statements/read define') - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2777,14 +2771,14 @@ def test_update_activity_with_oauth_containing_user(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - + # Put statements - should update existing activity since jane is in oauth group resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) acts = Activity.objects.all() @@ -2798,16 +2792,16 @@ def test_update_activity_created_with_oauth(self): # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = {"actor":{"objectType": "Agent", - "mbox":"mailto:bob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"}},"object": {"id":"test://test/define/scope"}} - param = {"statementId":put_guid} + stmt = {"actor": {"objectType": "Agent", + "mbox": "mailto:bob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"}}, "object": {"id": "test://test/define/scope"}} + param = {"statementId": put_guid} path = "%s?%s" % (url, urllib.urlencode(param)) - + # START PUT STMT oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='statements/write statements/read define') - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2818,25 +2812,25 @@ def test_update_activity_created_with_oauth(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature # Put statements - should update existing activity since jane is in oauth group resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) # ================================================================== - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bill@bill.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"test://test/define/scope", - 'definition': {'name': {'en-US':'testname', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc', 'en-GB': 'altdesc'},'type': 'type:course', - 'interactionType': 'other', 'correctResponsesPattern':[]}}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bill@bill.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "test://test/define/scope", + 'definition': {'name': {'en-US': 'testname', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc', 'en-GB': 'altdesc'}, 'type': 'type:course', + 'interactionType': 'other', 'correctResponsesPattern': []}}}) stmt_post = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) @@ -2844,23 +2838,23 @@ def test_update_activity_created_with_oauth(self): self.assertEqual(len(acts), 1) act = acts[0].to_dict() self.assertEqual(act['id'], 'test://test/define/scope') - self.assertIn('definition', act) + self.assertIn('definition', act) def test_multiple_client_get(self): url = 'http://testserver/XAPI/statements' # build stmt data and path put_guid = str(uuid.uuid1()) - stmt = {"actor":{"objectType": "Agent", - "mbox":"mailto:bob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"}},"object": {"id":"test://test/define/scope"}} - param = {"statementId":put_guid} + stmt = {"actor": {"objectType": "Agent", + "mbox": "mailto:bob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"}}, "object": {"id": "test://test/define/scope"}} + param = {"statementId": put_guid} path = "%s?%s" % (url, urllib.urlencode(param)) - + # START PUT STMT oauth_header_resource_params, access_token = self.oauth_handshake(scope_type='statements/write statements/read define') - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list = oauth_header_resource_params.split(",") oauth_header_resource_params_dict = {} for p in param_list: @@ -2871,29 +2865,29 @@ def test_multiple_client_get(self): # Create oauth request and add signature oauth_request = oauth.Request.from_token_and_callback(access_token, http_method='PUT', - http_url=path, parameters=oauth_header_resource_params_dict) + http_url=path, parameters=oauth_header_resource_params_dict) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) oauth_header_resource_params += ',oauth_signature="%s"' % signature - + # Put statements - should update existing activity since jane is in oauth group resp = self.client.put(path, data=stmt, content_type="application/json", - Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 204) # ================================================================== # build stmt data and path put_guid2 = str(uuid.uuid1()) - stmt2 = {"actor":{"objectType": "Agent", - "mbox":"mailto:billbob@bob.com", "name":"bob"},"verb":{"id": "http://example.com/verbs/passed", - "display": {"en-US":"passed"}},"object": {"id":"test://mult-test"}} - param2 = {"statementId":put_guid2} + stmt2 = {"actor": {"objectType": "Agent", + "mbox": "mailto:billbob@bob.com", "name": "bob"}, "verb": {"id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"}}, "object": {"id": "test://mult-test"}} + param2 = {"statementId": put_guid2} path2 = "%s?%s" % (url, urllib.urlencode(param2)) - + # START PUT STMT oauth_header_resource_params2, access_token2 = self.oauth_handshake(scope_type='statements/write define', consumer=self.consumer2jane) - - # from_token_and_callback takes a dictionary + + # from_token_and_callback takes a dictionary param_list2 = oauth_header_resource_params2.split(",") oauth_header_resource_params_dict2 = {} for p in param_list2: @@ -2904,35 +2898,33 @@ def test_multiple_client_get(self): # Create oauth request and add signature oauth_request2 = oauth.Request.from_token_and_callback(access_token2, http_method='PUT', - http_url=path2, parameters=oauth_header_resource_params_dict2) + http_url=path2, parameters=oauth_header_resource_params_dict2) signature_method2 = oauth.SignatureMethod_HMAC_SHA1() signature2 = signature_method2.sign(oauth_request2, self.consumer2jane, access_token2) oauth_header_resource_params2 += ',oauth_signature="%s"' % signature2 - + # Put statements - should update existing activity since jane is in oauth group resp2 = self.client.put(path2, data=stmt2, content_type="application/json", - Authorization=oauth_header_resource_params2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=oauth_header_resource_params2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp2.status_code, 204) # ================================================================== - - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:bill@bill.com", "name":"bill"}, - "verb":{"id": "http://example.com/verbs/accessed","display": {"en-US":"accessed"}}, - "object": {"id":"test://test/define/scope", - 'definition': {'name': {'en-US':'testname', 'en-GB': 'altname'}, - 'description': {'en-US':'testdesc', 'en-GB': 'altdesc'},'type': 'type:course', - 'interactionType': 'other', 'correctResponsesPattern':[]}}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:bill@bill.com", "name": "bill"}, + "verb": {"id": "http://example.com/verbs/accessed", "display": {"en-US": "accessed"}}, + "object": {"id": "test://test/define/scope", + 'definition': {'name': {'en-US': 'testname', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc', 'en-GB': 'altdesc'}, 'type': 'type:course', + 'interactionType': 'other', 'correctResponsesPattern': []}}}) stmt_post = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.jane_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(stmt_post.status_code, 200) # ================================================================== - stmt_get = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.jane_auth) self.assertEqual(stmt_get.status_code, 200) content = json.loads(stmt_get.content) self.assertEqual(len(content['statements']), 3) jane_clients = Consumer.objects.filter(user=self.user) - self.assertEqual(len(jane_clients), 2) \ No newline at end of file + self.assertEqual(len(jane_clients), 2) diff --git a/lrs/tests/StatementFilterTests.py b/lrs/tests/StatementFilterTests.py index f081825b..1636e339 100644 --- a/lrs/tests/StatementFilterTests.py +++ b/lrs/tests/StatementFilterTests.py @@ -22,6 +22,7 @@ from ..utils import convert_to_utc from adl_lrs.views import register + class StatementFilterTests(TestCase): @classmethod @@ -29,16 +30,16 @@ def setUpClass(cls): print "\n%s" % __name__ def setUp(self): - self.saved_stmt_limit=settings.SERVER_STMT_LIMIT - settings.SERVER_STMT_LIMIT=100 + self.saved_stmt_limit = settings.SERVER_STMT_LIMIT + settings.SERVER_STMT_LIMIT = 100 self.username = "tom" self.email = "tom@example.com" self.password = "1234" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version="1.0") - + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version="1.0") + def tearDown(self): settings.SERVER_STMT_LIMIT = 100 attach_folder_path = os.path.join(settings.MEDIA_ROOT, "attachment_payloads") @@ -48,48 +49,48 @@ def tearDown(self): os.unlink(file_path) except Exception, e: raise e - + def test_limit_filter(self): # Test limit - for i in range(1,4): - stmt = {"actor":{"mbox":"mailto:test%s@mail.com" % i},"verb":{"id":"http://tom.com/tested"},"object":{"id":"act:activity%s" %i}} + for i in range(1, 4): + stmt = {"actor": {"mbox": "mailto:test%s@mail.com" % i}, "verb": {"id": "http://tom.com/tested"}, "object": {"id": "act:activity%s" % i}} resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - limitGetResponse = self.client.post(reverse(statements),{"limit":2}, content_type="application/x-www-form-urlencoded", X_Experience_API_Version="1.0", Authorization=self.auth) + limitGetResponse = self.client.post(reverse(statements), {"limit": 2}, content_type="application/x-www-form-urlencoded", X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(limitGetResponse.status_code, 200) rsp = limitGetResponse.content respList = json.loads(rsp) stmts = respList["statements"] - self.assertEqual(len(stmts), 2) + self.assertEqual(len(stmts), 2) def test_get_id(self): stmt = { - "timestamp": "2013-04-08T21:07:11.459000+00:00", - "object": { + "timestamp": "2013-04-08T21:07:11.459000+00:00", + "object": { "id": "act:adlnet.gov/JsTetris_TCAPI/level18" - }, + }, "actor": { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" }, "verb": { - "id": "http://example.com/verbs/passed", + "id": "http://example.com/verbs/passed", "display": { "en-US": "passed" } - }, + }, "result": { "score": { - "raw": 1918560.0, + "raw": 1918560.0, "min": 0.0 - }, + }, "extensions": { - "ext:apm": "241", - "ext:lines": "165", + "ext:apm": "241", + "ext:lines": "165", "ext:time": "1119" } - }, + }, "context": { "contextActivities": { "grouping": { @@ -101,16 +102,16 @@ def test_get_id(self): resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) sid = Statement.objects.get(verb__verb_id="http://example.com/verbs/passed").statement_id - param = {"statementId":sid} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"statementId": sid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) self.assertEqual(obj['result']['score']['raw'], 1918560.0) def test_agent_filter_does_not_exist(self): - param = {"agent":{"mbox":"mailto:fail@faile.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:fail@faile.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0.1", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -119,65 +120,65 @@ def test_agent_filter_does_not_exist(self): def test_agent_filter(self): stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/stopped", + "id": "http://special.adlnet.gov/xapi/verbs/stopped", "display": { "en-US": "nixed" } - }, - "timestamp": "2013-04-11T23:24:03.603184+00:00", + }, + "timestamp": "2013-04-11T23:24:03.603184+00:00", "object": { - "timestamp": "2013-04-11T23:24:03.578795+00:00", + "timestamp": "2013-04-11T23:24:03.578795+00:00", "object": { - "id": "act:adlnet.gov/website", + "id": "act:adlnet.gov/website", "objectType": "Activity" - }, + }, "actor": { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/hacked", + "id": "http://special.adlnet.gov/xapi/verbs/hacked", "display": { "en-US": "hax0r5" } - }, + }, "objectType": "SubStatement" - }, + }, "actor": { - "mbox": "mailto:timmy@example.com", - "name": "timmy", + "mbox": "mailto:timmy@example.com", + "name": "timmy", "objectType": "Agent" } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-08T21:07:20.392000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI", + "timestamp": "2013-04-08T21:07:20.392000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI", "objectType": "Activity" - }, + }, "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom", + "mbox": "mailto:tom@example.com", + "name": "tom", "objectType": "Agent" - }, + }, "verb": { - "id": "http://example.com/verbs/completed", + "id": "http://example.com/verbs/completed", "display": { "en-US": "finished" } - }, + }, "result": { "score": { - "raw": 1918560.0, + "raw": 1918560.0, "min": 0.0 - }, + }, "extensions": { - "ext:level": "19", - "ext:apm": "241", - "ext:lines": "165", + "ext:level": "19", + "ext:apm": "241", + "ext:lines": "165", "ext:time": "1128" } } @@ -185,8 +186,8 @@ def test_agent_filter(self): resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"agent":{"mbox":"mailto:tom@example.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:tom@example.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -201,66 +202,66 @@ def test_agent_filter(self): def test_group_as_agent_filter(self): stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/started", + "id": "http://special.adlnet.gov/xapi/verbs/started", "display": { "en-US": "started" } }, - "timestamp": "2013-04-11T14:49:25.376782+00:00", + "timestamp": "2013-04-11T14:49:25.376782+00:00", "object": { - "id": "act:github.com/adlnet/ADL_LRS/tree/1.0dev", + "id": "act:github.com/adlnet/ADL_LRS/tree/1.0dev", "objectType": "Activity" - }, + }, "actor": { "member": [ { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, { - "mbox": "mailto:tom@example.com", - "name": "tom", + "mbox": "mailto:tom@example.com", + "name": "tom", "objectType": "Agent" } - ], - "mbox": "mailto:adllrsdevs@example.com", - "name": "adl lrs developers", + ], + "mbox": "mailto:adllrsdevs@example.com", + "name": "adl lrs developers", "objectType": "Group" } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-10T21:25:59.583000+00:00", + "timestamp": "2013-04-10T21:25:59.583000+00:00", "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, "actor": { "member": [ { - "mbox": "mailto:blobby@example.com", - "name": "blobby", + "mbox": "mailto:blobby@example.com", + "name": "blobby", "objectType": "Agent" - }, + }, { - "mbox": "mailto:timmy@example.com", - "name": "timmy", + "mbox": "mailto:timmy@example.com", + "name": "timmy", "objectType": "Agent" - }, + }, { - "mbox": "mailto:tom@example.com", - "name": "tom", + "mbox": "mailto:tom@example.com", + "name": "tom", "objectType": "Agent" } - ], - "name": "the tourists", + ], + "name": "the tourists", "objectType": "Group" }, "verb": { - "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", + "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", "display": { "en-US": "sighted" } @@ -275,8 +276,8 @@ def test_group_as_agent_filter(self): } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"agent":{"mbox":"mailto:adllrsdevs@example.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:adllrsdevs@example.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) count = len(Statement.objects.filter(actor__mbox=param['agent']['mbox'])) @@ -288,32 +289,32 @@ def test_group_as_agent_filter(self): def test_related_agents_filter(self): stmt = { - "timestamp": "2013-04-10T21:25:59.583000+00:00", + "timestamp": "2013-04-10T21:25:59.583000+00:00", "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, "actor": { "member": [ { - "mbox": "mailto:blobby@example.com", + "mbox": "mailto:blobby@example.com", "name": "blobby" - }, + }, { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "name": "the tourists", + ], + "name": "the tourists", "objectType": "Group" }, "verb": { - "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", + "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", "display": { "en-US": "sighted" } @@ -330,28 +331,28 @@ def test_related_agents_filter(self): self.assertEqual(resp.status_code, 200) stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/started", + "id": "http://special.adlnet.gov/xapi/verbs/started", "display": { "en-US": "started" } - }, - "timestamp": "2013-04-11T14:49:25.376782+00:00", + }, + "timestamp": "2013-04-11T14:49:25.376782+00:00", "object": { "id": "act:github.com/adlnet/ADL_LRS/tree/1.0dev" - }, + }, "actor": { "member": [ { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "mbox": "mailto:adllrsdevs@example.com", - "name": "adl lrs developers", + ], + "mbox": "mailto:adllrsdevs@example.com", + "name": "adl lrs developers", "objectType": "Group" } } @@ -359,38 +360,38 @@ def test_related_agents_filter(self): self.assertEqual(resp.status_code, 200) stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/stopped", + "id": "http://special.adlnet.gov/xapi/verbs/stopped", "display": { "en-US": "nixed" } }, - "timestamp": "2013-04-11T23:24:03.603184+00:00", + "timestamp": "2013-04-11T23:24:03.603184+00:00", "object": { - "timestamp": "2013-04-11T23:24:03.578795+00:00", + "timestamp": "2013-04-11T23:24:03.578795+00:00", "object": { "id": "act:adlnet.gov/website" - }, + }, "actor": { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/hacked", + "id": "http://special.adlnet.gov/xapi/verbs/hacked", "display": { "en-US": "hax0r5" } - }, + }, "objectType": "SubStatement" - }, + }, "actor": { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"agent":{"mbox":"mailto:louo@example.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -398,8 +399,8 @@ def test_related_agents_filter(self): # I'm in a group for one statement and the object in another self.assertEqual(len(stmts), 2) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "related_agents":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "related_agents": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -408,97 +409,97 @@ def test_related_agents_filter(self): def test_agent_filter_since_and_until(self): batch = [ - { - "timestamp": "2013-04-08T17:51:38.118000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/attempted", - "display": {"en-US": "started"} - } - }, - { - "timestamp": "2013-04-08T17:52:31.209000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/attempted", - "display": {"en-US": "started"} - } - }, - { - "timestamp": "2013-04-08T20:47:08.626000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/attempted", - "display": {"en-US": "started"} - } - }, - { - "timestamp": "2013-04-08T20:47:36.129000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI/level1" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/passed", - "display": {"en-US": "passed"} - } - }, - { - "timestamp": "2013-04-08T20:48:50.090000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI/level2" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" + { + "timestamp": "2013-04-08T17:51:38.118000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/attempted", + "display": {"en-US": "started"} + } }, - "verb": { - "id": "http://example.com/verbs/passed", - "display": {"en-US": "passed"} - } - }, - { - "timestamp": "2013-04-08T20:49:27.109000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI/level3" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" + { + "timestamp": "2013-04-08T17:52:31.209000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/attempted", + "display": {"en-US": "started"} + } }, - "verb": { - "id": "http://example.com/verbs/passed", - "display": {"en-US": "passed"} - } - }] + { + "timestamp": "2013-04-08T20:47:08.626000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/attempted", + "display": {"en-US": "started"} + } + }, + { + "timestamp": "2013-04-08T20:47:36.129000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI/level1" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + } + }, + { + "timestamp": "2013-04-08T20:48:50.090000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI/level2" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + } + }, + { + "timestamp": "2013-04-08T20:49:27.109000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI/level3" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + } + }] response = self.client.post(reverse(statements), json.dumps(batch), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - param = {"agent":{"mbox":"mailto:tom@example.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:tom@example.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -512,20 +513,20 @@ def test_agent_filter_since_and_until(self): self.assertTrue(param['agent']['mbox'] in str(s['actor'])) cnt_all = len(stmts) - since = stmts[int(math.floor(len(stmts)/1.5))]['stored'] - until = stmts[int(math.ceil(len(stmts)/3))]['stored'] - since_cnt = int(math.floor(len(stmts)/1.5)) - until_cnt = cnt_all - int(math.ceil(len(stmts)/3)) - since_until_cnt = int(math.floor(len(stmts)/1.5)) - int(math.ceil(len(stmts)/3)) - - param = {"agent":{"mbox":"mailto:tom@example.com"}, "since": since} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + since = stmts[int(math.floor(len(stmts) / 1.5))]['stored'] + until = stmts[int(math.ceil(len(stmts) / 3))]['stored'] + since_cnt = int(math.floor(len(stmts) / 1.5)) + until_cnt = cnt_all - int(math.ceil(len(stmts) / 3)) + since_until_cnt = int(math.floor(len(stmts) / 1.5)) - int(math.ceil(len(stmts) / 3)) + + param = {"agent": {"mbox": "mailto:tom@example.com"}, "since": since} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), since_cnt) - since_ids=[] + since_ids = [] for s in stmts: since_ids.append(s['id']) if param['agent']['mbox'] not in str(s['actor']): @@ -534,14 +535,14 @@ def test_agent_filter_since_and_until(self): else: self.assertTrue(param['agent']['mbox'] in str(s['actor'])) - param = {"agent":{"mbox":"mailto:tom@example.com"}, "until": until} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:tom@example.com"}, "until": until} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), until_cnt) - until_ids=[] + until_ids = [] for s in stmts: until_ids.append(s['id']) if param['agent']['mbox'] not in str(s['actor']): @@ -552,15 +553,15 @@ def test_agent_filter_since_and_until(self): same = [x for x in since_ids if x in until_ids] self.assertEqual(len(same), since_until_cnt) - param = {"agent":{"mbox":"mailto:tom@example.com"}, "since": since, "until": until} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:tom@example.com"}, "since": since, "until": until} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertTrue(len(stmts) < cnt_all) self.assertEqual(len(stmts), since_until_cnt) - slice_ids=[] + slice_ids = [] for s in stmts: slice_ids.append(s['id']) if param['agent']['mbox'] not in str(s['actor']): @@ -572,32 +573,32 @@ def test_agent_filter_since_and_until(self): def test_related_agents_filter_until(self): stmt = { - "timestamp": "2013-04-10T21:25:59.583000+00:00", + "timestamp": "2013-04-10T21:25:59.583000+00:00", "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, "actor": { "member": [ { - "mbox": "mailto:blobby@example.com", + "mbox": "mailto:blobby@example.com", "name": "blobby" - }, + }, { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "name": "the tourists", + ], + "name": "the tourists", "objectType": "Group" }, "verb": { - "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", + "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", "display": { "en-US": "sighted" } @@ -614,28 +615,28 @@ def test_related_agents_filter_until(self): self.assertEqual(resp.status_code, 200) stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/started", + "id": "http://special.adlnet.gov/xapi/verbs/started", "display": { "en-US": "started" } - }, - "timestamp": "2013-04-11T14:49:25.376782+00:00", + }, + "timestamp": "2013-04-11T14:49:25.376782+00:00", "object": { "id": "act:github.com/adlnet/ADL_LRS/tree/1.0dev" - }, + }, "actor": { "member": [ { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "mbox": "mailto:adllrsdevs@example.com", - "name": "adl lrs developers", + ], + "mbox": "mailto:adllrsdevs@example.com", + "name": "adl lrs developers", "objectType": "Group" } } @@ -643,38 +644,38 @@ def test_related_agents_filter_until(self): self.assertEqual(resp.status_code, 200) stmt = { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/stopped", + "id": "http://special.adlnet.gov/xapi/verbs/stopped", "display": { "en-US": "nixed" } }, - "timestamp": "2013-04-11T23:24:03.603184+00:00", + "timestamp": "2013-04-11T23:24:03.603184+00:00", "object": { - "timestamp": "2013-04-11T23:24:03.578795+00:00", + "timestamp": "2013-04-11T23:24:03.578795+00:00", "object": { "id": "act:adlnet.gov/website" - }, + }, "actor": { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/hacked", + "id": "http://special.adlnet.gov/xapi/verbs/hacked", "display": { "en-US": "hax0r5" } - }, + }, "objectType": "SubStatement" - }, + }, "actor": { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "related_agents":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "related_agents": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -692,8 +693,8 @@ def test_related_agents_filter_until(self): cnt_all = len(stmts) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "related_agents": True, "until": "2013-04-10T00:00Z"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "related_agents": True, "until": "2013-04-10T00:00Z"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -714,32 +715,32 @@ def test_related_agents_filter_until(self): def test_related_agents_filter_since(self): stmts = [{ - "timestamp": "2013-04-10T21:25:59.583000+00:00", + "timestamp": "2013-04-10T21:25:59.583000+00:00", "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", + "mbox": "mailto:louo@example.com", + "name": "louo", "objectType": "Agent" - }, + }, "actor": { "member": [ { - "mbox": "mailto:blobby@example.com", + "mbox": "mailto:blobby@example.com", "name": "blobby" - }, + }, { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "name": "the tourists", + ], + "name": "the tourists", "objectType": "Group" }, "verb": { - "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", + "id": "http://imaginarium.adlnet.org/xapi/verbs/sighted", "display": { "en-US": "sighted" } @@ -752,69 +753,69 @@ def test_related_agents_filter_since(self): } } }, - { + { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/started", + "id": "http://special.adlnet.gov/xapi/verbs/started", "display": { "en-US": "started" } - }, - "timestamp": "2013-04-11T14:49:25.376782+00:00", + }, + "timestamp": "2013-04-11T14:49:25.376782+00:00", "object": { "id": "act:github.com/adlnet/ADL_LRS/tree/1.0dev" - }, + }, "actor": { "member": [ { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" } - ], - "mbox": "mailto:adllrsdevs@example.com", - "name": "adl lrs developers", + ], + "mbox": "mailto:adllrsdevs@example.com", + "name": "adl lrs developers", "objectType": "Group" } }, - { + { "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/stopped", + "id": "http://special.adlnet.gov/xapi/verbs/stopped", "display": { "en-US": "nixed" } }, - "timestamp": "2013-04-11T23:24:03.603184+00:00", + "timestamp": "2013-04-11T23:24:03.603184+00:00", "object": { - "timestamp": "2013-04-11T23:24:03.578795+00:00", + "timestamp": "2013-04-11T23:24:03.578795+00:00", "object": { "id": "act:adlnet.gov/website" - }, + }, "actor": { - "mbox": "mailto:louo@example.com", + "mbox": "mailto:louo@example.com", "name": "louo" - }, + }, "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/hacked", + "id": "http://special.adlnet.gov/xapi/verbs/hacked", "display": { "en-US": "hax0r5" } - }, + }, "objectType": "SubStatement" - }, + }, "actor": { - "mbox": "mailto:timmy@example.com", + "mbox": "mailto:timmy@example.com", "name": "timmy" } }] response = self.client.post(reverse(statements), json.dumps(stmts), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "related_agents":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "related_agents": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -831,11 +832,11 @@ def test_related_agents_filter_since(self): self.assertTrue(param['agent']['mbox'] in str(s['actor'])) cnt_all = len(stmts) - since = stmts[int(math.floor(cnt_all/2))]['stored'] - since_cnt = int(math.floor(cnt_all/2)) + since = stmts[int(math.floor(cnt_all / 2))]['stored'] + since_cnt = int(math.floor(cnt_all / 2)) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "related_agents": True, "since": since} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "related_agents": True, "since": since} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -854,14 +855,13 @@ def test_related_agents_filter_since(self): self.assertTrue(param['agent']['mbox'] in str(s['actor'])) self.assertTrue(convert_to_utc(s['stored']) > since) - def test_since_filter_tz(self): stmt1_guid = str(uuid.uuid1()) - stmt1 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, "timestamp":"2013-02-02T12:00:00-05:00"}) + stmt1 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, "timestamp": "2013-02-02T12:00:00-05:00"}) - param = {"statementId":stmt1_guid} + param = {"statementId": stmt1_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = stmt1 resp = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") @@ -870,11 +870,11 @@ def test_since_filter_tz(self): Statement.objects.filter(statement_id=stmt1_guid).update(stored=time) stmt2_guid = str(uuid.uuid1()) - stmt2 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity2"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, "timestamp":"2013-02-02T20:00:00+05:00"}) + stmt2 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity2"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, "timestamp": "2013-02-02T20:00:00+05:00"}) - param = {"statementId":stmt2_guid} + param = {"statementId": stmt2_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = stmt2 resp = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") @@ -883,7 +883,7 @@ def test_since_filter_tz(self): Statement.objects.filter(statement_id=stmt2_guid).update(stored=time) param = {"since": "2013-02-02T14:00Z"} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) sinceGetResponse = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) @@ -892,7 +892,7 @@ def test_since_filter_tz(self): self.assertIn(stmt2_guid, rsp) param2 = {"since": "2013-02-02T16:00Z"} - path2 = "%s?%s" % (reverse(statements), urllib.urlencode(param2)) + path2 = "%s?%s" % (reverse(statements), urllib.urlencode(param2)) sinceGetResponse2 = self.client.get(path2, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(sinceGetResponse2.status_code, 200) @@ -903,98 +903,98 @@ def test_since_filter_tz(self): def test_verb_filter(self): theid = str(uuid.uuid1()) stmt = { - "id":theid, - "timestamp": "2013-04-10T21:27:15.613000+00:00", - "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", - "objectType":"Agent" - }, - "actor": { - "member": [ - { - "mbox": "mailto:blobby@example.com", - "name": "blobby" - }, - { - "mbox": "mailto:timmy@example.com", - "name": "timmy" - }, - { - "mbox": "mailto:tom@example.com", - "name": "tom" - } - ], - "name": "the tourists", - "objectType": "Group" - }, - "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/high-fived", - "display": {"en-US": "high-fived"} - }, - "context": { - "contextActivities": { - "parent": { - "id": "act:imaginarium.adlnet.org/xapi/imaginarium" + "id": theid, + "timestamp": "2013-04-10T21:27:15.613000+00:00", + "object": { + "mbox": "mailto:louo@example.com", + "name": "louo", + "objectType": "Agent" + }, + "actor": { + "member": [ + { + "mbox": "mailto:blobby@example.com", + "name": "blobby" + }, + { + "mbox": "mailto:timmy@example.com", + "name": "timmy" + }, + { + "mbox": "mailto:tom@example.com", + "name": "tom" + } + ], + "name": "the tourists", + "objectType": "Group" + }, + "verb": { + "id": "http://special.adlnet.gov/xapi/verbs/high-fived", + "display": {"en-US": "high-fived"} + }, + "context": { + "contextActivities": { + "parent": { + "id": "act:imaginarium.adlnet.org/xapi/imaginarium" + } } } } - } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stman_id = str(uuid.uuid1()) stmt = {"id": stman_id, - "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/frowned", - "display": { - "en-US": "frowned upon" - } - }, - - "timestamp": "2013-04-10T21:28:33.870000+00:00", - "object": { - "id": theid, - "objectType": "StatementRef" - }, - "actor": { - "member": [ - { - "mbox": "mailto:mrx@example.com", - "name": "mr x", - "objectType": "Agent" - }, - { - "mbox": "mailto:msy@example.com", - "name": "ms y", - "objectType": "Agent" - }, - { - "mbox": "mailto:drdre@example.com", - "name": "dr dre", - "objectType": "Agent" + "verb": { + "id": "http://special.adlnet.gov/xapi/verbs/frowned", + "display": { + "en-US": "frowned upon" + } + }, + + "timestamp": "2013-04-10T21:28:33.870000+00:00", + "object": { + "id": theid, + "objectType": "StatementRef" + }, + "actor": { + "member": [ + { + "mbox": "mailto:mrx@example.com", + "name": "mr x", + "objectType": "Agent" + }, + { + "mbox": "mailto:msy@example.com", + "name": "ms y", + "objectType": "Agent" + }, + { + "mbox": "mailto:drdre@example.com", + "name": "dr dre", + "objectType": "Agent" + } + ], + "name": "Managers", + "objectType": "Group" + } } - ], - "name": "Managers", - "objectType": "Group" - } - } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"verb":"http://special.adlnet.gov/xapi/verbs/high-fived"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"verb": "http://special.adlnet.gov/xapi/verbs/high-fived"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), 2) - stmt_ref_stmt_ids = [k['object']['id'] for k in stmts if k['object']['objectType']=='StatementRef'] - stmt_ids = [k['id'] for k in stmts if k['object']['objectType']!='StatementRef'] + stmt_ref_stmt_ids = [k['object']['id'] for k in stmts if k['object']['objectType'] == 'StatementRef'] + stmt_ids = [k['id'] for k in stmts if k['object']['objectType'] != 'StatementRef'] diffs = set(stmt_ref_stmt_ids) ^ set(stmt_ids) self.assertFalse(diffs) - param = {"agent":{"mbox":"mailto:drdre@example.com"},"verb":"http://special.adlnet.gov/xapi/verbs/high-fived"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:drdre@example.com"}, "verb": "http://special.adlnet.gov/xapi/verbs/high-fived"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1004,131 +1004,131 @@ def test_verb_filter(self): def test_registration_filter(self): theid = str(uuid.uuid1()) stmt = { - "id":theid, - "timestamp": "2013-04-10T21:27:15.613000+00:00", - "object": { - "mbox": "mailto:louo@example.com", - "name": "louo", - "objectType":"Agent" - }, - "actor": { - "member": [ - { - "mbox": "mailto:blobby@example.com", - "name": "blobby" - }, - { - "mbox": "mailto:timmy@example.com", - "name": "timmy" - }, - { - "mbox": "mailto:tom@example.com", - "name": "tom" - } - ], - "name": "the tourists", - "objectType": "Group" - }, - "verb": { - "id": "http://special.adlnet.gov/xapi/verbs/high-fived", - "display": {"en-US": "high-fived"} - }, - "context": { - "contextActivities": { - "parent": { - "id": "act:imaginarium.adlnet.org/xapi/imaginarium" - } + "id": theid, + "timestamp": "2013-04-10T21:27:15.613000+00:00", + "object": { + "mbox": "mailto:louo@example.com", + "name": "louo", + "objectType": "Agent" }, - "registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a92" - } + "actor": { + "member": [ + { + "mbox": "mailto:blobby@example.com", + "name": "blobby" + }, + { + "mbox": "mailto:timmy@example.com", + "name": "timmy" + }, + { + "mbox": "mailto:tom@example.com", + "name": "tom" + } + ], + "name": "the tourists", + "objectType": "Group" + }, + "verb": { + "id": "http://special.adlnet.gov/xapi/verbs/high-fived", + "display": {"en-US": "high-fived"} + }, + "context": { + "contextActivities": { + "parent": { + "id": "act:imaginarium.adlnet.org/xapi/imaginarium" + } + }, + "registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a92" + } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-08T17:51:38.118000+00:00", + "timestamp": "2013-04-08T17:51:38.118000+00:00", "object": { "id": "act:adlnet.gov/JsTetris_TCAPI" - }, + }, "actor": { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" - }, + }, "verb": { - "id": "http://example.com/verbs/attempted", + "id": "http://example.com/verbs/attempted", "display": {"en-US": "started"} }, "context": { - "registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91" + "registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91" } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - stmt = { - "timestamp": "2013-04-08T21:07:20.392000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI", - "objectType": "Activity" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/completed", - "display": {"en-US": "finished"} - }, - "result": { - "score": { - "raw": 1918560.0, - "min": 0.0 - }, - "extensions": { - "ext:level": "19", - "ext:apm": "241", - "ext:lines": "165", - "ext:time": "1128" + stmt = { + "timestamp": "2013-04-08T21:07:20.392000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI", + "objectType": "Activity" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/completed", + "display": {"en-US": "finished"} + }, + "result": { + "score": { + "raw": 1918560.0, + "min": 0.0 + }, + "extensions": { + "ext:level": "19", + "ext:apm": "241", + "ext:lines": "165", + "ext:time": "1128" + } + }, + "context": { + "registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91" } - }, - "context": { - "registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91" - } } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), 2) - param = {"registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91","verb":"http://special.adlnet.gov/xapi/verbs/high-fived"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91", "verb": "http://special.adlnet.gov/xapi/verbs/high-fived"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), 0) - param = {"registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91","verb":"http://example.com/verbs/completed"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91", "verb": "http://example.com/verbs/completed"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), 1) - param = {"agent":{"mbox":"mailto:tom@example.com"}, "registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91","verb":"http://example.com/verbs/completed"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:tom@example.com"}, "registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91", "verb": "http://example.com/verbs/completed"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) stmts = obj['statements'] self.assertEqual(len(stmts), 1) - param = {"agent":{"mbox":"mailto:louo@example.com"}, "registration":"05bb4c1a-9ddb-44a0-ba4f-52ff77811a91","verb":"http://example.com/verbs/completed"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louo@example.com"}, "registration": "05bb4c1a-9ddb-44a0-ba4f-52ff77811a91", "verb": "http://example.com/verbs/completed"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1137,48 +1137,48 @@ def test_registration_filter(self): def test_activity_filter(self): stmt = { - "timestamp": "2013-04-08T21:05:48.869000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI/level17", - "objectType": "Activity" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom", - }, - "verb": { - "id": "http://example.com/verbs/passed", - "display": {"en-US": "passed"} - }, - "context": { - "contextActivities": { - "grouping": { - "id": "act:adlnet.gov/JsTetris_TCAPI" + "timestamp": "2013-04-08T21:05:48.869000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI/level17", + "objectType": "Activity" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom", + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + }, + "context": { + "contextActivities": { + "grouping": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + } } } } - } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-08T21:07:11.459000+00:00", + "timestamp": "2013-04-08T21:07:11.459000+00:00", "object": { "id": "act:adlnet.gov/JsTetris_TCAPI/level18" - }, + }, "actor": { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" - }, + }, "verb": { - "id": "http://example.com/verbs/passed", + "id": "http://example.com/verbs/passed", "display": {"en-US": "passed"} - }, + }, "result": { "score": { - "raw": 1918560.0, + "raw": 1918560.0, "min": 0.0 } - }, + }, "context": { "contextActivities": { "grouping": { @@ -1190,51 +1190,51 @@ def test_activity_filter(self): resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-08T21:07:20.392000+00:00", - "object": { - "definition": { - "type": "type:media", - "name": { - "en-US": "Js Tetris - Tin Can Prototype" - }, - "description": { - "en-US": "A game of tetris." + "timestamp": "2013-04-08T21:07:20.392000+00:00", + "object": { + "definition": { + "type": "type:media", + "name": { + "en-US": "Js Tetris - Tin Can Prototype" + }, + "description": { + "en-US": "A game of tetris." + } + }, + "id": "act:adlnet.gov/JsTetris_TCAPI" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom" + }, + "verb": { + "id": "http://example.com/verbs/completed", + "display": {"en-US": "finished"} + }, + "result": { + "score": { + "raw": 1918560.0, + "min": 0.0 + }, + "extensions": { + "ext:level": "19", + "ext:apm": "241", + "ext:lines": "165", + "ext:time": "1128" } - }, - "id": "act:adlnet.gov/JsTetris_TCAPI" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom" - }, - "verb": { - "id": "http://example.com/verbs/completed", - "display": {"en-US": "finished"} - }, - "result": { - "score": { - "raw": 1918560.0, - "min": 0.0 - }, - "extensions": { - "ext:level": "19", - "ext:apm": "241", - "ext:lines": "165", - "ext:time": "1128" - } - }, - "context": { - "contextActivities": { - "grouping": { - "id": "act:adlnet.gov/JsTetris_TCAPI" + }, + "context": { + "contextActivities": { + "grouping": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + } } } } - } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - param = {"activity":"act:adlnet.gov/JsTetris_TCAPI"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"activity": "act:adlnet.gov/JsTetris_TCAPI"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1249,8 +1249,8 @@ def test_activity_filter(self): actcnt = len(stmts) self.assertEqual(actcnt, 1) - param = {"activity":"act:adlnet.gov/JsTetris_TCAPI", "related_activities":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"activity": "act:adlnet.gov/JsTetris_TCAPI", "related_activities": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1266,48 +1266,48 @@ def test_activity_filter(self): def test_no_activity_filter(self): stmt = { - "timestamp": "2013-04-08T21:05:48.869000+00:00", - "object": { - "id": "act:adlnet.gov/JsTetris_TCAPI/level17", - "objectType": "Activity" - }, - "actor": { - "mbox": "mailto:tom@example.com", - "name": "tom", - }, - "verb": { - "id": "http://example.com/verbs/passed", - "display": {"en-US": "passed"} - }, - "context": { - "contextActivities": { - "grouping": { - "id": "act:adlnet.gov/JsTetris_TCAPI" + "timestamp": "2013-04-08T21:05:48.869000+00:00", + "object": { + "id": "act:adlnet.gov/JsTetris_TCAPI/level17", + "objectType": "Activity" + }, + "actor": { + "mbox": "mailto:tom@example.com", + "name": "tom", + }, + "verb": { + "id": "http://example.com/verbs/passed", + "display": {"en-US": "passed"} + }, + "context": { + "contextActivities": { + "grouping": { + "id": "act:adlnet.gov/JsTetris_TCAPI" + } } } } - } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) stmt = { - "timestamp": "2013-04-08T21:07:11.459000+00:00", + "timestamp": "2013-04-08T21:07:11.459000+00:00", "object": { "id": "act:adlnet.gov/JsTetris_TCAPI/level18" - }, + }, "actor": { - "mbox": "mailto:tom@example.com", + "mbox": "mailto:tom@example.com", "name": "tom" - }, + }, "verb": { - "id": "http://example.com/verbs/passed", + "id": "http://example.com/verbs/passed", "display": {"en-US": "passed"} - }, + }, "result": { "score": { - "raw": 1918560.0, + "raw": 1918560.0, "min": 0.0 } - }, + }, "context": { "contextActivities": { "grouping": { @@ -1318,47 +1318,47 @@ def test_no_activity_filter(self): } resp = self.client.post(reverse(statements), json.dumps(stmt), Authorization=self.auth, content_type="application/json", X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 200) - actorGetResponse = self.client.post(reverse(statements), - {"activity":"http://notarealactivity.com"}, - content_type="application/x-www-form-urlencoded", X_Experience_API_Version="1.0", Authorization=self.auth) + actorGetResponse = self.client.post(reverse(statements), + {"activity": "http://notarealactivity.com"}, + content_type="application/x-www-form-urlencoded", X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(actorGetResponse.status_code, 200) rsp = json.loads(actorGetResponse.content) stmts = rsp['statements'] self.assertEqual(len(stmts), 0) def test_format_agent_filter(self): - stmt = json.dumps({"actor":{"name":"lou wolford", "mbox":"mailto:louwolford@example.com"}, - "verb":{"id":"http://special.adlnet.gov/xapi/verb/created", - "display":{"en-US":"made"}}, - "object":{"objectType":"Group","name":"androids","mbox":"mailto:androids@example.com", - "member":[{"name":"Adam Link", "mbox":"mailto:alink@example.com"}, - {"name":"Andrew Martin", "mbox":"mailto:amartin@example.com"}, - {"name":"Astro Boy", "mbox":"mailto:astroboy@example.com"}, - {"name":"C-3PO", "mbox":"mailto:c3po@example.com"}, - {"name":"R2 D2", "mbox":"mailto:r2d2@example.com"}, - {"name":"Marvin", "mbox":"mailto:marvin@example.com"}, - {"name":"Data", "mbox":"mailto:data@example.com"}, - {"name":"Mr. Roboto", "mbox":"mailto:mrroboto@example.com"} - ] - }, - "context":{"instructor":{"name":"Isaac Asimov", "mbox":"mailto:asimov@example.com"}, - "team":{"objectType":"Group", "name":"team kick***", - "member":[{"name":"lou wolford","mbox":"mailto:louwolford@example.com"}, - {"name":"tom creighton", "mbox":"mailto:tomcreighton@example.com"} - ] - } - } - }) + stmt = json.dumps({"actor": {"name": "lou wolford", "mbox": "mailto:louwolford@example.com"}, + "verb": {"id": "http://special.adlnet.gov/xapi/verb/created", + "display": {"en-US": "made"}}, + "object": {"objectType": "Group", "name": "androids", "mbox": "mailto:androids@example.com", + "member": [{"name": "Adam Link", "mbox": "mailto:alink@example.com"}, + {"name": "Andrew Martin", "mbox": "mailto:amartin@example.com"}, + {"name": "Astro Boy", "mbox": "mailto:astroboy@example.com"}, + {"name": "C-3PO", "mbox": "mailto:c3po@example.com"}, + {"name": "R2 D2", "mbox": "mailto:r2d2@example.com"}, + {"name": "Marvin", "mbox": "mailto:marvin@example.com"}, + {"name": "Data", "mbox": "mailto:data@example.com"}, + {"name": "Mr. Roboto", "mbox": "mailto:mrroboto@example.com"} + ] + }, + "context": {"instructor": {"name": "Isaac Asimov", "mbox": "mailto:asimov@example.com"}, + "team": {"objectType": "Group", "name": "team kick***", + "member": [{"name": "lou wolford", "mbox": "mailto:louwolford@example.com"}, + {"name": "tom creighton", "mbox": "mailto:tomcreighton@example.com"} + ] + } + } + }) guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) resp = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(resp.status_code, 204) - + agent_params = ['name', 'mbox', 'objectType'] - param = {"agent":{"mbox":"mailto:louwolford@example.com"}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louwolford@example.com"}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1385,8 +1385,8 @@ def test_format_agent_filter(self): for m in stmt_r['context']['team']['member']: self.assertItemsEqual(m.keys(), agent_params) - param = {"agent":{"mbox":"mailto:louwolford@example.com"}, "format":"ids"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:louwolford@example.com"}, "format": "ids"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1416,19 +1416,19 @@ def test_format_agent_filter(self): self.assertItemsEqual(m.keys(), agent_id_param) def test_agent_account(self): - account = {"homePage":"http://www.adlnet.gov","name":"freakshow"} - stmt = json.dumps({"actor": {"name": "freakshow", "account":account}, - "verb":{"id":"http://tom.com/tested"}, - "object":{"id":"act:tom.com/accountid"}}) + account = {"homePage": "http://www.adlnet.gov", "name": "freakshow"} + stmt = json.dumps({"actor": {"name": "freakshow", "account": account}, + "verb": {"id": "http://tom.com/tested"}, + "object": {"id": "act:tom.com/accountid"}}) guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) resp = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(resp.status_code, 204) - param = {"agent":{"account":account}} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"account": account}} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1439,38 +1439,36 @@ def test_agent_account(self): self.assertEqual(s['actor']['account']['name'], account['name']) self.assertEqual(s['actor']['account']['homePage'], account['homePage']) - - def test_activity_format(self): - stmt = {"actor":{"name":"chair", "mbox":"mailto:chair@example.com"}, - "verb": {"id": "http://tom.com/tested","display":{"en-US":"tested","es-US":"probado", "fr":"testé"}}, - "object": {"objectType":"Activity", "id":"act:format", - "definition":{"name":{"en-US":"format", "es-US":"formato", "fr":"format"}, - "description":{"en-US":"format used to return statement", - "es-US":"formato utilizado en este statement", - "fr":"format utilisé pour cette statement" - }, - "type":"type:thing" - } - }, - "context": {"contextActivities":{"parent":[{"id":"act:statementfiltertests", - "definition":{"name":{"en-US":"statement filter", "fr":"statement filter"}, - "description":{"en-US":"unit tests","fr":"unit tests"}, - "type":"type:parent-thing"} - }] - } + stmt = {"actor": {"name": "chair", "mbox": "mailto:chair@example.com"}, + "verb": {"id": "http://tom.com/tested", "display": {"en-US": "tested", "es-US": "probado", "fr": "testé"}}, + "object": {"objectType": "Activity", "id": "act:format", + "definition": {"name": {"en-US": "format", "es-US": "formato", "fr": "format"}, + "description": {"en-US": "format used to return statement", + "es-US": "formato utilizado en este statement", + "fr": "format utilisé pour cette statement" + }, + "type": "type:thing" + } + }, + "context": {"contextActivities": {"parent": [{"id": "act:statementfiltertests", + "definition": {"name": {"en-US": "statement filter", "fr": "statement filter"}, + "description": {"en-US": "unit tests", "fr": "unit tests"}, + "type": "type:parent-thing"} + }] + } } - } + } guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) resp = self.client.put(path, json.dumps(stmt), content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(resp.status_code, 204) - param = {"agent":{"mbox":"mailto:chair@example.com"}, "format":"exact"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:chair@example.com"}, "format": "exact"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1489,12 +1487,12 @@ def test_activity_format(self): self.assertItemsEqual(exact['context']['contextActivities']['parent'][0]['definition']['description'].keys(), stmt['context']['contextActivities']['parent'][0]['definition']['description'].keys()) self.assertEqual(exact['context']['contextActivities']['parent'][0]['definition']['type'], stmt['context']['contextActivities']['parent'][0]['definition']['type']) - param = {"agent":{"mbox":"mailto:chair@example.com"}, "format":"ids"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:chair@example.com"}, "format": "ids"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) - + ids = obj['statements'][0] self.assertNotIn('name', ids['actor']) self.assertEqual(ids['actor']['mbox'], stmt['actor']['mbox']) @@ -1505,13 +1503,13 @@ def test_activity_format(self): self.assertNotIn('definition', ids['object']) self.assertEqual(ids['context']['contextActivities']['parent'][0]['id'], stmt['context']['contextActivities']['parent'][0]['id']) self.assertNotIn('definition', ids['context']['contextActivities']['parent'][0]) - - param = {"agent":{"mbox":"mailto:chair@example.com"}, "format":"canonical"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + + param = {"agent": {"mbox": "mailto:chair@example.com"}, "format": "canonical"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) - + canon_enus = obj['statements'][0] self.assertEqual(canon_enus['actor']['name'], stmt['actor']['name']) self.assertEqual(canon_enus['actor']['mbox'], stmt['actor']['mbox']) @@ -1530,12 +1528,12 @@ def test_activity_format(self): self.assertIn(canon_enus['context']['contextActivities']['parent'][0]['definition']['description'].keys()[0], stmt['context']['contextActivities']['parent'][0]['definition']['description'].keys()) self.assertEqual(canon_enus['context']['contextActivities']['parent'][0]['definition']['type'], stmt['context']['contextActivities']['parent'][0]['definition']['type']) - param = {"agent":{"mbox":"mailto:chair@example.com"}, "format":"canonical"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"agent": {"mbox": "mailto:chair@example.com"}, "format": "canonical"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, Accept_Language="fr", X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) - + canon_fr = obj['statements'][0] self.assertEqual(canon_fr['actor']['name'], stmt['actor']['name']) self.assertEqual(canon_fr['actor']['mbox'], stmt['actor']['mbox']) @@ -1554,28 +1552,28 @@ def test_activity_format(self): self.assertIn(canon_fr['context']['contextActivities']['parent'][0]['definition']['description'].keys()[0], stmt['context']['contextActivities']['parent'][0]['definition']['description'].keys()) self.assertEqual(canon_fr['context']['contextActivities']['parent'][0]['definition']['type'], stmt['context']['contextActivities']['parent'][0]['definition']['type']) - self.assertNotEqual(canon_enus['object']['definition']['name'].keys()[0],canon_fr['object']['definition']['name'].keys()[0]) - self.assertNotEqual(canon_enus['object']['definition']['description'].keys()[0],canon_fr['object']['definition']['description'].keys()[0]) + self.assertNotEqual(canon_enus['object']['definition']['name'].keys()[0], canon_fr['object']['definition']['name'].keys()[0]) + self.assertNotEqual(canon_enus['object']['definition']['description'].keys()[0], canon_fr['object']['definition']['description'].keys()[0]) self.assertNotEqual(canon_enus['context']['contextActivities']['parent'][0]['definition']['name'].keys()[0], canon_fr['context']['contextActivities']['parent'][0]['definition']['name'].keys()[0]) self.assertNotEqual(canon_enus['context']['contextActivities']['parent'][0]['definition']['description'].keys()[0], canon_fr['context']['contextActivities']['parent'][0]['definition']['description'].keys()[0]) - + def single_stmt_get_canonical(self): ex_stmt = { - "actor":{"name":"chair", "mbox":"mailto:chair@example.com"}, - "verb": {"id": "http://tom.com/tested","display":{"en-US":"tested","es-US":"probado", "fr":"testé"}}, - "object": {"objectType":"Activity", "id":"act:tom.com/objs/heads", - "definition":{"name":{"en-US":"format", "es-US":"formato", "fr":"format"}, - "description":{"en-US":"format used to return statement", - "es-US":"formato utilizado en este statement", - "fr":"format utilisé pour cette statement" - }, - "type":"type:thing" - } - } + "actor": {"name": "chair", "mbox": "mailto:chair@example.com"}, + "verb": {"id": "http://tom.com/tested", "display": {"en-US": "tested", "es-US": "probado", "fr": "testé"}}, + "object": {"objectType": "Activity", "id": "act:tom.com/objs/heads", + "definition": {"name": {"en-US": "format", "es-US": "formato", "fr": "format"}, + "description": {"en-US": "format used to return statement", + "es-US": "formato utilizado en este statement", + "fr": "format utilisé pour cette statement" + }, + "type": "type:thing" + } + } } guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) resp = self.client.put(path, json.dumps(ex_stmt), content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(resp.status_code, 204) @@ -1583,66 +1581,66 @@ def single_stmt_get_canonical(self): stmt_id = str(uuid.uuid1()) stmt = { "id": stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"} + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"} } - + param = {"statementId": stmt_id} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) param["format"] = "canonical" - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) stmt_obj = json.loads(r.content) self.assertIn('definition', stmt_obj['object']) param["format"] = "exact" - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) stmt_obj = json.loads(r.content) self.assertNotIn('definition', stmt_obj['object']) @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') def test_voidedStatementId(self): - stmt = {"actor":{"mbox":"mailto:dog@example.com"}, - "verb":{"id":"http://tom.com/verb/ate"}, - "object":{"id":"act:my/homework"} - } + stmt = {"actor": {"mbox": "mailto:dog@example.com"}, + "verb": {"id": "http://tom.com/verb/ate"}, + "object": {"id": "act:my/homework"} + } guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) resp = self.client.put(path, json.dumps(stmt), content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(resp.status_code, 204) - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) - + obj = json.loads(r.content) self.assertEqual(obj['actor']['mbox'], stmt['actor']['mbox']) self.assertEqual(obj['verb']['id'], stmt['verb']['id']) self.assertEqual(obj['object']['id'], stmt['object']['id']) - - stmtv = {"actor":{"mbox":"mailto:darnhonestparents@example.com"}, - "verb":{"id":"http://adlnet.gov/expapi/verbs/voided"}, - "object":{"objectType":"StatementRef","id":guid} - } + + stmtv = {"actor": {"mbox": "mailto:darnhonestparents@example.com"}, + "verb": {"id": "http://adlnet.gov/expapi/verbs/voided"}, + "object": {"objectType": "StatementRef", "id": guid} + } guidv = str(uuid.uuid1()) - paramv = {"statementId":guidv} + paramv = {"statementId": guidv} pathv = "%s?%s" % (reverse(statements), urllib.urlencode(paramv)) respv = self.client.put(pathv, json.dumps(stmtv), content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0") self.assertEqual(respv.status_code, 204) - paramv = {"statementId":guidv} - pathv = "%s?%s" % (reverse(statements),urllib.urlencode(paramv)) + paramv = {"statementId": guidv} + pathv = "%s?%s" % (reverse(statements), urllib.urlencode(paramv)) r = self.client.get(pathv, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) objv = json.loads(r.content) @@ -1651,62 +1649,62 @@ def test_voidedStatementId(self): self.assertEqual(objv['object']['id'], stmtv['object']['id']) # first statement is voided now... should get a 404 if we try to request it - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 404) # but we can get it using the voidedStatementId param - param = {"voidedStatementId":guid} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"voidedStatementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) - + obj = json.loads(r.content) self.assertEqual(obj['actor']['mbox'], stmt['actor']['mbox']) self.assertEqual(obj['verb']['id'], stmt['verb']['id']) self.assertEqual(obj['object']['id'], stmt['object']['id']) def test_attachments(self): - stmt = [{"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = [{"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test11", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)11"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}, + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)11"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}, {"usageType": "http://example.com/attachment-usage/test12", - "display": {"en-US": "A test attachment12"}, - "description": {"en-US": "A test attachment (description)12"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test21", - "display": {"en-US": "A test attachment21"}, - "description": {"en-US": "A test attachment (description)21"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}, - {"usageType": "http://example.com/attachment-usage/test22", - "display": {"en-US": "A test attachment22"}, - "description": {"en-US": "A test attachment (description)22"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]} - ] + "display": {"en-US": "A test attachment12"}, + "description": {"en-US": "A test attachment (description)12"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test21", + "display": {"en-US": "A test attachment21"}, + "description": {"en-US": "A test attachment (description)21"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}, + {"usageType": "http://example.com/attachment-usage/test22", + "display": {"en-US": "A test attachment22"}, + "description": {"en-US": "A test attachment (description)22"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]} + ] message = MIMEMultipart(boundary="myboundary") txt11 = u"This is a text attachment11" txtsha11 = hashlib.sha256(txt11).hexdigest() stmt[0]['attachments'][0]["sha2"] = str(txtsha11) - + txt12 = u"This is a text attachment12" txtsha12 = hashlib.sha256(txt12).hexdigest() stmt[0]['attachments'][1]['sha2'] = str(txtsha12) @@ -1724,7 +1722,7 @@ def test_attachments(self): textdata12 = MIMEText(txt12, 'plain', 'utf-8') textdata21 = MIMEText(txt21, 'plain', 'utf-8') textdata22 = MIMEText(txt22, 'plain', 'utf-8') - + textdata11.add_header('X-Experience-API-Hash', txtsha11) textdata12.add_header('X-Experience-API-Hash', txtsha12) textdata21.add_header('X-Experience-API-Hash', txtsha21) @@ -1735,35 +1733,35 @@ def test_attachments(self): message.attach(textdata12) message.attach(textdata21) message.attach(textdata22) - + r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) param = {"attachments": True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'multipart/mixed; boundary=======ADL_LRS======') def test_attachments_no_payload(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) param = {"attachments": True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'application/json') @@ -1773,19 +1771,19 @@ def test_attachments_no_payload(self): self.assertIn('attachments', obj_from_json['statements'][0]) def test_attachments_no_payload_no_attach_param(self): - stmt = {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ + stmt = {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + response = self.client.post(reverse(statements), json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) r = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) @@ -1799,25 +1797,25 @@ def test_attachments_no_payload_no_attach_param(self): def test_attachments_no_payload_single_stmt_get(self): stmt_id = str(uuid.uuid1()) stmt = {"id": stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test", - "display": {"en-US": "A test attachment"}, - "description": {"en-US": "A test attachment (description)"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl": "http://my/file/url"}]} - + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test", + "display": {"en-US": "A test attachment"}, + "description": {"en-US": "A test attachment (description)"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/file/url"}]} + param = {"statementId": stmt_id} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, json.dumps(stmt), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) param["attachments"] = True - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'application/json') @@ -1825,16 +1823,16 @@ def test_attachments_no_payload_single_stmt_get(self): def test_attachments_payload_single_stmt_get(self): stmt_id = str(uuid.uuid1()) stmt = {"id": stmt_id, - "actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads"}, - "attachments": [ - {"usageType": "http://example.com/attachment-usage/test11", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)11"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]} + "actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads"}, + "attachments": [ + {"usageType": "http://example.com/attachment-usage/test11", + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)11"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]} message = MIMEMultipart(boundary="myboundary") txt11 = u"This is a text attachment11" @@ -1848,89 +1846,89 @@ def test_attachments_payload_single_stmt_get(self): message.attach(stmtdata) message.attach(textdata11) - + param = {"statementId": stmt_id} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) response = self.client.put(path, message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) param["attachments"] = True - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'multipart/mixed; boundary=======ADL_LRS======') def test_more_attachments_no_payload(self): - settings.SERVER_STMT_LIMIT=2 - stmts =[ - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads1"}, - "attachments": [ + settings.SERVER_STMT_LIMIT = 2 + stmts = [ + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads1"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test11", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)11"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://my/test/url11"}, + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)11"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/test/url11"}, {"usageType": "http://example.com/attachment-usage/test12", - "display": {"en-US": "A test attachment12"}, - "description": {"en-US": "A test attachment (description)12"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://my/test/url12"}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ + "display": {"en-US": "A test attachment12"}, + "description": {"en-US": "A test attachment (description)12"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/test/url12"}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test21", - "display": {"en-US": "A test attachment21"}, - "description": {"en-US": "A test attachment (description)21"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "fileUrl":"http://my/test/url21"}, + "display": {"en-US": "A test attachment21"}, + "description": {"en-US": "A test attachment (description)21"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "fileUrl": "http://my/test/url21"}, {"usageType": "http://example.com/attachment-usage/test22", - "display": {"en-US": "A test attachment22"}, - "description": {"en-US": "A test attachment (description)22"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "fileUrl":"http://my/test/url22"}]}, - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads3"}, - "attachments": [ + "display": {"en-US": "A test attachment22"}, + "description": {"en-US": "A test attachment (description)22"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "fileUrl": "http://my/test/url22"}]}, + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads3"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test31", - "display": {"en-US": "A test attachment31"}, - "description": {"en-US": "A test attachment (description)31"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://my/test/url31"}, + "display": {"en-US": "A test attachment31"}, + "description": {"en-US": "A test attachment (description)31"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/test/url31"}, {"usageType": "http://example.com/attachment-usage/test32", - "display": {"en-US": "A test attachment32"}, - "description": {"en-US": "A test attachment (description)32"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "fileUrl":"http://my/test/url32"}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads4"}, - "attachments": [ + "display": {"en-US": "A test attachment32"}, + "description": {"en-US": "A test attachment (description)32"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "fileUrl": "http://my/test/url32"}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads4"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test41", - "display": {"en-US": "A test attachment41"}, - "description": {"en-US": "A test attachment (description)41"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "fileUrl":"http://my/test/url41"}, + "display": {"en-US": "A test attachment41"}, + "description": {"en-US": "A test attachment (description)41"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "fileUrl": "http://my/test/url41"}, {"usageType": "http://example.com/attachment-usage/test42", - "display": {"en-US": "A test attachment42"}, - "description": {"en-US": "A test attachment (description)42"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "fileUrl":"http://my/test/url42"}]} + "display": {"en-US": "A test attachment42"}, + "description": {"en-US": "A test attachment (description)42"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "fileUrl": "http://my/test/url42"}]} ] response = self.client.post(reverse(statements), json.dumps(stmts), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) r = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) @@ -1939,69 +1937,69 @@ def test_more_attachments_no_payload(self): obj_from_json = json.loads(r.content) self.assertEqual(len(obj_from_json['statements']), 2) self.assertIn('attachments', obj_from_json['statements'][0].keys()) - self.assertIn('attachments', obj_from_json['statements'][1].keys()) + self.assertIn('attachments', obj_from_json['statements'][1].keys()) resp_url = obj_from_json['more'] resp_id = resp_url[-32:] - more_get = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + more_get = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(more_get.status_code, 200) self.assertEqual(more_get['Content-Type'], 'application/json') more_obj = json.loads(more_get.content) self.assertEqual(len(more_obj['statements']), 2) self.assertIn('attachments', more_obj['statements'][0].keys()) - self.assertIn('attachments', more_obj['statements'][1].keys()) + self.assertIn('attachments', more_obj['statements'][1].keys()) def test_more_attachments_with_payloads(self): - settings.SERVER_STMT_LIMIT=2 - stmts =[ - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads1"}, - "attachments": [ + settings.SERVER_STMT_LIMIT = 2 + stmts = [ + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads1"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test1", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)1"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)1"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test2", - "display": {"en-US": "A test attachment21"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads3"}, - "attachments": [ + "display": {"en-US": "A test attachment21"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads3"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test3", - "display": {"en-US": "A test attachment3"}, - "description": {"en-US": "A test attachment (description)3"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads4"}, - "attachments": [ + "display": {"en-US": "A test attachment3"}, + "description": {"en-US": "A test attachment (description)3"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads4"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test4", - "display": {"en-US": "A test attachment4"}, - "description": {"en-US": "A test attachment (description)4"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]} + "display": {"en-US": "A test attachment4"}, + "description": {"en-US": "A test attachment (description)4"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]} ] message = MIMEMultipart(boundary="myboundary") txt1 = u"This is a text attachment1" txtsha1 = hashlib.sha256(txt1).hexdigest() stmts[0]['attachments'][0]["sha2"] = str(txtsha1) - + txt2 = u"This is a text attachment2" txtsha2 = hashlib.sha256(txt2).hexdigest() stmts[1]['attachments'][0]['sha2'] = str(txtsha2) @@ -2019,7 +2017,7 @@ def test_more_attachments_with_payloads(self): textdata2 = MIMEText(txt2, 'plain', 'utf-8') textdata3 = MIMEText(txt3, 'plain', 'utf-8') textdata4 = MIMEText(txt4, 'plain', 'utf-8') - + textdata1.add_header('X-Experience-API-Hash', txtsha1) textdata2.add_header('X-Experience-API-Hash', txtsha2) textdata3.add_header('X-Experience-API-Hash', txtsha3) @@ -2032,19 +2030,19 @@ def test_more_attachments_with_payloads(self): message.attach(textdata4) r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - param= {"attachments":True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"attachments": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'multipart/mixed; boundary=======ADL_LRS======') headers_list1 = [txtsha1, txtsha2] headers_list2 = [txtsha3, txtsha4] - payload_list1 = [u"This is a text attachment1",u"This is a text attachment2"] - payload_list2 = [u"This is a text attachment3",u"This is a text attachment4"] + payload_list1 = [u"This is a text attachment1", u"This is a text attachment2"] + payload_list2 = [u"This is a text attachment3", u"This is a text attachment4"] # Have to add header to body so email lib will parse correctly msg = message_from_string("Content-Type:" + "multipart/mixed; boundary=======ADL_LRS======" + r.content) @@ -2059,7 +2057,7 @@ def test_more_attachments_with_payloads(self): self.assertTrue(isinstance(returned_json, dict)) self.assertEqual(len(returned_json['statements']), 2) resp_url = returned_json['more'] - resp_id = resp_url[-32:] + resp_id = resp_url[-32:] for part in parts[2:]: self.assertIn(part.get_payload(), payload_list2) @@ -2067,11 +2065,11 @@ def test_more_attachments_with_payloads(self): self.assertEqual(part.get('Content-Type'), 'text/plain; charset=utf-8') self.assertEqual(part.get('Content-Transfer-Encoding'), 'binary') - path = "%s?%s" % (reverse(statements_more,kwargs={'more_id':resp_id}), urllib.urlencode(param)) - more_get = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + path = "%s?%s" % (reverse(statements_more, kwargs={'more_id': resp_id}), urllib.urlencode(param)) + more_get = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(more_get.status_code, 200) - # Have to add header to body so email lib will parse correctly + # Have to add header to body so email lib will parse correctly more_msg = message_from_string("Content-Type:" + "multipart/mixed; boundary=======ADL_LRS======" + more_get.content) self.assertTrue(more_msg.is_multipart()) @@ -2090,56 +2088,55 @@ def test_more_attachments_with_payloads(self): self.assertEqual(more_part.get('Content-Type'), 'text/plain; charset=utf-8') self.assertEqual(more_part.get('Content-Transfer-Encoding'), 'binary') - def test_more_attachments_with_payloads_no_attach_param(self): - settings.SERVER_STMT_LIMIT=2 - stmts =[ - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads1"}, - "attachments": [ + settings.SERVER_STMT_LIMIT = 2 + stmts = [ + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads1"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test1", - "display": {"en-US": "A test attachment11"}, - "description": {"en-US": "A test attachment (description)1"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads2"}, - "attachments": [ + "display": {"en-US": "A test attachment11"}, + "description": {"en-US": "A test attachment (description)1"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads2"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test2", - "display": {"en-US": "A test attachment21"}, - "description": {"en-US": "A test attachment (description)2"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads3"}, - "attachments": [ + "display": {"en-US": "A test attachment21"}, + "description": {"en-US": "A test attachment (description)2"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads3"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test3", - "display": {"en-US": "A test attachment3"}, - "description": {"en-US": "A test attachment (description)3"}, - "contentType": "text/plain; charset=utf-8", - "length": 27, - "sha2":""}]}, - {"actor":{"mbox":"mailto:tom2@example.com"}, - "verb":{"id":"http://tom.com/verb/butted"}, - "object":{"id":"act:tom.com/objs/heads4"}, - "attachments": [ + "display": {"en-US": "A test attachment3"}, + "description": {"en-US": "A test attachment (description)3"}, + "contentType": "text/plain; charset=utf-8", + "length": 27, + "sha2": ""}]}, + {"actor": {"mbox": "mailto:tom2@example.com"}, + "verb": {"id": "http://tom.com/verb/butted"}, + "object": {"id": "act:tom.com/objs/heads4"}, + "attachments": [ {"usageType": "http://example.com/attachment-usage/test4", - "display": {"en-US": "A test attachment4"}, - "description": {"en-US": "A test attachment (description)4"}, - "contentType": "text/plain; charset=utf-8", - "length": 23, - "sha2":""}]} + "display": {"en-US": "A test attachment4"}, + "description": {"en-US": "A test attachment (description)4"}, + "contentType": "text/plain; charset=utf-8", + "length": 23, + "sha2": ""}]} ] message = MIMEMultipart(boundary="myboundary") txt1 = u"This is a text attachment1" txtsha1 = hashlib.sha256(txt1).hexdigest() stmts[0]['attachments'][0]["sha2"] = str(txtsha1) - + txt2 = u"This is a text attachment2" txtsha2 = hashlib.sha256(txt2).hexdigest() stmts[1]['attachments'][0]['sha2'] = str(txtsha2) @@ -2157,7 +2154,7 @@ def test_more_attachments_with_payloads_no_attach_param(self): textdata2 = MIMEText(txt2, 'plain', 'utf-8') textdata3 = MIMEText(txt3, 'plain', 'utf-8') textdata4 = MIMEText(txt4, 'plain', 'utf-8') - + textdata1.add_header('X-Experience-API-Hash', txtsha1) textdata2.add_header('X-Experience-API-Hash', txtsha2) textdata3.add_header('X-Experience-API-Hash', txtsha3) @@ -2170,11 +2167,11 @@ def test_more_attachments_with_payloads_no_attach_param(self): message.attach(textdata4) r = self.client.post(reverse(statements), message.as_string(), content_type="multipart/mixed", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) - param= {"attachments":False} - path = "%s?%s" % (reverse(statements),urllib.urlencode(param)) + param = {"attachments": False} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) r = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(r.status_code, 200) self.assertEqual(r['Content-Type'], 'application/json') @@ -2183,157 +2180,157 @@ def test_more_attachments_with_payloads_no_attach_param(self): resp_url = obj_from_json['more'] resp_id = resp_url[-32:] - more_get = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + more_get = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(more_get.status_code, 200) self.assertEqual(more_get['Content-Type'], 'application/json') def test_related_activities_filter_more(self): stmt_list = [] - stmt1 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt1 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt1) - stmt2 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt2 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt2) - stmt3 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt3 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt3) - stmt4 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt4 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt4) - stmt5 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt5 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt5) - stmt6 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt6 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt6) - stmt7 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt7 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt7) - stmt8 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt8 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt8) - stmt9 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt9 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt9) - stmt10 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt10 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt10) - stmt11 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt11 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt11) - stmt12 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt12 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt12) - stmt13 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt13 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt13) - stmt14 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt14 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt14) - stmt15 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt15 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt15) - stmt16 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt16 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt16) - stmt17 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt17 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt17) - stmt18 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt18 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt18) - stmt19 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt19 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt19) - stmt20 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt20 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt20) - stmt21 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt21 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt21) - stmt22 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt22 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt22) - stmt23 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt23 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt23) - stmt24 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt24 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt24) - stmt25 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt25 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt25) - stmt26 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://foobar"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + stmt26 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://foobar"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(stmt26) - stmt27 = {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{"id":"act://barfoo"},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}, - "context":{"contextActivities": {"other": {"id": "act://foobar"}}}} + stmt27 = {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"id": "act://barfoo"}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}, + "context": {"contextActivities": {"other": {"id": "act://foobar"}}}} stmt_list.append(stmt27) # Post statements post_statements = self.client.post(reverse(statements), json.dumps(stmt_list), - content_type="application/json",HTTP_AUTHORIZATION=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + content_type="application/json", HTTP_AUTHORIZATION=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post_statements.status_code, 200) # Get regular - get_param = {"activity":"act://foobar"} - path = "%s?%s" % (reverse(statements),urllib.urlencode(get_param)) + get_param = {"activity": "act://foobar"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(get_param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) returned = json.loads(r.content) @@ -2342,11 +2339,11 @@ def test_related_activities_filter_more(self): self.assertEqual(returned['more'], "") # Get related - get_param = {"activity":"act://foobar", "related_activities": True} - path = "%s?%s" % (reverse(statements),urllib.urlencode(get_param)) + get_param = {"activity": "act://foobar", "related_activities": True} + path = "%s?%s" % (reverse(statements), urllib.urlencode(get_param)) r = self.client.get(path, X_Experience_API_Version="1.0", Authorization=self.auth) self.assertEqual(r.status_code, 200) returned = json.loads(r.content) returned_stmts = returned['statements'] self.assertEqual(len(returned_stmts), len(stmt_list)) - self.assertEqual(returned['more'], "") \ No newline at end of file + self.assertEqual(returned['more'], "") diff --git a/lrs/tests/StatementManagerTests.py b/lrs/tests/StatementManagerTests.py index 9350d2ed..b5614269 100644 --- a/lrs/tests/StatementManagerTests.py +++ b/lrs/tests/StatementManagerTests.py @@ -12,8 +12,9 @@ from ..managers.ActivityManager import ActivityManager from adl_lrs.views import register + class StatementManagerTests(TestCase): - + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -23,15 +24,15 @@ def setUp(self): self.email = "test1@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) def test_minimum_stmt(self): - stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -44,15 +45,14 @@ def test_minimum_stmt(self): self.assertEqual(actor.mbox, "mailto:tincan@adlnet.gov") self.assertEqual(verb.verb_id, "http://example.com/verbs/created") - def test_given_stmtID_stmt(self): st_id = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created", "en-GB":"made"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":st_id})) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created", "en-GB": "made"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": st_id})) response = self.client.put(path, stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) stmt = Statement.objects.get(statement_id=st_id) @@ -66,11 +66,11 @@ def test_given_stmtID_stmt(self): self.assertEqual(v, 'made') elif k == 'en-US': self.assertEqual(v, 'created') - + self.assertEqual(activity.activity_id, "http://example.adlnet.gov/tincan/example/simplestatement") self.assertEqual(actor.mbox, "mailto:tincan@adlnet.gov") self.assertEqual(verb.verb_id, "http://example.com/verbs/created") - + st = Statement.objects.get(statement_id=st_id) self.assertEqual(st.object_activity.id, activity.id) self.assertEqual(st.verb.id, verb.id) @@ -78,76 +78,76 @@ def test_given_stmtID_stmt(self): def test_stmt_ref_as_object(self): st_id = str(uuid.uuid1()) - stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":st_id})) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": st_id})) response = self.client.put(path, stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) - stmt2 = json.dumps({"actor":{"name":"Example Admin", "mbox":"mailto:admin@example.com"}, - 'verb': {"id":"http://example.com/verbs/attempted"}, 'object': {'objectType':'StatementRef', - 'id': st_id}}) + stmt2 = json.dumps({"actor": {"name": "Example Admin", "mbox": "mailto:admin@example.com"}, + 'verb': {"id": "http://example.com/verbs/attempted"}, 'object': {'objectType': 'StatementRef', + 'id': st_id}}) response = self.client.post(reverse(statements), stmt2, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmts = Statement.objects.all() self.assertEqual(len(stmts), 2) def test_voided_wrong_type(self): - stmt = json.dumps({"actor":{"name":"Example Admin", "mbox":"mailto:admin@example.com"}, - 'verb': {"id":"http://adlnet.gov/expapi/verbs/voided"}, 'object': {'objectType':'Statement', 'id': "12345678-1234-5678-1234-567812345678"}}) + stmt = json.dumps({"actor": {"name": "Example Admin", "mbox": "mailto:admin@example.com"}, + 'verb': {"id": "http://adlnet.gov/expapi/verbs/voided"}, 'object': {'objectType': 'Statement', 'id': "12345678-1234-5678-1234-567812345678"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Statement with voided verb must have StatementRef as objectType") def test_no_verb_stmt(self): - stmt = json.dumps({"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}, "object": {'id':'act:activity2'}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}, "object": {'id': 'act:activity2'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Statement is missing actor, verb, or object') def test_no_object_stmt(self): - stmt = json.dumps({"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}, "verb": {"id":"verb:verb/url"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}, "verb": {"id": "verb:verb/url"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) - self.assertEqual(response.content, 'Statement is missing actor, verb, or object') + self.assertEqual(response.content, 'Statement is missing actor, verb, or object') def test_no_actor_stmt(self): - stmt = json.dumps({"object":{"id":"act:activity_test"}, "verb": {"id":"verb:verb/url"}}) + stmt = json.dumps({"object": {"id": "act:activity_test"}, "verb": {"id": "verb:verb/url"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Statement is missing actor, verb, or object') def test_voided_true_stmt(self): - stmt = json.dumps({'actor':{'objectType':'Agent', 'mbox':'mailto:l@l.com'}, 'verb': {"id":'verb:verb/url/kicked'},'voided': True, 'object': {'id':'act:activity3'}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:l@l.com'}, 'verb': {"id": 'verb:verb/url/kicked'}, 'voided': True, 'object': {'id': 'act:activity3'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Invalid field(s) found in Statement - voided') def test_result_stmt(self): time = "P0Y0M0DT1H311M01S" - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity12'}, - "result": {'completion': True, 'success': True, 'response': 'kicked', 'duration': time}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity12'}, + "result": {'completion': True, 'success': True, 'response': 'kicked', 'duration': time}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) - + activity = Activity.objects.get(id=stmt.object_activity.id) self.assertEqual(stmt.verb.verb_id, "verb:verb/url") @@ -163,16 +163,16 @@ def test_result_stmt(self): def test_result_ext_stmt(self): time = "P0Y0M0DT1H311M01S" - stmt = json.dumps({"actor":{'name':'jon', - 'mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity13'}, - "result": {'completion': True, 'success': True, 'response': 'yes', 'duration': time, - 'extensions':{'ext:key1': 'value1', 'ext:key2':'value2'}}}) + stmt = json.dumps({"actor": {'name': 'jon', + 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity13'}, + "result": {'completion': True, 'success': True, 'response': 'yes', 'duration': time, + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) - + activity = Activity.objects.get(id=stmt.object_activity.id) actor = Agent.objects.get(id=stmt.actor.id) extKeys = stmt.result_extensions.keys() @@ -201,113 +201,112 @@ def test_result_ext_stmt(self): self.assertIn('value2', extVals) def test_result_score_scaled_up_good(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'scaled':1.0},'completion': True, - 'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'scaled': 1.0}, 'completion': True, + 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) def test_result_score_scaled_down_good(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'scaled':00.000},'completion': True, - 'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'scaled': 00.000}, 'completion': True, + 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) def test_result_score_scaled_up_bad(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'scaled':1.01},'completion': True, - 'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'scaled': 1.01}, 'completion': True, + 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Score scaled value in statement result must be between -1 and 1') def test_result_score_scaled(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'scaled':-1.00001},'completion': True, - 'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'scaled': -1.00001}, 'completion': True, + 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Score scaled value in statement result must be between -1 and 1') def test_result_score_raw_up_good(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'raw':1.01,'min':-2.0, 'max':1.01}, - 'completion': True,'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'raw': 1.01, 'min': -2.0, 'max': 1.01}, + 'completion': True, 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) def test_result_score_raw_down_good(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'raw':-20.0,'min':-20.0, 'max':1.01}, - 'completion': True,'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'raw': -20.0, 'min': -20.0, 'max': 1.01}, + 'completion': True, 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) def test_result_score_raw_up_bad(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'raw':1.02,'min':-2.0, 'max':1.01}, - 'completion': True,'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'raw': 1.02, 'min': -2.0, 'max': 1.01}, + 'completion': True, 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Score raw value in statement result must be between minimum and maximum') def test_result_score_raw_down_bad(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'raw':-2.00001,'min':-2.0, 'max':1.01}, - 'completion': True,'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'raw': -2.00001, 'min': -2.0, 'max': 1.01}, + 'completion': True, 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Score raw value in statement result must be between minimum and maximum') def test_result_score_min_max_bad(self): - stmt = json.dumps({"actor":{'objectType':'Agent', - 'name':'jon','mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"}, - "object": {'id':'act:activity14'}, "result": {'score':{'raw':1.5,'min':2.0, 'max':1.01}, - 'completion': True,'success': True, 'response': 'yes'}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', + 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, + "object": {'id': 'act:activity14'}, "result": {'score': {'raw': 1.5, 'min': 2.0, 'max': 1.01}, + 'completion': True, 'success': True, 'response': 'yes'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Score minimum in statement result must be less than the maximum') def test_result_score_stmt(self): time = "P0Y0M0DT1H311M01S" - stmt = json.dumps({"actor":{'objectType':'Agent','name':'jon','mbox':'mailto:jon@example.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity14'}, "result": {'score':{'scaled':.95}, - 'completion': True, 'success': True, 'response': 'yes', 'duration': time, - 'extensions':{'ext:key1': 'value1', 'ext:key2':'value2'}}}) + stmt = json.dumps({"actor": {'objectType': 'Agent', 'name': 'jon', 'mbox': 'mailto:jon@example.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity14'}, "result": {'score': {'scaled': .95}, + 'completion': True, 'success': True, 'response': 'yes', 'duration': time, + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) - activity = Activity.objects.get(id=stmt.object_activity.id) actor = Agent.objects.get(id=stmt.actor.id) extKeys = stmt.result_extensions.keys() @@ -338,51 +337,50 @@ def test_result_score_stmt(self): self.assertIn('value1', extVals) self.assertIn('value2', extVals) - def test_no_registration_context_stmt(self): # expect the LRS to assign a context registration uuid - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'},"verb":{"id":"verb:verb/url"},"object": {'id':'act:activity14'}, - 'context': {'contextActivities': {'other': {'id': 'act:NewActivityID'}}}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, "verb": {"id": "verb:verb/url"}, "object": {'id': 'act:activity14'}, + 'context': {'contextActivities': {'other': {'id': 'act:NewActivityID'}}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) - - self.assertIsNotNone(stmt.context_registration) + + self.assertIsNotNone(stmt.context_registration) def test_wrong_statement_type_in_context(self): - stmt = json.dumps({'actor':{'objectType':'Agent', - 'mbox':'mailto:s@s.com'},'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity16'}, - 'context':{'contextActivities': {'other': {'id': 'act:NewActivityID'}}, - 'revision': 'foo', 'platform':'bar','language': 'en-US', - 'statement': {'objectType': 'Activity','id': "act:some/act"}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + stmt = json.dumps({'actor': {'objectType': 'Agent', + 'mbox': 'mailto:s@s.com'}, 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity16'}, + 'context': {'contextActivities': {'other': {'id': 'act:NewActivityID'}}, + 'revision': 'foo', 'platform': 'bar', 'language': 'en-US', + 'statement': {'objectType': 'Activity', 'id': "act:some/act"}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "StatementRef objectType must be set to 'StatementRef'") def test_invalid_context_registration(self): - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity15'}, - 'context':{'registration': "bbb", 'contextActivities': {'other': {'id': 'act:NewActivityID'}, 'grouping':{'id':'act:GroupID'}}, - 'revision': 'foo', 'platform':'bar', - 'language': 'en-US'}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity15'}, + 'context': {'registration': "bbb", 'contextActivities': {'other': {'id': 'act:NewActivityID'}, 'grouping': {'id': 'act:GroupID'}}, + 'revision': 'foo', 'platform': 'bar', + 'language': 'en-US'}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Context registration - bbb is not a valid UUID') def test_context_stmt(self): guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity15'}, - 'context':{'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}, - 'grouping':{'id':'act:GroupID'}},'revision': 'foo', 'platform':'bar','language': 'en-US'}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity15'}, + 'context': {'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}, + 'grouping': {'id': 'act:GroupID'}}, 'revision': 'foo', 'platform': 'bar', 'language': 'en-US'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -399,22 +397,22 @@ def test_context_stmt(self): st = Statement.objects.get(id=stmt.id) self.assertEqual(st.object_activity.id, activity.id) - self.assertEqual(st.context_registration, guid) + self.assertEqual(st.context_registration, guid) self.assertEqual(st.context_revision, 'foo') self.assertEqual(st.context_platform, 'bar') self.assertEqual(st.context_language, 'en-US') def test_context_activity_list(self): guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity15'}, - 'context':{'registration': guid, - 'contextActivities': {'other': [{'id': 'act:NewActivityID'},{'id':'act:anotherActID'}], - 'grouping':{'id':'act:GroupID'}}, - 'revision': 'foo', 'platform':'bar', - 'language': 'en-US'}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity15'}, + 'context': {'registration': guid, + 'contextActivities': {'other': [{'id': 'act:NewActivityID'}, {'id': 'act:anotherActID'}], + 'grouping': {'id': 'act:GroupID'}}, + 'revision': 'foo', 'platform': 'bar', + 'language': 'en-US'}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -424,7 +422,7 @@ def test_context_activity_list(self): context_activities_other = stmt.context_ca_other.all().values_list('activity_id', flat=True) context_activities_grouping = stmt.context_ca_grouping.all().values_list('activity_id', flat=True) self.assertEqual(len(context_activities_other) + len(context_activities_grouping), 3) - + self.assertIn('act:NewActivityID', context_activities_other) self.assertIn('act:anotherActID', context_activities_other) self.assertIn('act:GroupID', context_activities_grouping) @@ -435,19 +433,19 @@ def test_context_activity_list(self): st = Statement.objects.get(id=stmt.id) self.assertEqual(st.object_activity.id, activity.id) - self.assertEqual(st.context_registration, guid) + self.assertEqual(st.context_registration, guid) self.assertEqual(st.context_revision, 'foo') self.assertEqual(st.context_platform, 'bar') self.assertEqual(st.context_language, 'en-US') def test_context_ext_stmt(self): guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity16'}, - 'context':{'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, - 'revision': 'foo', 'platform':'bar','language': 'en-US', 'extensions':{'ext:k1': 'v1', 'ext:k2': 'v2'}}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity16'}, + 'context': {'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, + 'revision': 'foo', 'platform': 'bar', 'language': 'en-US', 'extensions': {'ext:k1': 'v1', 'ext:k2': 'v2'}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -474,25 +472,24 @@ def test_context_ext_stmt(self): self.assertIn('v1', extVals) self.assertIn('v2', extVals) - def test_stmtref_in_context_stmt(self): stmt_guid = str(uuid.uuid1()) - existing_stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url/outer"},"object": {'id':'act:activityy16'}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_guid})) + existing_stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url/outer"}, "object": {'id': 'act:activityy16'}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_guid})) response = self.client.put(path, existing_stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity16'}, - 'context':{'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, - 'revision': 'foo', 'platform':'bar','language': 'en-US', - 'statement': {'objectType': 'StatementRef','id': stmt_guid}}}) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity16'}, + 'context': {'registration': guid, 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, + 'revision': 'foo', 'platform': 'bar', 'language': 'en-US', + 'statement': {'objectType': 'StatementRef', 'id': stmt_guid}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -506,39 +503,38 @@ def test_stmtref_in_context_stmt(self): self.assertEqual(st.context_platform, 'bar') self.assertEqual(st.context_language, 'en-US') - def test_substmt_in_context_stmt(self): - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity16'}, - 'context':{'contextActivities': {'other': {'id': 'act:NewActivityID'}}, - 'revision': 'foo', 'platform':'bar','language': 'en-US', - 'statement': {'objectType':'SubStatement', 'actor':{'objectType':'Agent', - 'mbox':'mailto:sss@sss.com'},'verb':{'id':'verb:verb/url/nest/nest'}, - 'object':{'id':'act://activity/url'}}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity16'}, + 'context': {'contextActivities': {'other': {'id': 'act:NewActivityID'}}, + 'revision': 'foo', 'platform': 'bar', 'language': 'en-US', + 'statement': {'objectType': 'SubStatement', 'actor': {'objectType': 'Agent', + 'mbox': 'mailto:sss@sss.com'}, 'verb': {'id': 'verb:verb/url/nest/nest'}, + 'object': {'id': 'act://activity/url'}}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "StatementRef objectType must be set to 'StatementRef'") def test_instructor_in_context_stmt(self): stmt_guid = str(uuid.uuid1()) - existing_stmt = json.dumps({'actor':{'objectType':'Agent', - 'mbox':'mailto:s@s.com'},'verb': {"id":"verb:verb/url/outer"},"object": {'id':'act:activityy16'}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_guid})) + existing_stmt = json.dumps({'actor': {'objectType': 'Agent', + 'mbox': 'mailto:s@s.com'}, 'verb': {"id": "verb:verb/url/outer"}, "object": {'id': 'act:activityy16'}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_guid})) response = self.client.put(path, existing_stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:jon@example.com', - 'name':'jon'},'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity17'}, - 'context':{'registration': guid, 'instructor': {'objectType':'Agent','name':'jon', - 'mbox':'mailto:jon@example.com'},'contextActivities': {'other': {'id': 'act:NewActivityID'}}, - 'revision': 'foo', 'platform':'bar','language': 'en-US', 'statement': {'id': stmt_guid, - 'objectType':'StatementRef'}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:jon@example.com', + 'name': 'jon'}, 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity17'}, + 'context': {'registration': guid, 'instructor': {'objectType': 'Agent', 'name': 'jon', + 'mbox': 'mailto:jon@example.com'}, 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, + 'revision': 'foo', 'platform': 'bar', 'language': 'en-US', 'statement': {'id': stmt_guid, + 'objectType': 'StatementRef'}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -555,31 +551,30 @@ def test_instructor_in_context_stmt(self): self.assertEqual(st.context_revision, 'foo') self.assertEqual(st.context_platform, 'bar') self.assertEqual(st.context_language, 'en-US') - + self.assertEqual(st.context_instructor.objectType, 'Agent') - - self.assertEqual(st.context_instructor.name, 'jon') - self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') + self.assertEqual(st.context_instructor.name, 'jon') + self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') def test_actor_with_context_stmt(self): stmt_guid = str(uuid.uuid1()) - existing_stmt = json.dumps({'actor':{'objectType':'Agent', - 'mbox':'mailto:s@s.com'},'verb': {"id":"verb:verb/url/outer"},"object": {'id':'act:activityy16'}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_guid})) + existing_stmt = json.dumps({'actor': {'objectType': 'Agent', + 'mbox': 'mailto:s@s.com'}, 'verb': {"id": "verb:verb/url/outer"}, "object": {'id': 'act:activityy16'}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_guid})) response = self.client.put(path, existing_stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent', 'name': 'steve', - 'mbox':'mailto:mailto:s@s.com'},'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity18'}, - 'context':{'registration': guid, 'instructor': {'objectType':'Agent','name':'jon', - 'mbox':'mailto:jon@example.com'},'contextActivities': {'other': {'id': 'act:NewActivityID1'}}, - 'revision': 'foob', 'platform':'bard','language': 'en-US', 'statement': {'id':stmt_guid, - "objectType":"StatementRef"}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'name': 'steve', + 'mbox': 'mailto:mailto:s@s.com'}, 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity18'}, + 'context': {'registration': guid, 'instructor': {'objectType': 'Agent', 'name': 'jon', + 'mbox': 'mailto:jon@example.com'}, 'contextActivities': {'other': {'id': 'act:NewActivityID1'}}, + 'revision': 'foob', 'platform': 'bard', 'language': 'en-US', 'statement': {'id': stmt_guid, + "objectType": "StatementRef"}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -589,62 +584,62 @@ def test_actor_with_context_stmt(self): context_activities = stmt.context_ca_other.all() self.assertEqual(st.object_activity.id, activity.id) - self.assertEqual(st.verb.verb_id, "verb:verb/url" ) + self.assertEqual(st.verb.verb_id, "verb:verb/url") self.assertEqual(st.context_registration, guid) self.assertEqual(context_activities[0].activity_id, 'act:NewActivityID1') self.assertEqual(st.context_revision, 'foob') self.assertEqual(st.context_platform, 'bard') self.assertEqual(st.context_language, 'en-US') - + self.assertEqual(st.context_instructor.objectType, 'Agent') - - self.assertEqual(st.context_instructor.name, 'jon') - self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') + self.assertEqual(st.context_instructor.name, 'jon') + self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') def test_agent_as_object_with_context_stmt(self): stmt_guid = str(uuid.uuid1()) - existing_stmt = json.dumps({'actor':{'objectType':'Agent', - 'mbox':'mailto:mailto:s@s.com'},'verb': {"id":"verb:verb/url/outer"},"object": {'id':'act:activityy16'}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_guid})) + existing_stmt = json.dumps({'actor': {'objectType': 'Agent', + 'mbox': 'mailto:mailto:s@s.com'}, 'verb': {"id": "verb:verb/url/outer"}, "object": {'id': 'act:activityy16'}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_guid})) response = self.client.put(path, existing_stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) guid = str(uuid.uuid1()) stmt = json.dumps( - {'actor':{ - 'objectType':'Agent', - 'mbox':'mailto:l@l.com', - 'name':'lou' + { + 'actor': { + 'objectType': 'Agent', + 'mbox': 'mailto:l@l.com', + 'name': 'lou' }, - 'object':{ - 'objectType':'Agent', - 'name': 'lou', - 'mbox':'mailto:l@l.com' - }, - 'verb': {"id":"verb:verb/url"}, - 'context':{ - 'registration': guid, + 'object': { + 'objectType': 'Agent', + 'name': 'lou', + 'mbox': 'mailto:l@l.com' + }, + 'verb': {"id": "verb:verb/url"}, + 'context': { + 'registration': guid, 'instructor': { - 'objectType':'Agent', - 'name':'jon', - 'mbox':'mailto:jon@example.com' + 'objectType': 'Agent', + 'name': 'jon', + 'mbox': 'mailto:jon@example.com' }, 'contextActivities': { 'other': {'id': 'act:NewActivityID1'} - }, - 'language': 'en-US', + }, + 'language': 'en-US', 'statement': { 'id': stmt_guid, 'objectType': 'StatementRef' } - } } + } ) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -658,19 +653,18 @@ def test_agent_as_object_with_context_stmt(self): self.assertEqual(st.context_registration, guid) self.assertEqual(context_activities[0].activity_id, 'act:NewActivityID1') self.assertEqual(st.context_language, 'en-US') - + self.assertEqual(st.context_instructor.objectType, 'Agent') - + # Should be jon self.assertEqual(st.context_instructor.name, 'jon') - self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') - + self.assertEqual(st.context_instructor.mbox, 'mailto:jon@example.com') def test_agent_as_object(self): - stmt = json.dumps({'object':{'objectType':'Agent', 'name': 'lulu', 'openid':'id:luluid'}, - 'verb': {"id":"verb:verb/url"},'actor':{'objectType':'Agent','mbox':'mailto:t@t.com'}}) + stmt = json.dumps({'object': {'objectType': 'Agent', 'name': 'lulu', 'openid': 'id:luluid'}, + 'verb': {"id": "verb:verb/url"}, 'actor': {'objectType': 'Agent', 'mbox': 'mailto:t@t.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -680,42 +674,41 @@ def test_agent_as_object(self): self.assertEqual(agent.name, 'lulu') self.assertEqual(agent.openid, 'id:luluid') - def test_unallowed_substmt_field(self): - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"}, 'object':{'objectType':'SubStatement', - 'actor':{'objectType':'Agent','mbox':'mailto:ss@ss.com'},'verb': {"id":"verb:verb/url/nest"}, - 'object': {'objectType':'activity', 'id':'act:testex.com'}, - 'authority':{'objectType':'Agent','mbox':'mailto:s@s.com'}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, 'object': {'objectType': 'SubStatement', + 'actor': {'objectType': 'Agent', 'mbox': 'mailto:ss@ss.com'}, 'verb': {"id": "verb:verb/url/nest"}, + 'object': {'objectType': 'activity', 'id': 'act:testex.com'}, + 'authority': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Invalid field(s) found in SubStatement - authority') def test_nested_substatement(self): - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"}, 'object':{'objectType':'SubStatement', - 'actor':{'objectType':'Agent','mbox':'mailto:ss@ss.com'},'verb': {"id":"verb:verb/url/nest"}, - 'object': {'objectType':'SubStatement', 'actor':{'objectType':'Agent','mbox':'mailto:sss@sss.com'}, - 'verb':{'id':'verb:verb/url/nest/nest'}, 'object':{'id':'act://activity/url'}}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, 'object': {'objectType': 'SubStatement', + 'actor': {'objectType': 'Agent', 'mbox': 'mailto:ss@ss.com'}, 'verb': {"id": "verb:verb/url/nest"}, + 'object': {'objectType': 'SubStatement', 'actor': {'objectType': 'Agent', 'mbox': 'mailto:sss@sss.com'}, + 'verb': {'id': 'verb:verb/url/nest/nest'}, 'object': {'id': 'act://activity/url'}}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) - self.assertEqual(response.content, 'Cannot nest a SubStatement inside of another SubStatement') + self.assertEqual(response.content, 'Cannot nest a SubStatement inside of another SubStatement') def test_substatement_as_object(self): guid = str(uuid.uuid1()) - stmt = json.dumps({'actor':{'objectType':'Agent','mbox':'mailto:s@s.com'}, - 'verb': {"id":"verb:verb/url"}, 'object':{'objectType':'SubStatement', - 'actor':{'objectType':'Agent','mbox':'mailto:ss@ss.com'},'verb': {"id":"verb:verb/url/nest"}, - 'object': {'objectType':'Activity', 'id':'act:testex.com'}, 'result':{'completion': True, 'success': True, - 'response': 'kicked'}, 'context':{'registration': guid, - 'contextActivities': {'other': {'id': 'act:NewActivityID'}},'revision': 'foo', 'platform':'bar', - 'language': 'en-US', 'extensions':{'ext:k1': 'v1', 'ext:k2': 'v2'}}}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt = json.dumps({'actor': {'objectType': 'Agent', 'mbox': 'mailto:s@s.com'}, + 'verb': {"id": "verb:verb/url"}, 'object': {'objectType': 'SubStatement', + 'actor': {'objectType': 'Agent', 'mbox': 'mailto:ss@ss.com'}, 'verb': {"id": "verb:verb/url/nest"}, + 'object': {'objectType': 'Activity', 'id': 'act:testex.com'}, 'result': {'completion': True, 'success': True, + 'response': 'kicked'}, 'context': {'registration': guid, + 'contextActivities': {'other': {'id': 'act:NewActivityID'}}, 'revision': 'foo', 'platform': 'bar', + 'language': 'en-US', 'extensions': {'ext:k1': 'v1', 'ext:k2': 'v2'}}}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -726,26 +719,25 @@ def test_substatement_as_object(self): sub_act = Agent.objects.get(id=sub_stmt.actor.id) self.assertEqual(outer_stmt.verb.verb_id, "verb:verb/url") - self.assertEqual(outer_stmt.actor.mbox, 'mailto:s@s.com') + self.assertEqual(outer_stmt.actor.mbox, 'mailto:s@s.com') self.assertEqual(sub_stmt.verb.verb_id, "verb:verb/url/nest") self.assertEqual(sub_obj.activity_id, 'act:testex.com') self.assertEqual(sub_act.mbox, 'mailto:ss@ss.com') self.assertEqual(sub_stmt.context_registration, guid) self.assertEqual(sub_stmt.result_response, 'kicked') - def test_group_stmt(self): ot = "Group" name = "the group SMT" mbox = "mailto:the.groupSMT@example.com" - members = [{"name":"agentA","mbox":"mailto:agentA@example.com"}, - {"name":"agentB","mbox":"mailto:agentB@example.com"}] - testagent = {"objectType":ot, "name":name, "mbox":mbox,"member":members} - - stmt = json.dumps({"actor":testagent, 'verb': {"id":"verb:verb/url"},"object": {"id":"act:activity5", - "objectType": "Activity"}}) - response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + members = [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, + {"name": "agentB", "mbox": "mailto:agentB@example.com"}] + testagent = {"objectType": ot, "name": name, "mbox": mbox, "member": members} + + stmt = json.dumps({"actor": testagent, 'verb': {"id": "verb:verb/url"}, "object": {"id": "act:activity5", + "objectType": "Activity"}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] stmt = Statement.objects.get(statement_id=stmt_id) @@ -766,19 +758,18 @@ def test_group_stmt(self): def test_activity_correctresponsepattern(self): act1 = ActivityManager({ - 'objectType': 'Activity', 'id':'act:foo', - 'definition': {'name': {'en-US':'testname'},'description': {'en-US':'testdesc'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'true-false','correctResponsesPattern': ['true'], - 'extensions': {'ext:key1': 'value1'}}}) + 'objectType': 'Activity', 'id': 'act:foo', + 'definition': {'name': {'en-US': 'testname'}, 'description': {'en-US': 'testdesc'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'true-false', 'correctResponsesPattern': ['true'], + 'extensions': {'ext:key1': 'value1'}}}) act2 = ActivityManager({ - 'objectType': 'Activity', 'id':'act:baz', - 'definition': {'name': {'en-US':'testname2'},'description': {'en-US':'testdesc2'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'true-false','correctResponsesPattern': ['true'], - 'extensions': {'ext2:key1': 'value1'}}}) - + 'objectType': 'Activity', 'id': 'act:baz', + 'definition': {'name': {'en-US': 'testname2'}, 'description': {'en-US': 'testdesc2'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'true-false', 'correctResponsesPattern': ['true'], + 'extensions': {'ext2:key1': 'value1'}}}) acts = len(Activity.objects.all()) self.assertEqual(acts, 2) diff --git a/lrs/tests/StatementMoreTests.py b/lrs/tests/StatementMoreTests.py index 5dcc321a..008e3ecf 100644 --- a/lrs/tests/StatementMoreTests.py +++ b/lrs/tests/StatementMoreTests.py @@ -22,323 +22,323 @@ def setUpClass(cls): print "\n%s" % __name__ def setUp(self): - settings.SERVER_STMT_LIMIT=10 - + settings.SERVER_STMT_LIMIT = 10 + self.username = "auth1" self.email = "auth1@example.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {'username':self.username, 'email':self.email,'password':self.password,'password2':self.password} - self.client.post(reverse(register),form) + form = {'username': self.username, 'email': self.email, 'password': self.password, 'password2': self.password} + self.client.post(reverse(register), form) self.guid1 = str(uuid.uuid1()) self.guid2 = str(uuid.uuid1()) - self.guid3 = str(uuid.uuid1()) + self.guid3 = str(uuid.uuid1()) self.guid4 = str(uuid.uuid1()) self.guid5 = str(uuid.uuid1()) self.guid6 = str(uuid.uuid1()) self.guid7 = str(uuid.uuid1()) - self.guid8 = str(uuid.uuid1()) + self.guid8 = str(uuid.uuid1()) self.guid9 = str(uuid.uuid1()) self.guid10 = str(uuid.uuid1()) self.guid11 = str(uuid.uuid1()) self.guid12 = str(uuid.uuid1()) - self.guid13 = str(uuid.uuid1()) + self.guid13 = str(uuid.uuid1()) self.guid14 = str(uuid.uuid1()) self.guid15 = str(uuid.uuid1()) self.guid16 = str(uuid.uuid1()) self.guid17 = str(uuid.uuid1()) - self.guid18 = str(uuid.uuid1()) + self.guid18 = str(uuid.uuid1()) self.guid19 = str(uuid.uuid1()) self.guid20 = str(uuid.uuid1()) self.guid21 = str(uuid.uuid1()) self.guid22 = str(uuid.uuid1()) - self.guid23 = str(uuid.uuid1()) + self.guid23 = str(uuid.uuid1()) self.guid24 = str(uuid.uuid1()) self.guid25 = str(uuid.uuid1()) # Context guids self.cguid1 = str(uuid.uuid1()) - self.cguid2 = str(uuid.uuid1()) + self.cguid2 = str(uuid.uuid1()) self.cguid3 = str(uuid.uuid1()) self.cguid4 = str(uuid.uuid1()) self.cguid5 = str(uuid.uuid1()) self.mytime = str(datetime.utcnow().replace(tzinfo=utc).isoformat()) stmt_list = [] - self.existStmt1 = {"id":self.guid1,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id":"verb:attempted", - "display":{"en-US":"attempted", 'en-GB':"altattempted"}},"object": {'objectType': 'Activity', - 'id':'act:foogie','definition': {'name': {'en-US':'testname2', 'en-GB':'altname'}, - 'description': {'en-US':'testdesc2','en-GB':'altdesc'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'fill-in','correctResponsesPattern': ['answer'],'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}, "result": {'score':{'scaled':.85}, 'completion': True, 'success': True, - 'response': 'kicked','duration': "P3Y6M4DT12H30M5S", 'extensions':{'ext:key1': 'value1', 'ext:key2':'value2'}}, - 'context':{'registration': self.cguid1, 'contextActivities': {'other': {'id': 'act:NewActivityID2'}}, - 'revision': 'food', 'platform':'bard','language': 'en-US', 'extensions':{'ext:ckey1': 'cval1', - 'ext:ckey2': 'cval2'}}, 'authority':{'objectType':'Agent','name':'auth1','mbox':'mailto:auth1@example.com'}} + self.existStmt1 = {"id": self.guid1, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "verb:attempted", + "display": {"en-US": "attempted", 'en-GB': "altattempted"}}, "object": {'objectType': 'Activity', + 'id': 'act:foogie', 'definition': {'name': {'en-US': 'testname2', 'en-GB': 'altname'}, + 'description': {'en-US': 'testdesc2', 'en-GB': 'altdesc'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'fill-in', 'correctResponsesPattern': ['answer'], 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}, "result": {'score': {'scaled': .85}, 'completion': True, 'success': True, + 'response': 'kicked', 'duration': "P3Y6M4DT12H30M5S", 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}, + 'context': {'registration': self.cguid1, 'contextActivities': {'other': {'id': 'act:NewActivityID2'}}, + 'revision': 'food', 'platform': 'bard', 'language': 'en-US', 'extensions': {'ext:ckey1': 'cval1', + 'ext:ckey2': 'cval2'}}, 'authority': {'objectType': 'Agent', 'name': 'auth1', 'mbox': 'mailto:auth1@example.com'}} stmt_list.append(self.existStmt1) - self.existStmt2 = {"id":self.guid2,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id":"verb:verb/created", - "display":{"en-US":"created", 'en-GB':"altcreated"}}, "object": {'objectType': 'Activity', - 'id':'act:foogie','definition': {'name': {'en-US':'testname3'},'description': {'en-US':'testdesc3'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'fill-in','correctResponsesPattern': ['answers'], - 'extensions': {'ext:key11': 'value11', 'ext:key22': 'value22','ext:key33': 'value33'}}}, - "result": {'score':{'scaled':.75}, 'completion': True, 'success': True, 'response': 'shouted', - 'duration': "P3Y6M4DT12H30M5S", 'extensions':{'ext:dkey1': 'dvalue1', 'ext:dkey2':'dvalue2'}}, - 'context':{'registration': self.cguid2, 'contextActivities': {'other': {'id': 'act:NewActivityID24'}}, - 'revision': 'food', 'platform':'bard','language': 'en-US', 'extensions':{'ext:ckey11': 'cval11', - 'ext:ckey22': 'cval22'}}, 'authority':{'objectType':'Agent','name':'auth1','mbox':'mailto:auth1@example.com'}} + self.existStmt2 = {"id": self.guid2, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "verb:verb/created", + "display": {"en-US": "created", 'en-GB': "altcreated"}}, "object": {'objectType': 'Activity', + 'id': 'act:foogie', 'definition': {'name': {'en-US': 'testname3'}, 'description': {'en-US': 'testdesc3'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'fill-in', 'correctResponsesPattern': ['answers'], + 'extensions': {'ext:key11': 'value11', 'ext:key22': 'value22', 'ext:key33': 'value33'}}}, + "result": {'score': {'scaled': .75}, 'completion': True, 'success': True, 'response': 'shouted', + 'duration': "P3Y6M4DT12H30M5S", 'extensions': {'ext:dkey1': 'dvalue1', 'ext:dkey2': 'dvalue2'}}, + 'context': {'registration': self.cguid2, 'contextActivities': {'other': {'id': 'act:NewActivityID24'}}, + 'revision': 'food', 'platform': 'bard', 'language': 'en-US', 'extensions': {'ext:ckey11': 'cval11', + 'ext:ckey22': 'cval22'}}, 'authority': {'objectType': 'Agent', 'name': 'auth1', 'mbox': 'mailto:auth1@example.com'}} stmt_list.append(self.existStmt2) - self.existStmt3 = {"id":self.guid3,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id":"verb:created", - "display":{"en-US":"created", 'en-GB':"altcreated"}}, "object": {'objectType': 'Activity', - 'id':'act:foogals','definition': {'name': {'en-US':'testname3'},'description': {'en-US':'testdesc3'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'fill-in','correctResponsesPattern': ['answers'], - 'extensions': {'ext:key111': 'value111', 'ext:key222': 'value222','ext:key333': 'value333'}}}, - "result": {'score':{'scaled':.79}, 'completion': True, 'success': True, 'response': 'shouted', - 'duration': "P3Y6M4DT12H30M5S", 'extensions':{'ext:dkey1': 'dvalue1', 'ext:dkey2':'dvalue2'}}, - 'context':{'registration': self.cguid3, 'contextActivities': {'other': {'id': 'act:NewActivityID23'}}, - 'revision': 'food', 'platform':'bard','language': 'en-US','instructor':{'name':'bill', - 'mbox':'mailto:bill@bill.com'} , 'extensions':{'ext:ckey111': 'cval111', - 'ext:ckey222': 'cval222'}}, 'authority':{'objectType':'Agent','name':'auth1','mbox':'mailto:auth1@example.com'}} + self.existStmt3 = {"id": self.guid3, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "verb:created", + "display": {"en-US": "created", 'en-GB': "altcreated"}}, "object": {'objectType': 'Activity', + 'id': 'act:foogals', 'definition': {'name': {'en-US': 'testname3'}, 'description': {'en-US': 'testdesc3'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'fill-in', 'correctResponsesPattern': ['answers'], + 'extensions': {'ext:key111': 'value111', 'ext:key222': 'value222', 'ext:key333': 'value333'}}}, + "result": {'score': {'scaled': .79}, 'completion': True, 'success': True, 'response': 'shouted', + 'duration': "P3Y6M4DT12H30M5S", 'extensions': {'ext:dkey1': 'dvalue1', 'ext:dkey2': 'dvalue2'}}, + 'context': {'registration': self.cguid3, 'contextActivities': {'other': {'id': 'act:NewActivityID23'}}, + 'revision': 'food', 'platform': 'bard', 'language': 'en-US', 'instructor': {'name': 'bill', + 'mbox': 'mailto:bill@bill.com'}, 'extensions': {'ext:ckey111': 'cval111', + 'ext:ckey222': 'cval222'}}, 'authority': {'objectType': 'Agent', 'name': 'auth1', 'mbox': 'mailto:auth1@example.com'}} stmt_list.append(self.existStmt3) - self.existStmt4 = {"id":self.guid4,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id":"verb:verb/created", - "display":{"en-US":"created", 'en-GB':"altcreated"}}, "object": {'objectType': 'Activity', 'id':'act:foogal', - 'definition': {'name': {'en-US':'testname3'},'description': {'en-US':'testdesc3'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', - 'interactionType': 'fill-in','correctResponsesPattern': ['answers'], - 'extensions': {'ext:key111': 'value111', 'ext:key222': 'value222','ext:key333': 'value333'}}}, - "result": {'score':{'scaled':.79}, 'completion': True, 'success': True, 'response': 'shouted', - 'duration': "P3Y6M4DT12H30M5S", 'extensions':{'ext:dkey1': 'dvalue1', 'ext:dkey2':'dvalue2'}}, - 'context':{'registration': self.cguid4, 'contextActivities': {'other': {'id': 'act:NewActivityID22'}}, - 'revision': 'food', 'platform':'bard','language': 'en-US','instructor':{'name':'bill', - 'mbox':'mailto:bill@bill.com'}, 'extensions':{'ext:ckey111': 'cval111', - 'ext:ckey222': 'cval222'}}, 'authority':{'objectType':'Agent','name':'auth1','mbox':'mailto:auth1@example.com'}} + self.existStmt4 = {"id": self.guid4, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "verb:verb/created", + "display": {"en-US": "created", 'en-GB': "altcreated"}}, "object": {'objectType': 'Activity', 'id': 'act:foogal', + 'definition': {'name': {'en-US': 'testname3'}, 'description': {'en-US': 'testdesc3'}, 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', + 'interactionType': 'fill-in', 'correctResponsesPattern': ['answers'], + 'extensions': {'ext:key111': 'value111', 'ext:key222': 'value222', 'ext:key333': 'value333'}}}, + "result": {'score': {'scaled': .79}, 'completion': True, 'success': True, 'response': 'shouted', + 'duration': "P3Y6M4DT12H30M5S", 'extensions': {'ext:dkey1': 'dvalue1', 'ext:dkey2': 'dvalue2'}}, + 'context': {'registration': self.cguid4, 'contextActivities': {'other': {'id': 'act:NewActivityID22'}}, + 'revision': 'food', 'platform': 'bard', 'language': 'en-US', 'instructor': {'name': 'bill', + 'mbox': 'mailto:bill@bill.com'}, 'extensions': {'ext:ckey111': 'cval111', + 'ext:ckey222': 'cval222'}}, 'authority': {'objectType': 'Agent', 'name': 'auth1', 'mbox': 'mailto:auth1@example.com'}} stmt_list.append(self.existStmt4) - self.existStmt5 = {"id":self.guid5,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon1', - 'mbox':'mailto:jon1@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt5 = {"id": self.guid5, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon1', + 'mbox': 'mailto:jon1@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt5) - self.existStmt6 = {"id":self.guid6,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon2', - 'mbox':'mailto:jon2@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt6 = {"id": self.guid6, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon2', + 'mbox': 'mailto:jon2@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt6) - self.existStmt7 = {"id":self.guid7,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon3', - 'mbox':'mailto:jon3@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt7 = {"id": self.guid7, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon3', + 'mbox': 'mailto:jon3@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt7) - self.existStmt8 = {"id":self.guid8,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon4', - 'mbox':'mailto:jon4@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt8 = {"id": self.guid8, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon4', + 'mbox': 'mailto:jon4@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt8) - self.existStmt9 = {"id":self.guid9,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon5', - 'mbox':'mailto:jon5@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt9 = {"id": self.guid9, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon5', + 'mbox': 'mailto:jon5@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt9) - self.existStmt10 = {"id":self.guid10,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon33', - 'mbox':'mailto:jon33@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt10 = {"id": self.guid10, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon33', + 'mbox': 'mailto:jon33@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt10) - self.existStmt11 = {"id":self.guid11,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon6', - 'mbox':'mailto:jon6@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt11 = {"id": self.guid11, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon6', + 'mbox': 'mailto:jon6@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt11) - self.existStmt12 = {"id":self.guid12,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon7', - 'mbox':'mailto:jon7@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt12 = {"id": self.guid12, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon7', + 'mbox': 'mailto:jon7@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt12) - self.existStmt13 = {"id":self.guid13,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon8', - 'mbox':'mailto:jon8@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt13 = {"id": self.guid13, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon8', + 'mbox': 'mailto:jon8@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt13) - self.existStmt14 = {"id":self.guid14,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon9', - 'mbox':'mailto:jon9@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt14 = {"id": self.guid14, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon9', + 'mbox': 'mailto:jon9@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt14) - self.existStmt15 = {"id":self.guid15,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon10', - 'mbox':'mailto:jon10@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt15 = {"id": self.guid15, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon10', + 'mbox': 'mailto:jon10@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt15) - self.existStmt16 = {"id":self.guid16,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon11', - 'mbox':'mailto:jon11@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt16 = {"id": self.guid16, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon11', + 'mbox': 'mailto:jon11@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt16) - self.existStmt17 = {"id":self.guid17,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon12', - 'mbox':'mailto:jon12@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt17 = {"id": self.guid17, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon12', + 'mbox': 'mailto:jon12@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt17) - self.existStmt18 = {"id":self.guid18,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon13', - 'mbox':'mailto:jon13@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt18 = {"id": self.guid18, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon13', + 'mbox': 'mailto:jon13@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt18) - self.existStmt19 = {"id":self.guid19,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon14', - 'mbox':'mailto:jon14@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt19 = {"id": self.guid19, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon14', + 'mbox': 'mailto:jon14@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt19) - self.existStmt20 = {"id":self.guid20,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon15', - 'mbox':'mailto:jon15@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt20 = {"id": self.guid20, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon15', + 'mbox': 'mailto:jon15@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt20) - self.existStmt21 = {"id":self.guid21,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon16', - 'mbox':'mailto:jon16@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt21 = {"id": self.guid21, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon16', + 'mbox': 'mailto:jon16@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt21) - self.existStmt22 = {"id":self.guid22,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon17', - 'mbox':'mailto:jon17@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt22 = {"id": self.guid22, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon17', + 'mbox': 'mailto:jon17@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt22) - self.existStmt23 = {"id":self.guid23,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon18', - 'mbox':'mailto:jon18@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt23 = {"id": self.guid23, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon18', + 'mbox': 'mailto:jon18@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt23) - self.existStmt24 = {"id":self.guid24,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon19', - 'mbox':'mailto:jon19@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt24 = {"id": self.guid24, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon19', + 'mbox': 'mailto:jon19@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt24) - self.existStmt25 = {"id":self.guid25,"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object":{'objectType':'Agent','name':'jon20', - 'mbox':'mailto:jon20@jon.com'},"verb":{"id":"verb:verb/passed", - "display":{"en-US":"passed", 'en-GB':"altpassed"}}} + self.existStmt25 = {"id": self.guid25, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {'objectType': 'Agent', 'name': 'jon20', + 'mbox': 'mailto:jon20@jon.com'}, "verb": {"id": "verb:verb/passed", + "display": {"en-US": "passed", 'en-GB': "altpassed"}}} stmt_list.append(self.existStmt25) # Post statements post_statements = self.client.post(reverse(statements), json.dumps(stmt_list), - content_type="application/json",HTTP_AUTHORIZATION=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + content_type="application/json", HTTP_AUTHORIZATION=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(post_statements.status_code, 200) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=1)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=1)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid1).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid2).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid3).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid4).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=5)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=5)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid5).update(stored=time) - self.secondTime = str((datetime.utcnow()+timedelta(seconds=6)).replace(tzinfo=utc).isoformat()) + self.secondTime = str((datetime.utcnow() + timedelta(seconds=6)).replace(tzinfo=utc).isoformat()) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid6).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid7).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid8).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid9).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid10).update(stored=time) - self.thirdTime = str((datetime.utcnow()+timedelta(seconds=12)).replace(tzinfo=utc).isoformat()) + self.thirdTime = str((datetime.utcnow() + timedelta(seconds=12)).replace(tzinfo=utc).isoformat()) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=13)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=13)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid11).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=14)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=14)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid12).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=15)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=15)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid13).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=16)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=16)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid14).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=17)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=17)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid15).update(stored=time) - self.fourthTime = str((datetime.utcnow()+timedelta(seconds=18)).replace(tzinfo=utc).isoformat()) + self.fourthTime = str((datetime.utcnow() + timedelta(seconds=18)).replace(tzinfo=utc).isoformat()) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=19)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=19)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid16).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=20)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=20)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid17).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=21)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=21)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid18).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=22)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=22)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid19).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=23)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=23)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid20).update(stored=time) - self.fifthTime = str((datetime.utcnow()+timedelta(seconds=24)).replace(tzinfo=utc).isoformat()) - - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=25)).replace(tzinfo=utc).isoformat())) + self.fifthTime = str((datetime.utcnow() + timedelta(seconds=24)).replace(tzinfo=utc).isoformat()) + + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=25)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid21).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=26)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=26)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid22).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=27)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=27)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid23).update(stored=time) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=28)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=28)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid24).update(stored=time) - self.sixthTime = str((datetime.utcnow()+timedelta(seconds=29)).replace(tzinfo=utc).isoformat()) + self.sixthTime = str((datetime.utcnow() + timedelta(seconds=29)).replace(tzinfo=utc).isoformat()) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=30)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=30)).replace(tzinfo=utc).isoformat())) Statement.objects.filter(statement_id=self.guid25).update(stored=time) def tearDown(self): - settings.SERVER_STMT_LIMIT=100 + settings.SERVER_STMT_LIMIT = 100 attach_folder_path = os.path.join(settings.MEDIA_ROOT, "attachment_payloads") for the_file in os.listdir(attach_folder_path): file_path = os.path.join(attach_folder_path, the_file) @@ -348,14 +348,14 @@ def tearDown(self): raise e def test_unknown_more_id_url(self): - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth ) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 404) def test_not_full_page_stmts(self): - sincePostResponse = self.client.post(reverse(statements), {"until":self.secondTime}, - content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) - + sincePostResponse = self.client.post(reverse(statements), {"until": self.secondTime}, + content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) + self.assertEqual(sincePostResponse.status_code, 200) rsp = sincePostResponse.content self.assertIn(self.guid5, rsp) @@ -387,8 +387,8 @@ def test_not_full_page_stmts(self): def test_single_full_page_stmts(self): sincePostResponse = self.client.post(reverse(statements), - {"until":self.thirdTime}, - content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + {"until": self.thirdTime}, + content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sincePostResponse.status_code, 200) rsp = sincePostResponse.content self.assertIn(self.guid10, rsp) @@ -419,8 +419,8 @@ def test_single_full_page_stmts(self): self.assertNotIn(self.guid11, rsp) def test_single_full_second_not_full_more_stmts_url(self): - sincePostResponse = self.client.post(reverse(statements), {"until":self.fourthTime}, - content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sincePostResponse = self.client.post(reverse(statements), {"until": self.fourthTime}, + content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sincePostResponse.status_code, 200) rsp = sincePostResponse.content resp_json = json.loads(rsp) @@ -442,7 +442,7 @@ def test_single_full_second_not_full_more_stmts_url(self): self.assertNotIn(self.guid24, rsp) self.assertNotIn(self.guid23, rsp) self.assertNotIn(self.guid22, rsp) - self.assertNotIn(self.guid21, rsp) + self.assertNotIn(self.guid21, rsp) self.assertNotIn(self.guid20, rsp) self.assertNotIn(self.guid19, rsp) self.assertNotIn(self.guid18, rsp) @@ -455,8 +455,8 @@ def test_single_full_second_not_full_more_stmts_url(self): self.assertNotIn(self.guid1, rsp) # Simulate user clicking returned 'more' URL - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content @@ -484,12 +484,12 @@ def test_single_full_second_not_full_more_stmts_url(self): self.assertNotIn(self.guid9, more_rsp) self.assertNotIn(self.guid8, more_rsp) self.assertNotIn(self.guid7, more_rsp) - self.assertNotIn(self.guid6, more_rsp) + self.assertNotIn(self.guid6, more_rsp) self.assertNotIn(self.guid25, more_rsp) def test_two_pages_full_more_stmts_url(self): - sincePostResponse = self.client.post(reverse(statements), {"until":self.fifthTime}, - content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sincePostResponse = self.client.post(reverse(statements), {"until": self.fifthTime}, + content_type="application/x-www-form-urlencoded", X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sincePostResponse.status_code, 200) rsp = sincePostResponse.content resp_json = json.loads(rsp) @@ -511,7 +511,7 @@ def test_two_pages_full_more_stmts_url(self): self.assertNotIn(self.guid24, rsp) self.assertNotIn(self.guid23, rsp) self.assertNotIn(self.guid22, rsp) - self.assertNotIn(self.guid21, rsp) + self.assertNotIn(self.guid21, rsp) self.assertNotIn(self.guid10, rsp) self.assertNotIn(self.guid9, rsp) self.assertNotIn(self.guid8, rsp) @@ -524,8 +524,8 @@ def test_two_pages_full_more_stmts_url(self): self.assertNotIn(self.guid1, rsp) # Simulate user clicking returned 'more' URL - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content @@ -553,12 +553,12 @@ def test_two_pages_full_more_stmts_url(self): self.assertNotIn(self.guid14, more_rsp) self.assertNotIn(self.guid13, more_rsp) self.assertNotIn(self.guid12, more_rsp) - self.assertNotIn(self.guid11, more_rsp) + self.assertNotIn(self.guid11, more_rsp) self.assertNotIn(self.guid25, more_rsp) def test_two_pages_full_third_not_full_more_stmts_url(self): - sinceGetResponse = self.client.get(reverse(statements), {"until":self.sixthTime, "limit":10}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sinceGetResponse = self.client.get(reverse(statements), {"until": self.sixthTime, "limit": 10}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) rsp = sinceGetResponse.content resp_json = json.loads(rsp) @@ -591,11 +591,11 @@ def test_two_pages_full_third_not_full_more_stmts_url(self): self.assertNotIn(self.guid4, rsp) self.assertNotIn(self.guid3, rsp) self.assertNotIn(self.guid2, rsp) - self.assertNotIn(self.guid1, rsp) + self.assertNotIn(self.guid1, rsp) self.assertNotIn(self.guid25, rsp) - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content more_json = json.loads(more_rsp) @@ -626,11 +626,11 @@ def test_two_pages_full_third_not_full_more_stmts_url(self): self.assertNotIn(self.guid4, more_rsp) self.assertNotIn(self.guid3, more_rsp) self.assertNotIn(self.guid2, more_rsp) - self.assertNotIn(self.guid1, more_rsp) + self.assertNotIn(self.guid1, more_rsp) self.assertNotIn(self.guid25, more_rsp) - anotherURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(anotherURLGet.status_code, 200) another_rsp = anotherURLGet.content @@ -654,17 +654,16 @@ def test_two_pages_full_third_not_full_more_stmts_url(self): self.assertNotIn(self.guid12, another_rsp) self.assertNotIn(self.guid11, another_rsp) self.assertNotIn(self.guid10, another_rsp) - self.assertNotIn(self.guid9, another_rsp) + self.assertNotIn(self.guid9, another_rsp) self.assertNotIn(self.guid8, another_rsp) self.assertNotIn(self.guid7, another_rsp) self.assertNotIn(self.guid6, another_rsp) self.assertNotIn(self.guid5, another_rsp) - self.assertNotIn(self.guid25, another_rsp) - + self.assertNotIn(self.guid25, another_rsp) def test_limit_less_than_server_limit(self): - sinceGetResponse = self.client.get(reverse(statements), {"until":self.sixthTime, "limit":8}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sinceGetResponse = self.client.get(reverse(statements), {"until": self.sixthTime, "limit": 8}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) rsp = sinceGetResponse.content resp_json = json.loads(rsp) @@ -674,13 +673,13 @@ def test_limit_less_than_server_limit(self): self.assertEqual(len(resp_json['statements']), 8) self.assertIn(self.guid24, rsp) - self.assertIn(self.guid23, rsp) + self.assertIn(self.guid23, rsp) self.assertIn(self.guid22, rsp) self.assertIn(self.guid21, rsp) - self.assertIn(self.guid20, rsp) - self.assertIn(self.guid19, rsp) + self.assertIn(self.guid20, rsp) + self.assertIn(self.guid19, rsp) self.assertIn(self.guid18, rsp) - self.assertIn(self.guid17, rsp) + self.assertIn(self.guid17, rsp) self.assertNotIn(self.guid16, rsp) self.assertNotIn(self.guid15, rsp) @@ -697,11 +696,11 @@ def test_limit_less_than_server_limit(self): self.assertNotIn(self.guid4, rsp) self.assertNotIn(self.guid3, rsp) self.assertNotIn(self.guid2, rsp) - self.assertNotIn(self.guid1, rsp) + self.assertNotIn(self.guid1, rsp) self.assertNotIn(self.guid25, rsp) - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content more_json = json.loads(more_rsp) @@ -732,11 +731,11 @@ def test_limit_less_than_server_limit(self): self.assertNotIn(self.guid4, more_rsp) self.assertNotIn(self.guid3, more_rsp) self.assertNotIn(self.guid2, more_rsp) - self.assertNotIn(self.guid1, more_rsp) + self.assertNotIn(self.guid1, more_rsp) self.assertNotIn(self.guid25, more_rsp) - anotherURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(anotherURLGet.status_code, 200) another_rsp = anotherURLGet.content @@ -764,13 +763,12 @@ def test_limit_less_than_server_limit(self): self.assertNotIn(self.guid12, another_rsp) self.assertNotIn(self.guid11, another_rsp) self.assertNotIn(self.guid10, another_rsp) - self.assertNotIn(self.guid9, another_rsp) + self.assertNotIn(self.guid9, another_rsp) self.assertNotIn(self.guid25, another_rsp) - def test_limit_same_as_server_limit(self): - sinceGetResponse = self.client.get(reverse(statements), {"until":self.sixthTime, "limit":10}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sinceGetResponse = self.client.get(reverse(statements), {"until": self.sixthTime, "limit": 10}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) rsp = sinceGetResponse.content @@ -804,11 +802,11 @@ def test_limit_same_as_server_limit(self): self.assertNotIn(self.guid4, rsp) self.assertNotIn(self.guid3, rsp) self.assertNotIn(self.guid2, rsp) - self.assertNotIn(self.guid1, rsp) + self.assertNotIn(self.guid1, rsp) self.assertNotIn(self.guid25, rsp) - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content more_json = json.loads(more_rsp) @@ -839,11 +837,11 @@ def test_limit_same_as_server_limit(self): self.assertNotIn(self.guid4, more_rsp) self.assertNotIn(self.guid3, more_rsp) self.assertNotIn(self.guid2, more_rsp) - self.assertNotIn(self.guid1, more_rsp) + self.assertNotIn(self.guid1, more_rsp) self.assertNotIn(self.guid25, more_rsp) - anotherURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(anotherURLGet.status_code, 200) another_rsp = anotherURLGet.content @@ -867,23 +865,23 @@ def test_limit_same_as_server_limit(self): self.assertNotIn(self.guid12, another_rsp) self.assertNotIn(self.guid11, another_rsp) self.assertNotIn(self.guid10, another_rsp) - self.assertNotIn(self.guid9, another_rsp) + self.assertNotIn(self.guid9, another_rsp) self.assertNotIn(self.guid8, another_rsp) self.assertNotIn(self.guid7, another_rsp) self.assertNotIn(self.guid6, another_rsp) self.assertNotIn(self.guid5, another_rsp) - self.assertNotIn(self.guid25, another_rsp) + self.assertNotIn(self.guid25, another_rsp) def test_limit_more_than_server_limit(self): - sinceGetResponse = self.client.get(reverse(statements), {"until":self.sixthTime, "limit":12}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sinceGetResponse = self.client.get(reverse(statements), {"until": self.sixthTime, "limit": 12}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) rsp = sinceGetResponse.content resp_json = json.loads(rsp) resp_url = resp_json['more'] resp_id = resp_url[-32:] - self.assertEqual(len(resp_json['statements']), 10) + self.assertEqual(len(resp_json['statements']), 10) self.assertIn(self.guid24, rsp) self.assertIn(self.guid23, rsp) self.assertIn(self.guid22, rsp) @@ -908,11 +906,11 @@ def test_limit_more_than_server_limit(self): self.assertNotIn(self.guid4, rsp) self.assertNotIn(self.guid3, rsp) self.assertNotIn(self.guid2, rsp) - self.assertNotIn(self.guid1, rsp) + self.assertNotIn(self.guid1, rsp) self.assertNotIn(self.guid25, rsp) - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(moreURLGet.status_code, 200) more_rsp = moreURLGet.content more_json = json.loads(more_rsp) @@ -943,12 +941,11 @@ def test_limit_more_than_server_limit(self): self.assertNotIn(self.guid4, more_rsp) self.assertNotIn(self.guid3, more_rsp) self.assertNotIn(self.guid2, more_rsp) - self.assertNotIn(self.guid1, more_rsp) + self.assertNotIn(self.guid1, more_rsp) self.assertNotIn(self.guid25, more_rsp) - - anotherURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(anotherURLGet.status_code, 200) another_rsp = anotherURLGet.content @@ -972,7 +969,7 @@ def test_limit_more_than_server_limit(self): self.assertNotIn(self.guid12, another_rsp) self.assertNotIn(self.guid11, another_rsp) self.assertNotIn(self.guid10, another_rsp) - self.assertNotIn(self.guid9, another_rsp) + self.assertNotIn(self.guid9, another_rsp) self.assertNotIn(self.guid8, another_rsp) self.assertNotIn(self.guid7, another_rsp) self.assertNotIn(self.guid6, another_rsp) @@ -981,10 +978,10 @@ def test_limit_more_than_server_limit(self): def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): # Make initial complex get so 'more' will be required - sinceGetResponse = self.client.get(reverse(statements), {"until":self.sixthTime}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + sinceGetResponse = self.client.get(reverse(statements), {"until": self.sixthTime}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(sinceGetResponse.status_code, 200) - rsp = sinceGetResponse.content + rsp = sinceGetResponse.content resp_json = json.loads(rsp) resp_url = resp_json['more'] resp_id = resp_url[-32:] @@ -1013,12 +1010,12 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid4, rsp) self.assertNotIn(self.guid3, rsp) self.assertNotIn(self.guid2, rsp) - self.assertNotIn(self.guid1, rsp) + self.assertNotIn(self.guid1, rsp) self.assertNotIn(self.guid25, rsp) # Simulate user clicking returned 'more' URL - moreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + moreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) more_rsp = moreURLGet.content more_json = json.loads(more_rsp) more_resp_url = more_json['more'] @@ -1049,12 +1046,11 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid4, more_rsp) self.assertNotIn(self.guid3, more_rsp) self.assertNotIn(self.guid2, more_rsp) - self.assertNotIn(self.guid1, more_rsp) + self.assertNotIn(self.guid1, more_rsp) self.assertNotIn(self.guid25, more_rsp) - - more2URLGet = self.client.get(reverse(statements_more, kwargs={'more_id':more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + more2URLGet = self.client.get(reverse(statements_more, kwargs={'more_id': more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(more2URLGet.status_code, 200) more2_rsp = more2URLGet.content self.assertIn(self.guid4, more2_rsp) @@ -1076,17 +1072,17 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid14, more2_rsp) self.assertNotIn(self.guid13, more2_rsp) self.assertNotIn(self.guid12, more2_rsp) - self.assertNotIn(self.guid11, more2_rsp) + self.assertNotIn(self.guid11, more2_rsp) self.assertNotIn(self.guid10, more2_rsp) self.assertNotIn(self.guid9, more2_rsp) self.assertNotIn(self.guid8, more2_rsp) self.assertNotIn(self.guid7, more2_rsp) self.assertNotIn(self.guid6, more2_rsp) - self.assertNotIn(self.guid5, more2_rsp) + self.assertNotIn(self.guid5, more2_rsp) # Simulate user clicking returned 'more' URL - anotherMoreURLGet = self.client.get(reverse(statements_more,kwargs={'more_id':resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherMoreURLGet = self.client.get(reverse(statements_more, kwargs={'more_id': resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) another_more_rsp = anotherMoreURLGet.content another_more_json = json.loads(another_more_rsp) another_more_resp_url = another_more_json['more'] @@ -1117,12 +1113,12 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid4, another_more_rsp) self.assertNotIn(self.guid3, another_more_rsp) self.assertNotIn(self.guid2, another_more_rsp) - self.assertNotIn(self.guid1, another_more_rsp) + self.assertNotIn(self.guid1, another_more_rsp) self.assertNotIn(self.guid25, another_more_rsp) # Simulate user clicking returned 'more' URL - anotherMore2URLGet = self.client.get(reverse(statements_more, kwargs={'more_id':another_more_resp_id}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + anotherMore2URLGet = self.client.get(reverse(statements_more, kwargs={'more_id': another_more_resp_id}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(anotherMore2URLGet.status_code, 200) another_more2_rsp = anotherMore2URLGet.content self.assertIn(self.guid4, another_more2_rsp) @@ -1144,7 +1140,7 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid14, another_more2_rsp) self.assertNotIn(self.guid13, another_more2_rsp) self.assertNotIn(self.guid12, another_more2_rsp) - self.assertNotIn(self.guid11, another_more2_rsp) + self.assertNotIn(self.guid11, another_more2_rsp) self.assertNotIn(self.guid10, another_more2_rsp) self.assertNotIn(self.guid9, another_more2_rsp) self.assertNotIn(self.guid8, another_more2_rsp) @@ -1153,10 +1149,10 @@ def test_two_pages_full_third_not_full_more_stmts_multiple_hits(self): self.assertNotIn(self.guid5, another_more2_rsp) def test_get_order(self): - r = self.client.get(reverse(statements), {"limit":10}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements), {"limit": 10}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) more = sresults['more'][-32:] stmts = sresults['statements'] @@ -1173,10 +1169,10 @@ def test_get_order(self): self.assertEqual(stmts[8]['id'], self.guid17) self.assertEqual(stmts[9]['id'], self.guid16) - r = self.client.get(reverse(statements_more,kwargs={'more_id':more}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements_more, kwargs={'more_id': more}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) more = sresults['more'][-32:] stmts = sresults['statements'] @@ -1193,10 +1189,10 @@ def test_get_order(self): self.assertEqual(stmts[8]['id'], self.guid7) self.assertEqual(stmts[9]['id'], self.guid6) - r = self.client.get(reverse(statements_more,kwargs={'more_id':more}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements_more, kwargs={'more_id': more}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) stmts = sresults['statements'] @@ -1208,10 +1204,10 @@ def test_get_order(self): self.assertEqual(stmts[4]['id'], self.guid1) def test_get_rev_order(self): - r = self.client.get(reverse(statements), {"limit":10, "ascending":True}, - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements), {"limit": 10, "ascending": True}, + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) more = sresults['more'][-32:] stmts = sresults['statements'] @@ -1228,10 +1224,10 @@ def test_get_rev_order(self): self.assertEqual(stmts[8]['id'], self.guid9) self.assertEqual(stmts[9]['id'], self.guid10) - r = self.client.get(reverse(statements_more,kwargs={'more_id':more}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements_more, kwargs={'more_id': more}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) more = sresults['more'][-32:] stmts = sresults['statements'] @@ -1248,10 +1244,10 @@ def test_get_rev_order(self): self.assertEqual(stmts[8]['id'], self.guid19) self.assertEqual(stmts[9]['id'], self.guid20) - r = self.client.get(reverse(statements_more,kwargs={'more_id':more}), - X_Experience_API_Version=settings.XAPI_VERSION,HTTP_AUTHORIZATION=self.auth) + r = self.client.get(reverse(statements_more, kwargs={'more_id': more}), + X_Experience_API_Version=settings.XAPI_VERSION, HTTP_AUTHORIZATION=self.auth) self.assertEqual(r.status_code, 200) - c = r.content + c = r.content sresults = json.loads(c) stmts = sresults['statements'] @@ -1260,4 +1256,4 @@ def test_get_rev_order(self): self.assertEqual(stmts[1]['id'], self.guid22) self.assertEqual(stmts[2]['id'], self.guid23) self.assertEqual(stmts[3]['id'], self.guid24) - self.assertEqual(stmts[4]['id'], self.guid25) \ No newline at end of file + self.assertEqual(stmts[4]['id'], self.guid25) diff --git a/lrs/tests/StatementTests.py b/lrs/tests/StatementTests.py index 7b1efdf1..310c941b 100644 --- a/lrs/tests/StatementTests.py +++ b/lrs/tests/StatementTests.py @@ -18,7 +18,9 @@ from ..utils import retrieve_statement from adl_lrs.views import register + class StatementTests(TestCase): + @classmethod def setUpClass(cls): print "\n%s" % __name__ @@ -28,31 +30,31 @@ def setUp(self): self.email = "test1@tester.com" self.password = "test" self.auth = "Basic %s" % base64.b64encode("%s:%s" % (self.username, self.password)) - form = {"username":self.username, "email":self.email,"password":self.password,"password2":self.password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) + form = {"username": self.username, "email": self.email, "password": self.password, "password2": self.password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) self.username2 = "tester2" self.email2 = "test2@tester.com" self.password2 = "test2" self.auth2 = "Basic %s" % base64.b64encode("%s:%s" % (self.username2, self.password2)) - form2 = {"username":self.username2, "email":self.email2,"password":self.password2,"password2":self.password2} - self.client.post(reverse(register),form2, X_Experience_API_Version=settings.XAPI_VERSION) + form2 = {"username": self.username2, "email": self.email2, "password": self.password2, "password2": self.password2} + self.client.post(reverse(register), form2, X_Experience_API_Version=settings.XAPI_VERSION) self.firstTime = str(datetime.utcnow().replace(tzinfo=utc).isoformat()) self.guid1 = str(uuid.uuid1()) def bunchostmts(self): self.guid2 = str(uuid.uuid1()) - self.guid3 = str(uuid.uuid1()) + self.guid3 = str(uuid.uuid1()) self.guid4 = str(uuid.uuid1()) self.guid5 = str(uuid.uuid1()) self.guid6 = str(uuid.uuid1()) self.guid7 = str(uuid.uuid1()) self.guid8 = str(uuid.uuid1()) - self.guid9 = str(uuid.uuid1()) + self.guid9 = str(uuid.uuid1()) self.guid10 = str(uuid.uuid1()) self.cguid1 = str(uuid.uuid1()) - self.cguid2 = str(uuid.uuid1()) + self.cguid2 = str(uuid.uuid1()) self.cguid3 = str(uuid.uuid1()) self.cguid4 = str(uuid.uuid1()) self.cguid5 = str(uuid.uuid1()) @@ -60,234 +62,237 @@ def bunchostmts(self): self.cguid7 = str(uuid.uuid1()) self.cguid8 = str(uuid.uuid1()) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}, "object": {"id":"act:activity"}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "authority":{"objectType":"Agent","name":"tester1","mbox":"mailto:test1@tester.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "object": {"id": "act:activity"}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "authority": {"objectType": "Agent", "name": "tester1", "mbox": "mailto:test1@tester.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) stmt_id = json.loads(response.content)[0] self.existStmt = Statement.objects.get(statement_id=stmt_id) self.exist_stmt_id = self.existStmt.statement_id - self.existStmt1 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": self.cguid1, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}}) - - self.existStmt2 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@t.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname3", "en-GB": "altname"}, - "description": {"en-US":"testdesc3","en-GB":"altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key11": "value11", "ext:key22": "value22","ext:key33": "value33"}}}, - "result": {"score":{"scaled":.75}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid2, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey11": "cval11", - "ext:ckey22": "cval22"}}}) - - self.existStmt3 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogals", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key111": "value111", "ext:key222": "value222","ext:key333": "value333"}}}, - "result": {"score":{"scaled":.79}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid3, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US", - "instructor":{"objectType": "Agent", "name":"bob", "mbox":"mailto:bob@bob.com"}, - "extensions":{"ext:ckey111": "cval111","ext:ckey222": "cval222"}}}) - - self.existStmt4 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogal", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key111": "value111", "ext:key222": "value222","ext:key333": "value333"}}}, - "result": {"score":{"scaled":.79}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"registration": self.cguid4, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "platform":"bard","language": "en-US","instructor":{"name":"bill", "mbox":"mailto:bill@bill.com"}, - "extensions":{"ext:ckey111": "cval111","ext:ckey222": "cval222"}}}) - - self.existStmt5 = json.dumps({"object":{"objectType":"Agent","name":"jon","mbox":"mailto:jon@jon.com"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt6 = json.dumps({"actor": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "object":{"id": "act:test_activity"},"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}}}) - - self.existStmt7 = json.dumps({"object": {"objectType":"Agent","name":"max","mbox":"mailto:max@max.com"}, - "verb": {"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt8 = json.dumps({"object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}, - "verb": {"id": "http://example.com/verbs/missed","display": {"en-US":"missed"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}) - - self.existStmt9 = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:sub@sub.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:ss@ss.com"},"verb": {"id":"verb:verb/url/nested"}, - "object": {"objectType":"Activity", "id":"act:testex.com"}, "result":{"completion": True, "success": True, - "response": "kicked"}, "context":{"registration": self.cguid6, - "contextActivities": {"other": {"id": "act:NewActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:k1": "v1", "ext:k2": "v2"}}}}) - - self.existStmt10 = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:ref@ref.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"StatementRef", - "id":str(self.exist_stmt_id)}}) + self.existStmt1 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": self.cguid1, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}}) + + self.existStmt2 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@t.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname3", "en-GB": "altname"}, + "description": {"en-US": "testdesc3", "en-GB": "altdesc"}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key11": "value11", "ext:key22": "value22", "ext:key33": "value33"}}}, + "result": {"score": {"scaled": .75}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid2, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey11": "cval11", + "ext:ckey22": "cval22"}}}) + + self.existStmt3 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogals", + "definition": {"name": {"en-US": "testname3"}, + "description": {"en-US": "testdesc3"}, + "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key111": "value111", "ext:key222": "value222", + "ext:key333": "value333"}}}, + "result": {"score": {"scaled": .79}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid3, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", + "instructor": {"objectType": "Agent", "name": "bob", "mbox": "mailto:bob@bob.com"}, + "extensions": {"ext:ckey111": "cval111", "ext:ckey222": "cval222"}}}) + + self.existStmt4 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogal", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, + "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key111": "value111", "ext:key222": "value222", "ext:key333": "value333"}}}, + "result": {"score": {"scaled": .79}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"registration": self.cguid4, "contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "platform": "bard", "language": "en-US", "instructor": {"name": "bill", "mbox": "mailto:bill@bill.com"}, + "extensions": {"ext:ckey111": "cval111", "ext:ckey222": "cval222"}}}) + + self.existStmt5 = json.dumps({"object": {"objectType": "Agent", "name": "jon", "mbox": "mailto:jon@jon.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt6 = json.dumps({"actor": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "object": {"id": "act:test_activity"}, "verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}}) + + self.existStmt7 = json.dumps({"object": {"objectType": "Agent", "name": "max", "mbox": "mailto:max@max.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt8 = json.dumps({"object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}, + "verb": {"id": "http://example.com/verbs/missed", "display": {"en-US": "missed"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}) + + self.existStmt9 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:sub@sub.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, + "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:ss@ss.com"}, + "verb": {"id": "verb:verb/url/nested"}, + "object": {"objectType": "Activity", "id": "act:testex.com"}, + "result": {"completion": True, "success": True, + "response": "kicked"}, + "context": {"registration": self.cguid6, + "contextActivities": {"other": {"id": "act:NewActivityID"}}, + "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:k1": "v1", "ext:k2": "v2"}}}}) + + self.existStmt10 = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:ref@ref.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, + "object": {"objectType": "StatementRef", "id": str(self.exist_stmt_id)}}) # Put statements - param = {"statementId":self.guid1} + param = {"statementId": self.guid1} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt1 self.putresponse1 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse1.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=2)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid1).update(stored=time) - - param = {"statementId":self.guid3} + param = {"statementId": self.guid3} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt3 self.putresponse3 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse3.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=3)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid3).update(stored=time) - - param = {"statementId":self.guid4} + param = {"statementId": self.guid4} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt4 self.putresponse4 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse4.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=4)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid4).update(stored=time) - self.secondTime = str((datetime.utcnow()+timedelta(seconds=4)).replace(tzinfo=utc).isoformat()) - - param = {"statementId":self.guid2} + self.secondTime = str((datetime.utcnow() + timedelta(seconds=4)).replace(tzinfo=utc).isoformat()) + + param = {"statementId": self.guid2} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt2 - self.putresponse2 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.putresponse2 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse2.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=6)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=6)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid2).update(stored=time) - - param = {"statementId":self.guid5} + param = {"statementId": self.guid5} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt5 self.putresponse5 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse5.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=7)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid5).update(stored=time) - - param = {"statementId":self.guid6} + param = {"statementId": self.guid6} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt_payload = self.existStmt6 self.putresponse6 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse6.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=8)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid6).update(stored=time) - - param = {"statementId":self.guid7} + param = {"statementId": self.guid7} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt7 - self.putresponse7 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmt_payload = self.existStmt7 + self.putresponse7 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse7.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=9)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid7).update(stored=time) - - param = {"statementId":self.guid8} + param = {"statementId": self.guid8} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt8 + stmt_payload = self.existStmt8 self.putresponse8 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse8.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=10)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid8).update(stored=time) - + param = {"statementId": self.guid9} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt9 + stmt_payload = self.existStmt9 self.putresponse9 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse9.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid9).update(stored=time) param = {"statementId": self.guid10} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt_payload = self.existStmt10 + stmt_payload = self.existStmt10 self.putresponse10 = self.client.put(path, stmt_payload, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(self.putresponse10.status_code, 204) - time = retrieve_statement.convert_to_utc(str((datetime.utcnow()+timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) + time = retrieve_statement.convert_to_utc(str((datetime.utcnow() + timedelta(seconds=11)).replace(tzinfo=utc).isoformat())) stmt = Statement.objects.filter(statement_id=self.guid10).update(stored=time) def test_invalid_result_fields(self): - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogie"}, - "result": {"bad":"fields","foo":"bar","score":{"scaled":.85}, "completion": True, "success": True, - "response": "kicked","duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", - "ext:key2":"value2"}}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogie"}, + "result": {"bad": "fields", "foo": "bar", "score": {"scaled": .85}, "completion": True, "success": True, + "response": "kicked", "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", + "ext:key2": "value2"}}}) resp = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid field(s) found in Result - bad, foo') - def test_invalid_context_fields(self): - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogals", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answers"], - "extensions": {"ext:key111": "value111", "ext:key222": "value222","ext:key333": "value333"}}}, - "result": {"score":{"scaled":.79}, "completion": True, "success": True, "response": "shouted", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:dkey1": "dvalue1", "ext:dkey2":"dvalue2"}}, - "context":{"contextActivities": {"other": {"id": "act:NewActivityID22"}}, - "revision": "food", "bad":"foo","platform":"bard","language": "en-US", - "instructor":{"objectType": "Agent", "name":"bob", "mbox":"mailto:bob@bob.com"}, - "extensions":{"ext:ckey111": "cval111","ext:ckey222": "cval222"}}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogals", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answers"], + "extensions": {"ext:key111": "value111", "ext:key222": "value222", "ext:key333": "value333"}}}, + "result": {"score": {"scaled": .79}, "completion": True, "success": True, "response": "shouted", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:dkey1": "dvalue1", "ext:dkey2": "dvalue2"}}, + "context": {"contextActivities": {"other": {"id": "act:NewActivityID22"}}, + "revision": "food", "bad": "foo", "platform": "bard", "language": "en-US", + "instructor": {"objectType": "Agent", "name": "bob", "mbox": "mailto:bob@bob.com"}, + "extensions": {"ext:ckey111": "cval111", "ext:ckey222": "cval222"}}}) resp = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, 'Invalid field(s) found in Context - bad') - def test_post_with_no_valid_params(self): # Error will be thrown in statements class - resp = self.client.post(reverse(statements), {"feet":"yes","hands": {"id":"http://example.com/test_post"}}, - content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + resp = self.client.post(reverse(statements), {"feet": "yes", "hands": {"id": "http://example.com/test_post"}}, + content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp.status_code, 400) def test_post(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) act = Activity.objects.get(activity_id="act:test_post") self.assertEqual(act.activity_id, "act:test_post") @@ -295,115 +300,115 @@ def test_post(self): self.assertEqual(agent.name, "bob") def test_post_wrong_crp_type(self): - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/created"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": "wrong"}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/created"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": "wrong"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Activity definition correctResponsesPattern is not a properly formatted array') def test_post_wrong_choice_type(self): stmt = json.dumps( - {"verb":{"id": "http://example.com/verbs/created"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, - "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "choice","correctResponsesPattern": ["a1[,]a3[,]a6[,]a7"], - "choices":"wrong"}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}) + {"verb": {"id": "http://example.com/verbs/created"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, + "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "choice", "correctResponsesPattern": ["a1[,]a3[,]a6[,]a7"], + "choices": "wrong"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Activity definition choices is not a properly formatted array') def test_openid(self): - stmt = json.dumps({'object':{'objectType':'Agent', 'name': 'lulu', 'openid':'id:luluid'}, - 'verb': {"id":"verb:verb/url"},'actor':{'objectType':'Agent','mbox':'mailto:t@t.com'}}) + stmt = json.dumps({'object': {'objectType': 'Agent', 'name': 'lulu', 'openid': 'id:luluid'}, + 'verb': {"id": "verb:verb/url"}, 'actor': {'objectType': 'Agent', 'mbox': 'mailto:t@t.com'}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) agent = Agent.objects.get(name='lulu') self.assertEqual(agent.openid, 'id:luluid') def test_invalid_actor_fields(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob", "bad": "blah", - "foo":"bar"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob", "bad": "blah", + "foo": "bar"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Invalid field(s) found in Agent/Group - bad, foo') def test_invalid_activity_fields(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post", "bad":"foo", "foo":"bar"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post", "bad": "foo", "foo": "bar"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Invalid field(s) found in Activity - bad, foo") def test_invalid_activity_def_fields(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:t@t.com", "name":"bob"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {'objectType': 'Activity', 'id':'act:food', - 'definition': {'bad':'foo','name': {'en-FR':'testname2','en-US': 'testnameEN'},'description': {'en-CH':'testdesc2', - 'en-GB': 'testdescGB'},'type': 'type:course','interactionType': 'intType2', 'extensions': {'ext:key1': 'value1', - 'ext:key2': 'value2','ext:key3': 'value3'}}}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:t@t.com", "name": "bob"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {'objectType': 'Activity', 'id': 'act:food', + 'definition': {'bad': 'foo', 'name': {'en-FR': 'testname2', 'en-US': 'testnameEN'}, 'description': {'en-CH': 'testdesc2', + 'en-GB': 'testdescGB'}, 'type': 'type:course', 'interactionType': 'intType2', 'extensions': {'ext:key1': 'value1', + 'ext:key2': 'value2', 'ext:key3': 'value3'}}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Invalid field(s) found in Activity definition - bad') def test_post_wrong_duration(self): - stmt = json.dumps({"actor":{'name':'jon', - 'mbox':'mailto:jon@example.com'},'verb': {"id":"verb:verb/url"},"object": {'id':'act:activity13'}, - "result": {'completion': True, 'success': True, 'response': 'yes', 'duration': 'wrongduration', - 'extensions':{'ext:key1': 'value1', 'ext:key2':'value2'}}}) + stmt = json.dumps({"actor": {'name': 'jon', + 'mbox': 'mailto:jon@example.com'}, 'verb': {"id": "verb:verb/url"}, "object": {'id': 'act:activity13'}, + "result": {'completion': True, 'success': True, 'response': 'yes', 'duration': 'wrongduration', + 'extensions': {'ext:key1': 'value1', 'ext:key2': 'value2'}}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Error with result duration - Unable to parse duration string u'wrongduration'") def test_post_stmt_ref_no_existing_stmt(self): - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:ref@ref.com"}, - "verb":{"id": "http://example.com/verbs/missed"},"object":{"objectType":"StatementRef", - "id":"12345678-1234-5678-1234-567812345678"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:ref@ref.com"}, + "verb": {"id": "http://example.com/verbs/missed"}, "object": {"objectType": "StatementRef", + "id": "12345678-1234-5678-1234-567812345678"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) def test_post_with_actor(self): - stmt = json.dumps({"actor":{"mbox":"mailto:mr.t@example.com"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:i.pity.the.fool"}}) - + stmt = json.dumps({"actor": {"mbox": "mailto:mr.t@example.com"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:i.pity.the.fool"}}) + response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) Agent.objects.get(mbox="mailto:mr.t@example.com") def test_list_post(self): - stmts = json.dumps([{"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_list_post"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/failed","display": {"en-GB":"failed"}}, - "object": {"id":"act:test_list_post1"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_list_post"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/failed", "display": {"en-GB": "failed"}}, + "object": {"id": "act:test_list_post1"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) activity1 = Activity.objects.get(activity_id="act:test_list_post") activity2 = Activity.objects.get(activity_id="act:test_list_post1") @@ -417,7 +422,7 @@ def test_list_post(self): self.assertEqual(response.status_code, 200) self.assertEqual(stmt1.verb.verb_id, "http://example.com/verbs/passed") self.assertEqual(stmt2.verb.verb_id, "http://example.com/verbs/failed") - + self.assertEqual(lang_map1.keys()[0], "en-US") self.assertEqual(lang_map1.values()[0], "passed") self.assertEqual(lang_map2.keys()[0], "en-GB") @@ -426,10 +431,10 @@ def test_list_post(self): def test_put(self): guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 204) @@ -441,17 +446,17 @@ def test_put(self): self.assertEqual(stmt.actor.mbox, "mailto:t@t.com") self.assertEqual(stmt.authority.name, "tester1") self.assertEqual(stmt.authority.mbox, "mailto:test1@tester.com") - + self.assertEqual(stmt.version, settings.XAPI_VERSION) self.assertEqual(stmt.verb.verb_id, "http://example.com/verbs/passed") def test_put_1_0_0(self): guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0.0") self.assertEqual(putResponse.status_code, 204) @@ -463,15 +468,15 @@ def test_put_1_0_0(self): self.assertEqual(stmt.actor.mbox, "mailto:t@t.com") self.assertEqual(stmt.authority.name, "tester1") self.assertEqual(stmt.authority.mbox, "mailto:test1@tester.com") - + self.assertEqual(stmt.version, "1.0.0") self.assertEqual(stmt.verb.verb_id, "http://example.com/verbs/passed") def test_put_id_in_stmt(self): guid = str(uuid.uuid1()) - stmt = json.dumps({"id": guid, "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"id": guid, "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 400) @@ -479,10 +484,10 @@ def test_put_id_in_stmt(self): def test_put_id_in_both_same(self): guid = str(uuid.uuid1()) - param = {"statementId":guid} + param = {"statementId": guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"id": guid, "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"id": guid, "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 204) @@ -494,18 +499,18 @@ def test_put_id_in_both_same(self): self.assertEqual(stmt.actor.mbox, "mailto:t@t.com") self.assertEqual(stmt.authority.name, "tester1") self.assertEqual(stmt.authority.mbox, "mailto:test1@tester.com") - + self.assertEqual(stmt.version, settings.XAPI_VERSION) self.assertEqual(stmt.verb.verb_id, "http://example.com/verbs/passed") def test_put_id_in_both_different(self): guid1 = str(uuid.uuid1()) guid2 = str(uuid.uuid1()) - - param = {"statementId":guid1} + + param = {"statementId": guid1} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"id": guid2, "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + stmt = json.dumps({"id": guid2, "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putResponse.status_code, 400) @@ -517,32 +522,32 @@ def test_put_with_substatement(self): param = {"statementId": st_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:sass@sass.com"}, - "verb": {"id":"verb:verb/url/tested"}, "object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:ss@ss.com"},"verb": {"id":"verb:verb/url/nested"}, - "object": {"objectType":"Activity", "id":"act:testex.com"}, "result":{"completion": True, "success": True, - "response": "kicked"}, "context":{"registration": con_guid, - "contextActivities": {"other": {"id": "act:NewActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:k1": "v1", "ext:k2": "v2"}}}}) - + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:sass@sass.com"}, + "verb": {"id": "verb:verb/url/tested"}, "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:ss@ss.com"}, "verb": {"id": "verb:verb/url/nested"}, + "object": {"objectType": "Activity", "id": "act:testex.com"}, "result": {"completion": True, "success": True, + "response": "kicked"}, "context": {"registration": con_guid, + "contextActivities": {"other": {"id": "act:NewActivityID"}}, "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:k1": "v1", "ext:k2": "v2"}}}}) + response = self.client.put(path, stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(get_response.status_code, 200) rsp = get_response.content - self.assertIn("objectType",rsp) + self.assertIn("objectType", rsp) self.assertIn("SubStatement", rsp) - self.assertIn("actor",rsp) - self.assertIn("ss@ss.com",rsp) - self.assertIn("verb",rsp) + self.assertIn("actor", rsp) + self.assertIn("ss@ss.com", rsp) + self.assertIn("verb", rsp) self.assertIn("verb:verb/url/nested", rsp) self.assertIn("Activity", rsp) self.assertIn("act:testex.com", rsp) self.assertIn("result", rsp) - self.assertIn("completion",rsp) + self.assertIn("completion", rsp) self.assertIn("success", rsp) self.assertIn("response", rsp) self.assertIn("kicked", rsp) @@ -560,13 +565,13 @@ def test_put_with_substatement(self): self.assertIn("ext:k1", rsp) self.assertIn("v1", rsp) self.assertIn("ext:k2", rsp) - self.assertIn("v2", rsp) + self.assertIn("v2", rsp) def test_no_content_put(self): guid = str(uuid.uuid1()) - - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) stmt = json.dumps({}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) @@ -575,33 +580,33 @@ def test_no_content_put(self): def test_existing_stmtID_put(self): guid = str(uuid.uuid1()) - exist_stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:activity"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":guid})) + exist_stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:activity"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": guid})) response = self.client.put(path, exist_stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 204) - param = {"statementId":guid} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object":{"id":"act:test_existing_put"}, "actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + param = {"statementId": guid} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_existing_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) putResponse = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - - self.assertEqual(putResponse.status_code, 409) - def test_missing_stmtID_put(self): - stmt = json.dumps({"verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_put"},"actor":{"objectType":"Agent", "mbox":"mailto:t@t.com"}}) + self.assertEqual(putResponse.status_code, 409) + + def test_missing_stmtID_put(self): + stmt = json.dumps({"verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_put"}, "actor": {"objectType": "Agent", "mbox": "mailto:t@t.com"}}) response = self.client.put(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn(response.content, "Error -- statements - method = PUT, but no statementId parameter or ID given in statement") def test_get(self): self.bunchostmts() - param = {"statementId":self.guid1} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": self.guid1} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) getResponse = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(getResponse.status_code, 200) rsp = getResponse.content @@ -611,7 +616,7 @@ def test_get(self): def test_get_no_params(self): self.bunchostmts() getResponse = self.client.get(reverse(statements), X_Experience_API_Version=settings.XAPI_VERSION, - Authorization=self.auth) + Authorization=self.auth) self.assertEqual(getResponse.status_code, 200) self.assertIn('content-length', getResponse._headers) @@ -620,16 +625,16 @@ def test_get_no_params(self): def test_head(self): self.bunchostmts() - param = {"statementId":self.guid1} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": self.guid1} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) head_resp = self.client.head(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(head_resp.status_code, 200) self.assertEqual(head_resp.content, '') self.assertIn('content-length', head_resp._headers) def test_get_no_existing_ID(self): - param = {"statementId":"aaaaaa"} - path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) + param = {"statementId": "aaaaaa"} + path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) getResponse = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) self.assertEqual(getResponse.status_code, 404) @@ -688,12 +693,12 @@ def test_timeout_snafu(self): "objectType": "Agent" }, "id": "9cb78e42-45ec-11e3-b8dc-0af904863508" - }) + }) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 200) stmt = json.dumps({ "timestamp": "2013-11-08T08:41:55.985064+00:00", @@ -747,12 +752,12 @@ def test_timeout_snafu(self): "name": "adllrs", "objectType": "Agent" } - }) + }) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_amsterdam_snafu(self): stmt = json.dumps({ @@ -779,23 +784,23 @@ def test_amsterdam_snafu(self): } }) post_response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post_response.status_code, 200) def test_update_activity_wrong_auth(self): - existStmt1 = json.dumps({"verb":{"id": "http://example.com/verbs/created", - "display": {"en-US":"created"}},"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"},"description": {"en-US":"testdesc2", "en-GB": "altdesc"}, - "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": str(uuid.uuid1()), "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}}) - param = {"statementId":self.guid1} + existStmt1 = json.dumps({"verb": {"id": "http://example.com/verbs/created", + "display": {"en-US": "created"}}, "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": str(uuid.uuid1()), "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}}) + param = {"statementId": self.guid1} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) putresponse1 = self.client.put(path, existStmt1, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(putresponse1.status_code, 204) @@ -804,24 +809,24 @@ def test_update_activity_wrong_auth(self): wrong_email = "test2@tester.com" wrong_password = "test2" wrong_auth = "Basic %s" % base64.b64encode("%s:%s" % (wrong_username, wrong_password)) - form = {"username":wrong_username, "email":wrong_email,"password":wrong_password, - "password2":wrong_password} - self.client.post(reverse(register),form, X_Experience_API_Version=settings.XAPI_VERSION) - - stmt = json.dumps({"verb":{"id":"verb:verb/iri/attempted"},"actor":{"objectType":"Agent", "mbox":"mailto:r@r.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, - "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": str(uuid.uuid1()), "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}, "authority":{"objectType":"Agent","name":"auth","mbox":"mailto:auth@example.com"}}) + form = {"username": wrong_username, "email": wrong_email, "password": wrong_password, + "password2": wrong_password} + self.client.post(reverse(register), form, X_Experience_API_Version=settings.XAPI_VERSION) + + stmt = json.dumps({"verb": {"id": "verb:verb/iri/attempted"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": str(uuid.uuid1()), "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}, "authority": {"objectType": "Agent", "name": "auth", "mbox": "mailto:auth@example.com"}}) post_response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=wrong_auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=wrong_auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post_response.status_code, 200) acts = Activity.objects.filter(activity_id="act:foogie").count() @@ -829,19 +834,19 @@ def test_update_activity_wrong_auth(self): def test_update_activity_correct_auth(self): self.bunchostmts() - stmt = json.dumps({"verb": {"id":"verb:verb/url/changed-act"},"actor":{"objectType":"Agent", "mbox":"mailto:l@l.com"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname3"},"description": {"en-US":"testdesc3"}, - "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction","interactionType": "fill-in","correctResponsesPattern": ["answer"], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85}, "completion": True, "success": True, "response": "kicked", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:key1": "value1", "ext:key2":"value2"}}, - "context":{"registration": self.cguid8, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, - "revision": "food", "platform":"bard","language": "en-US", "extensions":{"ext:ckey1": "cval1", - "ext:ckey2": "cval2"}}, "authority":{"objectType":"Agent","name":"auth","mbox":"mailto:auth@example.com"}}) + stmt = json.dumps({"verb": {"id": "verb:verb/url/changed-act"}, "actor": {"objectType": "Agent", "mbox": "mailto:l@l.com"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname3"}, "description": {"en-US": "testdesc3"}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", "interactionType": "fill-in", "correctResponsesPattern": ["answer"], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85}, "completion": True, "success": True, "response": "kicked", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:key1": "value1", "ext:key2": "value2"}}, + "context": {"registration": self.cguid8, "contextActivities": {"other": {"id": "act:NewActivityID2"}}, + "revision": "food", "platform": "bard", "language": "en-US", "extensions": {"ext:ckey1": "cval1", + "ext:ckey2": "cval2"}}, "authority": {"objectType": "Agent", "name": "auth", "mbox": "mailto:auth@example.com"}}) post_response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(post_response.status_code, 200) act = Activity.objects.get(activity_id="act:foogie") @@ -860,11 +865,12 @@ def test_update_activity_correct_auth(self): self.assertEqual(desc_set.values()[0], "altdesc") def test_cors_post_put(self): - content = {"verb":{"id":"verb:verb/url"}, "actor":{"objectType":"Agent", "mbox": "mailto:r@r.com"}, - "object": {"id":"act:test_cors_post_put"}} - - bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5d&content=%s&Authorization=%s&Content-Type=application/json&X-Experience-API-Version=%s" % (content, self.auth, settings.XAPI_VERSION) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"method":"PUT"})) + content = {"verb": {"id": "verb:verb/url"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"id": "act:test_cors_post_put"}} + + bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5d&content=%s&Authorization=%s&Content-Type=application/json&X-Experience-API-Version=%s" % ( + content, self.auth, settings.XAPI_VERSION) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"method": "PUT"})) response = self.client.post(path, bdy, content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 204) @@ -876,11 +882,12 @@ def test_cors_post_put(self): self.assertEqual(agent.mbox, "mailto:test1@tester.com") def test_cors_post_put_1_0_0(self): - content = {"verb":{"id":"verb:verb/url"}, "actor":{"objectType":"Agent", "mbox": "mailto:r@r.com"}, - "object": {"id":"act:test_cors_post_put"}} - - bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5d&content=%s&Authorization=%s&Content-Type=application/json&X-Experience-API-Version=1.0.0" % (content, self.auth) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"method":"PUT"})) + content = {"verb": {"id": "verb:verb/url"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"id": "act:test_cors_post_put"}} + + bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5d&content=%s&Authorization=%s&Content-Type=application/json&X-Experience-API-Version=1.0.0" % ( + content, self.auth) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"method": "PUT"})) response = self.client.post(path, bdy, content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 204) @@ -892,42 +899,44 @@ def test_cors_post_put_1_0_0(self): self.assertEqual(agent.mbox, "mailto:test1@tester.com") def test_cors_post_put_wrong_version(self): - content = {"verb":{"id":"verb:verb/url"}, "actor":{"objectType":"Agent", "mbox": "mailto:r@r.com"}, - "object": {"id":"act:test_cors_post_put"}} - - bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5b&content=%s&Authorization=%s&X-Experience-API-Version=1.0.33&Content-Type=application/json" % (content, self.auth) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"method":"PUT"})) + content = {"verb": {"id": "verb:verb/url"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"id": "act:test_cors_post_put"}} + + bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5b&content=%s&Authorization=%s&X-Experience-API-Version=1.0.33&Content-Type=application/json" % ( + content, self.auth) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"method": "PUT"})) response = self.client.post(path, bdy, content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "X-Experience-API-Version is not supported") def test_cors_post_put_correct_version(self): - content = {"verb":{"id":"verb:verb/url"}, "actor":{"objectType":"Agent", "mbox": "mailto:r@r.com"}, - "object": {"id":"act:test_cors_post_put"}} - - bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5a&content=%s&Authorization=%s&X-Experience-API-Version=1.0.1&Content-Type=application/json" % (content, self.auth) - path = "%s?%s" % (reverse(statements), urllib.urlencode({"method":"PUT"})) + content = {"verb": {"id": "verb:verb/url"}, "actor": {"objectType": "Agent", "mbox": "mailto:r@r.com"}, + "object": {"id": "act:test_cors_post_put"}} + + bdy = "statementId=886313e1-3b8a-5372-9b90-0c9aee199e5a&content=%s&Authorization=%s&X-Experience-API-Version=1.0.1&Content-Type=application/json" % ( + content, self.auth) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"method": "PUT"})) response = self.client.post(path, bdy, content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 204) def test_issue_put(self): - stmt_id = "33f60b35-e1b2-4ddc-9c6f-7b3f65244430" - stmt = json.dumps({"verb":{"id":"verb:verb/iri"},"object":{"id":"act:scorm.com/JsTetris_TCAPI","definition":{"type":"type:media", - "name":{"en-US":"Js Tetris - Tin Can Prototype"},"description":{"en-US":"A game of tetris."}}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"6b1091be-2833-4886-b4a6-59e5e0b3c3f4"}, - "actor":{"mbox":"mailto:tom.creighton.ctr@adlnet.gov","name":"Tom Creighton"}}) - - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt_id = "33f60b35-e1b2-4ddc-9c6f-7b3f65244430" + stmt = json.dumps({"verb": {"id": "verb:verb/iri"}, "object": {"id": "act:scorm.com/JsTetris_TCAPI", "definition": {"type": "type:media", + "name": {"en-US": "Js Tetris - Tin Can Prototype"}, "description": {"en-US": "A game of tetris."}}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "6b1091be-2833-4886-b4a6-59e5e0b3c3f4"}, + "actor": {"mbox": "mailto:tom.creighton.ctr@adlnet.gov", "name": "Tom Creighton"}}) + + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_stmt.status_code, 204) + self.assertEqual(put_stmt.status_code, 204) def test_post_with_group(self): ot = "Group" name = "the group ST" mbox = "mailto:the.groupST@example.com" - stmt = json.dumps({"actor":{"objectType":ot, "name":name, "mbox":mbox,"member":[{"name":"agentA","mbox":"mailto:agentA@example.com"}, {"name":"agentB","mbox":"mailto:agentB@example.com"}]},"verb":{"id": "http://verb/iri/created", "display":{"en-US":"created"}}, - "object": {"id":"act:i.pity.the.fool"}}) + stmt = json.dumps({"actor": {"objectType": ot, "name": name, "mbox": mbox, "member": [{"name": "agentA", "mbox": "mailto:agentA@example.com"}, {"name": "agentB", "mbox": "mailto:agentB@example.com"}]}, "verb": {"id": "http://verb/iri/created", "display": {"en-US": "created"}}, + "object": {"id": "act:i.pity.the.fool"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) g = Agent.objects.get(mbox="mailto:the.groupST@example.com") @@ -942,8 +951,8 @@ def test_post_with_group_no_members_listed(self): ot = "Group" name = "the group ML" mbox = "mailto:the.groupML@example.com" - stmt = json.dumps({"actor":{"objectType":ot, "name":name, "mbox":mbox},"verb":{"id": "http://verb/iri/created", "display":{"en-US":"created"}}, - "object": {"id":"act:i.pity.the.fool"}}) + stmt = json.dumps({"actor": {"objectType": ot, "name": name, "mbox": mbox}, "verb": {"id": "http://verb/iri/created", "display": {"en-US": "created"}}, + "object": {"id": "act:i.pity.the.fool"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) g = Agent.objects.get(mbox="mailto:the.groupML@example.com") @@ -957,8 +966,8 @@ def test_post_with_group_member_not_array(self): name = "the group ST" mbox = "mailto:the.groupST@example.com" members = "wrong" - stmt = json.dumps({"actor":{"objectType":ot, "name":name, "mbox":mbox,"member":members},"verb":{"id": "http://verb/iri/created", "display":{"en-US":"created"}}, - "object": {"id":"act:i.pity.the.fool"}}) + stmt = json.dumps({"actor": {"objectType": ot, "name": name, "mbox": mbox, "member": members}, "verb": {"id": "http://verb/iri/created", "display": {"en-US": "created"}}, + "object": {"id": "act:i.pity.the.fool"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, 'Members is not a properly formatted array') @@ -968,65 +977,65 @@ def test_post_with_group_member_empty_array(self): name = "the group ST" mbox = "mailto:the.groupST@example.com" members = [] - stmt = json.dumps({"actor":{"objectType":ot, "name":name, "mbox":mbox,"member":members},"verb":{"id": "http://verb/iri/created", "display":{"en-US":"created"}}, - "object": {"id":"act:i.pity.the.fool"}}) + stmt = json.dumps({"actor": {"objectType": ot, "name": name, "mbox": mbox, "member": members}, "verb": {"id": "http://verb/iri/created", "display": {"en-US": "created"}}, + "object": {"id": "act:i.pity.the.fool"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, "Member property must contain agents") def test_issue_put_no_version_header(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244431' - stmt = json.dumps({"verb":"verb:completed","object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt = json.dumps({"verb": "verb:completed", "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth) self.assertEqual(put_stmt.status_code, 400) def test_issue_put_wrong_version_header(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244432' - stmt = json.dumps({"verb": {"id":"verb:completed"},"object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt = json.dumps({"verb": {"id": "verb:completed"}, "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="0.90") self.assertEqual(put_stmt.status_code, 400) def test_issue_put_wrong_version_header_again(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244432' - stmt = json.dumps({"verb":{"id":"verb:completed"},"object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt = json.dumps({"verb": {"id": "verb:completed"}, "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.0.") self.assertEqual(put_stmt.status_code, 400) def test_issue_put_wrong_version_header_1_1(self): stmt_id = '33f60b35-e1b2-4ddc-9c6f-7b3f65244432' - stmt = json.dumps({"verb":{"id":"verb:completed"},"object":{"id":"act:scorm.com/JsTetris_TCAPI/level2", - "definition":{"type":"media","name":{"en-US":"Js Tetris Level2"}, - "description":{"en-US":"Starting at 1, the higher the level, the harder the game."}}}, - "result":{"extensions":{"ext:time":104,"ext:apm":229,"ext:lines":5},"score":{"raw":9911,"min":0}}, - "context":{"contextActivities":{"grouping":{"id":"act:scorm.com/JsTetris_TCAPI"}}, - "registration":"b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, - "actor":{"name":"tom creighton","mbox":"mailto:tom@example.com"}}) - - path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId":stmt_id})) + stmt = json.dumps({"verb": {"id": "verb:completed"}, "object": {"id": "act:scorm.com/JsTetris_TCAPI/level2", + "definition": {"type": "media", "name": {"en-US": "Js Tetris Level2"}, + "description": {"en-US": "Starting at 1, the higher the level, the harder the game."}}}, + "result": {"extensions": {"ext:time": 104, "ext:apm": 229, "ext:lines": 5}, "score": {"raw": 9911, "min": 0}}, + "context": {"contextActivities": {"grouping": {"id": "act:scorm.com/JsTetris_TCAPI"}}, + "registration": "b7be7d9d-bfe2-4917-8ccd-41a0d18dd953"}, + "actor": {"name": "tom creighton", "mbox": "mailto:tom@example.com"}}) + + path = '%s?%s' % (reverse(statements), urllib.urlencode({"statementId": stmt_id})) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version="1.1.") self.assertEqual(put_stmt.status_code, 400) @@ -1034,46 +1043,46 @@ def test_issue_put_wrong_version_header_1_1(self): def test_all_fields_activity_as_object(self): self.bunchostmts() nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) + self.assertEqual(put_sub_stmt.status_code, 204) stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"uniqueName"}}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created", "en-GB":"made"}}, - "object": {"objectType": "Activity", "id":"http:adlnet.gov/my/Activity/URL", - "definition": {"name": {"en-US":"actName", "en-GB": "anotherActName"}, - "description": {"en-US":"This is my activity description.", "en-GB": "This is another activity description."}, - "type": "http://adlnet.gov/expapi/activities/cmi.interaction", - "moreInfo": "http://some/activity/url", - "interactionType": "choice", - "correctResponsesPattern": ["golf", "tetris"], - "choices":[{"id": "golf", "description": {"en-US":"Golf Example", "en-GB": "GOLF"}}, - {"id": "tetris","description":{"en-US": "Tetris Example", "en-GB": "TETRIS"}}, - {"id":"facebook", "description":{"en-US":"Facebook App", "en-GB": "FACEBOOK"}}, - {"id":"scrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], - "extensions": {"ext:key1": "value1", "ext:key2": "value2","ext:key3": "value3"}}}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": False, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}, - "grouping":{"id":"http://groupingID"} }, - "revision": "Spelling error in choices.", "platform":"Platform is web browser.","language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "uniqueName"}}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created", "en-GB": "made"}}, + "object": {"objectType": "Activity", "id": "http:adlnet.gov/my/Activity/URL", + "definition": {"name": {"en-US": "actName", "en-GB": "anotherActName"}, + "description": {"en-US": "This is my activity description.", "en-GB": "This is another activity description."}, + "type": "http://adlnet.gov/expapi/activities/cmi.interaction", + "moreInfo": "http://some/activity/url", + "interactionType": "choice", + "correctResponsesPattern": ["golf", "tetris"], + "choices": [{"id": "golf", "description": {"en-US": "Golf Example", "en-GB": "GOLF"}}, + {"id": "tetris", "description": {"en-US": "Tetris Example", "en-GB": "TETRIS"}}, + {"id": "facebook", "description": {"en-US": "Facebook App", "en-GB": "FACEBOOK"}}, + {"id": "scrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], + "extensions": {"ext:key1": "value1", "ext:key2": "value2", "ext:key3": "value3"}}}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": False, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}, + "grouping": {"id": "http://groupingID"}}, + "revision": "Spelling error in choices.", "platform": "Platform is web browser.", "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['version'], settings.XAPI_VERSION) @@ -1144,39 +1153,38 @@ def test_all_fields_activity_as_object(self): self.assertIn('golf', crp_str) self.assertIn('tetris', crp_str) - # Use this test to make sure stmts are being returned correctly with all data - doesn't check timestamp, stored fields def test_all_fields_agent_as_object(self): nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincan@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincan@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) + self.assertEqual(put_sub_stmt.status_code, 204) stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - msha = hashlib.sha1("mailto:tom@example.com").hexdigest() - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"louUniqueName"}}, - "verb":{"id": "http://example.com/verbs/helped","display": {"en-US":"helped", "en-GB":"assisted"}}, - "object": {"objectType":"Agent","name": "Tom Creighton","mbox_sha1sum":msha}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": True, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, - "language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) - + msha = hashlib.sha1("mailto:tom@example.com").hexdigest() + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "louUniqueName"}}, + "verb": {"id": "http://example.com/verbs/helped", "display": {"en-US": "helped", "en-GB": "assisted"}}, + "object": {"objectType": "Agent", "name": "Tom Creighton", "mbox_sha1sum": msha}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": True, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, + "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) + put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['version'], settings.XAPI_VERSION) @@ -1212,74 +1220,71 @@ def test_all_fields_agent_as_object(self): self.assertEqual(the_returned['authority']['name'], 'tester1') self.assertEqual(the_returned['authority']['mbox'], 'mailto:test1@tester.com') - self.assertEqual(the_returned['object']['objectType'], 'Agent') self.assertEqual(the_returned['object']['name'], 'Tom Creighton') self.assertEqual(the_returned['object']['mbox_sha1sum'], msha) - # Use this test to make sure stmts are being returned correctly with all data - doesn't check timestamps or stored fields def test_all_fields_substatement_as_object(self): nested_st_id = str(uuid.uuid1()) - nest_param = {"statementId":nested_st_id} + nest_param = {"statementId": nested_st_id} nest_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_param)) - nested_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincannest@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed", "en-GB":"graded"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement"}}) + nested_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincannest@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed", "en-GB": "graded"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement"}}) put_sub_stmt = self.client.put(nest_path, nested_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - self.assertEqual(put_sub_stmt.status_code, 204) - + self.assertEqual(put_sub_stmt.status_code, 204) nested_sub_st_id = str(uuid.uuid1()) - nest_sub_param = {"statementId":nested_sub_st_id} - nest_sub_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_sub_param)) - nested_sub_stmt = json.dumps({"actor":{"objectType":"Agent","mbox": "mailto:tincannestsub@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/verb","display": {"en-US":"verb", "en-GB":"altVerb"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplenestedsubstatement"}}) - put_nest_sub_stmt = self.client.put(nest_sub_path, nested_sub_stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + nest_sub_param = {"statementId": nested_sub_st_id} + nest_sub_path = "%s?%s" % (reverse(statements), urllib.urlencode(nest_sub_param)) + nested_sub_stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:tincannestsub@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/verb", "display": {"en-US": "verb", "en-GB": "altVerb"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplenestedsubstatement"}}) + put_nest_sub_stmt = self.client.put(nest_sub_path, nested_sub_stmt, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_nest_sub_stmt.status_code, 204) - stmt_id = str(uuid.uuid1()) - context_id= str(uuid.uuid1()) - sub_context_id= str(uuid.uuid1()) - param = {"statementId":stmt_id} + context_id = str(uuid.uuid1()) + sub_context_id = str(uuid.uuid1()) + param = {"statementId": stmt_id} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) - - stmt = json.dumps({"actor":{"objectType":"Agent","name": "Lou Wolford","account":{"homePage":"http://example.com", "name":"louUniqueName"}}, - "verb":{"id": "http://example.com/verbs/said","display": {"en-US":"said", "en-GB":"talked"}}, - "object": {"objectType": "SubStatement", "actor":{"objectType":"Agent","name":"Tom Creighton","mbox": "mailto:tom@adlnet.gov"}, - "verb":{"id": "http://example.com/verbs/assess","display": {"en-US":"assessed", "en-GB": "Graded"}}, - "object":{"id":"http://example.adlnet.gov/tincan/example/simplestatement", - 'definition': {'name': {'en-US':'SubStatement name'}, - 'description': {'en-US':'SubStatement description'}, - 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction','interactionType': 'matching', - 'correctResponsesPattern': ['lou.3,tom.2,andy.1'],'source':[{'id': 'lou', - 'description': {'en-US':'Lou', 'it': 'Luigi'}},{'id': 'tom','description':{'en-US': 'Tom', 'it':'Tim'}}, - {'id':'andy', 'description':{'en-US':'Andy'}}],'target':[{'id':'1', - 'description':{'en-US': 'ADL LRS'}},{'id':'2','description':{'en-US': 'lrs'}}, - {'id':'3', 'description':{'en-US': 'the adl lrs', 'en-CH': 'the lrs'}}]}}, - "result": {"score":{"scaled":.50, "raw": 50, "min":1, "max":51}, "completion": True, - "success": True, "response": "Poorly done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey11": "resultValue11", "ext:resultKey22":"resultValue22"}}, - "context":{"registration": sub_context_id, - "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test/nest"}}, - "revision": "Spelling error in target.", "platform":"Ipad.","language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_sub_st_id)}, - "extensions":{"ext:contextKey11": "contextVal11","ext:contextKey22": "contextVal22"}}}, - "result": {"score":{"scaled":.85, "raw": 85, "min":0, "max":100}, "completion": True, "success": True, "response": "Well done", - "duration": "P3Y6M4DT12H30M5S", "extensions":{"ext:resultKey1": "resultValue1", "ext:resultKey2":"resultValue2"}}, - "context":{"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, - "language": "en-US", - "statement":{"objectType":"StatementRef", "id":str(nested_st_id)}, - "extensions":{"ext:contextKey1": "contextVal1","ext:contextKey2": "contextVal2"}}, - "timestamp":self.firstTime}) + + stmt = json.dumps({"actor": {"objectType": "Agent", "name": "Lou Wolford", "account": {"homePage": "http://example.com", "name": "louUniqueName"}}, + "verb": {"id": "http://example.com/verbs/said", "display": {"en-US": "said", "en-GB": "talked"}}, + "object": {"objectType": "SubStatement", "actor": {"objectType": "Agent", "name": "Tom Creighton", "mbox": "mailto:tom@adlnet.gov"}, + "verb": {"id": "http://example.com/verbs/assess", "display": {"en-US": "assessed", "en-GB": "Graded"}}, + "object": {"id": "http://example.adlnet.gov/tincan/example/simplestatement", + 'definition': {'name': {'en-US': 'SubStatement name'}, + 'description': {'en-US': 'SubStatement description'}, + 'type': 'http://adlnet.gov/expapi/activities/cmi.interaction', 'interactionType': 'matching', + 'correctResponsesPattern': ['lou.3,tom.2,andy.1'], 'source': [{'id': 'lou', + 'description': {'en-US': 'Lou', 'it': 'Luigi'}}, {'id': 'tom', 'description': {'en-US': 'Tom', 'it': 'Tim'}}, + {'id': 'andy', 'description': {'en-US': 'Andy'}}], 'target': [{'id': '1', + 'description': {'en-US': 'ADL LRS'}}, {'id': '2', 'description': {'en-US': 'lrs'}}, + {'id': '3', 'description': {'en-US': 'the adl lrs', 'en-CH': 'the lrs'}}]}}, + "result": {"score": {"scaled": .50, "raw": 50, "min": 1, "max": 51}, "completion": True, + "success": True, "response": "Poorly done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey11": "resultValue11", "ext:resultKey22": "resultValue22"}}, + "context": {"registration": sub_context_id, + "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test/nest"}}, + "revision": "Spelling error in target.", "platform": "Ipad.", "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_sub_st_id)}, + "extensions": {"ext:contextKey11": "contextVal11", "ext:contextKey22": "contextVal22"}}}, + "result": {"score": {"scaled": .85, "raw": 85, "min": 0, "max": 100}, "completion": True, "success": True, "response": "Well done", + "duration": "P3Y6M4DT12H30M5S", "extensions": {"ext:resultKey1": "resultValue1", "ext:resultKey2": "resultValue2"}}, + "context": {"registration": context_id, "contextActivities": {"other": {"id": "http://example.adlnet.gov/tincan/example/test"}}, + "language": "en-US", + "statement": {"objectType": "StatementRef", "id": str(nested_st_id)}, + "extensions": {"ext:contextKey1": "contextVal1", "ext:contextKey2": "contextVal2"}}, + "timestamp": self.firstTime}) put_stmt = self.client.put(path, stmt, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(put_stmt.status_code, 204) - param = {"statementId":stmt_id} + param = {"statementId": stmt_id} get_response = self.client.get(path, X_Experience_API_Version=settings.XAPI_VERSION, Authorization=self.auth) - + the_returned = json.loads(get_response.content) self.assertEqual(the_returned['id'], stmt_id) self.assertEqual(the_returned['version'], settings.XAPI_VERSION) @@ -1291,11 +1296,11 @@ def test_all_fields_substatement_as_object(self): self.assertEqual(the_returned['verb']['id'], 'http://example.com/verbs/said') self.assertEqual(the_returned['verb']['display']['en-GB'], 'talked') self.assertEqual(the_returned['verb']['display']['en-US'], 'said') - + self.assertEqual(the_returned['object']['actor']['objectType'], 'Agent') self.assertEqual(the_returned['object']['actor']['name'], 'Tom Creighton') self.assertEqual(the_returned['object']['actor']['mbox'], 'mailto:tom@adlnet.gov') - + self.assertEqual(the_returned['object']['context']['registration'], sub_context_id) self.assertEqual(the_returned['object']['context']['language'], 'en-US') self.assertEqual(the_returned['object']['context']['platform'], 'Ipad.') @@ -1334,7 +1339,7 @@ def test_all_fields_substatement_as_object(self): self.assertIn('the lrs', target_str) self.assertIn('the adl lrs', target_str) self.assertIn('3', target_str) - + self.assertEqual(the_returned['object']['objectType'], 'SubStatement') self.assertEqual(the_returned['object']['result']['completion'], True) @@ -1347,7 +1352,7 @@ def test_all_fields_substatement_as_object(self): self.assertEqual(the_returned['object']['result']['score']['raw'], 50) self.assertEqual(the_returned['object']['result']['score']['scaled'], 0.5) self.assertEqual(the_returned['object']['result']['success'], True) - + self.assertEqual(the_returned['object']['verb']['id'], 'http://example.com/verbs/assess') self.assertEqual(the_returned['object']['verb']['display']['en-GB'], 'Graded') self.assertEqual(the_returned['object']['verb']['display']['en-US'], 'assessed') @@ -1380,38 +1385,38 @@ def test_post_list_rollback(self): self.bunchostmts() cguid1 = str(uuid.uuid1()) stmts = json.dumps([ - {"verb":{"id": "http://example.com/verbs/wrong-failed","display": {"en-US":"wrong-failed"}}, - "object": {"id":"act:test_wrong_list_post2"},"actor":{"objectType":"Agent", - "mbox":"mailto:wrong-t@t.com"},"result": {"score":{"scaled":.99}, "completion": True, "success": True, - "response": "wrong","extensions":{"ext:resultwrongkey1": "value1", "ext:resultwrongkey2":"value2"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}}, - "object": {"objectType": "Activity", "id":"act:test_wrong_list_post", - "definition": {"name": {"en-US":"wrongactName", "en-GB": "anotherActName"}, - "description": {"en-US":"This is my activity description.", "en-GB": "This is another activity description."}, - "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "choice", - "correctResponsesPattern": ["wronggolf", "wrongtetris"], - "choices":[{"id": "wronggolf", "description": {"en-US":"Golf Example", "en-GB": "GOLF"}}, - {"id": "wrongtetris","description":{"en-US": "Tetris Example", "en-GB": "TETRIS"}}, - {"id":"wrongfacebook", "description":{"en-US":"Facebook App", "en-GB": "FACEBOOK"}}, - {"id":"wrongscrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], - "extensions": {"ext:wrongkey1": "wrongvalue1", "ext:wrongkey2": "wrongvalue2","ext:wrongkey3": "wrongvalue3"}}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/wrong-passed","display": {"en-US":"wrong-passed"}},"object": {"id":"act:test_wrong_list_post1"}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"},"context":{"registration": cguid1, "contextActivities": {"other": {"id": "act:wrongActivityID2"}}, - "revision": "wrong", "platform":"wrong","language": "en-US", "extensions":{"ext:wrongkey1": "wrongval1", - "ext:wrongkey2": "wrongval2"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}},"object": {"id":"act:test_wrong_list_post2"}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked","display": {"en-US":"wrong-kicked"}},"object": {"id":"act:test_wrong_list_post4"}, "actor":{"objectType":"Agent", "mbox":"wrong-t@t.com"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + {"verb": {"id": "http://example.com/verbs/wrong-failed", "display": {"en-US": "wrong-failed"}}, + "object": {"id": "act:test_wrong_list_post2"}, "actor": {"objectType": "Agent", + "mbox": "mailto:wrong-t@t.com"}, "result": {"score": {"scaled": .99}, "completion": True, "success": True, + "response": "wrong", "extensions": {"ext:resultwrongkey1": "value1", "ext:resultwrongkey2": "value2"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, + "object": {"objectType": "Activity", "id": "act:test_wrong_list_post", + "definition": {"name": {"en-US": "wrongactName", "en-GB": "anotherActName"}, + "description": {"en-US": "This is my activity description.", "en-GB": "This is another activity description."}, + "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "choice", + "correctResponsesPattern": ["wronggolf", "wrongtetris"], + "choices":[{"id": "wronggolf", "description": {"en-US": "Golf Example", "en-GB": "GOLF"}}, + {"id": "wrongtetris", "description": {"en-US": "Tetris Example", "en-GB": "TETRIS"}}, + {"id": "wrongfacebook", "description": {"en-US": "Facebook App", "en-GB": "FACEBOOK"}}, + {"id": "wrongscrabble", "description": {"en-US": "Scrabble Example", "en-GB": "SCRABBLE"}}], + "extensions": {"ext:wrongkey1": "wrongvalue1", "ext:wrongkey2": "wrongvalue2", "ext:wrongkey3": "wrongvalue3"}}}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/wrong-passed", "display": {"en-US": "wrong-passed"}}, "object": {"id": "act:test_wrong_list_post1"}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}, "context": {"registration": cguid1, "contextActivities": {"other": {"id": "act:wrongActivityID2"}}, + "revision": "wrong", "platform": "wrong", "language": "en-US", "extensions": {"ext:wrongkey1": "wrongval1", + "ext:wrongkey2": "wrongval2"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, "object": {"id": "act:test_wrong_list_post2"}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked", "display": {"en-US": "wrong-kicked"}}, "object": {"id": "act:test_wrong_list_post4"}, "actor": {"objectType": "Agent", "mbox": "wrong-t@t.com"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) - + verbs = Verb.objects.filter(verb_id__contains='wrong') - + activities = Activity.objects.filter(activity_id__contains='test_wrong_list_post') - + stmts = Statement.objects.all() # 11 statements from setup self.assertEqual(len(stmts), 11) @@ -1421,26 +1426,26 @@ def test_post_list_rollback(self): def test_post_list_rollback_part_2(self): self.bunchostmts() - stmts = json.dumps([{"object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}, - "verb": {"id": "http://example.com/verbs/wrong","display": {"en-US":"wrong"}}, - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}}, - {"verb":{"id": "http://example.com/verbs/created"}, - "object": {"objectType": "Activity", "id":"act:foogie", - "definition": {"name": {"en-US":"testname2", "en-GB": "altname"}, - "description": {"en-US":"testdesc2", "en-GB": "altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", - "interactionType": "fill-in","correctResponsesPattern": ["answer"]}}, - "actor":{"objectType":"Agent", "mbox":"mailto:wrong-t@t.com"}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}, + "verb": {"id": "http://example.com/verbs/wrong", "display": {"en-US": "wrong"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}}, + {"verb": {"id": "http://example.com/verbs/created"}, + "object": {"objectType": "Activity", "id": "act:foogie", + "definition": {"name": {"en-US": "testname2", "en-GB": "altname"}, + "description": {"en-US": "testdesc2", "en-GB": "altdesc"}, "type": "http://www.adlnet.gov/experienceapi/activity-types/http://adlnet.gov/expapi/activities/cmi.interaction", + "interactionType": "fill-in", "correctResponsesPattern": ["answer"]}}, + "actor":{"objectType": "Agent", "mbox": "mailto:wrong-t@t.com"}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) created_verbs = Verb.objects.filter(verb_id__contains='http://example.com/verbs/created') wrong_verbs = Verb.objects.filter(verb_id__contains='http://example.com/verbs/wrong') - + activities = Activity.objects.filter(activity_id='act:foogie') - + stmts = Statement.objects.all() wrong_agent = Agent.objects.filter(mbox='mailto:wrong-t@t.com') @@ -1452,7 +1457,7 @@ def test_post_list_rollback_part_2(self): self.assertEqual(len(wrong_verbs), 0) self.assertEqual(len(activities), 1) - + self.assertEqual(len(stmts), 11) self.assertEqual(len(wrong_agent), 0) @@ -1463,12 +1468,12 @@ def test_post_list_rollback_part_2(self): def test_post_list_rollback_with_void(self): self.bunchostmts() - stmts = json.dumps([{"actor":{"objectType":"Agent","mbox":"mailto:only-s@s.com"}, - "object": {"objectType":"StatementRef","id":str(self.exist_stmt_id)}, - "verb": {"id": "http://adlnet.gov/expapi/verbs/voided","display": {"en-US":"voided"}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) + stmts = json.dumps([{"actor": {"objectType": "Agent", "mbox": "mailto:only-s@s.com"}, + "object": {"objectType": "StatementRef", "id": str(self.exist_stmt_id)}, + "verb": {"id": "http://adlnet.gov/expapi/verbs/voided", "display": {"en-US": "voided"}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) voided_st = Statement.objects.get(statement_id=str(self.exist_stmt_id)) @@ -1484,25 +1489,25 @@ def test_post_list_rollback_with_void(self): def test_post_list_rollback_with_subs(self): self.bunchostmts() sub_context_id = str(uuid.uuid1()) - stmts = json.dumps([{"actor":{"objectType":"Agent","mbox":"mailto:wrong-s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong","display": {"en-US":"wrong"}}, - "object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}}, - {"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong-next","display": {"en-US":"wrong-next"}}, - "object":{"objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:wrong-ss@ss.com"},"verb": {"id":"http://example.com/verbs/wrong-sub"}, - "object": {"objectType":"Activity", "id":"act:wrong-testex.com"}, "result":{"completion": True, "success": True, - "response": "sub-wrong-kicked"}, "context":{"registration": sub_context_id, - "contextActivities": {"other": {"id": "act:sub-wrong-ActivityID"}},"revision": "foo", "platform":"bar", - "language": "en-US", "extensions":{"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}}}}, - {"verb":{"id": "http://example.com/verbs/wrong-kicked"},"object": {"id":"act:test_wrong_list_post2"}}]) - response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + stmts = json.dumps([{"actor": {"objectType": "Agent", "mbox": "mailto:wrong-s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong", "display": {"en-US": "wrong"}}, + "object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}}, + {"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong-next", "display": {"en-US": "wrong-next"}}, + "object": {"objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-ss@ss.com"}, "verb": {"id": "http://example.com/verbs/wrong-sub"}, + "object": {"objectType": "Activity", "id": "act:wrong-testex.com"}, "result": {"completion": True, "success": True, + "response": "sub-wrong-kicked"}, "context": {"registration": sub_context_id, + "contextActivities": {"other": {"id": "act:sub-wrong-ActivityID"}}, "revision": "foo", "platform": "bar", + "language": "en-US", "extensions": {"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}}}}, + {"verb": {"id": "http://example.com/verbs/wrong-kicked"}, "object": {"id": "act:test_wrong_list_post2"}}]) + response = self.client.post(reverse(statements), stmts, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) s_agent = Agent.objects.filter(mbox="mailto:wrong-s@s.com") ss_agent = Agent.objects.filter(mbox="mailto:wrong-ss@ss.com") - john_agent = Agent.objects.filter(mbox="mailto:john@john.com") + john_agent = Agent.objects.filter(mbox="mailto:john@john.com") subs = SubStatement.objects.all() wrong_verb = Verb.objects.filter(verb_id__contains="wrong") activities = Activity.objects.filter(activity_id__contains="wrong") @@ -1517,44 +1522,43 @@ def test_post_list_rollback_with_subs(self): self.assertEqual(len(wrong_verb), 0) self.assertEqual(len(activities), 0) - def test_post_list_rollback_context_activities(self): self.bunchostmts() sub_context_id = str(uuid.uuid1()) # Will throw error and need to rollback b/c last stmt is missing actor stmts = json.dumps([{ - "actor":{"objectType":"Agent","mbox":"mailto:wrong-s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong","display": {"en-US":"wrong"}}, - "object": {"objectType":"Agent","name":"john","mbox":"mailto:john@john.com"}}, + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong", "display": {"en-US": "wrong"}}, + "object": {"objectType": "Agent", "name": "john", "mbox": "mailto:john@john.com"}}, { - "actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb": {"id": "http://example.com/verbs/wrong-next","display": {"en-US":"wrong-next"}}, - "object":{ - "objectType":"SubStatement", - "actor":{"objectType":"Agent","mbox":"mailto:wrong-ss@ss.com"}, - "verb": {"id":"http://example.com/verbs/wrong-sub"}, - "object": {"objectType":"Activity", "id":"act:wrong-testex.com"}, - "result":{"completion": True, "success": True,"response": "sub-wrong-kicked"}, - "context":{ - "registration": sub_context_id, - "contextActivities": { - "other": [{"id": "act:subwrongActivityID"},{"id":"act:foogie"}]}, - "revision": "foo", "platform":"bar","language": "en-US", - "extensions":{"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}} - } - }, + "actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/wrong-next", "display": {"en-US": "wrong-next"}}, + "object": { + "objectType": "SubStatement", + "actor": {"objectType": "Agent", "mbox": "mailto:wrong-ss@ss.com"}, + "verb": {"id": "http://example.com/verbs/wrong-sub"}, + "object": {"objectType": "Activity", "id": "act:wrong-testex.com"}, + "result": {"completion": True, "success": True, "response": "sub-wrong-kicked"}, + "context": { + "registration": sub_context_id, + "contextActivities": { + "other": [{"id": "act:subwrongActivityID"}, {"id": "act:foogie"}]}, + "revision": "foo", "platform": "bar", "language": "en-US", + "extensions": {"ext:wrong-k1": "v1", "ext:wrong-k2": "v2"}} + } + }, { - "verb":{"id": "http://example.com/verbs/wrong-kicked"}, - "object": {"id":"act:test_wrong_list_post2"}}]) - - response = self.client.post(reverse(statements), stmts, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + "verb": {"id": "http://example.com/verbs/wrong-kicked"}, + "object": {"id": "act:test_wrong_list_post2"}}]) + + response = self.client.post(reverse(statements), stmts, content_type="application/json", + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('actor is missing in Statement', response.content) s_agent = Agent.objects.filter(mbox="mailto:wrong-s@s.com") ss_agent = Agent.objects.filter(mbox="mailto:wrong-ss@ss.com") - john_agent = Agent.objects.filter(mbox="mailto:john@john.com") + john_agent = Agent.objects.filter(mbox="mailto:john@john.com") subs = SubStatement.objects.all() wrong_verb = Verb.objects.filter(verb_id__contains="wrong") wrong_activities = Activity.objects.filter(activity_id__contains="wrong") @@ -1570,19 +1574,18 @@ def test_post_list_rollback_context_activities(self): self.assertEqual(len(wrong_verb), 0) self.assertEqual(len(wrong_activities), 0) self.assertEqual(len(foogie_activities), 1) - def test_unique_actor_authority(self): - stmt = json.dumps({"actor":{"objectType": "Agent", "mbox":"mailto:timmay@timmay.com", "name":"timmay"}, - "verb":{"id": "http://example.com/verbs/passed","display": {"en-US":"passed"}}, - "object": {"id":"act:test_post"}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:timmay@timmay.com", "name": "timmay"}, + "verb": {"id": "http://example.com/verbs/passed", "display": {"en-US": "passed"}}, + "object": {"id": "act:test_post"}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) response2 = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth2, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth2, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response2.status_code, 200) acts = Activity.objects.filter(activity_id='act:test_post').count() @@ -1592,40 +1595,40 @@ def test_stmts_w_same_regid(self): stmt1_guid = str(uuid.uuid1()) stmt2_guid = str(uuid.uuid1()) reg_guid = str(uuid.uuid1()) - stmt1 = json.dumps({"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http:adlnet.gov/expapi/verbs/tested", - "display":{"en-US":"tested"}}, - "object":{"id":"test:same.regid"}, - "context":{"registration":reg_guid} + stmt1 = json.dumps({"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http:adlnet.gov/expapi/verbs/tested", + "display": {"en-US": "tested"}}, + "object": {"id": "test:same.regid"}, + "context": {"registration": reg_guid} }) - stmt2 = json.dumps({"actor":{"mbox":"mailto:tom@example.com"}, - "verb":{"id":"http:adlnet.gov/expapi/verbs/tested", - "display":{"en-US":"tested"}}, - "object":{"id":"test:same.regid.again"}, - "context":{"registration":reg_guid} + stmt2 = json.dumps({"actor": {"mbox": "mailto:tom@example.com"}, + "verb": {"id": "http:adlnet.gov/expapi/verbs/tested", + "display": {"en-US": "tested"}}, + "object": {"id": "test:same.regid.again"}, + "context": {"registration": reg_guid} }) - param1 = {"statementId":stmt1_guid} + param1 = {"statementId": stmt1_guid} path1 = "%s?%s" % (reverse(statements), urllib.urlencode(param1)) stmt_payload1 = stmt1 resp1 = self.client.put(path1, stmt_payload1, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp1.status_code, 204) - param2 = {"statementId":stmt2_guid} + param2 = {"statementId": stmt2_guid} path2 = "%s?%s" % (reverse(statements), urllib.urlencode(param2)) stmt_payload2 = stmt2 resp2 = self.client.put(path2, stmt_payload2, content_type="application/json", Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(resp2.status_code, 204) @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') def test_void(self): stmt_guid = str(uuid.uuid1()) - stmt = {"actor":{"mbox":"mailto:tinytom@example.com"}, - "verb":{"id":"http://tommy.com/my-testverbs/danced", - "display":{"en-US":"danced"}}, - "object":{"id":"act:the-macarena"}} - param = {"statementId":stmt_guid} + stmt = {"actor": {"mbox": "mailto:tinytom@example.com"}, + "verb": {"id": "http://tommy.com/my-testverbs/danced", + "display": {"en-US": "danced"}}, + "object": {"id": "act:the-macarena"}} + param = {"statementId": stmt_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) payload = json.dumps(stmt) @@ -1644,11 +1647,11 @@ def test_void(self): self.assertEqual(obj['object']['id'], stmt['object']['id']) stmt2_guid = str(uuid.uuid1()) - stmt2 = {"actor":{"mbox":"mailto:louo@example.com"}, - "verb":{"id":"http://tommy.com/my-testverbs/laughed", - "display":{"en-US":"laughed at"}}, - "object":{"objectType":"StatementRef","id":stmt_guid}} - param = {"statementId":stmt2_guid} + stmt2 = {"actor": {"mbox": "mailto:louo@example.com"}, + "verb": {"id": "http://tommy.com/my-testverbs/laughed", + "display": {"en-US": "laughed at"}}, + "object": {"objectType": "StatementRef", "id": stmt_guid}} + param = {"statementId": stmt2_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(param)) payload2 = json.dumps(stmt2) @@ -1662,18 +1665,18 @@ def test_void(self): objs = obj['statements'] for o in objs: if o['id'] == stmt_guid: - self.assertEqual(o['actor']['mbox'],stmt['actor']['mbox']) + self.assertEqual(o['actor']['mbox'], stmt['actor']['mbox']) self.assertEqual(o['verb']['id'], stmt['verb']['id']) self.assertEqual(o['object']['id'], stmt['object']['id']) else: - self.assertEqual(o['actor']['mbox'],stmt2['actor']['mbox']) + self.assertEqual(o['actor']['mbox'], stmt2['actor']['mbox']) self.assertEqual(o['verb']['id'], stmt2['verb']['id']) self.assertEqual(o['object']['id'], stmt2['object']['id']) - stmtv = {"actor":{"mbox":"mailto:hulk@example.com"}, - "verb":{"id":"http://adlnet.gov/expapi/verbs/voided"}, - "object":{"objectType":"StatementRef", - "id":"%s" % stmt_guid}} + stmtv = {"actor": {"mbox": "mailto:hulk@example.com"}, + "verb": {"id": "http://adlnet.gov/expapi/verbs/voided"}, + "object": {"objectType": "StatementRef", + "id": "%s" % stmt_guid}} v_guid = str(uuid.uuid1()) paramv = {"statementId": v_guid} path = "%s?%s" % (reverse(statements), urllib.urlencode(paramv)) @@ -1689,16 +1692,16 @@ def test_void(self): objs = obj['statements'] for o in objs: if o['id'] == v_guid: - self.assertEqual(o['actor']['mbox'],stmtv['actor']['mbox']) + self.assertEqual(o['actor']['mbox'], stmtv['actor']['mbox']) self.assertEqual(o['verb']['id'], stmtv['verb']['id']) self.assertEqual(o['object']['id'], stmtv['object']['id']) else: - self.assertEqual(o['actor']['mbox'],stmt2['actor']['mbox']) + self.assertEqual(o['actor']['mbox'], stmt2['actor']['mbox']) self.assertEqual(o['verb']['id'], stmt2['verb']['id']) self.assertEqual(o['object']['id'], stmt2['object']['id']) # get voided statement via voidedStatementId - path = "%s?%s" % (reverse(statements), urllib.urlencode({"voidedStatementId":stmt_guid})) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"voidedStatementId": stmt_guid})) r = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 200) obj = json.loads(r.content) @@ -1708,18 +1711,18 @@ def test_void(self): self.assertEqual(obj['object']['id'], stmt['object']['id']) # make sure voided statement returns a 404 on get w/ statementId req - path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId":stmt_guid})) + path = "%s?%s" % (reverse(statements), urllib.urlencode({"statementId": stmt_guid})) r = self.client.get(path, Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(r.status_code, 404) - + def test_act_id_iri(self): act_id = "act:Flügel" - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "object": {"id":act_id}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "object": {"id": act_id}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) stmt_db = Statement.objects.get(statement_id=json.loads(response.content)[0]) act = Activity.objects.get(id=stmt_db.object_activity.id) @@ -1727,44 +1730,44 @@ def test_act_id_iri(self): def test_invalid_act_id_iri(self): act_id = "Flügel" - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "object": {"id":act_id}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "object": {"id": act_id}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 400) self.assertIn('not a valid IRI', response.content) def test_tag_act_id_uri(self): act_id = "tag:adlnet.gov,2013:expapi:0.9:activities" - stmt = json.dumps({"actor":{"objectType":"Agent","mbox":"mailto:s@s.com"}, - "verb":{"id": "http://example.com/verbs/created","display": {"en-US":"created"}}, - "object": {"id":act_id}}) + stmt = json.dumps({"actor": {"objectType": "Agent", "mbox": "mailto:s@s.com"}, + "verb": {"id": "http://example.com/verbs/created", "display": {"en-US": "created"}}, + "object": {"id": act_id}}) response = self.client.post(reverse(statements), stmt, content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) - + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + self.assertEqual(response.status_code, 200) stmt_db = Statement.objects.get(statement_id=json.loads(response.content)[0]) act = Activity.objects.get(id=stmt_db.object_activity.id) self.assertEqual(act.activity_id, act_id) @override_settings(CELERY_ALWAYS_EAGER=True, - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner') + TEST_RUNNER='djcelery.contrib.test_runner.CeleryTestSuiteRunner') def test_large_batch(self): import random post_payload = [] - acts = ["http://tom.com/act/1/foo", "http://adlnet.gov/act/arrgs/2", "http://google.com/activity/eats/ants", "http://tom.com/act/3/boo"]; - ctxs = ["http://ctx.com/one", "http://ctx.com/two"]; + acts = ["http://tom.com/act/1/foo", "http://adlnet.gov/act/arrgs/2", "http://google.com/activity/eats/ants", "http://tom.com/act/3/boo"] + ctxs = ["http://ctx.com/one", "http://ctx.com/two"] for x in range(1, 500): - s = {"verb":{"id": "http://example.com/verbs/passed"},"object": {"id":""}, "actor":{"mbox":"mailto:t@t.com"}, - "context": {"contextActivities": {"grouping": [{"id": ""}]}}} + s = {"verb": {"id": "http://example.com/verbs/passed"}, "object": {"id": ""}, "actor": {"mbox": "mailto:t@t.com"}, + "context": {"contextActivities": {"grouping": [{"id": ""}]}}} - s['object']['id'] = acts[random.randrange(0, len(acts)-1)] - s['context']['contextActivities']['grouping'][0]['id'] = ctxs[random.randrange(0, len(ctxs)-1)] + s['object']['id'] = acts[random.randrange(0, len(acts) - 1)] + s['context']['contextActivities']['grouping'][0]['id'] = ctxs[random.randrange(0, len(ctxs) - 1)] post_payload.append(s) response = self.client.post(reverse(statements), json.dumps(post_payload), content_type="application/json", - Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) + Authorization=self.auth, X_Experience_API_Version=settings.XAPI_VERSION) self.assertEqual(response.status_code, 200) diff --git a/lrs/urls.py b/lrs/urls.py index 034954cd..a1394f67 100644 --- a/lrs/urls.py +++ b/lrs/urls.py @@ -2,15 +2,15 @@ from django.views.generic import RedirectView urlpatterns = patterns('lrs.views', - url(r'^$', RedirectView.as_view(url='/')), - url(r'^statements/more/(?P.{32})$', 'statements_more'), - url(r'^statements/more', 'statements_more_placeholder'), - url(r'^statements', 'statements'), - url(r'^activities/state', 'activity_state'), - url(r'^activities/profile', 'activity_profile'), - url(r'^activities', 'activities'), - url(r'^agents/profile', 'agent_profile'), - url(r'^agents', 'agents'), - url(r'^about', 'about'), - url(r'^OAuth/', include('oauth_provider.urls', namespace='oauth')), -) \ No newline at end of file + url(r'^$', RedirectView.as_view(url='/')), + url(r'^statements/more/(?P.{32})$', 'statements_more'), + url(r'^statements/more', 'statements_more_placeholder'), + url(r'^statements', 'statements'), + url(r'^activities/state', 'activity_state'), + url(r'^activities/profile', 'activity_profile'), + url(r'^activities', 'activities'), + url(r'^agents/profile', 'agent_profile'), + url(r'^agents', 'agents'), + url(r'^about', 'about'), + url(r'^OAuth/', include('oauth_provider.urls', namespace='oauth')), + ) diff --git a/lrs/utils/StatementValidator.py b/lrs/utils/StatementValidator.py index aeefcac4..8b37da1f 100644 --- a/lrs/utils/StatementValidator.py +++ b/lrs/utils/StatementValidator.py @@ -14,7 +14,7 @@ attachment_required_fields = ['usageType', 'display', 'contentType', 'length'] agent_ifis_can_only_be_one = ['mbox', 'mbox_sha1sum', 'openid', 'account'] -agent_allowed_fields = ['objectType', 'name', 'member', 'mbox', 'mbox_sha1sum', 'openid','account'] +agent_allowed_fields = ['objectType', 'name', 'member', 'mbox', 'mbox_sha1sum', 'openid', 'account'] account_fields = ['homePage', 'name'] @@ -37,679 +37,681 @@ context_allowed_fields = ['registration', 'instructor', 'team', 'contextActivities', 'revision', 'platform', 'language', 'statement', 'extensions'] + class StatementValidator(): - def __init__(self, data=None): - # If incoming is a string, ast eval it (exception will be caught with whatever is calling validator) - if data: - try: - self.data = convert_to_datatype(data) - except Exception, e: - self.return_error(e.message) - - def validate(self): - # If list, validate each stmt inside - if isinstance(self.data, list): - for st in self.data: - self.validate_statement(st) - return "All Statements are valid" - else: - self.validate_statement(self.data) - return "Statement is valid" - - def return_error(self, err_msg): - raise ParamError(err_msg) - - def validate_email(self, email): - if isinstance(email, basestring): - if email.startswith("mailto:"): - email_re = re.compile("[^@]+@[^@]+\.[^@]+") - if not email_re.match(email[7:]): - self.return_error("mbox value %s is not a valid email" % email) - else: - self.return_error("mbox value %s did not start with mailto:" % email) - else: - self.return_error("mbox value must be a string type") - - def validate_lang_tag(self, tag, field): - if tag: - lang_tag_re = re.compile('^[a-z]{2,3}(?:-[A-Z]{2,3}(?:-[a-zA-Z]{4})?)?$') - for lang in tag: - if not lang_tag_re.match(lang) or tag == 'test': - self.return_error("language %s is not valid in %s" % (tag, field)) - else: - self.return_error("language tags must contain at least one key/value pair in %s" % field) - - def validate_dict_values(self, values, field): - for v in values: - if not v: - self.return_error("%s contains a null value" % field) - - def validate_email_sha1sum(self, sha1sum): - if isinstance(sha1sum, basestring): - sha1sum_re = re.compile('([a-fA-F\d]{40}$)') - if not sha1sum_re.match(sha1sum): - self.return_error("mbox_sha1sum value [%s] is not a valid sha1sum" % sha1sum) - else: - self.return_error("mbox_sha1sum value must be a string type") - - def validate_iri(self, iri_value, field): - if isinstance(iri_value, basestring): - try: - iriparse(iri_value, rule='IRI') - except Exception: - self.return_error("%s with value %s was not a valid IRI" % (field, iri_value)) - else: - self.return_error("%s must be a string type" % field) - - def validate_uuid(self, uuid, field): - if isinstance(uuid, basestring): - try: - val = UUID(uuid, version=4) - except ValueError: - self.return_error("%s - %s is not a valid UUID" % (field, uuid)) - return val.hex == uuid - else: - self.return_error("%s must be a string type" % field) - - def check_if_dict(self, obj, field): - if not isinstance(obj, dict): - self.return_error("%s is not a properly formatted dictionary" % field) - - def check_if_list(self, obj, field): - if not isinstance(obj, list): - self.return_error("%s is not a properly formatted array" % field) - - def check_allowed_fields(self, allowed, obj, obj_name): - # Check for fields that aren't in spec - failed_list = [x for x in obj.keys() if not x in allowed] - if failed_list: - self.return_error("Invalid field(s) found in %s - %s" % (obj_name, ', '.join(failed_list))) - - def check_required_fields(self, required, obj, obj_name): - for field in required: - if not field in obj: - self.return_error("%s is missing in %s" % (field, obj_name)) - - def validate_statement(self, stmt): - # Ensure dict was submitted as stmt and check allowed and required fields - self.check_if_dict(stmt, "Statement") - self.check_allowed_fields(statement_allowed_fields, stmt, "Statement") - self.check_required_fields(statement_required_fields, stmt, "Statement") - - # If version included in stmt (usually in header instead) make sure it is 1.0.0 + - if 'version' in stmt: - if isinstance(stmt['version'], basestring): - version_regex = re.compile("^1\.0(\.\d+)?$") - if not version_regex.match(stmt['version']): - self.return_error("%s is not a supported version" % stmt['version']) - else: - self.return_error("Version must be a string") - - # If id included, make sure it is a valid UUID - if 'id' in stmt: - self.validate_uuid(stmt['id'], 'Statement id') - - # If timestamp included, make sure a valid date can be parsed from it - if 'timestamp' in stmt: - timestamp = stmt['timestamp'] - try: - parse_datetime(timestamp) - except Exception as e: - self.return_error("Timestamp error - There was an error while parsing the date from %s -- Error: %s" % (timestamp, e.message)) - - # Validate the actor and verb - self.validate_agent(stmt['actor'], 'actor') - self.validate_verb(stmt['verb'], stmt['object']) - - # Validate the object - stmt_object = stmt['object'] - self.validate_object(stmt_object) - - # If the object is validated and has no objectType, set to Activity - if not 'objectType' in stmt_object: - stmt['object']['objectType'] = 'Activity' - - # If result is included, validate it - if 'result' in stmt: - self.validate_result(stmt['result']) - - # If context is included, validate it - if 'context' in stmt: - self.validate_context(stmt['context'], stmt_object) - - # If authority is included, validate it - if 'authority' in stmt: - self.validate_agent(stmt['authority'], 'authority') - self.validate_authority(stmt['authority']) - - # If attachments is included, validate it - if 'attachments' in stmt: - self.validate_attachments(stmt['attachments']) - - def validate_authority(self, authority): - if authority['objectType'] == 'Group': - contains_account = len([x for m in authority['member'] for x in m.keys() if 'account' in x]) > 0 - if contains_account: - if len(authority['member']) == 2: - for agent in authority['member']: - if 'account' in agent: - if not 'oauth' in agent['account']['homePage'].lower(): - self.return_error("Statements cannot have a non-OAuth group as the authority") - # Probably an oauth group - else: - if set(authority.keys()) != set(['objectType', 'member']): - self.return_error("Statements cannot have a non-OAuth group as the authority") - else: - self.return_error("OAuth authority must only contain 2 members") - # No members contain an account so that means it's not an Oauth group - else: - self.return_error("Statements cannot have a non-OAuth group as the authority") - - def validate_attachments(self, attachments): - # Ensure attachments is a list - self.check_if_list(attachments, "Attachments") - - for attach in attachments: - # For each attachment, check allowed and required fields - self.check_allowed_fields(attachment_allowed_fields, attach, "Attachment") - self.check_required_fields(attachment_required_fields, attach, "Attachment") - - # Validate usageType - self.validate_iri(attach['usageType'], 'Attachments usageType') - - # If fileUrl included, validate it - if 'fileUrl' in attach: - self.validate_iri(attach['fileUrl'], 'Attachments fileUrl') - else: - # If fileUrl is not included, sha2 must be - only time sha2 is required - if not 'sha2' in attach: - self.return_error("Attachment sha2 is required when no fileUrl is given") - - # Ensure sha2 is submitted as string - if not isinstance(attach['sha2'], basestring): - self.return_error("Attachment sha2 must be a string") - - # Ensure length is an int - if not isinstance(attach['length'], int): - self.return_error("Attachment length must be an integer") - - # Ensure contentType is submitted as a string - if not isinstance(attach['contentType'], basestring): - self.return_error("Attachment contentType must be a string") - - # Ensure display is a dict (language map) - self.check_if_dict(attach['display'], "Attachment display") - self.validate_lang_tag(attach['display'].keys(), "attachment display") - - # If description included, ensure it is a dict (language map) - if 'description' in attach: - self.check_if_dict(attach['description'], "Attachment description") - self.validate_lang_tag(attach['description'].keys(), "attachment description") - - def validate_extensions(self, extensions, field): - # Ensure incoming extensions is a dict - self.check_if_dict(extensions, "%s extensions" % field) - - # Ensure each key in extensions is a valid IRI - for k, v in extensions.items(): - self.validate_iri(k, field) - - def validate_agent(self, agent, placement): - # Ensure incoming agent is a dict and check allowed fields - self.check_if_dict(agent, "Agent in %s" % placement) - self.check_allowed_fields(agent_allowed_fields, agent, "Agent/Group") - # If the agent is the object of a stmt, the objectType must be present - if placement == 'object' and not 'objectType' in agent: - self.return_error("objectType must be set when using an Agent as the object of a statement") - # If the agent is not the object of a stmt and objectType is given, it must be Agent or Group - elif placement != 'object' and 'objectType' in agent: - if agent['objectType'] != 'Agent' and agent['objectType'] != 'Group': - self.return_error("An agent's objectType must be either Agent or Group if given") - # If the agent is not the object of a stmt and objectType is not given, set it to Agent - elif placement != 'object' and not 'objectType' in agent: - agent['objectType'] = 'Agent' - # Agent must have only one inverse functionlal identifier (Group may be Anonymous Group where no IFI is - # required) - ifis = [a for a in agent_ifis_can_only_be_one if agent.get(a, None) != None] - if agent['objectType'] == 'Agent' and len(ifis) != 1: - self.return_error("One and only one of %s may be supplied with an Agent" % ", ".join(agent_ifis_can_only_be_one)) - elif agent['objectType'] == 'Group' and len(ifis) > 1: - self.return_error("None or one and only one of %s may be supplied with a Group" % ", ".join(agent_ifis_can_only_be_one)) - - if agent['objectType'] == 'Agent': - # If agent, if name given, ensure name is string and validate the IFI - if 'name' in agent and not isinstance(agent['name'], basestring): - self.return_error("If name is given in Agent, it must be a string") - self.validate_ifi(ifis[0], agent[ifis[0]]) - else: - # If group, if name given, ensure name is string - if 'name' in agent and not isinstance(agent['name'], basestring): - self.return_error("If name is given in Group, it must be a string") - - # If no IFIs, it is an anonymous group which must contain the member property - if not ifis: - # No ifi means anonymous group - must have member - if not 'member' in agent: - self.return_error("Anonymous groups must contain member") - else: - self.validate_members(agent) - else: - # IFI given, validate it - self.validate_ifi(ifis[0], agent[ifis[0]]) - if 'member' in agent: - self.validate_members(agent) - - def validate_members(self, agent): - # Ensure member list is array - members = agent['member'] - self.check_if_list(members, "Members") - if not members: - self.return_error("Member property must contain agents") - # Make sure no member of group is another group - object_types = [t['objectType'] for t in members if 'objectType' in t] - if 'Group' in object_types: - self.return_error('Group member value cannot be other groups') - - # Validate each member in group - for agent in members: - self.validate_agent(agent, 'member') - - def validate_ifi(self, ifis, ifi_value): - # Validate each IFI accordingly - if ifis == 'mbox': - self.validate_email(ifi_value) - elif ifis == 'mbox_sha1sum': - self.validate_email_sha1sum(ifi_value) - elif ifis == 'openid': - self.validate_iri(ifi_value, 'openid') - elif ifis == 'account': - self.validate_account(ifi_value) - - def validate_account(self, account): - # Ensure incoming account is a dict and check allowed and required fields - self.check_if_dict(account, "Account") - self.check_allowed_fields(account_fields, account, "Account") - self.check_required_fields(account_fields, account, "Account") - - # Ensure homePage is a valid IRI - self.validate_iri(account['homePage'], 'homePage') - - # Ensure name is a string - if not isinstance(account['name'], basestring): - self.return_error("account name must be a string") - - def validate_verb(self, verb, stmt_object=None): - # Ensure incoming verb is a dict and check allowed fields - self.check_if_dict(verb, "Verb") - self.check_allowed_fields(verb_allowed_fields, verb, "Verb") - - # Verb must conatin id - then validate it - if not 'id' in verb: - self.return_error('Verb must contain an id') - self.validate_iri(verb['id'], 'Verb id') - - if verb['id'] == "http://adlnet.gov/expapi/verbs/voided": - if stmt_object['objectType']: - if stmt_object['objectType'] != "StatementRef": - raise ParamError("Statement with voided verb must have StatementRef as objectType") - else: - raise ParamError("Statement with voided verb must have StatementRef as objectType") - - # If display given, ensure it's a dict (language map) - if 'display' in verb: - self.check_if_dict(verb['display'], "Verb display") - self.validate_lang_tag(verb['display'].keys(), "verb display") - self.validate_dict_values(verb['display'].values(), "verb display") - - def validate_object(self, stmt_object): - # Ensure incoming object is a dict - self.check_if_dict(stmt_object, "Object") - - # If objectType is not given or is Activity it is an Activity - # Validate the rest accordingly - if not 'objectType' in stmt_object or stmt_object['objectType'] == 'Activity': - self.validate_activity(stmt_object) - elif stmt_object['objectType'] == 'Agent' or stmt_object['objectType'] == 'Group': - self.validate_agent(stmt_object, 'object') - elif stmt_object['objectType'] == 'SubStatement': - self.validate_substatement(stmt_object) - elif stmt_object['objectType'] == 'StatementRef': - self.validate_statementref(stmt_object) - else: - self.return_error("The objectType in the statement's object is not valid - %s" % stmt_object['objectType']) - - def validate_statementref(self, ref): - # Ensure incoming StatementRef is a dictionary an check allowed and required fields - self.check_if_dict(ref, "StatementRef") - - # objectType must be StatementRef - if ref['objectType'] != "StatementRef": - self.return_error("StatementRef objectType must be set to 'StatementRef'") - - self.check_allowed_fields(ref_fields, ref, "StatementRef") - self.check_required_fields(ref_fields, ref, "StatementRef") - - # Ensure id is a valid UUID - self.validate_uuid(ref['id'], 'StatementRef id') - - def validate_activity(self, activity): - # Ensure incoming activity is a dict and check allowed fields - self.check_if_dict(activity, "Activity") - self.check_allowed_fields(activity_allowed_fields, activity, "Activity") - - # Id must be present - if not 'id' in activity: - self.return_error("Id field must be present in an Activity") - - # Id must be valid IRI - self.validate_iri(activity['id'], "Activity id") - - # If definition included, validate it - if 'definition' in activity: - self.validate_activity_definition(activity['definition']) - - def validate_activity_definition(self, definition): - # Ensure incoming def is a dict and check allowed fields - self.check_if_dict(definition, "Activity definition") - - # Make sure it's not an empty definition - if not definition: - self.return_error("Definition is empty") - - self.check_allowed_fields(act_def_allowed_fields, definition, "Activity definition") - - # If name or description included, ensure it is a dict (language map) - if 'name' in definition: - self.check_if_dict(definition['name'], "Activity definition name") - self.validate_lang_tag(definition['name'].keys(), "activity definition name") - if 'description' in definition: - self.check_if_dict(definition['description'], "Activity definition description") - self.validate_lang_tag(definition['description'].keys(), "activity definition description") - - # If type or moreInfo included, ensure it is valid IRI - if 'type' in definition: - self.validate_iri(definition['type'], 'Activity definition type') - if 'moreInfo' in definition: - self.validate_iri(definition['moreInfo'], 'Activity definition moreInfo') - - interactionType = None - # If interactionType included, ensure it is a string - if 'interactionType' in definition: - if not isinstance(definition['interactionType'], basestring): - self.return_error("Activity definition interactionType must be a string") - - scorm_interaction_types = ['true-false', 'choice', 'fill-in', 'long-fill-in', 'matching', 'performance', - 'sequencing', 'likert', 'numeric', 'other'] - - #Check if valid SCORM interactionType - if definition['interactionType'] not in scorm_interaction_types: - self.return_error("Activity definition interactionType %s is not valid" % definition['interactionType']) - - interactionType = definition['interactionType'] - # If crp included, ensure they are strings in a list - if 'correctResponsesPattern' in definition: - self.check_if_list(definition['correctResponsesPattern'], "Activity definition correctResponsesPattern") - for answer in definition['correctResponsesPattern']: - # For each answer, ensure it is a string - if not isinstance(answer, basestring): - self.return_error("Activity definition correctResponsesPattern answers must all be strings") - - self.validate_interaction_types(interactionType, definition) - - # If extensions, validate it - if 'extensions' in definition: - self.validate_extensions(definition['extensions'], 'activity definition') - - def check_other_interaction_component_fields(self, allowed, definition): - interaction_components = set(["choices", "scale", "source", "target", "steps"]) - keys = set(definition.keys()) - - both = interaction_components.intersection(keys) - not_allowed = list(both - set(allowed)) - - if not_allowed: - self.return_error("Only interaction component field(s) allowed (%s) - not allowed: %s" % (' '.join(allowed), ' '.join(not_allowed))) - - # not_allowed = any(x in keys for x in interaction_components if x not in allowed) - - def validate_interaction_types(self, interactionType, definition): - if interactionType == "choice" or interactionType == "sequencing": - # If choices included, ensure it is an array and validate it - if 'choices' in definition: - self.check_other_interaction_component_fields(['choices'], definition) - choices = definition['choices'] - self.check_if_list(choices, "Activity definition choices") - self.validate_interaction_activities(choices, 'choices') - elif interactionType == "likert": - # If scale included, ensure it is an array and validate it - if 'scale' in definition: - self.check_other_interaction_component_fields(['scale'], definition) - scale = definition['scale'] - self.check_if_list(scale, "Activity definition scale") - self.validate_interaction_activities(scale, 'scale') - elif interactionType == "matching": - # If scale included, ensure it is an array and validate it - if 'source' in definition: - self.check_other_interaction_component_fields(['target', 'source'], definition) - source = definition['source'] - self.check_if_list(source, "Activity definition source") - self.validate_interaction_activities(source, 'source') - # If target included, ensure it is an array and validate it - if 'target' in definition: - self.check_other_interaction_component_fields(['target', 'source'], definition) - target = definition['target'] - self.check_if_list(target, "Activity definition target") - self.validate_interaction_activities(target, 'target') - elif interactionType == "performance": - # If steps included, ensure it is an array and validate it - if 'steps' in definition: - self.check_other_interaction_component_fields(['steps'], definition) - steps = definition['steps'] - self.check_if_list(steps, "Activity definition steps") - self.validate_interaction_activities(steps, 'steps') - - def validate_interaction_activities(self, activities, field): - id_list = [] - for act in activities: - # Ensure each interaction activity is a dict and check allowed fields - self.check_if_dict(act, "%s interaction component" % field) - self.check_allowed_fields(int_act_fields, act, "Activity definition %s" % field) - self.check_required_fields(int_act_fields, act, "Activity definition %s" % field) - - # Ensure id value is string - if not isinstance(act['id'], basestring): - self.return_error("Interaction activity in component %s has an id that is not a string" % field) - - id_list.append(act['id']) - if 'description' in act: - # Ensure description is a dict (language map) - self.check_if_dict(act['description'], "%s interaction component description" % field) - self.validate_lang_tag(act['description'].keys(), "%s interaction component description" % field) - - # Check and make sure all ids being listed are unique - dups = set([i for i in id_list if id_list.count(i) > 1]) - if dups: - self.return_error("Interaction activities shared the same id(s) (%s) which is not allowed" % ' '.join(dups)) - - def validate_substatement(self, substmt): - # Ensure incoming substmt is a dict and check allowed and required fields - self.check_if_dict(substmt, "SubStatement") - self.check_allowed_fields(sub_allowed_fields, substmt, "SubStatement") - self.check_required_fields(sub_required_fields, substmt, "SubStatement") - - # If timestamp is included, ensure a valid time can be parsed - if 'timestamp' in substmt: - timestamp = substmt['timestamp'] - try: - parse_datetime(timestamp) - except Exception as e: - self.return_error("Timestamp error - There was an error while parsing the date from %s -- Error: %s" % (timestamp, e.message)) - - # Can't next substmts in other substmts - if not supplied it is an Activity - if 'objectType' in substmt['object']: - if substmt['object']['objectType'] == 'SubStatement': - self.return_error("Cannot nest a SubStatement inside of another SubStatement") - else: - substmt['object']['objectType'] = 'Activity' - - # Validate agent, verb, and object - self.validate_agent(substmt['actor'], 'actor') - self.validate_object(substmt['object']) - self.validate_verb(substmt['verb']) - - # If result included, validate it - if 'result' in substmt: - self.validate_result(substmt['result']) - - # If context included, validate it - if 'context' in substmt: - self.validate_context(substmt['context'], substmt['object']) - - def validate_result(self, result): - # Ensure incoming result is dict and check allowed fields - self.check_if_dict(result, "Result") - self.check_allowed_fields(result_allowed_fields, result, "Result") - - # If duration included, ensure valid duration can be parsed from it - if 'duration' in result: - try: - parse_duration(result['duration']) - except Exception as e: - self.return_error("Error with result duration - %s" % e.message) - - # If success or completion included, ensure they are boolean - if 'success' in result: - if not isinstance(result['success'], bool): - self.return_error("Result success must be a boolean value") - if 'completion' in result: - if not isinstance(result['completion'], bool): - self.return_error("Result completion must be a boolean value") - - # If response in result, ensure it is a string - if 'response' in result: - if not isinstance(result['response'], basestring): - self.return_error("Result response must be a string") - - # If extensions, validate - if 'extensions' in result: - self.validate_extensions(result['extensions'], 'result') - - # If score included, validate it - if 'score' in result: - self.validate_score(result['score']) - - def validate_score(self, score): - # Ensure incoming score is a dict and check allowed fields - self.check_if_dict(score, "Score") - self.check_allowed_fields(score_allowed_fields, score, "Score") - - if 'raw' in score: - # If raw included with min and max, ensure it is between min and ax - raw = score['raw'] - # Check raw type - if not (isinstance(raw, float) or isinstance(raw, int)): - self.return_error("Score raw is not a number") - else: - raw = None - - # If min and max are included, ensure min <= max - if 'min' in score and 'max' in score: - sc_min = score['min'] - sc_max = score['max'] - - # Check types of min and max - if not (isinstance(sc_min, float) or isinstance(sc_min, int)): - self.return_error("Score minimum is not a decimal") - - if not (isinstance(sc_max, float) or isinstance(sc_max, int)): - self.return_error("Score maximum is not a decimal") - - if sc_min >= sc_max: - self.return_error("Score minimum in statement result must be less than the maximum") - - if raw and (raw < sc_min or raw > sc_max): - self.return_error("Score raw value in statement result must be between minimum and maximum") - - # If scale is included make sure it's between -1 and 1 - if 'scaled' in score: - scaled = score['scaled'] - - # Check scaled type - if not (isinstance(scaled, float) or isinstance(scaled, int)): - self.return_error("Score scaled is not a decimal") - - if scaled < -1 or scaled > 1: - self.return_error("Score scaled value in statement result must be between -1 and 1") - - def validate_context(self, context, stmt_object): - # Ensure incoming context is a dict and check allowed fields - self.check_if_dict(context, "Context") - self.check_allowed_fields(context_allowed_fields, context, "Context") - - # If registration included, ensure it is valid UUID - if 'registration' in context: - self.validate_uuid(context['registration'], 'Context registration') - - # If instructor or team included, ensure they are valid agents - if 'instructor' in context: - self.validate_agent(context['instructor'], 'Context instructor') - if 'team' in context: - self.validate_agent(context['team'], 'Context team') - if not 'objectType' in context['team'] or context['team']['objectType'] == 'Agent': - self.return_error("Team in context must be a group") - - # If objectType of object in stmt is Agent/Group, context cannot have revision or platform fields - object_type = stmt_object['objectType'] - - if 'revision' in context: - # Check revision is string - if not isinstance(context['revision'], basestring): - self.return_error("Context revision must be a string") - - if object_type != 'Activity': - self.return_error("Revision is not allowed in context if statement object is not an Activity") - - if 'platform' in context: - # Check platform is string - if not isinstance(context['platform'], basestring): - self.return_error("Context platform must be a string") - - if object_type != 'Activity': - self.return_error("Platform is not allowed in context if statement object is not an Activity") - - # If language given, ensure it is string - if 'language' in context: - if not isinstance(context['language'], basestring): - self.return_error("Context language must be a string") - - # If statement given, ensure it is a valid StatementRef - if 'statement' in context: - self.validate_statementref(context['statement']) - - # If contextActivities given, ensure they are valid contextActivities - if 'contextActivities' in context: - self.validate_context_activities(context['contextActivities']) - - # If extensions, validate - if 'extensions' in context: - self.validate_extensions(context['extensions'], 'context') - - def validate_context_activities(self, conacts): - # Ensure incoming conact is dict - self.check_if_dict(conacts, "Context activity") - context_activity_types = ['parent', 'grouping', 'category', 'other'] - if conacts: - for conact in conacts.items(): - # Check if conact is a valid type - if not conact[0] in context_activity_types: - self.return_error("Context activity type is not valid - %s - must be %s" % (conact[0], ', '.join(context_activity_types))) - # Ensure conact is a list or dict - if isinstance(conact[1], list): - for act in conact[1]: - self.validate_activity(act) - elif isinstance(conact[1], dict): - self.validate_activity(conact[1]) - else: - self.return_error("contextActivities is not formatted correctly") - else: - self.return_error("contextActivities must contain at least one key/value pair") \ No newline at end of file + + def __init__(self, data=None): + # If incoming is a string, ast eval it (exception will be caught with whatever is calling validator) + if data: + try: + self.data = convert_to_datatype(data) + except Exception, e: + self.return_error(e.message) + + def validate(self): + # If list, validate each stmt inside + if isinstance(self.data, list): + for st in self.data: + self.validate_statement(st) + return "All Statements are valid" + else: + self.validate_statement(self.data) + return "Statement is valid" + + def return_error(self, err_msg): + raise ParamError(err_msg) + + def validate_email(self, email): + if isinstance(email, basestring): + if email.startswith("mailto:"): + email_re = re.compile("[^@]+@[^@]+\.[^@]+") + if not email_re.match(email[7:]): + self.return_error("mbox value %s is not a valid email" % email) + else: + self.return_error("mbox value %s did not start with mailto:" % email) + else: + self.return_error("mbox value must be a string type") + + def validate_lang_tag(self, tag, field): + if tag: + lang_tag_re = re.compile('^[a-z]{2,3}(?:-[A-Z]{2,3}(?:-[a-zA-Z]{4})?)?$') + for lang in tag: + if not lang_tag_re.match(lang) or tag == 'test': + self.return_error("language %s is not valid in %s" % (tag, field)) + else: + self.return_error("language tags must contain at least one key/value pair in %s" % field) + + def validate_dict_values(self, values, field): + for v in values: + if not v: + self.return_error("%s contains a null value" % field) + + def validate_email_sha1sum(self, sha1sum): + if isinstance(sha1sum, basestring): + sha1sum_re = re.compile('([a-fA-F\d]{40}$)') + if not sha1sum_re.match(sha1sum): + self.return_error("mbox_sha1sum value [%s] is not a valid sha1sum" % sha1sum) + else: + self.return_error("mbox_sha1sum value must be a string type") + + def validate_iri(self, iri_value, field): + if isinstance(iri_value, basestring): + try: + iriparse(iri_value, rule='IRI') + except Exception: + self.return_error("%s with value %s was not a valid IRI" % (field, iri_value)) + else: + self.return_error("%s must be a string type" % field) + + def validate_uuid(self, uuid, field): + if isinstance(uuid, basestring): + try: + val = UUID(uuid, version=4) + except ValueError: + self.return_error("%s - %s is not a valid UUID" % (field, uuid)) + return val.hex == uuid + else: + self.return_error("%s must be a string type" % field) + + def check_if_dict(self, obj, field): + if not isinstance(obj, dict): + self.return_error("%s is not a properly formatted dictionary" % field) + + def check_if_list(self, obj, field): + if not isinstance(obj, list): + self.return_error("%s is not a properly formatted array" % field) + + def check_allowed_fields(self, allowed, obj, obj_name): + # Check for fields that aren't in spec + failed_list = [x for x in obj.keys() if x not in allowed] + if failed_list: + self.return_error("Invalid field(s) found in %s - %s" % (obj_name, ', '.join(failed_list))) + + def check_required_fields(self, required, obj, obj_name): + for field in required: + if field not in obj: + self.return_error("%s is missing in %s" % (field, obj_name)) + + def validate_statement(self, stmt): + # Ensure dict was submitted as stmt and check allowed and required fields + self.check_if_dict(stmt, "Statement") + self.check_allowed_fields(statement_allowed_fields, stmt, "Statement") + self.check_required_fields(statement_required_fields, stmt, "Statement") + + # If version included in stmt (usually in header instead) make sure it is 1.0.0 + + if 'version' in stmt: + if isinstance(stmt['version'], basestring): + version_regex = re.compile("^1\.0(\.\d+)?$") + if not version_regex.match(stmt['version']): + self.return_error("%s is not a supported version" % stmt['version']) + else: + self.return_error("Version must be a string") + + # If id included, make sure it is a valid UUID + if 'id' in stmt: + self.validate_uuid(stmt['id'], 'Statement id') + + # If timestamp included, make sure a valid date can be parsed from it + if 'timestamp' in stmt: + timestamp = stmt['timestamp'] + try: + parse_datetime(timestamp) + except Exception as e: + self.return_error("Timestamp error - There was an error while parsing the date from %s -- Error: %s" % (timestamp, e.message)) + + # Validate the actor and verb + self.validate_agent(stmt['actor'], 'actor') + self.validate_verb(stmt['verb'], stmt['object']) + + # Validate the object + stmt_object = stmt['object'] + self.validate_object(stmt_object) + + # If the object is validated and has no objectType, set to Activity + if 'objectType' not in stmt_object: + stmt['object']['objectType'] = 'Activity' + + # If result is included, validate it + if 'result' in stmt: + self.validate_result(stmt['result']) + + # If context is included, validate it + if 'context' in stmt: + self.validate_context(stmt['context'], stmt_object) + + # If authority is included, validate it + if 'authority' in stmt: + self.validate_agent(stmt['authority'], 'authority') + self.validate_authority(stmt['authority']) + + # If attachments is included, validate it + if 'attachments' in stmt: + self.validate_attachments(stmt['attachments']) + + def validate_authority(self, authority): + if authority['objectType'] == 'Group': + contains_account = len([x for m in authority['member'] for x in m.keys() if 'account' in x]) > 0 + if contains_account: + if len(authority['member']) == 2: + for agent in authority['member']: + if 'account' in agent: + if 'oauth' not in agent['account']['homePage'].lower(): + self.return_error("Statements cannot have a non-OAuth group as the authority") + # Probably an oauth group + else: + if set(authority.keys()) != set(['objectType', 'member']): + self.return_error("Statements cannot have a non-OAuth group as the authority") + else: + self.return_error("OAuth authority must only contain 2 members") + # No members contain an account so that means it's not an Oauth group + else: + self.return_error("Statements cannot have a non-OAuth group as the authority") + + def validate_attachments(self, attachments): + # Ensure attachments is a list + self.check_if_list(attachments, "Attachments") + + for attach in attachments: + # For each attachment, check allowed and required fields + self.check_allowed_fields(attachment_allowed_fields, attach, "Attachment") + self.check_required_fields(attachment_required_fields, attach, "Attachment") + + # Validate usageType + self.validate_iri(attach['usageType'], 'Attachments usageType') + + # If fileUrl included, validate it + if 'fileUrl' in attach: + self.validate_iri(attach['fileUrl'], 'Attachments fileUrl') + else: + # If fileUrl is not included, sha2 must be - only time sha2 is required + if 'sha2' not in attach: + self.return_error("Attachment sha2 is required when no fileUrl is given") + + # Ensure sha2 is submitted as string + if not isinstance(attach['sha2'], basestring): + self.return_error("Attachment sha2 must be a string") + + # Ensure length is an int + if not isinstance(attach['length'], int): + self.return_error("Attachment length must be an integer") + + # Ensure contentType is submitted as a string + if not isinstance(attach['contentType'], basestring): + self.return_error("Attachment contentType must be a string") + + # Ensure display is a dict (language map) + self.check_if_dict(attach['display'], "Attachment display") + self.validate_lang_tag(attach['display'].keys(), "attachment display") + + # If description included, ensure it is a dict (language map) + if 'description' in attach: + self.check_if_dict(attach['description'], "Attachment description") + self.validate_lang_tag(attach['description'].keys(), "attachment description") + + def validate_extensions(self, extensions, field): + # Ensure incoming extensions is a dict + self.check_if_dict(extensions, "%s extensions" % field) + + # Ensure each key in extensions is a valid IRI + for k, v in extensions.items(): + self.validate_iri(k, field) + + def validate_agent(self, agent, placement): + # Ensure incoming agent is a dict and check allowed fields + self.check_if_dict(agent, "Agent in %s" % placement) + self.check_allowed_fields(agent_allowed_fields, agent, "Agent/Group") + # If the agent is the object of a stmt, the objectType must be present + if placement == 'object' and 'objectType' not in agent: + self.return_error("objectType must be set when using an Agent as the object of a statement") + # If the agent is not the object of a stmt and objectType is given, it must be Agent or Group + elif placement != 'object' and 'objectType' in agent: + if agent['objectType'] != 'Agent' and agent['objectType'] != 'Group': + self.return_error("An agent's objectType must be either Agent or Group if given") + # If the agent is not the object of a stmt and objectType is not given, set it to Agent + elif placement != 'object' and 'objectType' not in agent: + agent['objectType'] = 'Agent' + # Agent must have only one inverse functionlal identifier (Group may be Anonymous Group where no IFI is + # required) + ifis = [a for a in agent_ifis_can_only_be_one if agent.get(a, None) is not None] + if agent['objectType'] == 'Agent' and len(ifis) != 1: + self.return_error("One and only one of %s may be supplied with an Agent" % ", ".join(agent_ifis_can_only_be_one)) + elif agent['objectType'] == 'Group' and len(ifis) > 1: + self.return_error("None or one and only one of %s may be supplied with a Group" % ", ".join(agent_ifis_can_only_be_one)) + + if agent['objectType'] == 'Agent': + # If agent, if name given, ensure name is string and validate the IFI + if 'name' in agent and not isinstance(agent['name'], basestring): + self.return_error("If name is given in Agent, it must be a string") + self.validate_ifi(ifis[0], agent[ifis[0]]) + else: + # If group, if name given, ensure name is string + if 'name' in agent and not isinstance(agent['name'], basestring): + self.return_error("If name is given in Group, it must be a string") + + # If no IFIs, it is an anonymous group which must contain the member property + if not ifis: + # No ifi means anonymous group - must have member + if 'member' not in agent: + self.return_error("Anonymous groups must contain member") + else: + self.validate_members(agent) + else: + # IFI given, validate it + self.validate_ifi(ifis[0], agent[ifis[0]]) + if 'member' in agent: + self.validate_members(agent) + + def validate_members(self, agent): + # Ensure member list is array + members = agent['member'] + self.check_if_list(members, "Members") + if not members: + self.return_error("Member property must contain agents") + # Make sure no member of group is another group + object_types = [t['objectType'] for t in members if 'objectType' in t] + if 'Group' in object_types: + self.return_error('Group member value cannot be other groups') + + # Validate each member in group + for agent in members: + self.validate_agent(agent, 'member') + + def validate_ifi(self, ifis, ifi_value): + # Validate each IFI accordingly + if ifis == 'mbox': + self.validate_email(ifi_value) + elif ifis == 'mbox_sha1sum': + self.validate_email_sha1sum(ifi_value) + elif ifis == 'openid': + self.validate_iri(ifi_value, 'openid') + elif ifis == 'account': + self.validate_account(ifi_value) + + def validate_account(self, account): + # Ensure incoming account is a dict and check allowed and required fields + self.check_if_dict(account, "Account") + self.check_allowed_fields(account_fields, account, "Account") + self.check_required_fields(account_fields, account, "Account") + + # Ensure homePage is a valid IRI + self.validate_iri(account['homePage'], 'homePage') + + # Ensure name is a string + if not isinstance(account['name'], basestring): + self.return_error("account name must be a string") + + def validate_verb(self, verb, stmt_object=None): + # Ensure incoming verb is a dict and check allowed fields + self.check_if_dict(verb, "Verb") + self.check_allowed_fields(verb_allowed_fields, verb, "Verb") + + # Verb must conatin id - then validate it + if 'id' not in verb: + self.return_error('Verb must contain an id') + self.validate_iri(verb['id'], 'Verb id') + + if verb['id'] == "http://adlnet.gov/expapi/verbs/voided": + if stmt_object['objectType']: + if stmt_object['objectType'] != "StatementRef": + raise ParamError("Statement with voided verb must have StatementRef as objectType") + else: + raise ParamError("Statement with voided verb must have StatementRef as objectType") + + # If display given, ensure it's a dict (language map) + if 'display' in verb: + self.check_if_dict(verb['display'], "Verb display") + self.validate_lang_tag(verb['display'].keys(), "verb display") + self.validate_dict_values(verb['display'].values(), "verb display") + + def validate_object(self, stmt_object): + # Ensure incoming object is a dict + self.check_if_dict(stmt_object, "Object") + + # If objectType is not given or is Activity it is an Activity + # Validate the rest accordingly + if 'objectType' not in stmt_object or stmt_object['objectType'] == 'Activity': + self.validate_activity(stmt_object) + elif stmt_object['objectType'] == 'Agent' or stmt_object['objectType'] == 'Group': + self.validate_agent(stmt_object, 'object') + elif stmt_object['objectType'] == 'SubStatement': + self.validate_substatement(stmt_object) + elif stmt_object['objectType'] == 'StatementRef': + self.validate_statementref(stmt_object) + else: + self.return_error("The objectType in the statement's object is not valid - %s" % stmt_object['objectType']) + + def validate_statementref(self, ref): + # Ensure incoming StatementRef is a dictionary an check allowed and required fields + self.check_if_dict(ref, "StatementRef") + + # objectType must be StatementRef + if ref['objectType'] != "StatementRef": + self.return_error("StatementRef objectType must be set to 'StatementRef'") + + self.check_allowed_fields(ref_fields, ref, "StatementRef") + self.check_required_fields(ref_fields, ref, "StatementRef") + + # Ensure id is a valid UUID + self.validate_uuid(ref['id'], 'StatementRef id') + + def validate_activity(self, activity): + # Ensure incoming activity is a dict and check allowed fields + self.check_if_dict(activity, "Activity") + self.check_allowed_fields(activity_allowed_fields, activity, "Activity") + + # Id must be present + if 'id' not in activity: + self.return_error("Id field must be present in an Activity") + + # Id must be valid IRI + self.validate_iri(activity['id'], "Activity id") + + # If definition included, validate it + if 'definition' in activity: + self.validate_activity_definition(activity['definition']) + + def validate_activity_definition(self, definition): + # Ensure incoming def is a dict and check allowed fields + self.check_if_dict(definition, "Activity definition") + + # Make sure it's not an empty definition + if not definition: + self.return_error("Definition is empty") + + self.check_allowed_fields(act_def_allowed_fields, definition, "Activity definition") + + # If name or description included, ensure it is a dict (language map) + if 'name' in definition: + self.check_if_dict(definition['name'], "Activity definition name") + self.validate_lang_tag(definition['name'].keys(), "activity definition name") + if 'description' in definition: + self.check_if_dict(definition['description'], "Activity definition description") + self.validate_lang_tag(definition['description'].keys(), "activity definition description") + + # If type or moreInfo included, ensure it is valid IRI + if 'type' in definition: + self.validate_iri(definition['type'], 'Activity definition type') + if 'moreInfo' in definition: + self.validate_iri(definition['moreInfo'], 'Activity definition moreInfo') + + interactionType = None + # If interactionType included, ensure it is a string + if 'interactionType' in definition: + if not isinstance(definition['interactionType'], basestring): + self.return_error("Activity definition interactionType must be a string") + + scorm_interaction_types = ['true-false', 'choice', 'fill-in', 'long-fill-in', 'matching', 'performance', + 'sequencing', 'likert', 'numeric', 'other'] + + # Check if valid SCORM interactionType + if definition['interactionType'] not in scorm_interaction_types: + self.return_error("Activity definition interactionType %s is not valid" % definition['interactionType']) + + interactionType = definition['interactionType'] + # If crp included, ensure they are strings in a list + if 'correctResponsesPattern' in definition: + self.check_if_list(definition['correctResponsesPattern'], "Activity definition correctResponsesPattern") + for answer in definition['correctResponsesPattern']: + # For each answer, ensure it is a string + if not isinstance(answer, basestring): + self.return_error("Activity definition correctResponsesPattern answers must all be strings") + + self.validate_interaction_types(interactionType, definition) + + # If extensions, validate it + if 'extensions' in definition: + self.validate_extensions(definition['extensions'], 'activity definition') + + def check_other_interaction_component_fields(self, allowed, definition): + interaction_components = set(["choices", "scale", "source", "target", "steps"]) + keys = set(definition.keys()) + + both = interaction_components.intersection(keys) + not_allowed = list(both - set(allowed)) + + if not_allowed: + self.return_error("Only interaction component field(s) allowed (%s) - not allowed: %s" % (' '.join(allowed), ' '.join(not_allowed))) + + # not_allowed = any(x in keys for x in interaction_components if x not in allowed) + + def validate_interaction_types(self, interactionType, definition): + if interactionType == "choice" or interactionType == "sequencing": + # If choices included, ensure it is an array and validate it + if 'choices' in definition: + self.check_other_interaction_component_fields(['choices'], definition) + choices = definition['choices'] + self.check_if_list(choices, "Activity definition choices") + self.validate_interaction_activities(choices, 'choices') + elif interactionType == "likert": + # If scale included, ensure it is an array and validate it + if 'scale' in definition: + self.check_other_interaction_component_fields(['scale'], definition) + scale = definition['scale'] + self.check_if_list(scale, "Activity definition scale") + self.validate_interaction_activities(scale, 'scale') + elif interactionType == "matching": + # If scale included, ensure it is an array and validate it + if 'source' in definition: + self.check_other_interaction_component_fields(['target', 'source'], definition) + source = definition['source'] + self.check_if_list(source, "Activity definition source") + self.validate_interaction_activities(source, 'source') + # If target included, ensure it is an array and validate it + if 'target' in definition: + self.check_other_interaction_component_fields(['target', 'source'], definition) + target = definition['target'] + self.check_if_list(target, "Activity definition target") + self.validate_interaction_activities(target, 'target') + elif interactionType == "performance": + # If steps included, ensure it is an array and validate it + if 'steps' in definition: + self.check_other_interaction_component_fields(['steps'], definition) + steps = definition['steps'] + self.check_if_list(steps, "Activity definition steps") + self.validate_interaction_activities(steps, 'steps') + + def validate_interaction_activities(self, activities, field): + id_list = [] + for act in activities: + # Ensure each interaction activity is a dict and check allowed fields + self.check_if_dict(act, "%s interaction component" % field) + self.check_allowed_fields(int_act_fields, act, "Activity definition %s" % field) + self.check_required_fields(int_act_fields, act, "Activity definition %s" % field) + + # Ensure id value is string + if not isinstance(act['id'], basestring): + self.return_error("Interaction activity in component %s has an id that is not a string" % field) + + id_list.append(act['id']) + if 'description' in act: + # Ensure description is a dict (language map) + self.check_if_dict(act['description'], "%s interaction component description" % field) + self.validate_lang_tag(act['description'].keys(), "%s interaction component description" % field) + + # Check and make sure all ids being listed are unique + dups = set([i for i in id_list if id_list.count(i) > 1]) + if dups: + self.return_error("Interaction activities shared the same id(s) (%s) which is not allowed" % ' '.join(dups)) + + def validate_substatement(self, substmt): + # Ensure incoming substmt is a dict and check allowed and required fields + self.check_if_dict(substmt, "SubStatement") + self.check_allowed_fields(sub_allowed_fields, substmt, "SubStatement") + self.check_required_fields(sub_required_fields, substmt, "SubStatement") + + # If timestamp is included, ensure a valid time can be parsed + if 'timestamp' in substmt: + timestamp = substmt['timestamp'] + try: + parse_datetime(timestamp) + except Exception as e: + self.return_error("Timestamp error - There was an error while parsing the date from %s -- Error: %s" % (timestamp, e.message)) + + # Can't next substmts in other substmts - if not supplied it is an Activity + if 'objectType' in substmt['object']: + if substmt['object']['objectType'] == 'SubStatement': + self.return_error("Cannot nest a SubStatement inside of another SubStatement") + else: + substmt['object']['objectType'] = 'Activity' + + # Validate agent, verb, and object + self.validate_agent(substmt['actor'], 'actor') + self.validate_object(substmt['object']) + self.validate_verb(substmt['verb']) + + # If result included, validate it + if 'result' in substmt: + self.validate_result(substmt['result']) + + # If context included, validate it + if 'context' in substmt: + self.validate_context(substmt['context'], substmt['object']) + + def validate_result(self, result): + # Ensure incoming result is dict and check allowed fields + self.check_if_dict(result, "Result") + self.check_allowed_fields(result_allowed_fields, result, "Result") + + # If duration included, ensure valid duration can be parsed from it + if 'duration' in result: + try: + parse_duration(result['duration']) + except Exception as e: + self.return_error("Error with result duration - %s" % e.message) + + # If success or completion included, ensure they are boolean + if 'success' in result: + if not isinstance(result['success'], bool): + self.return_error("Result success must be a boolean value") + if 'completion' in result: + if not isinstance(result['completion'], bool): + self.return_error("Result completion must be a boolean value") + + # If response in result, ensure it is a string + if 'response' in result: + if not isinstance(result['response'], basestring): + self.return_error("Result response must be a string") + + # If extensions, validate + if 'extensions' in result: + self.validate_extensions(result['extensions'], 'result') + + # If score included, validate it + if 'score' in result: + self.validate_score(result['score']) + + def validate_score(self, score): + # Ensure incoming score is a dict and check allowed fields + self.check_if_dict(score, "Score") + self.check_allowed_fields(score_allowed_fields, score, "Score") + + if 'raw' in score: + # If raw included with min and max, ensure it is between min and ax + raw = score['raw'] + # Check raw type + if not (isinstance(raw, float) or isinstance(raw, int)): + self.return_error("Score raw is not a number") + else: + raw = None + + # If min and max are included, ensure min <= max + if 'min' in score and 'max' in score: + sc_min = score['min'] + sc_max = score['max'] + + # Check types of min and max + if not (isinstance(sc_min, float) or isinstance(sc_min, int)): + self.return_error("Score minimum is not a decimal") + + if not (isinstance(sc_max, float) or isinstance(sc_max, int)): + self.return_error("Score maximum is not a decimal") + + if sc_min >= sc_max: + self.return_error("Score minimum in statement result must be less than the maximum") + + if raw and (raw < sc_min or raw > sc_max): + self.return_error("Score raw value in statement result must be between minimum and maximum") + + # If scale is included make sure it's between -1 and 1 + if 'scaled' in score: + scaled = score['scaled'] + + # Check scaled type + if not (isinstance(scaled, float) or isinstance(scaled, int)): + self.return_error("Score scaled is not a decimal") + + if scaled < -1 or scaled > 1: + self.return_error("Score scaled value in statement result must be between -1 and 1") + + def validate_context(self, context, stmt_object): + # Ensure incoming context is a dict and check allowed fields + self.check_if_dict(context, "Context") + self.check_allowed_fields(context_allowed_fields, context, "Context") + + # If registration included, ensure it is valid UUID + if 'registration' in context: + self.validate_uuid(context['registration'], 'Context registration') + + # If instructor or team included, ensure they are valid agents + if 'instructor' in context: + self.validate_agent(context['instructor'], 'Context instructor') + if 'team' in context: + self.validate_agent(context['team'], 'Context team') + if 'objectType' not in context['team'] or context['team']['objectType'] == 'Agent': + self.return_error("Team in context must be a group") + + # If objectType of object in stmt is Agent/Group, context cannot have revision or platform fields + object_type = stmt_object['objectType'] + + if 'revision' in context: + # Check revision is string + if not isinstance(context['revision'], basestring): + self.return_error("Context revision must be a string") + + if object_type != 'Activity': + self.return_error("Revision is not allowed in context if statement object is not an Activity") + + if 'platform' in context: + # Check platform is string + if not isinstance(context['platform'], basestring): + self.return_error("Context platform must be a string") + + if object_type != 'Activity': + self.return_error("Platform is not allowed in context if statement object is not an Activity") + + # If language given, ensure it is string + if 'language' in context: + if not isinstance(context['language'], basestring): + self.return_error("Context language must be a string") + + # If statement given, ensure it is a valid StatementRef + if 'statement' in context: + self.validate_statementref(context['statement']) + + # If contextActivities given, ensure they are valid contextActivities + if 'contextActivities' in context: + self.validate_context_activities(context['contextActivities']) + + # If extensions, validate + if 'extensions' in context: + self.validate_extensions(context['extensions'], 'context') + + def validate_context_activities(self, conacts): + # Ensure incoming conact is dict + self.check_if_dict(conacts, "Context activity") + context_activity_types = ['parent', 'grouping', 'category', 'other'] + if conacts: + for conact in conacts.items(): + # Check if conact is a valid type + if not conact[0] in context_activity_types: + self.return_error("Context activity type is not valid - %s - must be %s" % (conact[0], ', '.join(context_activity_types))) + # Ensure conact is a list or dict + if isinstance(conact[1], list): + for act in conact[1]: + self.validate_activity(act) + elif isinstance(conact[1], dict): + self.validate_activity(conact[1]) + else: + self.return_error("contextActivities is not formatted correctly") + else: + self.return_error("contextActivities must contain at least one key/value pair") diff --git a/lrs/utils/XAPIVersionHeaderMiddleware.py b/lrs/utils/XAPIVersionHeaderMiddleware.py index 29f88c8b..4a2f5425 100644 --- a/lrs/utils/XAPIVersionHeaderMiddleware.py +++ b/lrs/utils/XAPIVersionHeaderMiddleware.py @@ -3,7 +3,9 @@ from django.conf import settings from django.http import HttpResponseBadRequest + class XAPIVersionHeader(object): + def process_request(self, request): try: version = request.META['X-Experience-API-Version'] @@ -36,7 +38,6 @@ def process_request(self, request): else: return HttpResponseBadRequest("X-Experience-API-Version header missing") - def process_response(self, request, response): response['X-Experience-API-Version'] = settings.XAPI_VERSION return response diff --git a/lrs/utils/__init__.py b/lrs/utils/__init__.py index 6250a959..5c213567 100644 --- a/lrs/utils/__init__.py +++ b/lrs/utils/__init__.py @@ -11,12 +11,14 @@ from ..exceptions import ParamError agent_ifps_can_only_be_one = ['mbox', 'mbox_sha1sum', 'openid', 'account'] + + def get_agent_ifp(data): - ifp_sent = [a for a in agent_ifps_can_only_be_one if data.get(a, None) != None] + ifp_sent = [a for a in agent_ifps_can_only_be_one if data.get(a, None) is not None] ifp = ifp_sent[0] ifp_dict = {} - + if not 'account' == ifp: ifp_dict[ifp] = data[ifp] else: @@ -29,6 +31,7 @@ def get_agent_ifp(data): ifp_dict['account_name'] = account['name'] return ifp_dict + def convert_to_utc(timestr): try: date_object = parse_datetime(timestr) @@ -36,6 +39,7 @@ def convert_to_utc(timestr): raise ParamError("There was an error while parsing the date from %s -- Error: %s" % (timestr, e.message)) return date_object + def convert_to_datatype(incoming_data): data = {} # GET data will be non JSON string-have to try literal_eval @@ -50,9 +54,11 @@ def convert_to_datatype(incoming_data): raise e return data + def convert_post_body_to_dict(incoming_data): qs = urlparse.parse_qsl(urllib.unquote_plus(incoming_data)) - return dict((k,v) for k, v in qs) + return dict((k, v) for k, v in qs) + def get_lang(langdict, lang): if lang: @@ -61,11 +67,12 @@ def get_lang(langdict, lang): else: # Return where key = lang try: - return {lang:langdict[lang]} + return {lang: langdict[lang]} except KeyError: pass - first = langdict.iteritems().next() - return {first[0]:first[1]} + first = langdict.iteritems().next() + return {first[0]: first[1]} + def autoregister(*app_list): for app_name in app_list: @@ -74,4 +81,4 @@ def autoregister(*app_list): try: admin.site.register(model) except AlreadyRegistered: - pass \ No newline at end of file + pass diff --git a/lrs/utils/authorization.py b/lrs/utils/authorization.py index d367213c..d5f79fc1 100755 --- a/lrs/utils/authorization.py +++ b/lrs/utils/authorization.py @@ -13,35 +13,38 @@ from oauth2_provider.provider.oauth2.models import Client # A decorator, that can be used to authenticate some requests at the site. + + def auth(func): @wraps(func) def inner(request, *args, **kwargs): # Note: The cases involving OAUTH_ENABLED are here if OAUTH_ENABLED is switched from true to false - # after a client has performed the handshake. (Not likely to happen, but could) + # after a client has performed the handshake. (Not likely to happen, but could) auth_type = request['auth']['type'] # There is an http auth_type request if auth_type == 'http': http_auth_helper(request) - elif auth_type == 'oauth' and settings.OAUTH_ENABLED: + elif auth_type == 'oauth' and settings.OAUTH_ENABLED: oauth_helper(request) elif auth_type == 'oauth2' and settings.OAUTH_ENABLED: oauth_helper(request, 2) # There is an oauth auth_type request and oauth is not enabled - elif (auth_type == 'oauth' or auth_type == 'oauth2') and not settings.OAUTH_ENABLED: + elif (auth_type == 'oauth' or auth_type == 'oauth2') and not settings.OAUTH_ENABLED: raise BadRequest("OAuth is not enabled. To enable, set the OAUTH_ENABLED flag to true in settings") return func(request, *args, **kwargs) return inner + def get_user_from_auth(auth): if not auth: return None - if type(auth) == User: - return auth #it is a User already + if type(auth) == User: + return auth # it is a User already else: oauth = 1 # it's a group.. gotta find out which of the 2 members is the client for member in auth.member.all(): - if member.account_name: + if member.account_name: key = member.account_name if 'oauth2' in member.account_homePage.lower(): oauth = 2 @@ -53,6 +56,7 @@ def get_user_from_auth(auth): user = Client.objects.get(client_id__exact=key).user return user + def validate_oauth_scope(req_dict): method = req_dict['method'] endpoint = req_dict['auth']['endpoint'] @@ -61,44 +65,44 @@ def validate_oauth_scope(req_dict): err_msg = "Incorrect permissions to %s at %s" % (str(method), str(endpoint)) - validator = {'GET':{"/statements": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, - "/statements/more": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, - "/activities": True if 'all' in scopes or 'all/read' in scopes else False, - "/activities/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False, - "/activities/state": True if 'all' in scopes or 'all/read' in scopes or 'state' in scopes else False, - "/agents": True if 'all' in scopes or 'all/read' in scopes else False, - "/agents/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False - }, - 'HEAD':{"/statements": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, - "/statements/more": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, - "/activities": True if 'all' in scopes or 'all/read' in scopes else False, - "/activities/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False, - "/activities/state": True if 'all' in scopes or 'all/read' in scopes or 'state' in scopes else False, - "/agents": True if 'all' in scopes or 'all/read' in scopes else False, - "/agents/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False - }, - 'PUT':{"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, - "/activities": True if 'all' in scopes or 'define' in scopes else False, - "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, - "/activities/state": True if 'all' in scopes or 'state' in scopes else False, - "/agents": True if 'all' in scopes or 'define' in scopes else False, - "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False - }, - 'POST':{"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, - "/activities": True if 'all' in scopes or 'define' in scopes else False, - "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, - "/activities/state": True if 'all' in scopes or 'state' in scopes else False, - "/agents": True if 'all' in scopes or 'define' in scopes else False, - "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False - }, - 'DELETE':{"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, - "/activities": True if 'all' in scopes or 'define' in scopes else False, - "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, - "/activities/state": True if 'all' in scopes or 'state' in scopes else False, - "/agents": True if 'all' in scopes or 'define' in scopes else False, - "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False - } - } + validator = {'GET': {"/statements": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, + "/statements/more": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, + "/activities": True if 'all' in scopes or 'all/read' in scopes else False, + "/activities/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False, + "/activities/state": True if 'all' in scopes or 'all/read' in scopes or 'state' in scopes else False, + "/agents": True if 'all' in scopes or 'all/read' in scopes else False, + "/agents/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False + }, + 'HEAD': {"/statements": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, + "/statements/more": True if 'all' in scopes or 'all/read' in scopes or 'statements/read' in scopes or 'statements/read/mine' in scopes else False, + "/activities": True if 'all' in scopes or 'all/read' in scopes else False, + "/activities/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False, + "/activities/state": True if 'all' in scopes or 'all/read' in scopes or 'state' in scopes else False, + "/agents": True if 'all' in scopes or 'all/read' in scopes else False, + "/agents/profile": True if 'all' in scopes or 'all/read' in scopes or 'profile' in scopes else False + }, + 'PUT': {"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, + "/activities": True if 'all' in scopes or 'define' in scopes else False, + "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, + "/activities/state": True if 'all' in scopes or 'state' in scopes else False, + "/agents": True if 'all' in scopes or 'define' in scopes else False, + "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False + }, + 'POST': {"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, + "/activities": True if 'all' in scopes or 'define' in scopes else False, + "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, + "/activities/state": True if 'all' in scopes or 'state' in scopes else False, + "/agents": True if 'all' in scopes or 'define' in scopes else False, + "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False + }, + 'DELETE': {"/statements": True if 'all' in scopes or 'statements/write' in scopes else False, + "/activities": True if 'all' in scopes or 'define' in scopes else False, + "/activities/profile": True if 'all' in scopes or 'profile' in scopes else False, + "/activities/state": True if 'all' in scopes or 'state' in scopes else False, + "/agents": True if 'all' in scopes or 'define' in scopes else False, + "/agents/profile": True if 'all' in scopes or 'profile' in scopes else False + } + } # Raise forbidden if requesting wrong endpoint or with wrong method than what's in scope if not validator[method][endpoint]: @@ -114,8 +118,9 @@ def validate_oauth_scope(req_dict): else: req_dict['auth']['define'] = False + def http_auth_helper(request): - if request['headers'].has_key('Authorization'): + if "Authorization" in request['headers']: auth = request['headers']['Authorization'].split() if len(auth) == 2: if auth[0].lower() == 'basic': @@ -133,7 +138,7 @@ def http_auth_helper(request): # If the user successfully logged in, then add/overwrite # the user object of this request. request['auth']['user'] = user - request['auth']['agent'] = Agent.objects.retrieve_or_create(**{'name':user.username, 'mbox':'mailto:%s' % user.email, 'objectType': 'Agent'})[0] + request['auth']['agent'] = Agent.objects.retrieve_or_create(**{'name': user.username, 'mbox': 'mailto:%s' % user.email, 'objectType': 'Agent'})[0] else: raise Unauthorized("Authorization failed, please verify your username and password") request['auth']['define'] = True @@ -145,6 +150,7 @@ def http_auth_helper(request): # The username/password combo was incorrect, or not provided. raise Unauthorized("Authorization header missing") + def oauth_helper(request, version=1): token = request['auth']['oauth_token'] user = token.user @@ -154,29 +160,29 @@ def oauth_helper(request, version=1): else: user_email = 'mailto:%s' % user.email - if version == 1 : - consumer = token.consumer + if version == 1: + consumer = token.consumer else: consumer = token.client members = [ - { - "account":{ - "name":consumer.key if version == 1 else consumer.client_id, - "homePage":"%s://%s/XAPI/OAuth/token/" % (settings.SITE_SCHEME, str(Site.objects.get_current().domain)) if version == 1 else \ - "%s://%s/XAPI/oauth2/access_token/" % (settings.SITE_SCHEME, str(Site.objects.get_current().domain)) - }, - "objectType": "Agent", - "oauth_identifier": "anonoauth:%s" % consumer.key if version == 1 else consumer.client_id - }, - { - "name":user_name, - "mbox":user_email, - "objectType": "Agent" - } + { + "account": { + "name": consumer.key if version == 1 else consumer.client_id, + "homePage": "%s://%s/XAPI/OAuth/token/" % (settings.SITE_SCHEME, str(Site.objects.get_current().domain)) if version == 1 else + "%s://%s/XAPI/oauth2/access_token/" % (settings.SITE_SCHEME, str(Site.objects.get_current().domain)) + }, + "objectType": "Agent", + "oauth_identifier": "anonoauth:%s" % consumer.key if version == 1 else consumer.client_id + }, + { + "name": user_name, + "mbox": user_email, + "objectType": "Agent" + } ] - kwargs = {"objectType":"Group", "member":members, "oauth_identifier": "anongroup:%s-%s" % (consumer.key if version == 1 else consumer.client_id, user_email)} + kwargs = {"objectType": "Group", "member": members, "oauth_identifier": "anongroup:%s-%s" % (consumer.key if version == 1 else consumer.client_id, user_email)} # create/get oauth group and set in dictionary oauth_group, created = Agent.objects.oauth_group(**kwargs) request['auth']['agent'] = oauth_group request['auth']['user'] = get_user_from_auth(oauth_group) - validate_oauth_scope(request) \ No newline at end of file + validate_oauth_scope(request) diff --git a/lrs/utils/etag.py b/lrs/utils/etag.py index d5c6bc79..90acb739 100644 --- a/lrs/utils/etag.py +++ b/lrs/utils/etag.py @@ -5,12 +5,14 @@ IF_MATCH = "HTTP_IF_MATCH" IF_NONE_MATCH = "HTTP_IF_NONE_MATCH" + def create_tag(resource): return hashlib.sha1(resource).hexdigest() + def get_etag_info(headers, required=True): etag = {} - etag[IF_MATCH] = headers.get(IF_MATCH, None) + etag[IF_MATCH] = headers.get(IF_MATCH, None) if not etag[IF_MATCH]: etag[IF_MATCH] = headers.get('If_Match', None) if not etag[IF_MATCH] and 'If-Match' in headers: @@ -26,6 +28,7 @@ def get_etag_info(headers, required=True): raise MissingEtagInfo("If-Match and If-None-Match headers were missing. One of these headers is required for this request.") return etag + def check_preconditions(request, contents, required=False): try: request_etag = request['headers']['ETAG'] @@ -53,14 +56,20 @@ def check_preconditions(request, contents, required=False): else: raise MissingEtagInfo("If-Match and If-None-Match headers were missing. One of these headers is required for this request.") + class MissingEtagInfo(Conflict): + def __init__(self, msg): self.message = msg + def __str__(self): return repr(self.message) + class EtagPreconditionFail(PreconditionFail): + def __init__(self, msg): self.message = msg + def __str__(self): - return repr(self.message) \ No newline at end of file + return repr(self.message) diff --git a/lrs/utils/jws.py b/lrs/utils/jws.py index 7d40a693..bb45cb43 100644 --- a/lrs/utils/jws.py +++ b/lrs/utils/jws.py @@ -9,12 +9,19 @@ # https://www.dlitz.net/software/pycrypto/api/current/ -fixb64padding = lambda s: s if len(s) % 4 == 0 else s + '=' * (4 - (len(s) % 4)) -rmb64padding = lambda s: s.rstrip('=') + +def fixb64padding(s): + return s if len(s) % 4 == 0 else s + '=' * (4 - (len(s) % 4)) + + +def rmb64padding(s): + return s.rstrip('=') + algs = {"RS256": SHA256, "RS384": SHA384, "RS512": SHA512} + class JWS(object): """ Class used to represent a JSON Web Signature (JWS). @@ -22,14 +29,15 @@ class JWS(object): Only covers the requirements outlined in the Experience API spec. see: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI.md#signature """ + def __init__(self, header=None, payload=None, jws=None): """ Init for a JWS object. - If you want to create a JWS, pass in the header and payload and call + If you want to create a JWS, pass in the header and payload and call :func:`JWS.create`. - If you want to parse and verify a JWS, pass in the JWS and call + If you want to parse and verify a JWS, pass in the JWS and call :func:`JWS.verify`. :param header: @@ -46,7 +54,7 @@ def __init__(self, header=None, payload=None, jws=None): self.jws = jws if self.jws: self._parsejws() - + def verify(self): """ Verifies the JWS Signature can be verified by the public key. @@ -58,7 +66,7 @@ def verify(self): pubkey = self._cert_to_key(self.headerobj['x5c'][0]) except: raise JWSException("Error importing public key") - + verifier = PKCS1_v1_5.new(pubkey) res = verifier.verify(self._hash(), self.jwssignature) if not res: @@ -70,7 +78,7 @@ def create(self, privatekey): """ Creates a JWS using the privatekey string to sign. - :param privatekey: + :param privatekey: String format of the private key to use to sign the JWS Signature Input. """ if not self.jws: @@ -84,15 +92,15 @@ def create(self, privatekey): # encode signature self.encjwssignature = rmb64padding(base64.urlsafe_b64encode(self.jwssignature)) # join 3 - self.jws = '.'.join([self.encheader,self.encpayload,self.encjwssignature]) + self.jws = '.'.join([self.encheader, self.encpayload, self.encjwssignature]) return self.jws def sha2(self, jwsobj=None, alg=None): """ - Hash (SHA256) the JWS according to xAPI attachment rules - for the sha2 attribute. Returns the hexdigest value. If - a parameter isn't provided, this will use the values provided + Hash (SHA256) the JWS according to xAPI attachment rules + for the sha2 attribute. Returns the hexdigest value. If + a parameter isn't provided, this will use the values provided when creating this jws object. :param jwsobj: @@ -121,7 +129,7 @@ def validate(self, stmt): stmtobj = stmt atts = stmtobj.pop('attachments', None) if atts: - atts = [a for a in atts if a.get('usageType',None) != "http://adlnet.gov/expapi/attachments/signature"] + atts = [a for a in atts if a.get('usageType', None) != "http://adlnet.gov/expapi/attachments/signature"] if atts: stmtobj['attachments'] = atts @@ -161,13 +169,13 @@ def _parsejws(self): self.jwssignature = base64.urlsafe_b64decode(fixb64padding(jwsparts[2])) def _hash(self): - return algs[self.headerobj['alg']].new('.'.join([self.encheader,self.encpayload]).encode('ascii')) - + return algs[self.headerobj['alg']].new('.'.join([self.encheader, self.encpayload]).encode('ascii')) + def _cert_to_key(self, cert): # Convert from PEM to DER if not cert.startswith('-----BEGIN CERTIFICATE-----') and not cert.endswith('-----END CERTIFICATE-----'): cert = "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----" % cert - lines = cert.replace(" ",'').split() + lines = cert.replace(" ", '').split() der = a2b_base64(''.join(lines[1:-1])) # Extract subjectPublicKeyInfo field from X.509 certificate (see RFC3280) @@ -183,5 +191,6 @@ def _cert_to_key(self, cert): class JWSException(Exception): """Generic exception class.""" + def __init__(self, message='JWS error occured.'): self.message = message diff --git a/lrs/utils/profile_decorator.py b/lrs/utils/profile_decorator.py index 158861d0..b6ca818a 100644 --- a/lrs/utils/profile_decorator.py +++ b/lrs/utils/profile_decorator.py @@ -3,6 +3,7 @@ PROFILE_LOG_BASE = '/home/ubuntu/Desktop/profiling/profiles/' + def profile_func(filename): """Function/method decorator that will cause only the decorated callable to be profiled and saved to the specified file. @@ -11,6 +12,7 @@ def profile_func(filename): @param filename: The filename to write the profile to.""" if not os.path.isabs(filename): filename = os.path.join(PROFILE_LOG_BASE, filename) + def proffunc(f): def profiled_func(*args, **kwargs): import cProfile @@ -33,4 +35,4 @@ def profiled_func(*args, **kwargs): return retval return profiled_func - return proffunc \ No newline at end of file + return proffunc diff --git a/lrs/utils/req_parse.py b/lrs/utils/req_parse.py index e219327a..480fd91b 100644 --- a/lrs/utils/req_parse.py +++ b/lrs/utils/req_parse.py @@ -19,7 +19,8 @@ from oauth_provider.store import store from oauth2_provider.provider.oauth2.models import AccessToken -att_cache = get_cache('attachment_cache') +att_cache = get_cache('attachment_cache') + def parse(request, more_id=None): # Parse request into body, headers, and params @@ -30,7 +31,7 @@ def parse(request, more_id=None): r_dict['auth'] = {} if 'Authorization' in r_dict['headers']: # OAuth will always be dict, not http auth. Set required fields for oauth module and type for authentication module - set_normal_authorization(request, r_dict) + set_normal_authorization(request, r_dict) elif 'Authorization' in request.body or 'HTTP_AUTHORIZATION' in request.body: # Authorization could be passed into body if cross origin request # CORS OAuth not currently supported... @@ -46,7 +47,7 @@ def parse(request, more_id=None): # Just parse body for all non IE CORS stuff else: parse_normal_request(request, r_dict) - + # Set method if not already set # CORS request will already be set - don't reset if 'method' not in r_dict: @@ -61,7 +62,7 @@ def parse(request, more_id=None): if not ('actor' in r_dict['body'] and 'verb' in r_dict['body'] and 'object' in r_dict['body']): # If body keys are in get params - GET - else invalid request if set(r_dict['body'].keys()).issubset(['statementId', 'voidedStatementId', 'agent', 'verb', 'activity', 'registration', - 'related_activities', 'related_agents', 'since', 'until', 'limit', 'format', 'attachments', 'ascending']): + 'related_activities', 'related_agents', 'since', 'until', 'limit', 'format', 'attachments', 'ascending']): r_dict['method'] = 'GET' else: raise BadRequest("Statement is missing actor, verb, or object") @@ -72,7 +73,7 @@ def parse(request, more_id=None): else: r_dict['method'] = 'GET' else: - # CORS request will already be set - don't reset + # CORS request will already be set - don't reset if 'method' not in r_dict: r_dict['method'] = request.method # Set if someone is hitting the statements/more endpoint @@ -80,10 +81,11 @@ def parse(request, more_id=None): r_dict['more_id'] = more_id return r_dict + def set_cors_authorization(request, r_dict): # Not allowed to set request body so this is just a copy body = convert_post_body_to_dict(request.body) - if 'HTTP_AUTHORIZATION' not in r_dict['headers'] and 'HTTP_AUTHORIZATION' not in r_dict['headers']: + if 'HTTP_AUTHORIZATION' not in r_dict['headers'] and 'HTTP_AUTHORIZATION' not in r_dict['headers']: if 'HTTP_AUTHORIZATION' in body: r_dict['headers']['Authorization'] = body.pop('HTTP_AUTHORIZATION') elif 'Authorization' in body: @@ -93,6 +95,7 @@ def set_cors_authorization(request, r_dict): r_dict['auth']['endpoint'] = get_endpoint(request) r_dict['auth']['type'] = 'http' + def set_normal_authorization(request, r_dict): auth_params = r_dict['headers']['Authorization'] # OAuth1 and basic http auth come in as string @@ -100,7 +103,7 @@ def set_normal_authorization(request, r_dict): if auth_params[:6] == 'OAuth ': oauth_request = get_oauth_request(request) # Returns HttpBadRequest if missing any params - missing = require_params(oauth_request) + missing = require_params(oauth_request) if missing: raise missing @@ -114,7 +117,7 @@ def set_normal_authorization(request, r_dict): # Consumer and token should be clean by now consumer = store.get_consumer(request, oauth_request, oauth_request['oauth_consumer_key']) token = store.get_access_token(request, oauth_request, consumer, oauth_request.get_parameter('oauth_token')) - + # Set consumer and token for authentication piece r_dict['auth']['oauth_consumer'] = consumer r_dict['auth']['oauth_token'] = token @@ -129,13 +132,14 @@ def set_normal_authorization(request, r_dict): raise OauthUnauthorized('Access Token has expired') r_dict['auth']['oauth_token'] = access_token r_dict['auth']['type'] = 'oauth2' - else: + else: r_dict['auth']['type'] = 'http' + def parse_normal_body(request, r_dict): if request.method == 'POST' or request.method == 'PUT': # If it is multipart/mixed we're expecting attachment data (also for signed statements) - if 'multipart/mixed' in r_dict['headers']['CONTENT_TYPE']: + if 'multipart/mixed' in r_dict['headers']['CONTENT_TYPE']: parse_attachment(request, r_dict) # If it's any other content-type try parsing it out else: @@ -155,13 +159,14 @@ def parse_normal_body(request, r_dict): # QueryDict will create {'foo':''} key for any string - does not care if valid query string or not for k, v in r_dict['body'].items(): if not v: - raise BadRequest("Could not parse request body, no value for: %s" % k) + raise BadRequest("Could not parse request body, no value for: %s" % k) else: r_dict['body'] = request.body else: raise BadRequest("No body in request") return r_dict + def parse_cors_request(request, r_dict): # Convert body to dict body = convert_post_body_to_dict(request.body) @@ -180,18 +185,18 @@ def parse_cors_request(request, r_dict): # Convert to dict if data is in form format (foo=bar) r_dict['body'] = QueryDict(str_body).dict() except Exception: - raise BadRequest("Could not parse request body in CORS request") + raise BadRequest("Could not parse request body in CORS request") else: # QueryDict will create {'foo':''} key for any string - does not care if valid query string or not for k, v in r_dict['body'].items(): if not v: - raise BadRequest("Could not parse request body in CORS request, no value for: %s" % k) + raise BadRequest("Could not parse request body in CORS request, no value for: %s" % k) else: r_dict['body'] = str_body # Catch attachments early if 'attachments' in r_dict['body']: raise BadRequest(("Attachments are not supported in cross origin requests since they require a " - "multipart/mixed Content-Type")) + "multipart/mixed Content-Type")) # Remove extra headers from body that we already captured in get_headers body.pop('X-Experience-API-Version', None) @@ -205,24 +210,26 @@ def parse_cors_request(request, r_dict): r_dict['params'].update(body) # Add query string params for k in request.GET: - # make sure the method param goes in the special method spot + # make sure the method param goes in the special method spot if k == 'method': r_dict[k] = request.GET[k].upper() else: r_dict['params'][k] = request.GET[k] - #If it is a CORS PUT OR POST make sure it has content + # If it is a CORS PUT OR POST make sure it has content if (r_dict['method'] == 'PUT' or r_dict['method'] == 'POST') \ - and 'body' not in r_dict: + and 'body' not in r_dict: raise BadRequest("CORS PUT or POST both require content parameter") set_agent_param(r_dict) + def parse_normal_request(request, r_dict): r_dict = parse_normal_body(request, r_dict) # Update dict with any GET data r_dict['params'].update(request.GET.dict()) set_agent_param(r_dict) + def parse_attachment(request, r_dict): # Email library insists on having the multipart header in the body - workaround message = request.body @@ -247,7 +254,7 @@ def parse_attachment(request, r_dict): # Find the signature sha2 from the list attachment values in the statements (there should only be one) if isinstance(r_dict['body'], list): signature_att = list(itertools.chain(*[[a.get('sha2', None) for a in s['attachments'] if a.get('usageType', None) == "http://adlnet.gov/expapi/attachments/signature"] for s in r_dict['body'] if 'attachments' in s])) - else: + else: signature_att = [a.get('sha2', None) for a in r_dict['body']['attachments'] if a.get('usageType', None) == "http://adlnet.gov/expapi/attachments/signature" and 'attachments' in r_dict['body']] # Get all sha2s from the request @@ -263,7 +270,7 @@ def parse_attachment(request, r_dict): if sig not in payload_sha2s: raise BadRequest("Signature attachment is missing from request") else: - raise BadRequest("Signature attachment is missing from request") + raise BadRequest("Signature attachment is missing from request") # We know all sha2s are there so set it and loop through each payload r_dict['payload_sha2s'] = payload_sha2s @@ -288,7 +295,7 @@ def parse_attachment(request, r_dict): att_stmts.append(r_dict['body']) if att_stmts: # find if any of those statements with attachments have a signed statement - signed_stmts = [(s,a) for s in att_stmts for a in s.get('attachments', None) if a['usageType'] == "http://adlnet.gov/expapi/attachments/signature"] + signed_stmts = [(s, a) for s in att_stmts for a in s.get('attachments', None) if a['usageType'] == "http://adlnet.gov/expapi/attachments/signature"] for ss in signed_stmts: attmnt = b64decode(att_cache.get(ss[1]['sha2'])) jws = JWS(jws=attmnt) @@ -298,13 +305,15 @@ def parse_attachment(request, r_dict): except JWSException as jwsx: raise BadRequest(jwsx) + def get_endpoint(request): # Used for OAuth scope endpoint = request.path[5:] # Since we accept with or without / on end if endpoint.endswith("/"): return endpoint[:-1] - return endpoint + return endpoint + def get_headers(headers): header_dict = {} @@ -313,7 +322,7 @@ def get_headers(headers): try: header_dict['updated'] = parse_datetime(headers.pop('HTTP_UPDATED')) except (Exception, ISO8601Error): - raise ParamError("Updated header was not a valid ISO8601 timestamp") + raise ParamError("Updated header was not a valid ISO8601 timestamp") elif 'updated' in headers: try: header_dict['updated'] = parse_datetime(headers.pop('updated')) @@ -347,13 +356,14 @@ def get_headers(headers): # Get xapi version if 'X-Experience-API-Version' in headers: - header_dict['X-Experience-API-Version'] = headers.pop('X-Experience-API-Version') + header_dict['X-Experience-API-Version'] = headers.pop('X-Experience-API-Version') return header_dict + def set_agent_param(r_dict): # Convert agent to dict if get param for statements if 'agent' in r_dict['params'] and r_dict['auth']['endpoint'] == '/statements': try: r_dict['params']['agent'] = convert_to_datatype(r_dict['params']['agent']) except Exception: - raise BadRequest("Agent param was not a valid JSON structure") \ No newline at end of file + raise BadRequest("Agent param was not a valid JSON structure") diff --git a/lrs/utils/req_process.py b/lrs/utils/req_process.py index 7a9c4eda..50596db9 100644 --- a/lrs/utils/req_process.py +++ b/lrs/utils/req_process.py @@ -11,18 +11,19 @@ from retrieve_statement import complex_get, parse_more_request from ..models import Statement, Agent, Activity from ..managers.ActivityProfileManager import ActivityProfileManager -from ..managers.ActivityStateManager import ActivityStateManager +from ..managers.ActivityStateManager import ActivityStateManager from ..managers.AgentProfileManager import AgentProfileManager from ..managers.StatementManager import StatementManager from ..tasks import check_activity_metadata, void_statements + def process_statement(stmt, auth, version, payload_sha2s): # Add id to statement if not present - if not 'id' in stmt: + if 'id' not in stmt: stmt['id'] = str(uuid.uuid1()) # Add version to statement if not present - if not 'version' in stmt: + if 'version' not in stmt: stmt['version'] = version # Convert context activities to list if dict @@ -42,7 +43,7 @@ def process_statement(stmt, auth, version, payload_sha2s): stmt['stored'] = str(datetime.utcnow().replace(tzinfo=utc).isoformat()) # Add stored as timestamp if timestamp not present - if not 'timestamp' in stmt: + if 'timestamp' not in stmt: stmt['timestamp'] = stmt['stored'] # Copy full statement and send off to StatementManager to save @@ -53,9 +54,11 @@ def process_statement(stmt, auth, version, payload_sha2s): return st.statement_id, st.object_statementref return st.statement_id, None + def process_body(stmts, auth, version, payload_sha2s): return [process_statement(st, auth, version, payload_sha2s) for st in stmts] + def process_complex_get(req_dict): mime_type = "application/json" # Parse out params into single dict-GET data not in body @@ -63,11 +66,11 @@ def process_complex_get(req_dict): try: param_dict = req_dict['body'] except KeyError: - pass # no params in the body + pass # no params in the body param_dict.update(req_dict['params']) format = param_dict['format'] - - # Set language if one pull from req_dict since language is from a header, not an arg + + # Set language if one pull from req_dict since language is from a header, not an arg language = None if 'headers' in req_dict and ('format' in param_dict and param_dict['format'] == "canonical"): if 'language' in req_dict['headers']: @@ -94,7 +97,7 @@ def process_complex_get(req_dict): # Create returned stmt list from the req dict stmt_result = complex_get(param_dict, limit, language, format, attachments) - + # Get the length of the response - make sure in string format to count every character if isinstance(stmt_result, dict): content_length = len(json.dumps(stmt_result)) @@ -110,9 +113,10 @@ def process_complex_get(req_dict): if isinstance(stmt_result, dict): stmt_result = json.dumps(stmt_result) - resp = HttpResponse(stmt_result, content_type=mime_type, status=200) + resp = HttpResponse(stmt_result, content_type=mime_type, status=200) return resp, content_length + def statements_post(req_dict): auth = req_dict['auth'] # If single statement, put in list @@ -129,6 +133,7 @@ def statements_post(req_dict): void_statements.delay(stmts_to_void) return HttpResponse(json.dumps([st for st in stmt_ids]), mimetype="application/json", status=200) + def statements_put(req_dict): auth = req_dict['auth'] # Since it is single stmt put in list @@ -137,11 +142,12 @@ def statements_put(req_dict): stmts_to_void = [stmt_tup[1] for stmt_tup in stmt_responses if stmt_tup[1]] check_activity_metadata.delay(stmt_ids) if stmts_to_void: - void_statements.delay(stmts_to_void) + void_statements.delay(stmts_to_void) return HttpResponse("No Content", status=204) + def statements_more_get(req_dict): - stmt_result, attachments = parse_more_request(req_dict['more_id']) + stmt_result, attachments = parse_more_request(req_dict['more_id']) if isinstance(stmt_result, dict): content_length = len(json.dumps(stmt_result)) @@ -159,45 +165,46 @@ def statements_more_get(req_dict): resp = HttpResponse(stmt_result, content_type=mime_type, status=200) else: resp = HttpResponse(json.dumps(stmt_result), content_type=mime_type, status=200) - + # Add consistent header and set content-length try: resp['X-Experience-API-Consistent-Through'] = str(Statement.objects.latest('stored').stored) except: resp['X-Experience-API-Consistent-Through'] = str(datetime.now()) resp['Content-Length'] = str(content_length) - + # If it's a HEAD request if req_dict['method'].lower() != 'get': resp.body = '' return resp + def statements_get(req_dict): stmt_result = {} mime_type = "application/json" # If statementId is in req_dict then it is a single get - can still include attachments # or have a different format - if 'statementId' in req_dict: + if 'statementId' in req_dict: if req_dict['params']['attachments']: resp, content_length = process_complex_get(req_dict) else: st = Statement.objects.get(statement_id=req_dict['statementId']) - + stmt_result = json.dumps(st.to_dict(format=req_dict['params']['format']), sort_keys=False) resp = HttpResponse(stmt_result, content_type=mime_type, status=200) content_length = len(stmt_result) # Complex GET else: resp, content_length = process_complex_get(req_dict) - + # Set consistent through and content length headers for all responses try: resp['X-Experience-API-Consistent-Through'] = str(Statement.objects.latest('stored').stored) except: resp['X-Experience-API-Consistent-Through'] = str(datetime.now()) - - resp['Content-Length'] = str(content_length) + + resp['Content-Length'] = str(content_length) # If it's a HEAD request if req_dict['method'].lower() != 'get': @@ -205,6 +212,7 @@ def statements_get(req_dict): return resp + def build_response(stmt_result): sha2s = [] mime_type = "application/json" @@ -224,7 +232,7 @@ def build_response(stmt_result): # If attachments have payloads if sha2s: # Create multipart message and attach json message to it - string_list =[] + string_list = [] line_feed = "\r\n" boundary = "======ADL_LRS======" string_list.append(line_feed + "--" + boundary + line_feed) @@ -233,7 +241,7 @@ def build_response(stmt_result): string_list.append(json.dumps(stmt_result) + line_feed) else: string_list.append(stmt_result + line_feed) - + for sha2 in sha2s: string_list.append("--" + boundary + line_feed) string_list.append("Content-Type:%s" % str(sha2[2]) + line_feed) @@ -249,8 +257,8 @@ def build_response(stmt_result): except OSError: raise OSError(2, "No such file or directory", sha2[1].name.split("/")[1]) string_list.append("".join(chunks) + line_feed) - - string_list.append("--" + boundary + "--") + + string_list.append("--" + boundary + "--") mime_type = "multipart/mixed; boundary=" + boundary attachment_body = "".join([s for s in string_list]) return attachment_body, mime_type, len(attachment_body) @@ -262,6 +270,7 @@ def build_response(stmt_result): else: return stmt_result, mime_type, len(stmt_result) + def activity_state_post(req_dict): # test ETag for concurrency agent = req_dict['params']['agent'] @@ -270,6 +279,7 @@ def activity_state_post(req_dict): actstate.post_state(req_dict) return HttpResponse("", status=204) + def activity_state_put(req_dict): # test ETag for concurrency agent = req_dict['params']['agent'] @@ -278,6 +288,7 @@ def activity_state_put(req_dict): actstate.put_state(req_dict) return HttpResponse("", status=204) + def activity_state_get(req_dict): # add ETag for concurrency state_id = req_dict['params'].get('stateId', None) @@ -286,7 +297,7 @@ def activity_state_get(req_dict): a = Agent.objects.retrieve(**agent) if not a: response = HttpResponseNotFound("No agent found for activity state") - else: + else: registration = req_dict['params'].get('registration', None) actstate = ActivityStateManager(a) # state id means we want only 1 item @@ -302,13 +313,14 @@ def activity_state_get(req_dict): since = req_dict['params'].get('since', None) resource = actstate.get_state_ids(activity_id, registration, since) response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json") - + # If it's a HEAD request if req_dict['method'].lower() != 'get': response.body = '' return response + def activity_state_delete(req_dict): agent = req_dict['params']['agent'] a = Agent.objects.retrieve(**agent) @@ -320,28 +332,31 @@ def activity_state_delete(req_dict): actstate.delete_state(req_dict) return HttpResponse('', status=204) + def activity_profile_post(req_dict): - #Instantiate ActivityProfile + # Instantiate ActivityProfile ap = ActivityProfileManager() - #Put profile and return 204 response + # Put profile and return 204 response ap.post_profile(req_dict) return HttpResponse('', status=204) + def activity_profile_put(req_dict): - #Instantiate ActivityProfile + # Instantiate ActivityProfile ap = ActivityProfileManager() - #Put profile and return 204 response + # Put profile and return 204 response ap.put_profile(req_dict) return HttpResponse('', status=204) + def activity_profile_get(req_dict): # Instantiate ActivityProfile ap = ActivityProfileManager() # Get profileId and activityId profileId = req_dict['params'].get('profileId', None) if 'params' in req_dict else None activityId = req_dict['params'].get('activityId', None) if 'params' in req_dict else None - - #If the profileId exists, get the profile and return it in the response + + # If the profileId exists, get the profile and return it in the response if profileId: resource = ap.get_profile(profileId, activityId) if resource.profile: @@ -350,33 +365,35 @@ def activity_profile_get(req_dict): except IOError: response = HttpResponseNotFound("Error reading file, could not find: %s" % profileId) else: - response = HttpResponse(resource.json_profile, content_type=resource.content_type) + response = HttpResponse(resource.json_profile, content_type=resource.content_type) response['ETag'] = '"%s"' % resource.etag return response - #Return IDs of profiles stored since profileId was not submitted + # Return IDs of profiles stored since profileId was not submitted since = req_dict['params'].get('since', None) if 'params' in req_dict else None resource = ap.get_profile_ids(activityId, since) response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json") response['since'] = since - + # If it's a HEAD request if req_dict['method'].lower() != 'get': response.body = '' return response + def activity_profile_delete(req_dict): - #Instantiate activity profile + # Instantiate activity profile ap = ActivityProfileManager() # Delete profile and return success ap.delete_profile(req_dict) return HttpResponse('', status=204) + def activities_get(req_dict): activityId = req_dict['params']['activityId'] act = Activity.objects.get(activity_id=activityId, authority__isnull=False) - return_act = json.dumps(act.to_dict('all'), sort_keys=False) + return_act = json.dumps(act.to_dict('all'), sort_keys=False) resp = HttpResponse(return_act, mimetype="application/json", status=200) resp['Content-Length'] = str(len(return_act)) # If it's a HEAD request @@ -385,6 +402,7 @@ def activities_get(req_dict): return resp + def agent_profile_post(req_dict): # test ETag for concurrency agent = req_dict['params']['agent'] @@ -394,6 +412,7 @@ def agent_profile_post(req_dict): return HttpResponse("", status=204) + def agent_profile_put(req_dict): # test ETag for concurrency agent = req_dict['params']['agent'] @@ -403,6 +422,7 @@ def agent_profile_put(req_dict): return HttpResponse("", status=204) + def agent_profile_get(req_dict): # add ETag for concurrency agent = req_dict['params']['agent'] @@ -418,20 +438,21 @@ def agent_profile_get(req_dict): if resource.profile: response = HttpResponse(resource.profile.read(), content_type=resource.content_type) else: - response = HttpResponse(resource.json_profile, content_type=resource.content_type) + response = HttpResponse(resource.json_profile, content_type=resource.content_type) response['ETag'] = '"%s"' % resource.etag return response since = req_dict['params'].get('since', None) if 'params' in req_dict else None resource = ap.get_profile_ids(since) response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json") - + # If it's a HEAD request if req_dict['method'].lower() != 'get': response.body = '' return response + def agent_profile_delete(req_dict): agent = req_dict['params']['agent'] a = Agent.objects.retrieve(**agent) @@ -443,12 +464,13 @@ def agent_profile_delete(req_dict): return HttpResponse('', status=204) + def agents_get(req_dict): - a = Agent.objects.get(**req_dict['agent_ifp']) + a = Agent.objects.get(**req_dict['agent_ifp']) agent_data = json.dumps(a.to_dict_person(), sort_keys=False) resp = HttpResponse(agent_data, mimetype="application/json") resp['Content-Length'] = str(len(agent_data)) # If it's a HEAD request if req_dict['method'].lower() != 'get': resp.body = '' - return resp \ No newline at end of file + return resp diff --git a/lrs/utils/req_validate.py b/lrs/utils/req_validate.py index bf0db595..46176504 100644 --- a/lrs/utils/req_validate.py +++ b/lrs/utils/req_validate.py @@ -9,9 +9,11 @@ from ..models import Statement, Agent, Activity, ActivityState, ActivityProfile, AgentProfile from ..exceptions import ParamConflict, ParamError, Forbidden, NotFound, BadRequest, IDNotFoundError + def check_for_existing_statementId(stmtID): return Statement.objects.filter(statement_id=stmtID).exists() + def check_for_no_other_params_supplied(query_dict): supplied = True if len(query_dict) <= 1: @@ -19,11 +21,13 @@ def check_for_no_other_params_supplied(query_dict): return supplied # Extra agent validation for state and profile -def validate_oauth_state_or_profile_agent(req_dict, endpoint): + + +def validate_oauth_state_or_profile_agent(req_dict, endpoint): ag = req_dict['params']['agent'] token = req_dict['auth']['oauth_token'] scopes = token.scope_to_list() - if not 'all' in scopes: + if 'all' not in scopes: if not isinstance(ag, dict): ag = json.loads(ag) try: @@ -32,12 +36,13 @@ def validate_oauth_state_or_profile_agent(req_dict, endpoint): err_msg = "Agent in %s cannot be found to match user in authorization" % endpoint raise NotFound(err_msg) - if not agent in req_dict['auth']['agent'].member.all(): + if agent not in req_dict['auth']['agent'].member.all(): err_msg = "Authorization doesn't match agent in %s" % endpoint raise Forbidden(err_msg) + def validate_void_statement(void_id): - # Retrieve statement, check if the verb is 'voided' - if not then set the voided flag to true else return error + # Retrieve statement, check if the verb is 'voided' - if not then set the voided flag to true else return error # since you cannot unvoid a statement and should just reissue the statement under a new ID. stmts = Statement.objects.filter(statement_id=void_id) if len(stmts) > 1: @@ -46,7 +51,8 @@ def validate_void_statement(void_id): if stmts[0].voided: err_msg = "Statement with ID: %s is already voided, cannot unvoid. Please re-issue the statement under a new ID." % void_id raise BadRequest(err_msg) - + + def validate_stmt_authority(stmt, auth): # If not validated yet - validate auth first since it supercedes any auth in stmt if auth['agent']: @@ -58,9 +64,11 @@ def validate_stmt_authority(stmt, auth): err_msg = "OAuth authority must only contain 2 members" raise ParamError(err_msg) + def validate_body(body, auth, payload_sha2s, content_type): - [server_validate_statement(stmt, auth, payload_sha2s, content_type) for stmt in body] - + [server_validate_statement(stmt, auth, payload_sha2s, content_type) for stmt in body] + + def server_validate_statement(stmt, auth, payload_sha2s, content_type): if 'id' in stmt: statement_id = stmt['id'] @@ -76,6 +84,7 @@ def server_validate_statement(stmt, auth, payload_sha2s, content_type): attachment_data = stmt['attachments'] validate_attachments(attachment_data, payload_sha2s, content_type) + @auth def statements_post(req_dict): if req_dict['params'].keys(): @@ -97,13 +106,15 @@ def statements_post(req_dict): return req_dict + @auth def statements_more_get(req_dict): - if not 'more_id' in req_dict: + if 'more_id' not in req_dict: err_msg = "Missing more_id while trying to hit /more endpoint" raise ParamError(err_msg) return req_dict + def validate_statementId(req_dict): if 'statementId' in req_dict['params'] and 'voidedStatementId' in req_dict['params']: err_msg = "Cannot have both statementId and voidedStatementId in a GET request" @@ -115,7 +126,7 @@ def validate_statementId(req_dict): statementId = req_dict['params']['voidedStatementId'] voided = True - not_allowed = ["agent", "verb", "activity", "registration", + not_allowed = ["agent", "verb", "activity", "registration", "related_activities", "related_agents", "since", "until", "limit", "ascending"] bad_keys = set(not_allowed) & set(req_dict['params'].keys()) @@ -123,7 +134,7 @@ def validate_statementId(req_dict): err_msg = "Cannot have %s in a GET request only 'format' and/or 'attachments' are allowed with 'statementId' and 'voidedStatementId'" % ', '.join(bad_keys) raise ParamError(err_msg) - # Try to retrieve stmt, if DNE then return empty else return stmt info + # Try to retrieve stmt, if DNE then return empty else return stmt info try: st = Statement.objects.get(statement_id=statementId) except Statement.DoesNotExist: @@ -137,7 +148,7 @@ def validate_statementId(req_dict): if mine_only and st.authority.id != auth['agent'].id: err_msg = "Incorrect permissions to view statements" raise Forbidden(err_msg) - + if st.voided != voided: if st.voided: err_msg = 'The requested statement (%s) is voided. Use the "voidedStatementId" parameter to retrieve your statement.' % statementId @@ -147,11 +158,12 @@ def validate_statementId(req_dict): return statementId + @auth def statements_get(req_dict): - rogueparams = set(req_dict['params']) - set(["statementId","voidedStatementId","agent", "verb", "activity", "registration", - "related_activities", "related_agents", "since", - "until", "limit", "format", "attachments", "ascending"]) + rogueparams = set(req_dict['params']) - set(["statementId", "voidedStatementId", "agent", "verb", "activity", "registration", + "related_activities", "related_agents", "since", + "until", "limit", "format", "attachments", "ascending"]) if rogueparams: raise ParamError("The get statements request contained unexpected parameters: %s" % ", ".join(rogueparams)) @@ -160,8 +172,8 @@ def statements_get(req_dict): if req_dict['params']['format'] not in formats: raise ParamError("The format filter value (%s) was not one of the known values: %s" % (req_dict['params']['format'], ','.join(formats))) else: - req_dict['params']['format'] = 'exact' - + req_dict['params']['format'] = 'exact' + # StatementId could be for voided statement as well if 'params' in req_dict and ('statementId' in req_dict['params'] or 'voidedStatementId' in req_dict['params']): req_dict['statementId'] = validate_statementId(req_dict) @@ -189,6 +201,7 @@ def statements_get(req_dict): req_dict['params']['attachments'] = False return req_dict + @auth def statements_put(req_dict): # Find any unexpected parameters @@ -197,7 +210,7 @@ def statements_put(req_dict): raise ParamError("The put statements request contained unexpected parameters: %s" % ", ".join(rogueparams)) # Statement id can must be supplied in query param. If in the body too, it must be the same - if not 'statementId' in req_dict['params']: + if 'statementId' not in req_dict['params']: raise ParamError("Error -- statements - method = %s, but no statementId parameter or ID given in statement" % req_dict['method']) else: statement_id = req_dict['params']['statementId'] @@ -211,7 +224,7 @@ def statements_put(req_dict): # If ids exist in both places, check if they are equal if statement_body_id and statement_id != statement_body_id: raise ParamError("Error -- statements - method = %s, param and body ID both given, but do not match" % req_dict['method']) - + # Set id inside of statement with param id if not statement_body_id: req_dict['body']['id'] = statement_id @@ -231,7 +244,8 @@ def statements_put(req_dict): validate_body([req_dict['body']], req_dict['auth'], req_dict.get('payload_sha2s', None), req_dict['headers']['CONTENT_TYPE']) return req_dict -def validate_attachments(attachment_data, payload_sha2s, content_type): + +def validate_attachments(attachment_data, payload_sha2s, content_type): if "multipart/mixed" in content_type: for attachment in attachment_data: # If the attachment data has a sha2 field, must validate it against the payload data @@ -239,19 +253,20 @@ def validate_attachments(attachment_data, payload_sha2s, content_type): sha2 = attachment['sha2'] # Check if the sha2 field is a key in the payload dict if payload_sha2s: - if not sha2 in payload_sha2s and not 'fileUrl' in attachment: + if sha2 not in payload_sha2s and 'fileUrl' not in attachment: err_msg = "Could not find attachment payload with sha: %s" % sha2 raise ParamError(err_msg) else: - if not 'fileUrl' in attachment: + if 'fileUrl' not in attachment: raise BadRequest("Missing X-Experience-API-Hash field in header") elif "application/json" == content_type: for attachment in attachment_data: - if not 'fileUrl' in attachment: + if 'fileUrl' not in attachment: raise BadRequest("When sending statements with attachments as 'application/json', you must include fileUrl field") else: raise BadRequest('Invalid Content-Type %s when sending statements with attachments' % content_type) + @auth def activity_state_post(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "agent", "stateId", "registration"]) @@ -265,9 +280,9 @@ def activity_state_post(req_dict): err_msg = "Error -- activity_state - method = %s, but activityId parameter is missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'stateId' in req_dict['params']: + if 'stateId' not in req_dict['params']: err_msg = "Error -- activity_state - method = %s, but stateId parameter is missing.." % req_dict['method'] - raise ParamError(err_msg) + raise ParamError(err_msg) if 'registration' in req_dict['params']: validator.validate_uuid(req_dict['params']['registration'], "registration param for activity state") @@ -282,12 +297,12 @@ def activity_state_post(req_dict): else: err_msg = "Error -- activity_state - method = %s, but agent parameter is missing.." % req_dict['method'] raise ParamError(err_msg) - + # Must have body included for state if 'body' not in req_dict: err_msg = "Could not find the state" raise ParamError(err_msg) - + # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': validate_oauth_state_or_profile_agent(req_dict, "state") @@ -295,31 +310,32 @@ def activity_state_post(req_dict): # Check the content type if the document already exists registration = req_dict['params'].get('registration', None) agent = req_dict['params']['agent'] - a = Agent.objects.retrieve_or_create(**agent)[0] + a = Agent.objects.retrieve_or_create(**agent)[0] exists = False if registration: try: s = ActivityState.objects.get(state_id=req_dict['params']['stateId'], agent=a, - activity_id=req_dict['params']['activityId'], registration_id=req_dict['params']['registration']) + activity_id=req_dict['params']['activityId'], registration_id=req_dict['params']['registration']) exists = True except ActivityState.DoesNotExist: pass else: try: s = ActivityState.objects.get(state_id=req_dict['params']['stateId'], agent=a, - activity_id=req_dict['params']['activityId']) + activity_id=req_dict['params']['activityId']) exists = True except ActivityState.DoesNotExist: pass if exists: - if str(s.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or \ - req_dict['headers']['CONTENT_TYPE'] != "application/json"): + if str(s.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or + req_dict['headers']['CONTENT_TYPE'] != "application/json"): raise ParamError("Neither original document or document to be posted has a Content-Type of 'application/json'") # Set state req_dict['state'] = req_dict.pop('raw_body', req_dict.pop('body', None)) return req_dict + @auth def activity_state_put(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "agent", "stateId", "registration"]) @@ -333,9 +349,9 @@ def activity_state_put(req_dict): err_msg = "Error -- activity_state - method = %s, but activityId parameter is missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'stateId' in req_dict['params']: + if 'stateId' not in req_dict['params']: err_msg = "Error -- activity_state - method = %s, but stateId parameter is missing.." % req_dict['method'] - raise ParamError(err_msg) + raise ParamError(err_msg) if 'registration' in req_dict['params']: validator.validate_uuid(req_dict['params']['registration'], "registration param for activity state") @@ -350,12 +366,12 @@ def activity_state_put(req_dict): else: err_msg = "Error -- activity_state - method = %s, but agent parameter is missing.." % req_dict['method'] raise ParamError(err_msg) - + # Must have body included for state if 'body' not in req_dict: err_msg = "Could not find the state" raise ParamError(err_msg) - + # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': validate_oauth_state_or_profile_agent(req_dict, "state") @@ -364,6 +380,7 @@ def activity_state_put(req_dict): req_dict['state'] = req_dict.pop('raw_body', req_dict.pop('body', None)) return req_dict + @auth def activity_state_get(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "agent", "stateId", "registration", "since"]) @@ -397,12 +414,12 @@ def activity_state_get(req_dict): except (Exception, ISO8601Error): raise ParamError("Since parameter was not a valid ISO8601 timestamp") - # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': - validate_oauth_state_or_profile_agent(req_dict, "state") + validate_oauth_state_or_profile_agent(req_dict, "state") return req_dict + @auth def activity_state_delete(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "agent", "stateId", "registration"]) @@ -429,12 +446,13 @@ def activity_state_delete(req_dict): else: err_msg = "Error -- activity_state - method = %s, but agent parameter is missing.." % req_dict['method'] raise ParamError(err_msg) - + # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': validate_oauth_state_or_profile_agent(req_dict, "state") return req_dict + @auth def activity_profile_post(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "profileId"]) @@ -448,31 +466,32 @@ def activity_profile_post(req_dict): err_msg = "Error -- activity_profile - method = %s, but activityId parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- activity_profile - method = %s, but profileId parameter missing.." % req_dict['method'] raise ParamError(err_msg) - + if 'body' not in req_dict: err_msg = "Could not find the profile document" raise ParamError(err_msg) - # Check the content type if the document already exists + # Check the content type if the document already exists exists = False try: - p = ActivityProfile.objects.get(activityId=req_dict['params']['activityId'], - profileId=req_dict['params']['profileId']) + p = ActivityProfile.objects.get(activityId=req_dict['params']['activityId'], + profileId=req_dict['params']['profileId']) exists = True except ActivityProfile.DoesNotExist: pass if exists: - if str(p.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or \ - req_dict['headers']['CONTENT_TYPE'] != "application/json"): + if str(p.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or + req_dict['headers']['CONTENT_TYPE'] != "application/json"): raise ParamError("Neither original document or document to be posted has a Content-Type of 'application/json'") req_dict['profile'] = req_dict.pop('raw_body', req_dict.pop('body', None)) return req_dict + @auth def activity_profile_put(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "profileId"]) @@ -486,10 +505,10 @@ def activity_profile_put(req_dict): err_msg = "Error -- activity_profile - method = %s, but activityId parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- activity_profile - method = %s, but profileId parameter missing.." % req_dict['method'] - raise ParamError(err_msg) - + raise ParamError(err_msg) + if 'body' not in req_dict: err_msg = "Could not find the profile document" raise ParamError(err_msg) @@ -499,6 +518,7 @@ def activity_profile_put(req_dict): req_dict['profile'] = req_dict.pop('raw_body', req_dict.pop('body', None)) return req_dict + @auth def activity_profile_get(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "profileId", "since"]) @@ -520,6 +540,7 @@ def activity_profile_get(req_dict): return req_dict + @auth def activity_profile_delete(req_dict): rogueparams = set(req_dict['params']) - set(["activityId", "profileId"]) @@ -533,12 +554,13 @@ def activity_profile_delete(req_dict): err_msg = "Error -- activity_profile - method = %s, but activityId parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- activity_profile - method = %s, but profileId parameter missing.." % req_dict['method'] - raise ParamError(err_msg) + raise ParamError(err_msg) return req_dict + @auth def activities_get(req_dict): rogueparams = set(req_dict['params']) - set(["activityId"]) @@ -554,12 +576,13 @@ def activities_get(req_dict): # Try to retrieve activity, if DNE then return empty else return activity info try: Activity.objects.get(activity_id=activityId, authority__isnull=False) - except Activity.DoesNotExist: + except Activity.DoesNotExist: err_msg = "No activity found with ID %s" % activityId raise IDNotFoundError(err_msg) return req_dict + @auth def agent_profile_post(req_dict): rogueparams = set(req_dict['params']) - set(["agent", "profileId"]) @@ -578,10 +601,10 @@ def agent_profile_post(req_dict): err_msg = "Error -- agent_profile - method = %s, but agent parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- agent_profile - method = %s, but profileId parameter missing.." % req_dict['method'] raise ParamError(err_msg) - + if 'body' not in req_dict: err_msg = "Could not find the profile document" raise ParamError(err_msg) @@ -589,20 +612,20 @@ def agent_profile_post(req_dict): # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': validate_oauth_state_or_profile_agent(req_dict, "profile") - - # Check the content type if the document already exists + + # Check the content type if the document already exists exists = False agent = req_dict['params']['agent'] - a = Agent.objects.retrieve_or_create(**agent)[0] + a = Agent.objects.retrieve_or_create(**agent)[0] try: - p = AgentProfile.objects.get(profileId=req_dict['params']['profileId'],agent=a) + p = AgentProfile.objects.get(profileId=req_dict['params']['profileId'], agent=a) exists = True except AgentProfile.DoesNotExist: pass if exists: - if str(p.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or \ - req_dict['headers']['CONTENT_TYPE'] != "application/json"): + if str(p.content_type) != "application/json" or ("application/json" not in req_dict['headers']['CONTENT_TYPE'] or + req_dict['headers']['CONTENT_TYPE'] != "application/json"): raise ParamError("Neither original document or document to be posted has a Content-Type of 'application/json'") # Set profile @@ -610,6 +633,7 @@ def agent_profile_post(req_dict): return req_dict + @auth def agent_profile_put(req_dict): rogueparams = set(req_dict['params']) - set(["agent", "profileId"]) @@ -628,10 +652,10 @@ def agent_profile_put(req_dict): err_msg = "Error -- agent_profile - method = %s, but agent parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- agent_profile - method = %s, but profileId parameter missing.." % req_dict['method'] - raise ParamError(err_msg) - + raise ParamError(err_msg) + if 'body' not in req_dict: err_msg = "Could not find the profile document" raise ParamError(err_msg) @@ -642,6 +666,7 @@ def agent_profile_put(req_dict): req_dict['profile'] = req_dict.pop('raw_body', req_dict.pop('body', None)) return req_dict + @auth def agent_profile_get(req_dict): rogueparams = set(req_dict['params']) - set(["agent", "profileId", "since"]) @@ -671,6 +696,7 @@ def agent_profile_get(req_dict): validate_oauth_state_or_profile_agent(req_dict, "profile") return req_dict + @auth def agent_profile_delete(req_dict): rogueparams = set(req_dict['params']) - set(["agent", "profileId"]) @@ -689,22 +715,23 @@ def agent_profile_delete(req_dict): err_msg = "Error -- agent_profile - method = %s, but agent parameter missing.." % req_dict['method'] raise ParamError(err_msg) - if not 'profileId' in req_dict['params']: + if 'profileId' not in req_dict['params']: err_msg = "Error -- agent_profile - method = %s, but profileId parameter missing.." % req_dict['method'] - raise ParamError(err_msg) - + raise ParamError(err_msg) + # Extra validation if oauth if req_dict['auth']['type'] == 'oauth': validate_oauth_state_or_profile_agent(req_dict, "profile") return req_dict + @auth def agents_get(req_dict): rogueparams = set(req_dict['params']) - set(["agent"]) if rogueparams: raise ParamError("The get agent request contained unexpected parameters: %s" % ", ".join(rogueparams)) - try: + try: req_dict['params']['agent'] except KeyError: err_msg = "Error -- agents url, but no agent parameter.. the agent parameter is required" @@ -717,4 +744,4 @@ def agents_get(req_dict): raise IDNotFoundError("Error with Agent. The agent partial did not match any agents on record") req_dict['agent_ifp'] = params - return req_dict \ No newline at end of file + return req_dict diff --git a/lrs/utils/retrieve_statement.py b/lrs/utils/retrieve_statement.py index 3ddff69d..0bded8ed 100644 --- a/lrs/utils/retrieve_statement.py +++ b/lrs/utils/retrieve_statement.py @@ -14,6 +14,7 @@ from ..models import Statement, Agent from ..exceptions import NotFound + def complex_get(param_dict, limit, language, format, attachments): voidQ = Q(voided=False) # keep track if a filter other than time or sequence is used @@ -47,7 +48,7 @@ def complex_get(param_dict, limit, language, format, attachments): reffilter = True agent = None data = param_dict['agent'] - related = 'related_agents' in param_dict and param_dict['related_agents'] + related = 'related_agents' in param_dict and param_dict['related_agents'] agent = Agent.objects.retrieve(**data) if agent: @@ -64,17 +65,17 @@ def complex_get(param_dict, limit, language, format, attachments): me = chain([agent], groups) for a in me: agentQ = agentQ | Q(object_agent=a) | Q(authority=a) \ - | Q(context_instructor=a) | Q(context_team=a) \ - | Q(object_substatement__actor=a) \ - | Q(object_substatement__object_agent=a) \ - | Q(object_substatement__context_instructor=a) \ - | Q(object_substatement__context_team=a) + | Q(context_instructor=a) | Q(context_team=a) \ + | Q(object_substatement__actor=a) \ + | Q(object_substatement__object_agent=a) \ + | Q(object_substatement__context_instructor=a) \ + | Q(object_substatement__context_team=a) verbQ = Q() if 'verb' in param_dict: reffilter = True verbQ = Q(verb__verb_id=param_dict['verb']) - + # activity activityQ = Q() if 'activity' in param_dict: @@ -82,14 +83,14 @@ def complex_get(param_dict, limit, language, format, attachments): activityQ = Q(object_activity__activity_id=param_dict['activity']) if 'related_activities' in param_dict and param_dict['related_activities']: activityQ = activityQ | Q(context_ca_parent__activity_id=param_dict['activity']) \ - | Q(context_ca_grouping__activity_id=param_dict['activity']) \ - | Q(context_ca_category__activity_id=param_dict['activity']) \ - | Q(context_ca_other__activity_id=param_dict['activity']) \ - | Q(object_substatement__object_activity__activity_id=param_dict['activity']) \ - | Q(object_substatement__context_ca_parent__activity_id=param_dict['activity']) \ - | Q(object_substatement__context_ca_grouping__activity_id=param_dict['activity']) \ - | Q(object_substatement__context_ca_category__activity_id=param_dict['activity']) \ - | Q(object_substatement__context_ca_other__activity_id=param_dict['activity']) + | Q(context_ca_grouping__activity_id=param_dict['activity']) \ + | Q(context_ca_category__activity_id=param_dict['activity']) \ + | Q(context_ca_other__activity_id=param_dict['activity']) \ + | Q(object_substatement__object_activity__activity_id=param_dict['activity']) \ + | Q(object_substatement__context_ca_parent__activity_id=param_dict['activity']) \ + | Q(object_substatement__context_ca_grouping__activity_id=param_dict['activity']) \ + | Q(object_substatement__context_ca_category__activity_id=param_dict['activity']) \ + | Q(object_substatement__context_ca_other__activity_id=param_dict['activity']) registrationQ = Q() if 'registration' in param_dict: @@ -99,18 +100,18 @@ def complex_get(param_dict, limit, language, format, attachments): # If want ordered by ascending stored_param = '-stored' if 'ascending' in param_dict and param_dict['ascending']: - stored_param = 'stored' + stored_param = 'stored' - stmtset = Statement.objects.prefetch_related('object_agent','object_activity','object_substatement','actor','verb','context_team','context_instructor','authority', \ - 'context_ca_parent', 'context_ca_grouping', 'context_ca_category', 'context_ca_other') \ + stmtset = Statement.objects.prefetch_related('object_agent', 'object_activity', 'object_substatement', 'actor', 'verb', 'context_team', 'context_instructor', 'authority', + 'context_ca_parent', 'context_ca_grouping', 'context_ca_category', 'context_ca_other') \ .filter(untilQ & sinceQ & authQ & agentQ & verbQ & activityQ & registrationQ) - + stmtset = list(set(stmtset.values_list('statement_id', flat=True))) # only find references when a filter other than - # since, until, or limit was used + # since, until, or limit was used if reffilter: stmtset = stmtset + stmt_ref_search(stmtset, untilQ, sinceQ) - + # Calculate limit of stmts to return return_limit = set_limit(limit) @@ -122,6 +123,7 @@ def complex_get(param_dict, limit, language, format, attachments): else: return create_under_limit_stmt_result(stmtset, stored_param, language, format) + def stmt_ref_search(stmt_list, untilQ, sinceQ): # find statements where ids in list are used in other statements' objects, context, substatements, and substatement context stmtreflist = list(Statement.objects.filter(Q(object_statementref__in=stmt_list) & untilQ & sinceQ).values_list('statement_id', flat=True)) @@ -131,13 +133,15 @@ def stmt_ref_search(stmt_list, untilQ, sinceQ): # get the statements that have a statement ref_id in the stmtreflist, recurse return stmtreflist + list(set(stmt_ref_search(Statement.objects.filter(Q(object_statementref__in=stmt_list) & untilQ & sinceQ).values_list('statement_id', flat=True), - untilQ, sinceQ))) + untilQ, sinceQ))) + def set_limit(req_limit): if not req_limit or req_limit > settings.SERVER_STMT_LIMIT: req_limit = settings.SERVER_STMT_LIMIT return req_limit + def create_under_limit_stmt_result(stmt_set, stored, language, format): stmt_result = {} if stmt_set: @@ -146,14 +150,15 @@ def create_under_limit_stmt_result(stmt_set, stored, language, format): if format == 'exact': stmt_result = '{"statements": [%s], "more": ""}' % ",".join([json.dumps(stmt.full_statement, sort_keys=False) for stmt in stmt_set.order_by(stored)]) else: - stmt_result['statements'] = [stmt.to_dict(language, format) for stmt in \ - stmt_set.order_by(stored)] + stmt_result['statements'] = [stmt.to_dict(language, format) for stmt in + stmt_set.order_by(stored)] stmt_result['more'] = "" else: stmt_result['statements'] = [] stmt_result['more'] = "" return stmt_result + def create_cache_key(stmt_list): # Create unique hash data to use for the cache key hash_data = [] @@ -164,6 +169,7 @@ def create_cache_key(stmt_list): key = hashlib.md5(bencode.bencode(hash_data)).hexdigest() return key + def create_over_limit_stmt_result(stmt_list, stored, limit, language, format, attachments): from ..views import statements_more_placeholder # First time someone queries POST/GET @@ -189,24 +195,25 @@ def create_over_limit_stmt_result(stmt_list, stored, limit, language, format, at cache_list.append(language) cache_list.append(format) cache_list.append(stored) - + # Encode data encoded_info = json.dumps(cache_list) # Save encoded_dict in cache - cache.set(cache_key,encoded_info) + cache.set(cache_key, encoded_info) # Return first page of results if format == 'exact': - result = '{"statements": [%s], "more": "%s"}' % (",".join([json.dumps(stmt.full_statement, sort_keys=False) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(1).object_list).order_by(stored)]), - reverse(statements_more_placeholder).lower() + "/" + cache_key) + result = '{"statements": [%s], "more": "%s"}' % (",".join([json.dumps(stmt.full_statement, sort_keys=False) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(1).object_list).order_by(stored)]), + reverse(statements_more_placeholder).lower() + "/" + cache_key) else: - result['statements'] = [stmt.to_dict(language, format) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(1).object_list).order_by(stored)] - result['more'] = "%s/%s" % (reverse(statements_more_placeholder).lower(), cache_key) + result['statements'] = [stmt.to_dict(language, format) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(1).object_list).order_by(stored)] + result['more'] = "%s/%s" % (reverse(statements_more_placeholder).lower(), cache_key) return result -def parse_more_request(req_id): + +def parse_more_request(req_id): # Retrieve encoded info for statements encoded_info = cache.get(req_id) # Could have expired or never existed @@ -232,6 +239,8 @@ def parse_more_request(req_id): # Gets called from req_process after complex_get with list of django objects and also gets called from parse_more_request when # more_id is used so list will be serialized + + def build_statement_result(more_id, **data): from ..views import statements_more_placeholder result = {} @@ -241,11 +250,11 @@ def build_statement_result(more_id, **data): stmt_pager = Paginator(data["stmt_list"], data["limit"]) # Return first page of results if data["format"] == 'exact': - result = '{"statements": [%s], "more": ""}' % ",".join([json.dumps(stmt.to_dict(data["language"], data["format"]), sort_keys=False) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])]) + result = '{"statements": [%s], "more": ""}' % ",".join([json.dumps(stmt.to_dict(data["language"], data["format"]), sort_keys=False) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])]) else: - result['statements'] = [stmt.to_dict(data["language"], data["format"]) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])] + result['statements'] = [stmt.to_dict(data["language"], data["format"]) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])] result['more'] = "" # Set current page back for when someone hits the URL again current_page -= 1 @@ -263,13 +272,13 @@ def build_statement_result(more_id, **data): cache_key = create_cache_key(data["stmt_list"]) # Return first page of results if data["format"] == 'exact': - result = '{"statements": [%s], "more": "%s"}' % (",".join([json.dumps(stmt.to_dict(data["language"], data["format"]), sort_keys=False) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])]), - reverse(statements_more_placeholder).lower() + "/" + cache_key) + result = '{"statements": [%s], "more": "%s"}' % (",".join([json.dumps(stmt.to_dict(data["language"], data["format"]), sort_keys=False) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])]), + reverse(statements_more_placeholder).lower() + "/" + cache_key) else: # Set result to have selected page of stmts and more endpoint - result['statements'] = [stmt.to_dict(data["language"], data["format"]) for stmt in \ - Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])] + result['statements'] = [stmt.to_dict(data["language"], data["format"]) for stmt in + Statement.objects.filter(id__in=stmt_pager.page(current_page).object_list).order_by(data["stored"])] result['more'] = "%s/%s" % (reverse(statements_more_placeholder).lower(), cache_key) more_cache_list = [] # Increment next page @@ -285,4 +294,4 @@ def build_statement_result(more_id, **data): # Encode info encoded_list = json.dumps(more_cache_list) cache.set(cache_key, encoded_list) - return result \ No newline at end of file + return result diff --git a/lrs/views.py b/lrs/views.py index ac1a7777..b4e8d308 100644 --- a/lrs/views.py +++ b/lrs/views.py @@ -15,11 +15,12 @@ # This uses the lrs logger for LRS specific information logger = logging.getLogger(__name__) + @require_http_methods(["GET", "HEAD"]) def about(request): - lrs_data = { + lrs_data = { "version": settings.XAPI_VERSIONS, - "extensions":{ + "extensions": { "xapi": { "statements": { @@ -38,14 +39,14 @@ def about(request): "activities_state": { "name": "Activities State", - "methods": ["PUT","POST","GET","DELETE", "HEAD"], + "methods": ["PUT", "POST", "GET", "DELETE", "HEAD"], "endpoint": reverse('lrs.views.activity_state'), "description": "Stores, fetches, or deletes the document specified by the given stateId that exists in the context of the specified activity, agent, and registration (if specified).", }, "activities_profile": { "name": "Activities Profile", - "methods": ["PUT","POST","GET","DELETE", "HEAD"], + "methods": ["PUT", "POST", "GET", "DELETE", "HEAD"], "endpoint": reverse('lrs.views.activity_profile'), "description": "Saves/retrieves/deletes the specified profile document in the context of the specified activity.", }, @@ -59,139 +60,148 @@ def about(request): "agents_profile": { "name": "Agent Profile", - "methods": ["PUT","POST","GET","DELETE", "HEAD"], + "methods": ["PUT", "POST", "GET", "DELETE", "HEAD"], "endpoint": reverse('lrs.views.agent_profile'), "description": "Saves/retrieves/deletes the specified profile document in the context of the specified agent.", } } } - } - return HttpResponse(json.dumps(lrs_data), mimetype="application/json", status=200) + } + return HttpResponse(json.dumps(lrs_data), mimetype="application/json", status=200) + @require_http_methods(["GET", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def statements_more(request, more_id): return handle_request(request, more_id) + @require_http_methods(["GET", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def statements_more_placeholder(request): return HttpResponseForbidden("Forbidden") + @require_http_methods(["PUT", "GET", "POST", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def statements(request): return handle_request(request) -@require_http_methods(["PUT","POST","GET","DELETE", "HEAD"]) + +@require_http_methods(["PUT", "POST", "GET", "DELETE", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def activity_state(request): - return handle_request(request) + return handle_request(request) + @require_http_methods(["PUT", "POST", "GET", "DELETE", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def activity_profile(request): return handle_request(request) + @require_http_methods(["GET", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def activities(request): return handle_request(request) -@require_http_methods(["PUT", "POST", "GET", "DELETE", "HEAD"]) + +@require_http_methods(["PUT", "POST", "GET", "DELETE", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def agent_profile(request): return handle_request(request) + @require_http_methods(["GET", "HEAD"]) @decorator_from_middleware(XAPIVersionHeaderMiddleware.XAPIVersionHeader) def agents(request): return handle_request(request) validators = { - reverse(statements).lower() : { - "POST" : req_validate.statements_post, - "GET" : req_validate.statements_get, - "PUT" : req_validate.statements_put, - "HEAD" : req_validate.statements_get + reverse(statements).lower(): { + "POST": req_validate.statements_post, + "GET": req_validate.statements_get, + "PUT": req_validate.statements_put, + "HEAD": req_validate.statements_get }, reverse(statements_more_placeholder).lower(): { - "GET" : req_validate.statements_more_get, - "HEAD" : req_validate.statements_more_get - }, - reverse(activity_state).lower() : { + "GET": req_validate.statements_more_get, + "HEAD": req_validate.statements_more_get + }, + reverse(activity_state).lower(): { "POST": req_validate.activity_state_post, - "PUT" : req_validate.activity_state_put, - "GET" : req_validate.activity_state_get, - "HEAD" : req_validate.activity_state_get, - "DELETE" : req_validate.activity_state_delete + "PUT": req_validate.activity_state_put, + "GET": req_validate.activity_state_get, + "HEAD": req_validate.activity_state_get, + "DELETE": req_validate.activity_state_delete }, - reverse(activity_profile).lower() : { + reverse(activity_profile).lower(): { "POST": req_validate.activity_profile_post, - "PUT" : req_validate.activity_profile_put, - "GET" : req_validate.activity_profile_get, - "HEAD" : req_validate.activity_profile_get, - "DELETE" : req_validate.activity_profile_delete + "PUT": req_validate.activity_profile_put, + "GET": req_validate.activity_profile_get, + "HEAD": req_validate.activity_profile_get, + "DELETE": req_validate.activity_profile_delete }, - reverse(activities).lower() : { - "GET" : req_validate.activities_get, - "HEAD" : req_validate.activities_get + reverse(activities).lower(): { + "GET": req_validate.activities_get, + "HEAD": req_validate.activities_get }, - reverse(agent_profile).lower() : { + reverse(agent_profile).lower(): { "POST": req_validate.agent_profile_post, - "PUT" : req_validate.agent_profile_put, - "GET" : req_validate.agent_profile_get, - "HEAD" : req_validate.agent_profile_get, - "DELETE" : req_validate.agent_profile_delete + "PUT": req_validate.agent_profile_put, + "GET": req_validate.agent_profile_get, + "HEAD": req_validate.agent_profile_get, + "DELETE": req_validate.agent_profile_delete }, - reverse(agents).lower() : { - "GET" : req_validate.agents_get, - "HEAD" : req_validate.agents_get - } + reverse(agents).lower(): { + "GET": req_validate.agents_get, + "HEAD": req_validate.agents_get + } } processors = { - reverse(statements).lower() : { - "POST" : req_process.statements_post, - "GET" : req_process.statements_get, - "HEAD" : req_process.statements_get, - "PUT" : req_process.statements_put + reverse(statements).lower(): { + "POST": req_process.statements_post, + "GET": req_process.statements_get, + "HEAD": req_process.statements_get, + "PUT": req_process.statements_put }, reverse(statements_more_placeholder).lower(): { - "GET" : req_process.statements_more_get, - "HEAD" : req_process.statements_more_get - }, - reverse(activity_state).lower() : { + "GET": req_process.statements_more_get, + "HEAD": req_process.statements_more_get + }, + reverse(activity_state).lower(): { "POST": req_process.activity_state_post, - "PUT" : req_process.activity_state_put, - "GET" : req_process.activity_state_get, - "HEAD" : req_process.activity_state_get, - "DELETE" : req_process.activity_state_delete + "PUT": req_process.activity_state_put, + "GET": req_process.activity_state_get, + "HEAD": req_process.activity_state_get, + "DELETE": req_process.activity_state_delete }, - reverse(activity_profile).lower() : { + reverse(activity_profile).lower(): { "POST": req_process.activity_profile_post, - "PUT" : req_process.activity_profile_put, - "GET" : req_process.activity_profile_get, - "HEAD" : req_process.activity_profile_get, - "DELETE" : req_process.activity_profile_delete + "PUT": req_process.activity_profile_put, + "GET": req_process.activity_profile_get, + "HEAD": req_process.activity_profile_get, + "DELETE": req_process.activity_profile_delete }, - reverse(activities).lower() : { - "GET" : req_process.activities_get, - "HEAD" : req_process.activities_get + reverse(activities).lower(): { + "GET": req_process.activities_get, + "HEAD": req_process.activities_get }, - reverse(agent_profile).lower() : { + reverse(agent_profile).lower(): { "POST": req_process.agent_profile_post, - "PUT" : req_process.agent_profile_put, - "GET" : req_process.agent_profile_get, - "HEAD" : req_process.agent_profile_get, - "DELETE" : req_process.agent_profile_delete + "PUT": req_process.agent_profile_put, + "GET": req_process.agent_profile_get, + "HEAD": req_process.agent_profile_get, + "DELETE": req_process.agent_profile_delete }, - reverse(agents).lower() : { - "GET" : req_process.agents_get, - "HEAD" : req_process.agents_get - } + reverse(agents).lower(): { + "GET": req_process.agents_get, + "HEAD": req_process.agents_get + } } + @transaction.commit_on_success def handle_request(request, more_id=None): try: @@ -219,7 +229,7 @@ def handle_request(request, more_id=None): return HttpResponse(oauth_err.message, status=400) except Unauthorized as autherr: log_exception(request.path, autherr) - r = HttpResponse(autherr, status = 401) + r = HttpResponse(autherr, status=401) r['WWW-Authenticate'] = 'Basic realm="ADLLRS"' return r except OauthUnauthorized as oauth_err: @@ -245,6 +255,7 @@ def handle_request(request, more_id=None): log_exception(request.path, err) return HttpResponse(err.message, status=500) + def log_exception(path, ex): logger.info("\nException while processing: %s" % path) - logger.exception(ex) \ No newline at end of file + logger.exception(ex) diff --git a/oauth2_provider/provider/__init__.py b/oauth2_provider/provider/__init__.py index aa60386a..1357d8d3 100644 --- a/oauth2_provider/provider/__init__.py +++ b/oauth2_provider/provider/__init__.py @@ -1,2 +1 @@ __version__ = "0.2.6.1" - diff --git a/oauth2_provider/provider/compat/urls.py b/oauth2_provider/provider/compat/urls.py index d3026312..9e50c204 100644 --- a/oauth2_provider/provider/compat/urls.py +++ b/oauth2_provider/provider/compat/urls.py @@ -1,4 +1,4 @@ try: from django.conf.urls import patterns, url, include -except ImportError: # django 1.3 +except ImportError: # django 1.3 from django.conf.urls.defaults import patterns, url, include diff --git a/oauth2_provider/provider/forms.py b/oauth2_provider/provider/forms.py index 9b7fd609..55415efa 100644 --- a/oauth2_provider/provider/forms.py +++ b/oauth2_provider/provider/forms.py @@ -40,6 +40,7 @@ class OAuthForm(forms.Form): The different types of errors are outlined in :rfc:`4.2.2.1` and :rfc:`5.2`. """ + def __init__(self, *args, **kwargs): self.client = kwargs.pop('client', None) super(OAuthForm, self).__init__(*args, **kwargs) diff --git a/oauth2_provider/provider/oauth2/__init__.py b/oauth2_provider/provider/oauth2/__init__.py index 34796220..c17a312e 100644 --- a/oauth2_provider/provider/oauth2/__init__.py +++ b/oauth2_provider/provider/oauth2/__init__.py @@ -3,4 +3,4 @@ import managers import models import urls -import views \ No newline at end of file +import views diff --git a/oauth2_provider/provider/oauth2/backends.py b/oauth2_provider/provider/oauth2/backends.py index db0fb853..e39552cf 100644 --- a/oauth2_provider/provider/oauth2/backends.py +++ b/oauth2_provider/provider/oauth2/backends.py @@ -8,6 +8,7 @@ class BaseBackend(object): Base backend used to authenticate clients as defined in :rfc:`1` against our database. """ + def authenticate(self, request=None): """ Override this method to implement your own authentication backend. @@ -21,6 +22,7 @@ class BasicClientBackend(object): Backend that tries to authenticate a client through HTTP authorization headers as defined in :rfc:`2.3.1`. """ + def authenticate(self, request=None): auth = request.META.get('HTTP_AUTHORIZATION') @@ -49,6 +51,7 @@ class RequestParamsClientBackend(object): Backend that tries to authenticate a client through request parameters which might be in the request body or URI as defined in :rfc:`2.3.1`. """ + def authenticate(self, request=None): if request is None: return None @@ -90,6 +93,6 @@ class AccessTokenBackend(object): def authenticate(self, access_token=None, client=None): try: return AccessToken.objects.get(token=access_token, - expires__gt=now(), client=client) + expires__gt=now(), client=client) except AccessToken.DoesNotExist: return None diff --git a/oauth2_provider/provider/oauth2/forms.py b/oauth2_provider/provider/oauth2/forms.py index e9839e62..05d92ba6 100644 --- a/oauth2_provider/provider/oauth2/forms.py +++ b/oauth2_provider/provider/oauth2/forms.py @@ -36,10 +36,10 @@ def clean(self): data = self.cleaned_data try: client = Client.objects.get(client_id=data.get('client_id'), - client_secret=data.get('client_secret')) + client_secret=data.get('client_secret')) except Client.DoesNotExist: raise forms.ValidationError(_("Client could not be validated with " - "key pair.")) + "key pair.")) data['client'] = client return data @@ -79,14 +79,15 @@ def validate(self, value): if not self.valid_value(val): raise OAuthValidationError({ 'error': 'invalid_request', - 'error_description': _("'%s' is not a valid scope.") % \ - val}) + 'error_description': _("'%s' is not a valid scope.") % + val}) class ScopeMixin(object): """ Form mixin to clean scope fields. """ + def clean_scope(self): """ The scope is assembled by combining all the set flags into a single @@ -146,7 +147,7 @@ def clean_response_type(self): if not response_type: raise OAuthValidationError({'error': 'invalid_request', - 'error_description': "No 'response_type' supplied."}) + 'error_description': "No 'response_type' supplied."}) types = response_type.split(" ") @@ -155,7 +156,7 @@ def clean_response_type(self): raise OAuthValidationError({ 'error': 'unsupported_response_type', 'error_description': u"'%s' is not a supported response " - "type." % type}) + "type." % type}) return response_type @@ -171,7 +172,7 @@ def clean_redirect_uri(self): raise OAuthValidationError({ 'error': 'invalid_request', 'error_description': _("The requested redirect didn't " - "match the client settings.")}) + "match the client settings.")}) return redirect_uri @@ -209,7 +210,7 @@ def clean_refresh_token(self): try: token = RefreshToken.objects.get(token=token, - expired=False, client=self.client) + expired=False, client=self.client) except RefreshToken.DoesNotExist: raise OAuthValidationError({'error': 'invalid_grant'}) @@ -302,7 +303,7 @@ def clean(self): data = self.cleaned_data user = authenticate(username=data.get('username'), - password=data.get('password')) + password=data.get('password')) if user is None: raise OAuthValidationError({'error': 'invalid_grant'}) @@ -331,7 +332,7 @@ def clean(self): except Client.DoesNotExist: raise OAuthValidationError({'error': 'invalid_client'}) - if client.client_type != 1: # public + if client.client_type != 1: # public raise OAuthValidationError({'error': 'invalid_client'}) data['client'] = client diff --git a/oauth2_provider/provider/oauth2/managers.py b/oauth2_provider/provider/oauth2/managers.py index 5521c53f..fe1919f8 100644 --- a/oauth2_provider/provider/oauth2/managers.py +++ b/oauth2_provider/provider/oauth2/managers.py @@ -3,5 +3,6 @@ class AccessTokenManager(models.Manager): + def get_token(self, token): return self.get(token=token, expires__gt=now()) diff --git a/oauth2_provider/provider/oauth2/models.py b/oauth2_provider/provider/oauth2/models.py index 249f7b30..cab58da3 100644 --- a/oauth2_provider/provider/oauth2/models.py +++ b/oauth2_provider/provider/oauth2/models.py @@ -38,7 +38,7 @@ class Client(models.Model): Clients are outlined in the :rfc:`2` and its subsections. """ user = models.ForeignKey(AUTH_USER_MODEL, related_name='oauth2_client', - blank=True, null=True) + blank=True, null=True) name = models.CharField(max_length=255, blank=True) url = models.URLField(help_text="Your application's URL.") redirect_uri = models.URLField(help_text="Your application's callback URL") @@ -136,7 +136,7 @@ class AccessToken(models.Model): expires = models.DateTimeField() # LRS CHANGE - DEFAULT TO FIRST TWO VALUES IN SCOPES WHICH SHOULD BE SET AS STATEMENTS_WRITE AND STATEMENTS_READ_MINE IN settings.py scope = models.IntegerField(default=constants.SCOPES[0][0] | constants.SCOPES[1][0], - choices=constants.SCOPES) + choices=constants.SCOPES) objects = AccessTokenManager() @@ -165,11 +165,12 @@ def get_expire_delta(self, reference=None): reference = timezone.make_aware(reference, timezone.utc) timedelta = expiration - reference - return timedelta.days*86400 + timedelta.seconds + return timedelta.days * 86400 + timedelta.seconds def scope_to_list(self): return to_names(self.scope) + class RefreshToken(models.Model): """ Default refresh token implementation. A refresh token can be swapped for a @@ -186,7 +187,7 @@ class RefreshToken(models.Model): user = models.ForeignKey(AUTH_USER_MODEL) token = models.CharField(max_length=255, default=long_token) access_token = models.OneToOneField(AccessToken, - related_name='refresh_token') + related_name='refresh_token') client = models.ForeignKey(Client) expired = models.BooleanField(default=False) diff --git a/oauth2_provider/provider/oauth2/tests.py b/oauth2_provider/provider/oauth2/tests.py index 53de8af2..25630100 100644 --- a/oauth2_provider/provider/oauth2/tests.py +++ b/oauth2_provider/provider/oauth2/tests.py @@ -19,6 +19,7 @@ @skipIfCustomUser class BaseOAuth2TestCase(TestCase): + def login(self): self.client.login(username='test-user-1', password='test') @@ -260,7 +261,7 @@ def _login_authorize_get_token(self): for prop in required_props: self.assertIn(prop, token, "Access token response missing " - "required property: %s" % prop) + "required property: %s" % prop) return token @@ -284,7 +285,7 @@ def test_fetching_access_token_with_invalid_grant_type(self): self.assertEqual(400, response.status_code) self.assertEqual('unsupported_grant_type', json.loads(response.content)['error'], - response.content) + response.content) def test_fetching_single_access_token(self): constants.SINGLE_ACCESS_TOKEN = True @@ -362,11 +363,11 @@ def test_refreshing_an_access_token(self): self.assertEqual(400, response.status_code) self.assertEqual('invalid_grant', json.loads(response.content)['error'], - response.content) + response.content) def test_password_grant_public(self): c = self.get_client() - c.client_type = 1 # public + c.client_type = 1 # public c.save() response = self.client.post(self.access_token_url(), { @@ -385,7 +386,7 @@ def test_password_grant_public(self): def test_password_grant_confidential(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -401,7 +402,7 @@ def test_password_grant_confidential(self): def test_password_grant_confidential_no_secret(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -415,7 +416,7 @@ def test_password_grant_confidential_no_secret(self): def test_password_grant_invalid_password_public(self): c = self.get_client() - c.client_type = 1 # public + c.client_type = 1 # public c.save() response = self.client.post(self.access_token_url(), { @@ -430,7 +431,7 @@ def test_password_grant_invalid_password_public(self): def test_password_grant_invalid_password_confidential(self): c = self.get_client() - c.client_type = 0 # confidential + c.client_type = 0 # confidential c.save() response = self.client.post(self.access_token_url(), { @@ -476,7 +477,7 @@ def test_access_token_backend(self): backend = AccessTokenBackend() token = AccessToken.objects.create(user=user, client=client) authenticated = backend.authenticate(access_token=token.token, - client=client) + client=client) self.assertIsNotNone(authenticated) @@ -506,9 +507,10 @@ def test_access_token_enforces_SSL(self): class ClientFormTest(TestCase): + def test_client_form(self): form = ClientForm({'name': 'TestName', 'url': 'http://127.0.0.1:8000', - 'redirect_uri': 'http://localhost:8000/'}) + 'redirect_uri': 'http://localhost:8000/'}) self.assertFalse(form.is_valid()) @@ -522,6 +524,7 @@ def test_client_form(self): class ScopeTest(TestCase): + def setUp(self): self._scopes = constants.SCOPES constants.SCOPES = constants.DEFAULT_SCOPES diff --git a/oauth2_provider/provider/oauth2/urls.py b/oauth2_provider/provider/oauth2/urls.py index a3ca7a33..754f99bc 100644 --- a/oauth2_provider/provider/oauth2/urls.py +++ b/oauth2_provider/provider/oauth2/urls.py @@ -40,16 +40,16 @@ urlpatterns = patterns('', - url('^authorize/?$', - login_required(Capture.as_view()), - name='capture'), - url('^authorize/confirm/?$', - login_required(Authorize.as_view()), - name='authorize'), - url('^redirect/?$', - login_required(Redirect.as_view()), - name='redirect'), - url('^access_token/?$', - csrf_exempt(AccessTokenView.as_view()), - name='access_token'), -) + url('^authorize/?$', + login_required(Capture.as_view()), + name='capture'), + url('^authorize/confirm/?$', + login_required(Authorize.as_view()), + name='authorize'), + url('^redirect/?$', + login_required(Redirect.as_view()), + name='redirect'), + url('^access_token/?$', + csrf_exempt(AccessTokenView.as_view()), + name='access_token'), + ) diff --git a/oauth2_provider/provider/oauth2/views.py b/oauth2_provider/provider/oauth2/views.py index e0f5e312..71f77b2a 100644 --- a/oauth2_provider/provider/oauth2/views.py +++ b/oauth2_provider/provider/oauth2/views.py @@ -10,10 +10,12 @@ from .models import Client, RefreshToken, AccessToken from .backends import BasicClientBackend, RequestParamsClientBackend, PublicPasswordBackend + class Capture(Capture): """ Implementation of :class:`provider.views.Capture`. """ + def get_redirect_url(self, request): return reverse('oauth2:authorize') @@ -22,6 +24,7 @@ class Authorize(Authorize): """ Implementation of :class:`provider.views.Authorize`. """ + def get_request_form(self, client, data): return AuthorizationRequestForm(data, client=client) diff --git a/oauth2_provider/provider/scope.py b/oauth2_provider/provider/scope.py index 46c9d4b7..149eafcd 100644 --- a/oauth2_provider/provider/scope.py +++ b/oauth2_provider/provider/scope.py @@ -101,4 +101,4 @@ def to_int(*names, **kwargs): """ return reduce(lambda prev, next: (prev | SCOPE_NAME_DICT.get(next, 0)), - names, kwargs.pop('default', 0)) + names, kwargs.pop('default', 0)) diff --git a/oauth2_provider/provider/sphinx.py b/oauth2_provider/provider/sphinx.py index c93fe81e..7bcfd98b 100644 --- a/oauth2_provider/provider/sphinx.py +++ b/oauth2_provider/provider/sphinx.py @@ -5,6 +5,7 @@ base_url = "http://tools.ietf.org/html/rfc6749" + def rfclink(name, rawtext, text, lineno, inliner, options={}, content=[]): """Link to the OAuth2 draft. @@ -25,6 +26,7 @@ def rfclink(name, rawtext, text, lineno, inliner, options={}, content=[]): return [node], [] + def setup(app): """ Install the plugin. diff --git a/oauth2_provider/provider/tests/test_utils.py b/oauth2_provider/provider/tests/test_utils.py index 72aea0be..112b5f05 100644 --- a/oauth2_provider/provider/tests/test_utils.py +++ b/oauth2_provider/provider/tests/test_utils.py @@ -9,6 +9,7 @@ class UtilsTestCase(TestCase): + def test_serialization(self): class SomeModel(models.Model): dt = models.DateTimeField() @@ -31,5 +32,5 @@ class SomeModel(models.Model): # AssertionError: # datetime.time(10, 6, 28, 705776) != # datetime.time(10, 6, 28, 705000) - self.assertEqual(int(t1.microsecond/1000), - int(t2.microsecond/1000)) + self.assertEqual(int(t1.microsecond / 1000), + int(t2.microsecond / 1000)) diff --git a/oauth2_provider/provider/utils.py b/oauth2_provider/provider/utils.py index fb3a5496..e15cd234 100644 --- a/oauth2_provider/provider/utils.py +++ b/oauth2_provider/provider/utils.py @@ -4,7 +4,7 @@ from django.conf import settings from django.utils import dateparse from django.db.models.fields import (DateTimeField, DateField, - TimeField, FieldDoesNotExist) + TimeField, FieldDoesNotExist) from django.core.serializers.json import DjangoJSONEncoder from .constants import EXPIRE_DELTA, EXPIRE_DELTA_PUBLIC, EXPIRE_CODE_DELTA @@ -18,6 +18,7 @@ except ImportError: timezone = None + def now(): if timezone: return timezone.now() diff --git a/oauth2_provider/provider/views.py b/oauth2_provider/provider/views.py index 49555b79..652a3308 100644 --- a/oauth2_provider/provider/views.py +++ b/oauth2_provider/provider/views.py @@ -49,6 +49,7 @@ class Mixin(object): Mixin providing common methods required in the OAuth view defined in :attr:`provider.views`. """ + def get_data(self, request, key='params'): """ Return stored data from the session store. @@ -113,18 +114,18 @@ def get_redirect_url(self, request): """ raise NotImplementedError - def handle(self, request, data): + def handle(self, request, data): self.cache_data(request, data) if constants.ENFORCE_SECURE and not request.is_secure(): return self.render_to_response({'error': 'access_denied', - 'error_description': _("A secure connection is required."), - 'next': None}, - status=400) + 'error_description': _("A secure connection is required."), + 'next': None}, + status=400) return HttpResponseRedirect(self.get_redirect_url(request)) - def get(self, request): + def get(self, request): return self.handle(request, request.GET) def post(self, request): @@ -158,7 +159,7 @@ def get_redirect_url(self, request): """ :return: ``str`` - The client URL to display in the template after authorization succeeded or failed. - """ + """ raise NotImplementedError def get_request_form(self, client, data): @@ -209,7 +210,7 @@ def _validate_client(self, request, data): raise OAuthError({ 'error': 'unauthorized_client', 'error_description': _("An unauthorized client tried to access" - " your resources.") + " your resources.") }) form = self.get_request_form(client, data) @@ -259,7 +260,7 @@ def handle(self, request, post_data=None): return self.error_response(request, e.args[0], status=400) authorization_form = self.get_authorization_form(request, client, - post_data, data) + post_data, data) if not authorization_form.is_bound or not authorization_form.is_valid(): return self.render_to_response({ @@ -268,7 +269,7 @@ def handle(self, request, post_data=None): 'oauth_data': data, }) code = self.save_authorization(request, client, - authorization_form, data) + authorization_form, data) # be sure to serialize any objects that aren't natively json # serializable because these values are stored as session data @@ -293,13 +294,13 @@ class Redirect(OAuthView, Mixin): """ def error_response(self, error, mimetype='application/json', status=400, - **kwargs): + **kwargs): """ Return an error response to the client with default status code of *400* stating the error as outlined in :rfc:`5.2`. """ return HttpResponse(json.dumps(error), mimetype=mimetype, - status=status, **kwargs) + status=status, **kwargs) def get(self, request): data = self.get_data(request) @@ -458,13 +459,13 @@ def invalidate_access_token(self, access_token): raise NotImplementedError def error_response(self, error, mimetype='application/json', status=400, - **kwargs): + **kwargs): """ Return an error response to the client with default status code of *400* stating the error as outlined in :rfc:`5.2`. """ return HttpResponse(json.dumps(error), mimetype=mimetype, - status=status, **kwargs) + status=status, **kwargs) def access_token_response(self, access_token): """ @@ -497,13 +498,13 @@ def authorization_code(self, request, data, client): :rfc:`4.1.3`. """ grant = self.get_authorization_code_grant(request, request.POST, - client) + client) if constants.SINGLE_ACCESS_TOKEN: at = self.get_access_token(request, grant.user, grant.scope, client) else: at = self.create_access_token(request, grant.user, grant.scope, client) rt = self.create_refresh_token(request, grant.user, grant.scope, at, - client) + client) self.invalidate_grant(grant) @@ -520,7 +521,7 @@ def refresh_token(self, request, data, client): self.invalidate_access_token(rt.access_token) at = self.create_access_token(request, rt.user, rt.access_token.scope, - client) + client) rt = self.create_refresh_token(request, at.user, at.scope, at, client) return self.access_token_response(at) @@ -576,11 +577,11 @@ def post(self, request): 'error': 'invalid_request', 'error_description': _("A secure connection is required.")}) - if not 'grant_type' in request.POST: + if 'grant_type' not in request.POST: return self.error_response({ 'error': 'invalid_request', 'error_description': _("No 'grant_type' included in the " - "request.")}) + "request.")}) grant_type = request.POST['grant_type'] diff --git a/oauth_provider/__init__.py b/oauth_provider/__init__.py index 27a9a3b3..8255a91f 100644 --- a/oauth_provider/__init__.py +++ b/oauth_provider/__init__.py @@ -1,3 +1,2 @@ VERSION = (2, 2, 4) # PEP 386 __version__ = ".".join([str(x) for x in VERSION]) - diff --git a/oauth_provider/admin.py b/oauth_provider/admin.py index 4fa4223b..b5ae4bbb 100644 --- a/oauth_provider/admin.py +++ b/oauth_provider/admin.py @@ -18,4 +18,4 @@ class TokenAdmin(admin.ModelAdmin): # admin.site.register(Scope, ScopeAdmin) admin.site.register(Consumer, ConsumerAdmin) -admin.site.register(Token, TokenAdmin) \ No newline at end of file +admin.site.register(Token, TokenAdmin) diff --git a/oauth_provider/backends.py b/oauth_provider/backends.py index 264de705..706707a3 100644 --- a/oauth_provider/backends.py +++ b/oauth_provider/backends.py @@ -42,4 +42,4 @@ def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: - return None \ No newline at end of file + return None diff --git a/oauth_provider/compat.py b/oauth_provider/compat.py index 5e07caec..defc305f 100644 --- a/oauth_provider/compat.py +++ b/oauth_provider/compat.py @@ -4,7 +4,6 @@ from django.conf.urls import patterns, url, include - # in Django>=1.5 CustomUser models can be specified if django.VERSION >= (1, 5): from django.contrib.auth import get_user_model @@ -21,7 +20,7 @@ import random # fallback for older versions of django (<=1.3). You shouldn't use them get_random_string = lambda length: ''.join([random.choice('abcdefghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(length)]) + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(length)]) try: from django.utils.timezone import now @@ -42,8 +41,9 @@ from django.http import HttpResponse class UnsafeRedirect(HttpResponse): + def __init__(self, url, *args, **kwargs): super(UnsafeRedirect, self).__init__(*args, status=302, **kwargs) self["Location"] = url else: - from django.http import HttpResponseRedirect as UnsafeRedirect \ No newline at end of file + from django.http import HttpResponseRedirect as UnsafeRedirect diff --git a/oauth_provider/consts.py b/oauth_provider/consts.py index 79f1911c..838bf3f8 100644 --- a/oauth_provider/consts.py +++ b/oauth_provider/consts.py @@ -7,7 +7,7 @@ REGULAR_SECRET_SIZE = getattr(settings, 'OAUTH_PROVIDER_REGULAR_SECRET_SIZE', 16) VERIFIER_SIZE = getattr(settings, 'OAUTH_PROVIDER_VERIFIER_SIZE', 10) CONSUMER_KEY_SIZE = getattr(settings, 'OAUTH_PROVIDER_CONSUMER_KEY_SIZE', 256) -MAX_URL_LENGTH = 2083 # http://www.boutell.com/newfaq/misc/urllength.html +MAX_URL_LENGTH = 2083 # http://www.boutell.com/newfaq/misc/urllength.html PENDING = 1 ACCEPTED = 2 @@ -15,7 +15,7 @@ REJECTED = 4 CONSUMER_STATES = ( - (PENDING, _('Pending')), + (PENDING, _('Pending')), (ACCEPTED, _('Accepted')), (CANCELED, _('Canceled')), (REJECTED, _('Rejected')), @@ -23,6 +23,6 @@ PARAMETERS_NAMES = ('consumer_key', 'token', 'signature', 'signature_method', 'timestamp', 'nonce') -OAUTH_PARAMETERS_NAMES = ['oauth_'+s for s in PARAMETERS_NAMES] +OAUTH_PARAMETERS_NAMES = ['oauth_' + s for s in PARAMETERS_NAMES] -OUT_OF_BAND = 'oob' \ No newline at end of file +OUT_OF_BAND = 'oob' diff --git a/oauth_provider/decorators.py b/oauth_provider/decorators.py index 7e3029ec..a3e9cf98 100644 --- a/oauth_provider/decorators.py +++ b/oauth_provider/decorators.py @@ -18,6 +18,7 @@ class CheckOauth(object): CheckOAuth object is used as a method decorator, the view function is properly bound to its instance. """ + def __init__(self, scope_name=None): self.scope_name = scope_name @@ -25,7 +26,7 @@ def __new__(cls, arg=None): if not callable(arg): return super(CheckOauth, cls).__new__(cls) else: - obj = super(CheckOauth, cls).__new__(cls) + obj = super(CheckOauth, cls).__new__(cls) obj.__init__() return obj(arg) @@ -50,8 +51,8 @@ def wrapped_view(request, *args, **kwargs): if not verify_oauth_request(request, oauth_request, consumer, token): return COULD_NOT_VERIFY_OAUTH_REQUEST_RESPONSE - if self.scope_name and (not token.scope - or token.scope.name != self.scope_name): + if self.scope_name and (not token.scope or + token.scope.name != self.scope_name): return INVALID_SCOPE_RESPONSE if token.user: @@ -81,12 +82,12 @@ def check_access_token(self, request): return ('params', 'Could not verify OAuth request.') # LRS CHANGE - SCOPE IS JUST A CHARFIELD NOW - JUST COMPARE THE VALUES - if self.scope_name and (not token.scope - or token.scope != self.scope_name): + if self.scope_name and (not token.scope or + token.scope != self.scope_name): return ('params', 'You are not allowed to access this resource.') if token.user: - request.user = token.user + request.user = token.user return (None, None) -oauth_required = CheckOauth \ No newline at end of file +oauth_required = CheckOauth diff --git a/oauth_provider/forms.py b/oauth_provider/forms.py index 5e94432c..edae4e5c 100644 --- a/oauth_provider/forms.py +++ b/oauth_provider/forms.py @@ -11,9 +11,12 @@ SCOPES_LIST.append((p[1], p[1])) FORM_SCOPES = tuple(SCOPES_LIST) + class MyCheckboxSelectMultiple(forms.CheckboxSelectMultiple): + def render(self, name, value, attrs=None, choices=()): - if value is None: value = [] + if value is None: + value = [] has_id = attrs and 'id' in attrs final_attrs = self.build_attrs(attrs, name=name) output = [u'

'] @@ -36,11 +39,12 @@ def render(self, name, value, attrs=None, choices=()): output.append(u'

') return mark_safe(u'\n'.join(output)) + class AuthorizeRequestTokenForm(forms.Form): scopes = forms.MultipleChoiceField(required=False, initial=FORM_SCOPES[0], - widget=MyCheckboxSelectMultiple(), choices=FORM_SCOPES) - authorize_access = forms.IntegerField(widget=forms.HiddenInput, initial=1) - obj_id = forms.IntegerField(widget=forms.HiddenInput, initial=0) + widget=MyCheckboxSelectMultiple(), choices=FORM_SCOPES) + authorize_access = forms.IntegerField(widget=forms.HiddenInput, initial=1) + obj_id = forms.IntegerField(widget=forms.HiddenInput, initial=0) oauth_token = forms.CharField(widget=forms.HiddenInput) def clean(self): @@ -53,23 +57,23 @@ def clean(self): if "statements/read/mine" in scopes and "statements/read" in scopes: raise forms.ValidationError("'statements/read/mine' and 'statements/read' are conflicting scope values. choose one.") - + # if all is in defaults scopes, any changes must just be limiting scope if "all" in default_scopes: return cleaned - elif "all" in scopes: + elif "all" in scopes: # if all wasn't in default_scopes but it's in scopes, error raise forms.ValidationError("Can't raise permissions beyond what the consumer registered.") - + # if scope and default aren't the same, see if any scope raises permissions if set(scopes) != set(default_scopes): # now we know all isn't in default scope and something changed from defaults # see if the change is ok nomatch = [k for k in scopes if k not in default_scopes] - if not ("all/read" in nomatch or - ("statements/read" in nomatch and "all/read" in default_scopes) or + if not ("all/read" in nomatch or + ("statements/read" in nomatch and "all/read" in default_scopes) or ("statements/read/mine" in nomatch and ("all/read" in default_scopes or "statements/read" in default_scopes))): raise forms.ValidationError("Can't raise permissions beyond what the consumer registered.") - - return cleaned \ No newline at end of file + + return cleaned diff --git a/oauth_provider/managers.py b/oauth_provider/managers.py index aa5138e6..84fe168a 100644 --- a/oauth_provider/managers.py +++ b/oauth_provider/managers.py @@ -2,12 +2,15 @@ # LRS CHANGE - ADDED IS_APPROVED FOR ACCESS_TOKENS BEING CREATED (SHOULD HAVE SAME VALUE AS REQUEST_TOKEN # WHICH AT THIS POINT WILL BE TRUE) + + class TokenManager(models.Manager): + def create_token(self, consumer, token_type, timestamp, scope, - is_approved=False, user=None, callback=None, callback_confirmed=False): + is_approved=False, user=None, callback=None, callback_confirmed=False): """Shortcut to create a token with random key/secret.""" - token, created = self.get_or_create(consumer=consumer, - token_type=token_type, + token, created = self.get_or_create(consumer=consumer, + token_type=token_type, timestamp=timestamp, scope=scope, is_approved=is_approved, @@ -20,4 +23,4 @@ def create_token(self, consumer, token_type, timestamp, scope, token.secret = consumer.secret token.save() token.generate_random_codes() - return token \ No newline at end of file + return token diff --git a/oauth_provider/models.py b/oauth_provider/models.py index d4c616da..d9a82571 100644 --- a/oauth_provider/models.py +++ b/oauth_provider/models.py @@ -18,7 +18,7 @@ class Nonce(models.Model): token_key = models.CharField(max_length=KEY_SIZE) consumer_key = models.CharField(max_length=CONSUMER_KEY_SIZE) key = models.CharField(max_length=255) - timestamp = models.PositiveIntegerField(db_index=True) + timestamp = models.PositiveIntegerField(db_index=True) def __unicode__(self): return u"Nonce %s for %s" % (self.key, self.consumer_key) @@ -46,7 +46,7 @@ def __unicode__(self): class Consumer(models.Model): name = models.CharField(max_length=255) description = models.TextField(blank=True) - + # LRS CHANGE - ADDED DEFAULT SCOPES FOR CONSUMER WHEN FIRST REGISTERED # default_scopes = models.CharField(max_length=100, default="statements/write statements/read/mine") @@ -56,8 +56,8 @@ class Consumer(models.Model): status = models.SmallIntegerField(choices=CONSUMER_STATES, default=PENDING) user = models.ForeignKey(AUTH_USER_MODEL, null=True, blank=True) - xauth_allowed = models.BooleanField("Allow xAuth", default = False) - + xauth_allowed = models.BooleanField("Allow xAuth", default=False) + def __unicode__(self): return u"Consumer %s with key %s" % (self.name, self.key) @@ -77,23 +77,24 @@ def generate_rsa_key(self): return None return RSA.importKey(self.secret) + class Token(models.Model): REQUEST = 1 ACCESS = 2 TOKEN_TYPES = ((REQUEST, u'Request'), (ACCESS, u'Access')) - + key = models.CharField(max_length=KEY_SIZE, null=True, blank=True) secret = models.CharField(max_length=RSA_SECRET_SIZE, null=True, blank=True) token_type = models.SmallIntegerField(choices=TOKEN_TYPES) timestamp = models.IntegerField(default=long(time())) is_approved = models.BooleanField(default=False) - + user = models.ForeignKey(AUTH_USER_MODEL, null=True, blank=True, related_name='tokens') consumer = models.ForeignKey(Consumer) # LRS CHANGE - LRS SCOPES AREN'T RESOURCES # scope = models.ForeignKey(Scope, null=True, blank=True) scope = models.CharField(max_length=100, default="statements/write statements/read/mine") - + @property def resource(self): return self.scope @@ -102,19 +103,19 @@ def resource(self): def resource(self, value): self.scope = value - ## OAuth 1.0a stuff + # OAuth 1.0a stuff verifier = models.CharField(max_length=VERIFIER_SIZE) callback = models.CharField(max_length=MAX_URL_LENGTH, null=True, blank=True) callback_confirmed = models.BooleanField(default=False) - + objects = TokenManager() - + def __unicode__(self): return u"%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer) def to_string(self, only_key=False): token_dict = { - 'oauth_token': self.key, + 'oauth_token': self.key, 'oauth_token_secret': self.secret, 'oauth_callback_confirmed': self.callback_confirmed and 'true' or 'error' } @@ -129,8 +130,8 @@ def to_string(self, only_key=False): def generate_random_codes(self): """ - Used to generate random key/secret pairings. - Use this after you've added the other data in place of save(). + Used to generate random key/secret pairings. + Use this after you've added the other data in place of save(). """ self.key = uuid.uuid4().hex if not self.consumer.rsa_signature: @@ -157,19 +158,19 @@ def get_callback_url(self, args=None): if args is not None: query += "&%s" % urllib.urlencode(args) return urlparse.urlunparse((scheme, netloc, path, params, - query, fragment)) + query, fragment)) args = args is not None and "?%s" % urllib.urlencode(args) or "" return self.callback and self.callback + args def set_callback(self, callback): - if callback != OUT_OF_BAND: # out of band, says "we can't do this!" + if callback != OUT_OF_BAND: # out of band, says "we can't do this!" if check_valid_callback(callback): self.callback = callback self.callback_confirmed = True self.save() else: raise oauth.Error('Invalid callback URL.') - + # LRS CHANGE - ADDED HELPER FUNCTIONS def scope_to_list(self): return self.scope.split(" ") diff --git a/oauth_provider/runtests/manage.py b/oauth_provider/runtests/manage.py index ce154ff5..adf10094 100644 --- a/oauth_provider/runtests/manage.py +++ b/oauth_provider/runtests/manage.py @@ -1,12 +1,13 @@ #!/usr/bin/env python # put django-oauth in PYTHONPATH -import sys, os +import sys +import os sys.path = [os.path.join(os.getcwd(), '../../')] + sys.path from django.core.management import execute_manager try: - import settings # Assumed to be in the same directory. + import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) diff --git a/oauth_provider/runtests/runtests.py b/oauth_provider/runtests/runtests.py index 716db1b2..3a460807 100644 --- a/oauth_provider/runtests/runtests.py +++ b/oauth_provider/runtests/runtests.py @@ -13,6 +13,7 @@ from django.test.utils import get_runner from south.management.commands import patch_for_test_db_setup + def usage(): return """ Usage: python runtests.py [UnitTestClass].[method] diff --git a/oauth_provider/runtests/settings.py b/oauth_provider/runtests/settings.py index 0fee4475..57815640 100644 --- a/oauth_provider/runtests/settings.py +++ b/oauth_provider/runtests/settings.py @@ -6,7 +6,7 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'testdb.sqlite', # Or path to database file if using sqlite3. 'USER': '', # Not used with sqlite3. 'PASSWORD': '', # Not used with sqlite3. @@ -69,4 +69,4 @@ TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' TEST_OUTPUT_VERBOSE = True TEST_OUTPUT_DESCRIPTIONS = True - TEST_OUTPUT_DIR = 'junitxml' \ No newline at end of file + TEST_OUTPUT_DIR = 'junitxml' diff --git a/oauth_provider/runtests/test_app/__init__.py b/oauth_provider/runtests/test_app/__init__.py index 7c68785e..40a96afc 100644 --- a/oauth_provider/runtests/test_app/__init__.py +++ b/oauth_provider/runtests/test_app/__init__.py @@ -1 +1 @@ -# -*- coding: utf-8 -*- \ No newline at end of file +# -*- coding: utf-8 -*- diff --git a/oauth_provider/runtests/test_app/models.py b/oauth_provider/runtests/test_app/models.py index 60a59efe..84fcb6cb 100644 --- a/oauth_provider/runtests/test_app/models.py +++ b/oauth_provider/runtests/test_app/models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django.contrib.auth.models import AbstractUser + class TestUser(AbstractUser): pass diff --git a/oauth_provider/runtests/urls.py b/oauth_provider/runtests/urls.py index 897f9d49..ac0c3516 100644 --- a/oauth_provider/runtests/urls.py +++ b/oauth_provider/runtests/urls.py @@ -3,6 +3,7 @@ from oauth_provider.decorators import oauth_required from oauth_provider.views import protected_resource_example + @oauth_required("some") def resource_some_scope_view(request): return HttpResponse() @@ -14,8 +15,8 @@ def resource_None_scope_view(request): urlpatterns = patterns('', - url(r'^oauth/', include('oauth_provider.urls')), - url(r'^oauth/photo/$', protected_resource_example, name='oauth_example'), - url(r'^oauth/some/$', resource_some_scope_view, name='oauth_resource_some_scope'), - url(r'^oauth/none/$', resource_None_scope_view, name='oauth_resource_None_scope'), -) + url(r'^oauth/', include('oauth_provider.urls')), + url(r'^oauth/photo/$', protected_resource_example, name='oauth_example'), + url(r'^oauth/some/$', resource_some_scope_view, name='oauth_resource_some_scope'), + url(r'^oauth/none/$', resource_None_scope_view, name='oauth_resource_None_scope'), + ) diff --git a/oauth_provider/store/__init__.py b/oauth_provider/store/__init__.py index a6d652a7..ba3d89fa 100644 --- a/oauth_provider/store/__init__.py +++ b/oauth_provider/store/__init__.py @@ -40,6 +40,7 @@ class Store(object): Token itself, `get_consumer_for_request_token` can simply return `request_token.consumer`. """ + def get_consumer(self, request, oauth_request, consumer_key): """ Return the Consumer for `consumer_key` or raise `InvalidConsumerError`. @@ -137,7 +138,7 @@ def get_user_for_access_token(self, request, oauth_request, access_token): def get_user_for_consumer(self, request, oauth_request, consumer): """ Return the associated User for `consumer`. - + `request`: The Django request object. `oauth_request`: The `oauth2.Request` object. `consumer`: The Consumer that made the request. diff --git a/oauth_provider/store/db.py b/oauth_provider/store/db.py index 8597124e..72c50aa4 100644 --- a/oauth_provider/store/db.py +++ b/oauth_provider/store/db.py @@ -9,10 +9,12 @@ NONCE_VALID_PERIOD = getattr(settings, "OAUTH_NONCE_VALID_PERIOD", None) SCOPES = [x[1] for x in settings.OAUTH_SCOPES] + class ModelStore(Store): """ Store implementation using the Django models defined in `piston.models`. """ + def get_consumer(self, request, oauth_request, consumer_key): try: # LRS CHANGE - ADDED STATUS OF CONSUMER TO BE ACCEPTED diff --git a/oauth_provider/tests/__init__.py b/oauth_provider/tests/__init__.py index 7c68785e..40a96afc 100644 --- a/oauth_provider/tests/__init__.py +++ b/oauth_provider/tests/__init__.py @@ -1 +1 @@ -# -*- coding: utf-8 -*- \ No newline at end of file +# -*- coding: utf-8 -*- diff --git a/oauth_provider/tests/auth.py b/oauth_provider/tests/auth.py index f5d5c90e..2711b140 100644 --- a/oauth_provider/tests/auth.py +++ b/oauth_provider/tests/auth.py @@ -18,6 +18,7 @@ class BaseOAuthTestCase(TestCase): + def setUp(self): self.username = 'jane' self.password = 'toto' @@ -29,7 +30,7 @@ def setUp(self): self.CONSUMER_SECRET = 'kd94hf93k423kf44' consumer = self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET, - name='printer.example.com', user=self.jane) + name='printer.example.com', user=self.jane) consumer.save() self.callback_token = self.callback = 'http://printer.example.com/request_token_ready' @@ -51,12 +52,12 @@ def _request_token(self, method=METHOD_URL_QUERY, **parameters_overriden): } parameters.update(parameters_overriden) - if method==METHOD_AUTHORIZATION_HEADER: + if method == METHOD_AUTHORIZATION_HEADER: header = self._get_http_authorization_header(parameters) response = self.c.get("/oauth/request_token/", HTTP_AUTHORIZATION=header) - elif method==METHOD_URL_QUERY: + elif method == METHOD_URL_QUERY: response = self.c.get("/oauth/request_token/", parameters) - elif method==METHOD_POST_REQUEST_BODY: + elif method == METHOD_POST_REQUEST_BODY: body = urllib.urlencode(parameters) response = self.c.post("/oauth/request_token/", body, content_type="application/x-www-form-urlencoded") else: @@ -68,7 +69,7 @@ def _request_token(self, method=METHOD_URL_QUERY, **parameters_overriden): self.assert_( re.match(r'oauth_token_secret=[^&]+&oauth_token=[^&]+&oauth_callback_confirmed=true', response.content - )) + )) token = self.request_token = list(Token.objects.all())[-1] self.assert_(token.key in response.content) @@ -115,12 +116,12 @@ def _access_token(self, method=METHOD_URL_QUERY, **parameters_overriden): } parameters.update(parameters_overriden) - if method==METHOD_AUTHORIZATION_HEADER: + if method == METHOD_AUTHORIZATION_HEADER: header = self._get_http_authorization_header(parameters) response = self.c.get("/oauth/access_token/", HTTP_AUTHORIZATION=header) - elif method==METHOD_URL_QUERY: + elif method == METHOD_URL_QUERY: response = self.c.get("/oauth/access_token/", parameters) - elif method==METHOD_POST_REQUEST_BODY: + elif method == METHOD_POST_REQUEST_BODY: body = urllib.urlencode(parameters) response = self.c.post("/oauth/access_token/", body, content_type="application/x-www-form-urlencoded") else: @@ -138,6 +139,7 @@ def _get_http_authorization_header(self, parameters): authorization_header += ", scope=%s" % self.scope.name return authorization_header + class TestOAuthDifferentAuthorizationMethods(BaseOAuthTestCase): def test_request_token_with_authorization_header(self): @@ -159,4 +161,4 @@ def test_access_token_with_url_query(self): def test_access_token_with_post_request_body(self): self._request_token(METHOD_POST_REQUEST_BODY) - self._authorize_and_access_token_using_form(METHOD_POST_REQUEST_BODY) \ No newline at end of file + self._authorize_and_access_token_using_form(METHOD_POST_REQUEST_BODY) diff --git a/oauth_provider/tests/compat.py b/oauth_provider/tests/compat.py index 20cebb7c..7a855ab2 100644 --- a/oauth_provider/tests/compat.py +++ b/oauth_provider/tests/compat.py @@ -3,6 +3,7 @@ class Issue45ErrorLoadingOauthStoreModule(TestCase): + def test_store_import(self): from oauth_provider.store import store self.assertIsNotNone(store) @@ -12,4 +13,4 @@ def test_import_user_from_compat(self): from oauth_provider.compat import AUTH_USER_MODEL self.assertIsNotNone(get_user_model()) - self.assertIsNotNone(AUTH_USER_MODEL) \ No newline at end of file + self.assertIsNotNone(AUTH_USER_MODEL) diff --git a/oauth_provider/tests/decorators.py b/oauth_provider/tests/decorators.py index 07a37473..2c47a669 100644 --- a/oauth_provider/tests/decorators.py +++ b/oauth_provider/tests/decorators.py @@ -1,4 +1,4 @@ -## -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- import time import urllib from oauth_provider.models import Scope @@ -6,6 +6,7 @@ class OAuthTestOauthRequiredDecorator(BaseOAuthTestCase): + def setUp(self): # create Scope 'all' for all requests without scope specified super(OAuthTestOauthRequiredDecorator, self).setUp() @@ -17,17 +18,17 @@ def _oauth_signed_get(self, url, method=METHOD_URL_QUERY): 'oauth_version': "1.0", 'oauth_token': self.ACCESS_TOKEN_KEY, 'oauth_timestamp': str(int(time.time())), - 'oauth_nonce': str(int(time.time()))+"nonce", + 'oauth_nonce': str(int(time.time())) + "nonce", 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), "additional_data": "whoop", # some additional data - } + } - if method==METHOD_AUTHORIZATION_HEADER: + if method == METHOD_AUTHORIZATION_HEADER: header = self._get_http_authorization_header(parameters) response = self.c.get(url, HTTP_AUTHORIZATION=header) - elif method==METHOD_URL_QUERY: + elif method == METHOD_URL_QUERY: response = self.c.get(url, parameters) - elif method==METHOD_POST_REQUEST_BODY: + elif method == METHOD_POST_REQUEST_BODY: body = urllib.urlencode(parameters) response = self.c.post(url, body, content_type="application/x-www-form-urlencoded") else: @@ -38,9 +39,9 @@ def _oauth_signed_get(self, url, method=METHOD_URL_QUERY): def test_resource_some_scope_view_authorized(self): """Tests view that was created using @oauth_required("some") decorator """ - #ensure there is a Scope object for this scope + # ensure there is a Scope object for this scope self.scope = Scope.objects.create(name="some") - #set scope for requested token + # set scope for requested token self._request_token(scope=self.scope.name) self._authorize_and_access_token_using_form() @@ -61,7 +62,7 @@ def test_resource_None_view(self): """Tests that view created using @oauth_required decorator gives access when requested using token without scope specified """ - #request token without setting scope + # request token without setting scope self._request_token() self._authorize_and_access_token_using_form() @@ -72,7 +73,7 @@ def test_resource_None_scope_view_not_authorized(self): """Tests that view created with @oauth_required decorator won't give access when requested using token with scope!="all" """ - #ensure there is a Scope object for this scope + # ensure there is a Scope object for this scope self.scope = Scope.objects.create(name="some_new_scope") self._request_token(scope=self.scope.name) self._authorize_and_access_token_using_form() @@ -81,7 +82,7 @@ def test_resource_None_scope_view_not_authorized(self): self.assertEqual(response.status_code, 401) def test_get_with_header_auth(self): - #request token without setting scope + # request token without setting scope self._request_token() self._authorize_and_access_token_using_form() @@ -89,7 +90,7 @@ def test_get_with_header_auth(self): self.assertEqual(response.status_code, 200) def test_get_with_url_query_auth(self): - #request token without setting scope + # request token without setting scope self._request_token() self._authorize_and_access_token_using_form() @@ -97,9 +98,9 @@ def test_get_with_url_query_auth(self): self.assertEqual(response.status_code, 200) def test_get_with_request_body_auth(self): - #request token without setting scope + # request token without setting scope self._request_token() self._authorize_and_access_token_using_form() response = self._oauth_signed_get("/oauth/none/", method=METHOD_POST_REQUEST_BODY) - self.assertEqual(response.status_code, 200) \ No newline at end of file + self.assertEqual(response.status_code, 200) diff --git a/oauth_provider/tests/issues.py b/oauth_provider/tests/issues.py index 516d6d2b..adcb5ebb 100644 --- a/oauth_provider/tests/issues.py +++ b/oauth_provider/tests/issues.py @@ -19,6 +19,7 @@ class OAuthTestsBug10(BaseOAuthTestCase): """ See https://code.welldev.org/django-oauth-plus/issue/10/malformed-callback-url-when-user-denies """ + def test_Request_token_request_succeeds_with_valid_request_token_parameters(self): self._request_token() token = self.request_token @@ -47,7 +48,9 @@ def test_Requesting_user_authorization_fails_when_user_denies_authorization(self self.assertEqual('http://printer.example.com/request_token_ready?error=Access+not+granted+by+user.', response['Location']) self.c.logout() + class OAuthOutOfBoundTests(BaseOAuthTestCase): + def test_Requesting_user_authorization_succeeds_when_oob(self): self._request_token(oauth_callback="oob") @@ -59,14 +62,16 @@ def test_Requesting_user_authorization_succeeds_when_oob(self): response.status_code, 200) + class OauthTestIssue24(BaseOAuthTestCase): """ See https://bitbucket.org/david/django-oauth-plus/issue/24/utilspy-initialize_server_request-should """ + def setUp(self): super(OauthTestIssue24, self).setUp() - #setting the access key/secret to made-up strings + # setting the access key/secret to made-up strings self.access_token = Token( key="key", secret="secret", @@ -77,7 +82,6 @@ def setUp(self): ) self.access_token.save() - def __make_querystring_with_HMAC_SHA1(self, http_method, path, data, content_type): """ Utility method for creating a request which is signed using HMAC_SHA1 method @@ -87,10 +91,10 @@ def __make_querystring_with_HMAC_SHA1(self, http_method, path, data, content_typ url = "http://testserver:80" + path - #if data is json, we want it in the body, else as parameters (i.e. queryparams on get) - parameters=None + # if data is json, we want it in the body, else as parameters (i.e. queryparams on get) + parameters = None body = "" - if content_type=="application/json": + if content_type == "application/json": body = data else: parameters = data @@ -119,11 +123,11 @@ def test_that_initialize_server_request_when_custom_content_type(self): content_type = "application/json" querystring = self.__make_querystring_with_HMAC_SHA1("POST", "/path/to/post", data, content_type) - #we're just using the request, don't bother faking sending it + # we're just using the request, don't bother faking sending it rf = RequestFactory() request = rf.post(querystring, data, content_type) - #this is basically a "remake" of the relevant parts of OAuthAuthentication in django-rest-framework + # this is basically a "remake" of the relevant parts of OAuthAuthentication in django-rest-framework oauth_request = utils.get_oauth_request(request) consumer_key = oauth_request.get_parameter('oauth_consumer_key') @@ -134,7 +138,7 @@ def test_that_initialize_server_request_when_custom_content_type(self): oauth_server, oauth_request = utils.initialize_server_request(request) - #check that this does not throw an oauth.Error + # check that this does not throw an oauth.Error oauth_server.verify_request(oauth_request, consumer, token) def test_post_using_in_authorization_header_and_PLAINTEXT(self): @@ -147,9 +151,9 @@ def test_post_using_in_authorization_header_and_PLAINTEXT(self): 'oauth_version': "1.0", 'oauth_token': self.ACCESS_TOKEN_KEY, 'oauth_timestamp': str(int(time.time())), - 'oauth_nonce': str(int(time.time()))+"nonce", + 'oauth_nonce': str(int(time.time())) + "nonce", 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - } + } header = self._get_http_authorization_header(parameters) response = self.c.post("/oauth/photo/", HTTP_AUTHORIZATION=header) @@ -168,12 +172,12 @@ def test_post_using_auth_in_post_body_and_PLAINTEXT(self): 'oauth_version': "1.0", 'oauth_token': self.ACCESS_TOKEN_KEY, 'oauth_timestamp': str(int(time.time())), - 'oauth_nonce': str(int(time.time()))+"nonce", + 'oauth_nonce': str(int(time.time())) + "nonce", 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - "additional_data": "whoop" # additional data - } + "additional_data": "whoop" # additional data + } response = self.c.post("/oauth/photo/", urllib.urlencode(parameters, True), - content_type="application/x-www-form-urlencoded") + content_type="application/x-www-form-urlencoded") self.assertEqual(response.status_code, 200) def test_post_using_auth_in_header_with_content_type_json_and_PLAINTEXT(self): @@ -186,9 +190,9 @@ def test_post_using_auth_in_header_with_content_type_json_and_PLAINTEXT(self): 'oauth_version': "1.0", 'oauth_token': self.ACCESS_TOKEN_KEY, 'oauth_timestamp': str(int(time.time())), - 'oauth_nonce': str(int(time.time()))+"nonce", + 'oauth_nonce': str(int(time.time())) + "nonce", 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - } + } header = self._get_http_authorization_header(parameters) response = self.c.post("/oauth/photo/", HTTP_AUTHORIZATION=header, CONTENT_TYPE="application/json") @@ -203,15 +207,15 @@ def test_post_using_auth_in_body_content_type_and_application_x_www_form_urlenco self._request_token() self._authorize_and_access_token_using_form() - data={"foo": "bar"} + data = {"foo": "bar"} content_type = "application/x-www-form-urlencoded" querystring = self.__make_querystring_with_HMAC_SHA1("POST", "/path/to/post", data, content_type) - #we're just using the request, don't bother faking sending it + # we're just using the request, don't bother faking sending it rf = RequestFactory() request = rf.post(querystring, urllib.urlencode(data), content_type) - #this is basically a "remake" of the relevant parts of OAuthAuthentication in django-rest-framework + # this is basically a "remake" of the relevant parts of OAuthAuthentication in django-rest-framework oauth_request = utils.get_oauth_request(request) consumer_key = oauth_request.get_parameter('oauth_consumer_key') @@ -222,11 +226,12 @@ def test_post_using_auth_in_body_content_type_and_application_x_www_form_urlenco oauth_server, oauth_request = utils.initialize_server_request(request) - #check that this does not throw an oauth.Error + # check that this does not throw an oauth.Error oauth_server.verify_request(oauth_request, consumer, token) class OAuthTestsBug2UrlParseNonHttpScheme(BaseOAuthTestCase): + def test_non_http_url_callback_scheme(self): # @vmihailenco callback example @@ -245,6 +250,7 @@ def test_non_http_url_callback_scheme(self): # assert query part of url is not malformed assert "?q=1&" in response["Location"] + class OAuthTestIssue41XForwardedProto(BaseOAuthTestCase): def setUp(self): @@ -288,7 +294,6 @@ def test_when_same_protocol(self): response = self.c.get(url, **kwargs) self.assertEqual(response.status_code, 200) - def test_when_protocol_mismatch(self): """Test that signature does not vierifies when protocol is diffrent from that which was used for signing request """ @@ -323,7 +328,6 @@ def test_when_x_forwarded_proto_header_has_valid_protocol(self): response = self.c.get(url.replace('https', 'http'), **kwargs) self.assertEqual(response.status_code, 200) - url = "http://testserver/oauth/none/" kwargs = { 'wsgi.url_scheme': "https", @@ -336,6 +340,7 @@ def test_when_x_forwarded_proto_header_has_valid_protocol(self): class OAuthTestIssue16NoncesCheckedAgainstTimestamp(BaseOAuthTestCase): + def test_timestamp_ok(self): self._request_token() self._authorize_and_access_token_using_form() @@ -346,9 +351,9 @@ def test_timestamp_ok(self): 'oauth_version': "1.0", 'oauth_token': self.ACCESS_TOKEN_KEY, 'oauth_timestamp': str(int(time.time())), - 'oauth_nonce': str(int(time.time()))+"nonce1", + 'oauth_nonce': str(int(time.time())) + "nonce1", 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - } + } response = self.c.get("/oauth/photo/", parameters) @@ -368,7 +373,7 @@ def test_timestamp_repeated_nonce(self): 'oauth_timestamp': timestamp, 'oauth_nonce': nonce, 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - } + } response = self.c.get("/oauth/photo/", parameters) self.assertEqual(response.status_code, 200) @@ -380,7 +385,7 @@ def test_timestamp_old_nonce(self): self._request_token() self._authorize_and_access_token_using_form() - #make this nonce older + # make this nonce older timestamp = str(int(datetime.datetime.now().strftime("%s")) - (settings.OAUTH_NONCE_VALID_PERIOD + 1)) nonce = timestamp + "nonce" parameters = { @@ -391,7 +396,7 @@ def test_timestamp_old_nonce(self): 'oauth_timestamp': timestamp, 'oauth_nonce': nonce, 'oauth_signature': "%s&%s" % (self.CONSUMER_SECRET, self.ACCESS_TOKEN_SECRET), - } + } response = self.c.get("/oauth/photo/", parameters) self.assertEqual(response.status_code, 401) @@ -401,6 +406,7 @@ class OAuthTestIssue39(BaseOAuthTestCase): """ See https://bitbucket.org/david/django-oauth-plus/issue/39/request-token-scope-unused. """ + def setUp(self): super(OAuthTestIssue39, self).setUp() Scope.objects.create(name='scope1') @@ -433,6 +439,7 @@ def test_different_token_scopes(self): class OAuthTestIssue44PostRequestBodyInSignature(BaseOAuthTestCase): + def test_POST_with_x_www_form_urlencoded_body_params_and_auth_header(self): """Test issue when user's request has authorization header and uses application/x-www-form-urlencoded content type with some @@ -464,7 +471,6 @@ def test_POST_with_x_www_form_urlencoded_body_params_and_auth_header(self): self.assertEqual(response.status_code, 200) - def test_POST_with_x_www_form_urlencoded_body_params_and_auth_header_unauthorized(self): """Test issue when user's request has authorization header and uses application/x-www-form-urlencoded content type with some @@ -520,4 +526,4 @@ def _make_auth_header_with_HMAC_SHA1(self, http_method, path, get_params, body_p # Sign the request. signature_method = oauth.SignatureMethod_HMAC_SHA1() request.sign_request(signature_method, consumer, token) - return request.to_header() \ No newline at end of file + return request.to_header() diff --git a/oauth_provider/tests/models.py b/oauth_provider/tests/models.py index 7c68785e..40a96afc 100644 --- a/oauth_provider/tests/models.py +++ b/oauth_provider/tests/models.py @@ -1 +1 @@ -# -*- coding: utf-8 -*- \ No newline at end of file +# -*- coding: utf-8 -*- diff --git a/oauth_provider/tests/protocol.py b/oauth_provider/tests/protocol.py index f7f53c9b..e0bdec5c 100644 --- a/oauth_provider/tests/protocol.py +++ b/oauth_provider/tests/protocol.py @@ -15,12 +15,13 @@ class ProtocolExample(BaseOAuthTestCase): """Set of tests, based on ProtocolExample document """ + def _last_created_request_token(self): return list(Token.objects.filter(token_type=Token.REQUEST))[-1] - + def _last_created_access_token(self): return list(Token.objects.filter(token_type=Token.ACCESS))[-1] - + def _update_token_from_db(self, request_token): """Get fresh copy of the token from the DB""" return Token.objects.get(key=request_token.key) @@ -34,7 +35,7 @@ def _make_request_token_parameters(self): 'oauth_nonce': 'requestnonce', 'oauth_version': '1.0', 'oauth_callback': 'http://printer.example.com/request_token_ready', - 'scope': 'photos', # custom argument to specify Protected Resource + 'scope': 'photos', # custom argument to specify Protected Resource } def _make_access_token_parameters(self, token): @@ -71,7 +72,7 @@ def test_returns_invalid_params_empty_request(self): self.assertEqual(response.content, 'Invalid request parameters.') def test_returns_401_wrong_callback(self): - #If you try to put a wrong callback, it will return an error + # If you try to put a wrong callback, it will return an error parameters = self._make_request_token_parameters() parameters['oauth_callback'] = 'wrongcallback' parameters['oauth_nonce'] = 'requestnoncewrongcallback' @@ -374,8 +375,8 @@ def test_positive(self): (using the Signature Base String as text and self.CONSUMER_SECRET as key) """ oauth_request = oauth.Request.from_token_and_callback(access_token, - http_url='http://testserver/oauth/photo/', - parameters=parameters) + http_url='http://testserver/oauth/photo/', + parameters=parameters) signature_method = oauth.SignatureMethod_HMAC_SHA1() signature = signature_method.sign(oauth_request, self.consumer, access_token) diff --git a/oauth_provider/tests/xauth.py b/oauth_provider/tests/xauth.py index 0b5e8d87..efbe5337 100644 --- a/oauth_provider/tests/xauth.py +++ b/oauth_provider/tests/xauth.py @@ -7,6 +7,7 @@ class XAuthTestCase(BaseOAuthTestCase): + def setUp(self): super(XAuthTestCase, self).setUp() self.consumer.xauth_allowed = True @@ -27,12 +28,12 @@ def _accesss_token(self, method=METHOD_URL_QUERY): 'x_auth_username': self.username, } - if method==METHOD_AUTHORIZATION_HEADER: + if method == METHOD_AUTHORIZATION_HEADER: header = self._get_http_authorization_header(parameters) response = self.c.get("/oauth/access_token/", HTTP_AUTHORIZATION=header) - elif method==METHOD_URL_QUERY: + elif method == METHOD_URL_QUERY: response = self.c.get("/oauth/access_token/", parameters) - elif method==METHOD_POST_REQUEST_BODY: + elif method == METHOD_POST_REQUEST_BODY: body = urllib.urlencode(parameters) response = self.c.post("/oauth/access_token/", body, content_type="application/x-www-form-urlencoded") else: @@ -58,4 +59,4 @@ def test_xauth_using_email(self): x_auth_username=self.email) assert self.ACCESS_TOKEN_KEY - assert self.ACCESS_TOKEN_SECRET \ No newline at end of file + assert self.ACCESS_TOKEN_SECRET diff --git a/oauth_provider/urls.py b/oauth_provider/urls.py index bce36462..ac6ba2ed 100644 --- a/oauth_provider/urls.py +++ b/oauth_provider/urls.py @@ -4,12 +4,12 @@ # LRS CHANGE - ADDED SPEC COMPLIANT ENDPOINTS urlpatterns = patterns('', - url(r'^initiate', request_token, name='oauth_request_token'), - url(r'^authorize', user_authorization, name='oauth_user_authorization'), - url(r'^token', access_token, name='oauth_access_token'), -) + url(r'^initiate', request_token, name='oauth_request_token'), + url(r'^authorize', user_authorization, name='oauth_user_authorization'), + url(r'^token', access_token, name='oauth_access_token'), + ) # urlpatterns = patterns('', # url(r'^request_token/$', request_token, name='oauth_request_token'), # url(r'^authorize/$', user_authorization, name='oauth_user_authorization'), # url(r'^access_token/$', access_token, name='oauth_access_token'), -# ) \ No newline at end of file +# ) diff --git a/oauth_provider/utils.py b/oauth_provider/utils.py index 4360001e..ce212d92 100644 --- a/oauth_provider/utils.py +++ b/oauth_provider/utils.py @@ -15,9 +15,10 @@ from consts import MAX_URL_LENGTH OAUTH_REALM_KEY_NAME = getattr(settings, 'OAUTH_REALM_KEY_NAME', '') -OAUTH_SIGNATURE_METHODS = getattr(settings, 'OAUTH_SIGNATURE_METHODS', ['plaintext', 'hmac-sha1','rsa-sha1']) +OAUTH_SIGNATURE_METHODS = getattr(settings, 'OAUTH_SIGNATURE_METHODS', ['plaintext', 'hmac-sha1', 'rsa-sha1']) OAUTH_BLACKLISTED_HOSTNAMES = getattr(settings, 'OAUTH_BLACKLISTED_HOSTNAMES', []) + def initialize_server_request(request): """Shortcut for initialization.""" oauth_request = get_oauth_request(request) @@ -34,6 +35,7 @@ def initialize_server_request(request): oauth_server = None return oauth_server, oauth_request + def send_oauth_error(err=None): """Shortcut for sending an error.""" # send a 401 error @@ -43,7 +45,7 @@ def send_oauth_error(err=None): response = HttpResponse(err, mimetype="text/plain") else: response = HttpResponse(err.message.encode('utf-8'), mimetype="text/plain") - + response.status_code = 401 # return the authenticate header header = oauth.build_authenticate_header(realm=OAUTH_REALM_KEY_NAME) @@ -51,6 +53,7 @@ def send_oauth_error(err=None): response[k] = v return response + def get_oauth_request(request): """ Converts a Django request object into an `oauth2.Request` object. """ # Django converts Authorization header in HTTP_AUTHORIZATION @@ -59,8 +62,7 @@ def get_oauth_request(request): if 'Authorization' in request.META: auth_header = {'Authorization': request.META['Authorization']} elif 'HTTP_AUTHORIZATION' in request.META: - auth_header = {'Authorization': request.META['HTTP_AUTHORIZATION']} - + auth_header = {'Authorization': request.META['HTTP_AUTHORIZATION']} # include POST parameters if content type is # 'application/x-www-form-urlencoded' and request @@ -83,11 +85,12 @@ def get_oauth_request(request): absolute_uri = urlunparse((scheme, ) + urlparse(absolute_uri)[1:]) return oauth.Request.from_request(request.method, - absolute_uri, - headers=auth_header, - parameters=parameters, - query_string=request.META.get('QUERY_STRING', '') - ) + absolute_uri, + headers=auth_header, + parameters=parameters, + query_string=request.META.get('QUERY_STRING', '') + ) + def verify_oauth_request(request, oauth_request, consumer, token=None): """ Helper function to verify requests. """ @@ -115,8 +118,10 @@ def verify_oauth_request(request, oauth_request, consumer, token=None): return True + def is_xauth_request(request): - return request.get('x_auth_password') and request.get('x_auth_username') + return request.get('x_auth_password') and request.get('x_auth_username') + def verify_xauth_request(request, oauth_request): """ @@ -134,6 +139,7 @@ def verify_xauth_request(request, oauth_request): request.user = user return user + def require_params(oauth_request, parameters=None): """ Ensures that the request contains all required parameters. """ params = [ @@ -152,20 +158,24 @@ def require_params(oauth_request, parameters=None): return None + def check_valid_callback(callback): """ Checks the size and nature of the callback. """ callback_url = urlparse(callback) - return (callback_url.scheme - and callback_url.hostname not in OAUTH_BLACKLISTED_HOSTNAMES - and len(callback) < MAX_URL_LENGTH) + return (callback_url.scheme and + callback_url.hostname not in OAUTH_BLACKLISTED_HOSTNAMES and + len(callback) < MAX_URL_LENGTH) # LRS CHANGE - ADDED ESCAPE FUNCTION AND RSA_SHA1 CLASS (MISSING BEFORE) + + def escape(s): """Escape a URL including any /.""" return urllib.quote(s, safe='~') + class SignatureMethod_RSA_SHA1(oauth.SignatureMethod): name = 'RSA-SHA1' @@ -177,7 +187,7 @@ def signing_base(self, request, consumer, token): escape(request.method), escape(request.normalized_url), escape(request.get_normalized_parameters()), - ) + ) # If incoming consumer is Consumer model if hasattr(consumer, 'id'): @@ -185,7 +195,7 @@ def signing_base(self, request, consumer, token): # If incoming consumer is consumer object from verify else: key = RSA.importKey(consumer.secret) - + raw = '&'.join(sig) return key, raw @@ -221,4 +231,4 @@ def _pkcs1imify(key, data): SHA1_DIGESTINFO = '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14' size = len(long_to_bytes(key.n)) filler = '\xff' * (size - len(SHA1_DIGESTINFO) - len(data) - 3) - return '\x00\x01' + filler + '\x00' + SHA1_DIGESTINFO + data \ No newline at end of file + return '\x00\x01' + filler + '\x00' + SHA1_DIGESTINFO + data diff --git a/oauth_provider/views.py b/oauth_provider/views.py index 71b2e7e9..7d87a765 100644 --- a/oauth_provider/views.py +++ b/oauth_provider/views.py @@ -24,6 +24,7 @@ UNSAFE_REDIRECTS = getattr(settings, "OAUTH_UNSAFE_REDIRECTS", False) + @csrf_exempt def request_token(request): oauth_request = get_oauth_request(request) @@ -58,6 +59,8 @@ def request_token(request): return HttpResponse(ret, content_type='application/x-www-form-urlencoded') # LRS CHANGE - CHANGED FORM_CLASS TO OUR CUSTOM FORM + + @login_required(login_url="/accounts/login") def user_authorization(request, form_class=AuthorizeRequestTokenForm): if 'oauth_token' not in request.REQUEST: @@ -82,9 +85,9 @@ def user_authorization(request, form_class=AuthorizeRequestTokenForm): request.session['oauth'] = '' if form.cleaned_data['authorize_access']: request_token = store.authorize_request_token(request, oauth_request, request_token) - args = { 'oauth_token': request_token.key } + args = {'oauth_token': request_token.key} else: - args = { 'error': _('Access not granted by user.') } + args = {'error': _('Access not granted by user.')} if request_token.callback is not None and request_token.callback != OUT_OF_BAND: callback_url = request_token.get_callback_url(args) if UNSAFE_REDIRECTS: @@ -94,11 +97,11 @@ def user_authorization(request, form_class=AuthorizeRequestTokenForm): else: # try to get custom callback view callback_view_str = getattr(settings, OAUTH_CALLBACK_VIEW, - 'oauth_provider.views.fake_callback_view') + 'oauth_provider.views.fake_callback_view') try: view_callable = get_callable(callback_view_str) except AttributeError: - raise Exception, "%s view doesn't exist." % callback_view_str + raise Exception("%s view doesn't exist." % callback_view_str) # try to treat it as Class Based View (CBV) try: @@ -106,18 +109,18 @@ def user_authorization(request, form_class=AuthorizeRequestTokenForm): except AttributeError: # if it appears not to be CBV treat it like FBV callback_view = view_callable - + response = callback_view(request, **args) else: response = send_oauth_error(oauth.Error(_('Action not allowed.'))) - else: + else: # try to get custom authorize view - authorize_view_str = getattr(settings, OAUTH_AUTHORIZE_VIEW, - 'oauth_provider.views.fake_authorize_view') + authorize_view_str = getattr(settings, OAUTH_AUTHORIZE_VIEW, + 'oauth_provider.views.fake_authorize_view') try: view_callable = get_callable(authorize_view_str) except AttributeError: - raise Exception, "%s view doesn't exist." % authorize_view_str + raise Exception("%s view doesn't exist." % authorize_view_str) # try to treat it as Class Based View (CBV) try: @@ -130,9 +133,10 @@ def user_authorization(request, form_class=AuthorizeRequestTokenForm): # set the oauth flag request.session['oauth'] = request_token.key response = authorize_view(request, request_token, request_token.get_callback_url(), params) - + return response + @csrf_exempt def access_token(request): oauth_request = get_oauth_request(request) @@ -165,12 +169,12 @@ def access_token(request): # Verify Signature if not verify_oauth_request(request, oauth_request, consumer, request_token): return HttpResponseBadRequest('Could not verify OAuth request.') - + # Check Verifier if oauth_request.get('oauth_verifier', None) != request_token.verifier: return HttpResponseBadRequest('Invalid OAuth verifier.') - else: # xAuth + else: # xAuth # Check Parameters missing_params = require_params(oauth_request, ('x_auth_username', 'x_auth_password', 'x_auth_mode')) @@ -195,10 +199,10 @@ def access_token(request): return HttpResponseBadRequest('xAuth username or password is not valid') else: request.user = user - + # Handle Request Token try: - #request_token = store.create_request_token(request, oauth_request, consumer, oauth_request.get('oauth_callback')) + # request_token = store.create_request_token(request, oauth_request, consumer, oauth_request.get('oauth_callback')) request_token = store.create_request_token(request, oauth_request, consumer, OUT_OF_BAND) request_token = store.authorize_request_token(request, oauth_request, request_token) except oauth.Error, err: @@ -213,11 +217,13 @@ def access_token(request): return HttpResponse(ret, content_type='application/x-www-form-urlencoded') # LRS CHANGE - ADDED OUR REAL VIEWS + + @login_required(login_url="/accounts/login") def authorize_client(request, token=None, callback=None, params=None, form=None): if not form: form = AuthorizeRequestTokenForm(initial={'scopes': token.scope_to_list(), - 'obj_id': token.pk}) + 'obj_id': token.pk}) d = {} d['oauth_scopes'] = settings.OAUTH_SCOPES d['scopes'] = json.dumps(token.scope_to_list()) @@ -228,6 +234,7 @@ def authorize_client(request, token=None, callback=None, params=None, form=None) d['oauth_token'] = token.key return render_to_response('oauth_authorize_client.html', d, context_instance=RequestContext(request)) + @login_required(login_url="/accounts/login") def callback_view(request, **args): d = {} diff --git a/requirements.txt b/requirements.txt index b1a5a229..d044f6c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,4 @@ amqp==1.4.6 celery==3.1.18 supervisor==3.0a12 rfc3987==1.3.4 -requests==2.7.0 \ No newline at end of file +requests==2.7.0