Skip to content

Commit f665537

Browse files
csevern
andauthored
SAK-51199 LTI traceback while retrieving line items (#13496)
Co-authored-by: Earle Nietzel <[email protected]>
1 parent 2043567 commit f665537

File tree

3 files changed

+99
-30
lines changed

3 files changed

+99
-30
lines changed

lti/lti-common/src/java/org/sakaiproject/lti/util/SakaiLTIUtil.java

+59-21
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import org.sakaiproject.entity.api.ResourceProperties;
7474
import org.sakaiproject.event.cover.UsageSessionService;
7575
import org.sakaiproject.exception.IdUnusedException;
76+
import org.sakaiproject.exception.PermissionException;
7677
import org.sakaiproject.grading.api.model.Gradebook;
7778
import org.sakaiproject.linktool.LinkToolUtil;
7879
import org.sakaiproject.lti.api.LTIService;
@@ -633,7 +634,8 @@ public static String getCurrentUserSakaiRole(User user, String context) {
633634
}
634635
if (StringUtils.isNotBlank(sakaiRole)) return sakaiRole;
635636
} catch (GroupNotDefinedException e) {
636-
log.error("site realm not found {}", e.getMessage());
637+
log.error("site realm not found {}", e.toString());
638+
log.debug("Stacktrace:", e);
637639
}
638640
return null;
639641
}
@@ -834,6 +836,7 @@ public static boolean sakaiInfo(Properties props, String context, String placeme
834836
site = SiteService.getSite(context);
835837
} catch (IdUnusedException e) {
836838
log.error("No site/page associated with Launch context={}", context);
839+
log.debug("Stacktrace:", e);
837840
return false;
838841
}
839842

@@ -1165,6 +1168,7 @@ public static String[] postLaunchHTML(Map<String, Object> content, Map<String, O
11651168
site = SiteService.getSite(context);
11661169
} catch (IdUnusedException e) {
11671170
log.error("No site/page associated with Launch context={}", context);
1171+
log.debug("Stacktrace:", e);
11681172
return postError("<p>" + getRB(rb, "error.site.missing", "Cannot load site.") + context + "</p>");
11691173
}
11701174

@@ -1421,9 +1425,10 @@ public static Key getPublicKey(Map<String, Object> tool, String id_token)
14211425
try {
14221426
publicKey = LTI13KeySetUtil.getKeyFromKeySet(incoming_kid, tool_keyset);
14231427
} catch (Exception e) {
1424-
log.error(e.getMessage(), e);
1428+
log.error(e.toString(), e);
1429+
log.debug("Stacktrace:", e);
14251430
// Sorry - too many exceptions to explain here - lets keep it simple after logging it
1426-
throw new RuntimeException("Unable to retrieve kid="+incoming_kid+" from "+tool_keyset+" detail="+e.getMessage());
1431+
throw new RuntimeException("Unable to retrieve kid="+incoming_kid+" from "+tool_keyset+" detail="+e.toString());
14271432
}
14281433
// TODO: Store in Earle's super-cluster-cache one day - SAK-43700
14291434

@@ -1565,6 +1570,7 @@ public static String[] postContentItemSelectionRequest(Long toolKey, Map<String,
15651570
site = SiteService.getSite(context);
15661571
} catch (IdUnusedException e) {
15671572
log.error("No site/page associated with Launch context={}", context);
1573+
log.debug("Stacktrace:", e);
15681574
return postError("<p>" + getRB(rb, "error.site.missing", "Cannot load site.") + context + "</p>");
15691575
}
15701576

@@ -1919,7 +1925,7 @@ public static String[] postLaunchJWT(Properties toolProps, Properties ltiProps,
19191925
lj.email = ltiProps.getProperty(LTIConstants.LIS_PERSON_CONTACT_EMAIL_PRIMARY);
19201926

19211927
lj.nonce = toolProps.getProperty("nonce");
1922-
lj.issued = new Long(System.currentTimeMillis() / 1000L);
1928+
lj.issued = Long.valueOf(System.currentTimeMillis() / 1000L);
19231929
lj.expires = lj.issued + 3600L;
19241930
lj.deployment_id = getDeploymentId(context_id);
19251931

@@ -2356,7 +2362,8 @@ private static String getExternalRealmId(String siteId) {
23562362
AuthzGroup realm = ComponentManager.get(AuthzGroupService.class).getAuthzGroup(realmId);
23572363
rv = realm.getProviderGroupId();
23582364
} catch (GroupNotDefinedException e) {
2359-
log.error("SiteParticipantHelper.getExternalRealmId: site realm not found {}", e.getMessage());
2365+
log.error("SiteParticipantHelper.getExternalRealmId: site realm not found {}", e.toString());
2366+
log.debug("Stacktrace:", e);
23602367
}
23612368
return rv;
23622369
} // getExternalRealmId
@@ -2519,7 +2526,7 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque
25192526

25202527
// If we are not supposed to lookup or set the grade, we are done
25212528
if (isRead == false && isDelete == false && scoreGiven == null) {
2522-
return new Boolean(matched);
2529+
return Boolean.valueOf(matched);
25232530
}
25242531

25252532
// Look up the gradebook column so we can find the max points
@@ -2592,7 +2599,7 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque
25922599
String actualGrade = gradingService.getAssignmentScoreString(gradebookUid, siteId, gradebookColumn.getId(), user_id);
25932600
Double dGrade = null;
25942601
if (StringUtils.isNotBlank(actualGrade)) {
2595-
dGrade = new Double(actualGrade);
2602+
dGrade = Double.valueOf(actualGrade);
25962603
dGrade = dGrade / gradebookColumn.getPoints();
25972604
}
25982605
CommentDefinition commentDef = gradingService.getAssignmentScoreComment(gradebookUid, gradebookColumn.getId(), user_id);
@@ -2622,7 +2629,7 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque
26222629
retval = Boolean.TRUE;
26232630
}
26242631
} catch (Exception e) {
2625-
retval = "Grade failure " + e.getMessage() + " siteId=" + siteId;
2632+
retval = "Grade failure " + e.toString() + " siteId=" + siteId;
26262633
log.warn("handleGradebook Grade failure in site: {}, error: {}", siteId, e);
26272634
} finally {
26282635
sess.invalidate(); // Make sure to leave no traces
@@ -2642,6 +2649,8 @@ public static Object handleGradebookLTI13(Site site, Long tool_id, Map<String,
26422649
Object retval;
26432650
String title;
26442651

2652+
log.debug("siteid: {} tool_id: {} lineitem_key: {} userId: {} scoreObj: {}", site.getId(), tool_id, lineitem_key, userId, scoreObj);
2653+
26452654
// An empty / null score given means to delete the score
26462655
SakaiLineItem lineItem = new SakaiLineItem();
26472656
String siteId = site.getId();
@@ -2668,6 +2677,29 @@ public static Object handleGradebookLTI13(Site site, Long tool_id, Map<String,
26682677
log.error("Could not determine assignment_name title {}", content.get(LTIService.LTI_ID));
26692678
return "Unable to load column for lineitem_key="+lineitem_key;
26702679
}
2680+
2681+
// Check if this is a gradebook column that is owned by assignments
2682+
String external_id = gradebookColumn.getExternalId();
2683+
log.debug("external_id: {} {}", external_id);
2684+
if ( external_id != null && LineItemUtil.isAssignmentColumn(external_id) ) {
2685+
org.sakaiproject.assignment.api.AssignmentService assignmentService = ComponentManager.get(org.sakaiproject.assignment.api.AssignmentService.class);
2686+
org.sakaiproject.assignment.api.model.Assignment assignment;
2687+
try {
2688+
org.sakaiproject.assignment.api.AssignmentReferenceReckoner.AssignmentReference assignmentReference = org.sakaiproject.assignment.api.AssignmentReferenceReckoner.reckoner().reference(external_id).reckon();
2689+
log.debug("assignmentReference.id {}", assignmentReference.getId());
2690+
assignment = assignmentService.getAssignment(assignmentReference.getId());
2691+
} catch (Exception e) {
2692+
assignment = null;
2693+
log.error("Unexpected error getting assignment: {}", e.toString());
2694+
log.debug("Stacktrace:", e);
2695+
}
2696+
2697+
if ( assignment != null ) {
2698+
log.debug("Gradebook column is owned by assignment: {}", assignment.getId());
2699+
retval = handleAssignment(assignment, userId, scoreObj);
2700+
return retval;
2701+
}
2702+
}
26712703
title = gradebookColumn.getName();
26722704
}
26732705

@@ -2677,10 +2709,9 @@ public static Object handleGradebookLTI13(Site site, Long tool_id, Map<String,
26772709
}
26782710

26792711
// Send the grades to the gradebook
2680-
Double scoreGiven = scoreObj.scoreGiven;
2712+
Double scoreGiven = scoreObj.getScoreGiven();
26812713
String comment = scoreObj.comment;
2682-
if ( scoreObj.scoreMaximum == null ) scoreObj.scoreMaximum = lineItem.scoreMaximum != null ? lineItem.scoreMaximum : 100D;
2683-
Double scoreMaximum = scoreObj.scoreMaximum;
2714+
Double scoreMaximum = scoreObj.getScoreMaximum();
26842715
log.debug("scoreGiven={} scoreMaximum={} userId={} comment={}", scoreGiven, scoreMaximum, userId, comment);
26852716

26862717
// Look up the gradebook column so we can find the max points
@@ -2731,7 +2762,7 @@ public static Object handleGradebookLTI13(Site site, Long tool_id, Map<String,
27312762
return Boolean.TRUE;
27322763
}
27332764
} catch (NumberFormatException | AssessmentNotFoundException e) {
2734-
retval = "Grade failure " + e.getMessage() + " siteId=" + siteId;
2765+
retval = "Grade failure " + e.toString() + " siteId=" + siteId;
27352766
log.warn("handleGradebook Grade failure in site: {}, error: {}", siteId, e);
27362767
} finally {
27372768
sess.invalidate(); // Make sure to leave no traces
@@ -2757,15 +2788,20 @@ public static org.sakaiproject.assignment.api.model.Assignment getAssignment(Sit
27572788
return a;
27582789
}
27592790
return null;
2760-
} finally {
2791+
} catch (Exception e) {
2792+
log.error("Unexpected error getting assignment: {}", e.toString());
2793+
log.debug("Stacktrace:", e);
2794+
} finally {
27612795
popAdvisor();
27622796
}
2797+
return null;
27632798
}
27642799

27652800
public static Object handleAssignment(org.sakaiproject.assignment.api.model.Assignment a, String userId, Score scoreObj) {
27662801

27672802
Integer scaledGrade = null;
27682803
String stringGrade = null;
2804+
log.debug("handleAssignment assignment: {} {} user: {} {}", a.getId(), a.getTitle(), userId, scoreObj.getScoreGiven());
27692805

27702806
// Scale up the score if appropriate
27712807
if (scoreObj.scoreGiven != null) {
@@ -2774,12 +2810,11 @@ public static Object handleAssignment(org.sakaiproject.assignment.api.model.Assi
27742810
// Sanity check - don't ever divide by zero
27752811
if ( assignmentScale == 0 ) assignmentScale = 1;
27762812

2777-
Integer incomingScoreGiven = new Double(scoreObj.scoreGiven * assignmentScale).intValue();
2778-
Integer incomingScoreMax = new Double(scoreObj.scoreMaximum * assignmentScale).intValue();
2813+
Integer incomingScoreGiven = Double.valueOf(scoreObj.getScoreGiven() * assignmentScale).intValue();
2814+
Integer incomingScoreMax = Double.valueOf(scoreObj.getScoreMaximum() * assignmentScale).intValue();
27792815
if ( incomingScoreMax == 0 ) incomingScoreMax = assignmentMax;
27802816
if ( incomingScoreMax == 0 ) incomingScoreMax = 100 * assignmentScale;
27812817

2782-
27832818
if ( incomingScoreMax.equals(assignmentMax) ) {
27842819
scaledGrade = incomingScoreGiven;
27852820
} else {
@@ -2794,11 +2829,13 @@ public static Object handleAssignment(org.sakaiproject.assignment.api.model.Assi
27942829

27952830
String activityProgress = scoreObj.activityProgress != null ? scoreObj.activityProgress : Score.ACTIVITY_COMPLETED ;
27962831
String gradingProgress = scoreObj.gradingProgress != null ? scoreObj.gradingProgress : Score.GRADING_FULLYGRADED;
2832+
log.debug("activityProgress: {} gradingProgress: {}", activityProgress, gradingProgress);
27972833

27982834
User user;
27992835
try {
28002836
user = UserDirectoryService.getUser(userId);
28012837
} catch (org.sakaiproject.user.api.UserNotDefinedException e) {
2838+
log.debug("Could not look up user {} {}", userId, e.toString());
28022839
return "Could not look up user "+userId;
28032840
}
28042841

@@ -2808,6 +2845,7 @@ public static Object handleAssignment(org.sakaiproject.assignment.api.model.Assi
28082845
if ( submission == null ) {
28092846
submission = assignmentService.addSubmission(a.getId(), user.getId());
28102847
}
2848+
log.debug("submission: {} {} {}", scaledGrade, user.getId(), submission);
28112849

28122850
StringBuilder logEntry = new StringBuilder();
28132851
DateTimeFormatter dtf = DateTimeFormatter.RFC_1123_DATE_TIME
@@ -2867,7 +2905,7 @@ public static Object handleAssignment(org.sakaiproject.assignment.api.model.Assi
28672905

28682906
try {
28692907
assignmentService.updateSubmission(submission);
2870-
log.info("Submitted submission={} userId={} log={}", submission.getId(), userId, logEntry.toString());
2908+
log.debug("Submitted submission={} userId={} log={}", submission.getId(), userId, logEntry.toString());
28712909
} catch (org.sakaiproject.exception.PermissionException e) {
28722910
log.warn("Could not update submission: {}, {}", submission.getId(), e);
28732911
return "Could not update submission="+submission.getId()+" "+e;
@@ -2886,7 +2924,7 @@ private static String getNextSubmissionLogKey(org.sakaiproject.assignment.api.mo
28862924
Map<String, String> properties = submission.getProperties();
28872925
List<Integer> keys = properties.keySet().stream()
28882926
.filter(k -> k.startsWith("log"))
2889-
.map(k -> new Integer(StringUtils.split(k, "log")[0]))
2927+
.map(k -> Integer.valueOf(StringUtils.split(k, "log")[0]))
28902928
.sorted()
28912929
.collect(Collectors.toList());
28922930
int next = keys.isEmpty() ? 0 : keys.get(keys.size() - 1) + 1;
@@ -2945,10 +2983,10 @@ public static org.sakaiproject.grading.api.Assignment getGradebookColumn(Site si
29452983
returnColumn.setGradebookUid(returnGradebookUid);
29462984
log.info("Added gradebook column: {} with Id: {}", title, gradebookColumnId);
29472985
} catch (ConflictingAssignmentNameException e) {
2948-
log.warn("ConflictingAssignmentNameException while adding gradebook column {}", e.getMessage());
2986+
log.warn("ConflictingAssignmentNameException while adding gradebook column {}", e.toString());
29492987
returnColumn = null; // Just to make sure
29502988
} catch (Exception e) {
2951-
log.warn("Exception (may be because GradeBook has not yet been added to the Site) {}", e.getMessage());
2989+
log.warn("Exception (may be because GradeBook has not yet been added to the Site) {}", e.toString());
29522990
returnColumn = null; // Just to make double sure
29532991
} finally {
29542992
popAdvisor();
@@ -2966,7 +3004,7 @@ public static org.sakaiproject.grading.api.Assignment getGradebookColumn(Site si
29663004
// Returns scoreGiven * points rounded to 2 digits (as a String)
29673005
// Used for testing and to avoid precision problems
29683006
public static String getRoundedGrade(Double scoreGiven, Double points) throws Exception {
2969-
if (scoreGiven < 0.0 || scoreGiven > 1.0) {
3007+
if (scoreGiven == null || scoreGiven < 0.0 || scoreGiven > 1.0) {
29703008
throw new Exception("Grade out of range");
29713009
}
29723010
scoreGiven = scoreGiven * points;

lti/lti-common/src/java/org/sakaiproject/lti13/LineItemUtil.java

+16-9
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,10 @@ public static Assignment createLineItem(String context_id, Long tool_id, Map<Str
220220
log.info("Updated assignment: {} with Id: {}", lineItem.label, gradebookColumnId);
221221
}
222222
} catch (ConflictingAssignmentNameException e) {
223-
failure = "ConflictingAssignmentNameException while adding assignment " + e.getMessage();
223+
failure = "ConflictingAssignmentNameException while adding assignment " + e.toString();
224224
gradebookColumn = null; // Just to make sure
225225
} catch (Exception e) {
226-
failure = "Exception (may be because GradeBook has not yet been added to the Site) "+ e.getMessage();
226+
failure = "Exception (may be because GradeBook has not yet been added to the Site) "+ e.toString();
227227
gradebookColumn = null; // Just to make double sure
228228
} finally {
229229
popAdvisor();
@@ -323,8 +323,9 @@ public static Map<String, String> getExternalIdsForToolAssignments(String contex
323323
if ( content == null ) continue;
324324
retval.put(assignmentReference, constructExternalId(content, null));
325325
}
326-
} catch (Throwable e) {
327-
log.error("Unexpected Throwable", e.getMessage());
326+
} catch (Exception e) {
327+
log.error("Unexpected Throwable", e.toString());
328+
log.debug("Stacktrace", e);
328329
}
329330
return retval;
330331
}
@@ -367,7 +368,8 @@ protected static List<Assignment> getColumnsForToolDAO(String context_id, Long t
367368
retval.add(gbColumn);
368369
}
369370
} catch (Throwable e) {
370-
log.error("Unexpected Throwable", e.getMessage());
371+
log.error("Unexpected Throwable", e.toString());
372+
log.debug("Stacktrace:", e);
371373
retval = null;
372374
} finally {
373375
popAdvisor();
@@ -390,7 +392,8 @@ protected static List<Assignment> getColumnsForContextDAO(String context_id) {
390392
List<Assignment> gradebookColumns = gradingService.getAssignments(context_id, context_id, SortType.SORT_BY_NONE);
391393
return gradebookColumns;
392394
} catch (Throwable e) {
393-
log.error("Unexpected Throwable", e.getMessage());
395+
log.error("Unexpected Throwable", e.toString());
396+
log.debug("Stacktrace:", e);
394397
retval = null;
395398
} finally {
396399
popAdvisor();
@@ -441,7 +444,8 @@ protected static Assignment getColumnByLabelDAO(String context_id, Long tool_id,
441444
}
442445
}
443446
} catch (Throwable e) {
444-
log.error("Unexpected Throwable", e.getMessage());
447+
log.error("Unexpected Throwable", e.toString());
448+
log.debug("Stacktrace:", e);
445449
retval = null;
446450
} finally {
447451
popAdvisor();
@@ -486,7 +490,7 @@ public static boolean isGradebookColumnLTI(Assignment gradebookColumn) {
486490
}
487491

488492
public static boolean isAssignmentColumn(String external_id) {
489-
return external_id.startsWith(ASSIGNMENT_REFERENCE_PREFIX);
493+
return external_id != null && external_id.startsWith(ASSIGNMENT_REFERENCE_PREFIX);
490494
}
491495

492496
/**
@@ -515,13 +519,15 @@ public static List<SakaiLineItem> getLineItemsForTool(String signed_placement, S
515519
for (Iterator i = gradebookColumns.iterator(); i.hasNext();) {
516520
Assignment gbColumn = (Assignment) i.next();
517521
String external_id = gbColumn.getExternalId();
522+
log.debug("gbColumn: {} {}", gbColumn.getName(), external_id);
518523
if ( isGradebookColumnLTI(gbColumn) ) {
519524
// We are good to go
520-
} else if ( isAssignmentColumn(external_id) ) {
525+
} else if ( StringUtils.isNotEmpty(external_id) && isAssignmentColumn(external_id) ) {
521526
if ( externalIds == null ) {
522527
externalIds = getExternalIdsForToolAssignments(context_id);
523528
}
524529
external_id = externalIds.get(external_id);
530+
log.debug("derived assignment based on external_id: {} {}", external_id, externalIds);
525531
if ( external_id == null ) continue;
526532
}
527533

@@ -546,6 +552,7 @@ public static List<SakaiLineItem> getLineItemsForTool(String signed_placement, S
546552
}
547553
} catch (Throwable e) {
548554
log.error("Unexpected Throwable", e.getMessage());
555+
log.debug("Stacktrace:", e);
549556
} finally {
550557
popAdvisor();
551558
}

lti/tsugi-util/src/java/org/tsugi/ags2/objects/Score.java

+24
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,15 @@ public class Score extends org.tsugi.jackson.objects.JacksonBase {
7575

7676
@JsonProperty("timestamp")
7777
public String timestamp;
78+
/*
79+
* All scoreGiven values MUST be positive number (including 0). scoreMaximum represents the denominator and MUST be present
80+
* when scoreGiven is present. When scoreGiven is not present or null, this indicates there is presently no score for
81+
* that user, and the platform should clear any previous score value it may have previously received from the tool and
82+
*stored for that user and line item.
83+
*/
7884
@JsonProperty("scoreGiven")
7985
public Double scoreGiven;
86+
// The maximum score for this line item. Maximum score MUST be a numeric non-null value, strictly greater than 0.
8087
@JsonProperty("scoreMaximum")
8188
public Double scoreMaximum;
8289
@JsonProperty("userId")
@@ -87,4 +94,21 @@ public class Score extends org.tsugi.jackson.objects.JacksonBase {
8794
public String activityProgress;
8895
@JsonProperty("gradingProgress")
8996
public String gradingProgress;
97+
98+
public Double getScoreGiven() {
99+
if (scoreGiven == null ) return null;
100+
if ( scoreGiven < 0.0 ) return 0.0;
101+
return scoreGiven;
102+
}
103+
104+
public Double getScoreMaximum() {
105+
if ( scoreMaximum != null && scoreMaximum >= 0.0 ) return scoreMaximum;
106+
Double sg = getScoreGiven();
107+
if ( sg != null && sg < 2.0 ) return 1.0;
108+
return 100.0;
109+
}
110+
111+
public String toString() {
112+
return "Score: " + scoreGiven + " / " + scoreMaximum + " " + userId;
113+
}
90114
}

0 commit comments

Comments
 (0)