Skip to content

Commit

Permalink
Merge pull request #70 from mikaelGusse/master
Browse files Browse the repository at this point in the history
Add ability to test A+ integration locally
  • Loading branch information
Harman-Aalto authored Jan 22, 2025
2 parents 527e01d + b6da9ec commit 08314f1
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 24 deletions.
13 changes: 12 additions & 1 deletion doc/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,15 @@ Note: The root folder contains the script "run_loadsubmission.sh" which correctl
2. `./run_loadsubmissions.sh ${directory_with_submissions} {course}/{exercise} 1`<br>
This goes through the directory, places each submission into it's own folder and creates a subfolder inside there to put the submission in. After this folder distribution is done, it runs the manage.py loadsubmissions command for each submission. The last variable is the delay, which determines how long we should wait between sending submissions to the service
3. Wait until the script finishes
4. Run `python manage.py matchsubmissions {course}/exercise` and the submissions should be matched.
4. Run `python manage.py matchsubmissions {course}/exercise` and the submissions should be matched.

## Testing with A+ locally

To test the LTI integration and features between Radar and A+ locally, you first should follow the instructions in the root directory's README.rst on "Configuring with A+".

After this, ensure Radar is not running on the default localhost:8000. Use for example localhost:8009. This can be achieved by adding the desired port to the end of the runserver command `python manage.py runserver 8009`

Also ensure that DEBUG = True is set in the settings at root/radar/settings.py

Now you should be able to login to Radar using LTI from A+ as well as import automatically or manually configured exercises from A+. Only thing not working is automatic fetching of submissions and automatic matching. To match submissions you will still have to run
`python manage.py matchsubmissions <course_id>/<exercise_id>`
3 changes: 3 additions & 0 deletions ltilogin/receivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def add_course_permissions(sender, **kwargs):
)
raise PermissionDenied("LTI request is missing some fields to allow login")

if 'plus:8000' in course_api:
course_api = course_api.replace('plus:8000', 'localhost:8000')

# store API token
site = Site.get_by_url(course_api)
user.add_api_token(api_token, site) # will not add duplicates
Expand Down
22 changes: 17 additions & 5 deletions provider/aplus.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from django.conf import settings
import requests

from django.core.cache import caches as django_caches
Expand Down Expand Up @@ -154,7 +155,15 @@ def load_exercise_template_from_api_data(exercise_data, course):
# Join all non-empty templates into a single string, separated by newlines.
# If there is only one non-empty template in template_data,
# this will simply evaluate to that template, with no extra newline.
source = '\n'.join(t for t in template_data if t)
try:
source = '\n'.join(t for t in template_data if t)
except Exception as e:
logger.error(
"Error while attempting to load exercise template from %s: %s",
template_urls_str,
str(e),
)
return source
return source


Expand Down Expand Up @@ -237,10 +246,13 @@ def async_api_read(request, course, has_radar_config):
Queue an read of all exercises on a given course from the A+ REST API.
Return an id for the celery.result.AsyncResult that was queued.
"""
async_task = tasks.get_full_course_config.delay(
request.user.id, course.id, has_radar_config
)
return async_task.id
if not settings.DEBUG:
async_task = tasks.get_full_course_config.delay(
request.user.id, course.id, has_radar_config
)
return async_task.id
async_task = tasks.get_full_course_config(request.user.id, course.id, has_radar_config)
return async_task


def recompare_all_unmatched(course):
Expand Down
3 changes: 2 additions & 1 deletion provider/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ def reload_exercise_submissions(exercise_id, submissions_api_url):
exercise.matching_start_time,
)
# All submissions created, now match them
matcher_tasks.match_all_new_submissions_to_exercise.delay(exercise_id)
if not settings.DEBUG:
matcher_tasks.match_all_new_submissions_to_exercise.delay(exercise_id)


@celery.shared_task
Expand Down
6 changes: 3 additions & 3 deletions radar/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
# "UID": "...", # set to "radar" below, can be changed
"PRIVATE_KEY": None,
"PUBLIC_KEY": None,
"REMOTE_AUTHENTICATOR_UID": None, # The UID of the remote authenticator, e.g. "aplus"
"REMOTE_AUTHENTICATOR_UID": "aplus", # The UID of the remote authenticator, e.g. "aplus"
"REMOTE_AUTHENTICATOR_KEY": None, # The public key of the remote authenticator
"REMOTE_AUTHENTICATOR_URL": None, # probably "https://<A+ domain>/api/v2/get-token/"
"REMOTE_AUTHENTICATOR_URL": "localhost:8000/api/v2/get-token/", # probably "https://<A+ domain>/api/v2/get-token/"
# "UID_TO_KEY": {...}
# "TRUSTED_UIDS": [...],
# "TRUSTING_REMOTES": [...],
# "DISABLE_JWT_SIGNING": False,
# "DISABLE_LOGIN_CHECKS": False,
"DISABLE_LOGIN_CHECKS": True,
}

# Messaging library
Expand Down
38 changes: 24 additions & 14 deletions review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def marked_submissions(request, course_key=None, course=None):


@access_resource
def configure_course(request, course_key=None, course=None):
def configure_course(request, course_key=None, course=None): #pylint: disable=too-many-branches
context = {
"hierarchy": (
(settings.APP_NAME, reverse("index")),
Expand Down Expand Up @@ -307,21 +307,31 @@ def configure_course(request, course_key=None, course=None):
if pending_api_read["task_id"]:
# Task is pending, check state and return result if ready
async_result = AsyncResult(pending_api_read["task_id"])
if async_result.ready():
if not settings.DEBUG:
if async_result.ready():
pending_api_read["ready"] = True
pending_api_read["task_id"] = None
if async_result.state == "SUCCESS":
exercise_data = async_result.get()
async_result.forget()
config_table = template_loader.get_template(
"review/configure_table.html"
)
exercise_data["config_type"] = pending_api_read["config_type"]
pending_api_read["resultHTML"] = config_table.render(
exercise_data, request
)
else:
pending_api_read["resultHTML"] = ''
else:
# Debug mode, return result immediately
print("DEBUG MODE")
pending_api_read["ready"] = True
exercise_data = pending_api_read['task_id']
config_table = template_loader.get_template("review/configure_table.html")
exercise_data["config_type"] = pending_api_read["config_type"]
pending_api_read["resultHTML"] = config_table.render(exercise_data, request)
pending_api_read["task_id"] = None
if async_result.state == "SUCCESS":
exercise_data = async_result.get()
async_result.forget()
config_table = template_loader.get_template(
"review/configure_table.html"
)
exercise_data["config_type"] = pending_api_read["config_type"]
pending_api_read["resultHTML"] = config_table.render(
exercise_data, request
)
else:
pending_api_read["resultHTML"] = ''
return JsonResponse(pending_api_read)

if pending_api_read["ready"]:
Expand Down

0 comments on commit 08314f1

Please sign in to comment.