Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync grades back to the LMS for auto grading #6672

Merged
merged 3 commits into from
Sep 19, 2024
Merged

Conversation

marcospri
Copy link
Member

@marcospri marcospri commented Sep 10, 2024

For:

Basic API endpoint to support the first version of the "Sync grades" button.

Testing

use a request like:

curl 'http://localhost:8001/api/dashboard/assignments/121/grading/sync' -X POST \
  -H 'Accept: */*' \
  -H "Content-Type: application/json" \
  -H 'Authorization: XXXXXXX' \
  --data '{"grades": [{"h_userid": "acct:[email protected]", "grade": 0.7}]}'

with a token from an instructor (it won't work for staff members).

@marcospri marcospri force-pushed the sync-grades-dashbaord branch from 6ed9f3b to c783b22 Compare September 10, 2024 15:58
@marcospri marcospri force-pushed the lms-user-v13-id-code branch 2 times, most recently from 486e72b to 1f65d03 Compare September 11, 2024 08:33
Base automatically changed from lms-user-v13-id-code to main September 11, 2024 08:37
@marcospri marcospri force-pushed the sync-grades-dashbaord branch 3 times, most recently from 91aa414 to 2f1ebc0 Compare September 11, 2024 09:51
@@ -284,6 +284,10 @@ def includeme(config): # noqa: PLR0915
config.add_route(
"api.dashboard.assignment", r"/api/dashboard/assignments/{assignment_id}"
)
config.add_route(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New API endpoint

@@ -1,8 +1,8 @@
from pyramid.httpexceptions import HTTPNotFound, HTTPUnauthorized
from sqlalchemy import select

from lms.models import Assignment, Organization
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some type annos around here to get autocompletion.

@@ -83,15 +83,32 @@ def read_result(self, grading_id) -> GradingResult:
def get_score_maximum(self, resource_link_id) -> float | None:
return self._read_grading_configuration(resource_link_id).get("scoreMaximum")

def sync_grade( # noqa: PLR0913
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New method to sync an individual grade.

We don't use the existing record_result because:

  • We'd need to backport now any changes here for the LTI1.1 as the share a common interface.

  • That method is more complex as it deals with comments (that might need to be formatted before), "pre_record_hook", to change the shape of the payload...

I reckon the simple method is the best solution right now.

permission=Permissions.GRADE_ASSIGNMENT,
schema=AutoGradeSyncSchema,
)
def auto_grading_sync(self):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an endpoint that would need many changes before is ready for the MVP:

  • Don't start a sync if there's already one running.
  • Run the actual sync of grades asynchronously on a celery task.

I also image we'll need a GET endpoint to fetch progress (state of the last one?) of any running sync.

)
def auto_grading_sync(self):
assignment = self.dashboard_service.get_request_assignment(self.request)
assert assignment.lis_outcome_service_url, "Assignment wihtout grading URL"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asserts for the type checker.

ltia_service=self.request.find_service(LTIAHTTPService),
line_item_url=None,
line_item_container_url=None,
product_family=None, # type: ignore
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be None in the grading service but to refactor that we have to refactor the v11 version as well as they share an interface. I'll have to do that once we have the MVP.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it makes sense to optionally inject a grading service in the constructor, and fall back to this if not provided. That way you can still use this at runtime, but pass a mock in tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, but views are "built" by the framework itself.

This sticks out like a shore thumb so I reckon the right fix is to refactor the service to take this as parameters in v11 and v13.

Crated a note on the main issue to keep track of that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but views are "built" by the framework itself.

Oh, I didn't think about that. Let's keep it as is for now and apply your suggested improvements afterwards.



class AutoGradeSyncSchema(JSONPyramidRequestSchema):
grades = fields.List(fields.Nested(_GradeSchema), required=True)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint takes the grades from the frontend. I reckon this makes sense because:

  • It saves the BE to doing double work of calculating the grades again.
  • It guarantees that what you see in the dashboard is what we are going to send to the LMS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this as well, and I also think it makes sense.

It would even allow to eventually let instructors adjust the pre-calculated grade before syncing, right from the dashboard, if at some point we want to allow that.

@marcospri marcospri requested a review from acelaya September 11, 2024 10:01
@marcospri marcospri changed the title [WIP] Sync grades back to the LMS for auto grading Sync grades back to the LMS for auto grading Sep 11, 2024
Copy link
Contributor

@acelaya acelaya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add the new endpoint to the DashboardRoutes definition. Other than that, this looks good.



class AutoGradeSyncSchema(JSONPyramidRequestSchema):
grades = fields.List(fields.Nested(_GradeSchema), required=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this as well, and I also think it makes sense.

It would even allow to eventually let instructors adjust the pre-calculated grade before syncing, right from the dashboard, if at some point we want to allow that.

ltia_service=self.request.find_service(LTIAHTTPService),
line_item_url=None,
line_item_container_url=None,
product_family=None, # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it makes sense to optionally inject a grading service in the constructor, and fall back to this if not provided. That way you can still use this at runtime, but pass a mock in tests.

@marcospri marcospri mentioned this pull request Sep 11, 2024
2 tasks
@marcospri marcospri force-pushed the sync-grades-dashbaord branch from fe680b6 to 5b10d03 Compare September 16, 2024 07:43
This will allow us to expose the configuring and calculating side of
auto grading while we work on the syncing part.
@marcospri marcospri force-pushed the sync-grades-dashbaord branch from 9f04f16 to d9d3665 Compare September 16, 2024 12:42
@marcospri marcospri merged commit a02651c into main Sep 19, 2024
9 checks passed
@marcospri marcospri deleted the sync-grades-dashbaord branch September 19, 2024 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants