diff --git a/.env.example b/.env.example index fb7892f..0a743e7 100644 --- a/.env.example +++ b/.env.example @@ -9,6 +9,10 @@ DB_PORT=5432 AAF_URL=https://rapid.test.aaf.edu.au/jwt/authnrequest/research/your-custom-url-here AAF_SECRET=SECERET_USED_FOR_AAF_APP_REGISTRATION +# API Secret for single consumer (can be extended) +API_SECRET=supersecretsharedsecretstring +# THIS MUST BE CHANGED TO YOUR FQDN +API_URL='' # Set to 0 in production DEBUG=1 diff --git a/clatoolkit_project/clatoolkit_project/settings.py b/clatoolkit_project/clatoolkit_project/settings.py index 932abfb..b891fdd 100644 --- a/clatoolkit_project/clatoolkit_project/settings.py +++ b/clatoolkit_project/clatoolkit_project/settings.py @@ -60,6 +60,8 @@ EMAIL_HOST_USER = '' EMAIL_HOST_PASSWORD = '' #EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # During development only +API_SECRET=os.environ.get('API_SECRET') +API_URL=os.enivron.get('API_URL') # Application definition diff --git a/clatoolkit_project/dashboard/utils.py b/clatoolkit_project/dashboard/utils.py index 6684ee1..619a691 100644 --- a/clatoolkit_project/dashboard/utils.py +++ b/clatoolkit_project/dashboard/utils.py @@ -31,6 +31,23 @@ from xapi.statement.xapi_filter import xapi_filter from xapi.oauth_consumer.operative import LRS_Auth +def get_user_truncated_xapi(user, platforms=None, course_id=None): + user_lrs = LearningRecord.objects.filter(user_id=user) + if platforms: + platforms = [platform.capitalize() for platform in platforms] + user_lrs = user_lrs.filter(platform__in=platforms) + if course_id: + user_lrs = user_lrs.filter(unit_id=course_id) + data = [] + for lr in user_lrs: + trunc_xapi = {} + trunc_xapi['verb'] = lr.verb + trunc_xapi['object'] = lr.platformid + trunc_xapi['date'] = lr.datetimestamp + trunc_xapi['platform'] = lr.platform + data.append(trunc_xapi) + + return data def getPluginKey(platform): diff --git a/clatoolkit_project/dashboard/views.py b/clatoolkit_project/dashboard/views.py index 6fd64a7..61132af 100644 --- a/clatoolkit_project/dashboard/views.py +++ b/clatoolkit_project/dashboard/views.py @@ -24,6 +24,37 @@ from xapi.statement.xapi_filter import xapi_filter from xapi.statement.xapi_getter import xapi_getter +# custom jwt auth for api endpoints (currently only for one consumer, have models/form in place to extend to sign-ups) +def jwt_auth(fn): + """ + Decorator to authorize an api endpoint against specific user in the toolkit + using a jwt. For now, this is implemented as a single consumer (i.e. only + one consumer can be specified atm in settings.py (API_SECRET/API_URL). This can + be extended upon to allow arbitrary/niche + access and imports of data into the toolkit. + + Receives the jwt from the HTTP_AUTHORIZATION header, decodes using shared secret + (settings.API_SECRET) and verifies the HTTP_REFERER against the consumers web location + (settings.API_URL). If all criteria is passed, the decorator logs in (fills request.user) the user and returns + the appropriate data as defined by the view. + + :return: View with user added to request.user + """ + def _wrapped_fn(request, *args, **kwargs): + try: + token = request.META['HTTP_API_AUTH'] + except: + raise Exception(request.META) + ver_jwt = jwt.decode(token, settings.API_SECRET) + if request.META.get('HTTP_REFERER', '') == settings.API_URL: + user = User.objects.get(email=ver_jwt['user']) + if user is not None: + user.backend = 'django.contrib.auth.backends.ModelBackend' + login(request, user) + return fn(request, *args, **kwargs) + else: + return PermissionDenied + return _wrapped_fn #API endpoint to grab a list of trello boards to attach to course @@ -642,13 +673,17 @@ def get_platform_activities(request): return response +@jwt_auth def get_user_acitivities(request): - platform_names = request.GET.get('platform').split(',') - val = get_user_acitivities_dataset(request.GET.get('course_code'), platform_names) - response = JsonResponse(val, status=status.HTTP_200_OK) + platforms = request.GET.get('platform', None) + course_id = request.GET.get('course_id', None) + if platforms: + platforms = platforms.split(',') + # val = get_user_acitivities_dataset(request.GET.get('course_code'), platform_names) + val = get_user_truncated_xapi(request.user, platforms=platforms, course_id=course_id) + response = JsonResponse(dict(user_activities=list(val)), status=status.HTTP_200_OK) return response - @login_required def get_all_repos(request): course_id = request.GET.get('course_id')