Skip to content

Commit

Permalink
Merge branch 'master' into SAK-50888
Browse files Browse the repository at this point in the history
  • Loading branch information
ottenhoff authored Jan 29, 2025
2 parents 62a9719 + 4965ff6 commit 6b389f3
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9100,24 +9100,13 @@ private void post_save_assignment(RunData data, String postOrSave) {
}

if ((newAssignment && !a.getDraft()) || (!a.getDraft() && !newAssignment)) {

Collection aGroups = a.getGroups();
if (aGroups.size() != 0) {
// If already open
if (openTime.isBefore(Instant.now())) {
eventTrackingService.post(eventTrackingService.newEvent(AssignmentConstants.EVENT_UPDATE_ASSIGNMENT_ACCESS, assignmentReference, true));
} else {
// Not open yet, delay the event
eventTrackingService.delay(eventTrackingService.newEvent(AssignmentConstants.EVENT_AVAILABLE_ASSIGNMENT, assignmentReference,
true), openTime);
}
// If already open
if (openTime.isBefore(Instant.now())) {
// post new assignment event since it is fully initialized by now
eventTrackingService.post(eventTrackingService.newEvent(AssignmentConstants.EVENT_ADD_ASSIGNMENT, assignmentReference, true));
} else {
if (openTime.isBefore(Instant.now())) {
// post new assignment event since it is fully initialized by now
eventTrackingService.post(eventTrackingService.newEvent(AssignmentConstants.EVENT_ADD_ASSIGNMENT, assignmentReference, true));
} else {
eventTrackingService.delay(eventTrackingService.newEvent(AssignmentConstants.EVENT_AVAILABLE_ASSIGNMENT, assignmentReference, true), openTime);
}
// Not open yet, delay the event
eventTrackingService.delay(eventTrackingService.newEvent(AssignmentConstants.EVENT_AVAILABLE_ASSIGNMENT, assignmentReference, true), openTime);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,12 @@ public boolean isVisible() {
sakaiRubricButton.setVisible(true);
}

String ownerId = studentUuid;
if (assignment.getExternallyMaintained()) {
sakaiRubricButton.add(AttributeModifier.append("tool-id", AssignmentConstants.TOOL_ID));
String[] bits = assignment.getExternalId().split("/");
if (bits != null && bits.length >= 1) {
String assignmentId = bits[bits.length-1];
String ownerId = studentUuid;
if (assignment.getExternalAppName().equals(assignmentService.getToolId())) {
try {
org.sakaiproject.assignment.api.model.Assignment assignmentsAssignment = assignmentService.getAssignment(assignmentId);
Expand All @@ -419,7 +419,8 @@ public boolean isVisible() {
}).findAny();

if (groupId.isPresent()) {
ownerId = groupId.get();
String[] groupBits = groupId.get().split("/");
ownerId = groupBits[groupBits.length-1];
} else {
log.error("Assignment {} is a group assignment, but {} was not in any of the groups", assignmentId, studentUuid);
}
Expand Down Expand Up @@ -454,7 +455,7 @@ public boolean isVisible() {
}
}

sakaiRubricButton.add(AttributeModifier.append("evaluated-item-owner-id", studentUuid));
sakaiRubricButton.add(AttributeModifier.append("evaluated-item-owner-id", ownerId));

gradeScore.add(sakaiRubricButton);
}
Expand Down
9 changes: 7 additions & 2 deletions lessonbuilder/api/src/resources/lessons.properties
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,12 @@ simplepage.additional-instructions-label=Frequently Asked Questions about multim
simplepage.additional-website-instructions-label=Frequently Asked Questions about uploading content from ZIP file

simplepage.link=Add Link
simplepage.linkTitle=Link Title
simplepage.addlink_header=Add A New Link
simplepage.addLink_label=URL:
simplepage.addLink_label_add=Add a URL:
simplepage.addlink_label_name = Custom name to display for URL [optional]
simplepage.addFile_label_name = Custom name for uploaded file [optional]
simplepage.addLink_label_add_or=Or add a URL or "embed code"
simplepage.editText=Edit This Text
simplepage.editItem=Edit
Expand Down Expand Up @@ -675,8 +677,7 @@ simplepage.format.heading=Display Options
simplepage.format.window=Open in New Window
simplepage.format.inline=Embed on page
simplepage.format.page=Open in New Lessons tool Page with 'next' and 'back' buttons
simplepage.format.item_removed=<p style='font-family:arial, helvetica; padding:4px; font-size:80%; border:2px solid black'><span style='color:#c00'>ERROR:</span> The item that should have been displayed here has been removed. Please use the "Edit" button next to this item and pick "Change External Tool" to recreate the item or choose a new one.</p>

simplepage.format.item_removed_text=The item that should have been displayed here has been removed. Please use the "Edit" button next to this item and pick "Change External Tool" to recreate the item or choose a new one.
simplepage.more-tools=More Tools
simplepage.forum-descrip=Link to a Forum or Topic
simplepage.blti-descrip=Link to a web service that uses the IMS LTI standard to integrate with this system
Expand Down Expand Up @@ -961,3 +962,7 @@ simplepage.max-file-upload-size=The upload size limit of
simplepage.max-file-upload-size-save=MB has been exceeded. Remove one or more files below to proceed. Other files may be uploaded assuming the total file size does not exceed this limit.

lessons_comment=Lessons Comment

lti.tool.missing=Content Item has no LTI tool, please re-select
lti.tool.import.incomplete=LTI tool for this item needs further configuration
lti.tool.is.draft=LTI tool for this item is still draft, needs configuration
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import java.util.HashMap;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

import org.json.simple.JSONObject;

import lombok.extern.slf4j.Slf4j;
Expand All @@ -51,6 +53,7 @@
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.util.ResourceLoader;

import org.tsugi.lti.LTIUtil;
import org.sakaiproject.lti.util.SakaiLTIUtil;
Expand All @@ -67,6 +70,7 @@
public class BltiEntity implements LessonEntity, BltiInterface {
private static Cache bltiCache = null;
protected static final int DEFAULT_EXPIRATION = 10 * 60;
protected static ResourceLoader rb = new ResourceLoader("lessons");

private SimplePageBean simplePageBean;

Expand Down Expand Up @@ -313,27 +317,37 @@ public String getIcon() {
}

private String getErrorUrl() {
return "javascript:document.write('" + messageLocator.getMessage("simplepage.format.item_removed").replace("'", "\\'") + "')";
return "javascript:alert('" + messageLocator.getMessage("simplepage.format.item_removed_text").replace("'", "\\'") + "')";
}

public String getEditNote() {
loadContent();
if ( content == null ) return null; // Lessons will show *deleted*

if ( tool == null ) {
return rb.getString("lti.tool.missing");
}


String siteId = getSiteId();
if ( StringUtils.isNotEmpty(siteId) && siteId.equals((String) tool.get(LTIService.LTI_SITE_ID))
&& LTIService.LTI_SECRET_INCOMPLETE.equals((String) tool.get(LTIService.LTI_SECRET))
&& LTIService.LTI_SECRET_INCOMPLETE.equals((String) tool.get(LTIService.LTI_CONSUMERKEY)) ) {
return rb.getString("lti.tool.import.incomplete");
}

if ( ltiService.isDraft(tool) ) {
return rb.getString("lti.tool.is.draft");
}

return null;
}

// TODO: Concern regarding the lack of the returnUrl when this is called
public String getUrl() {
loadContent();
// If I return null here, it appears that I cause an NPE in LB
if ( content == null ) return getErrorUrl();
String ret = (String) content.get("launch_url");
if ( ltiService != null && tool != null && ltiService.isMaintain(getSiteId())
&& LTIService.LTI_SECRET_INCOMPLETE.equals((String) tool.get(LTIService.LTI_SECRET))
&& LTIService.LTI_SECRET_INCOMPLETE.equals((String) tool.get(LTIService.LTI_CONSUMERKEY)) ) {

String toolId = getCurrentTool("sakai.siteinfo");
if ( toolId != null ) {
ret = editItemUrl(toolId);
ret = ret + "&secretonly=true";
return ret;
}
}

if ( ret == null ) return getErrorUrl();
ret = ServerConfigurationService.getServerUrl() + ret;
return ret;
}
Expand Down Expand Up @@ -457,6 +471,7 @@ public String doImportTool(String launchUrl, String bltiTitle, String strXml, St
// Allow the content item to choose open in popup so the user can change it in the Lessons UI
props.setProperty(LTIService.LTI_NEWPAGE, "2");
props.setProperty(LTIService.LTI_XMLIMPORT,strXml);
props.setProperty(LTIService.LTI13,"0");
if (custom != null)
props.setProperty(LTIService.LTI_CUSTOM, custom);
Object result = ltiService.insertTool(props, simplePageBean.getCurrentSiteId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public interface LessonEntity {
public String getTitle();
public String getDescription();
public String getUrl();
// Returns a note to display near the link for editors (i.e. like Deleted)
default public String getEditNote() {
return null;
}
public Date getDueDate();
// for forums, where we have a hiearchy of topics
public int getLevel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,7 @@ public void printSubpage(List<SimplePageItem> itemList, boolean first, UIBranchC
// javascript that prepares
// the jQuery dialogs
String itemGroupString = null;
String editNote = null;
boolean entityDeleted = false;
boolean notPublished = false;
if (canEditPage) {
Expand Down Expand Up @@ -1606,19 +1607,18 @@ else if (assignment.notPublished())
UIOutput.make(tableRow, "type", "b");
LessonEntity blti = (bltiEntity == null ? null : bltiEntity.getEntity(i.getSakaiId()));
if (blti != null) {
String editUrl = blti.editItemUrl(simplePageBean);
if (editUrl != null)
UIOutput.make(tableRow, "edit-url", editUrl);
UIOutput.make(tableRow, "item-format", i.getFormat());

if (i.getHeight() != null)
UIOutput.make(tableRow, "item-height", i.getHeight());
itemGroupString = simplePageBean.getItemGroupString(i, null, true);
UIOutput.make(tableRow, "item-groups", itemGroupString );
if (!blti.objectExists())
entityDeleted = true;
else if (blti.notPublished())
notPublished = true;
String editUrl = blti.editItemUrl(simplePageBean);
editNote = blti.getEditNote();
if (editUrl != null) UIOutput.make(tableRow, "edit-url", editUrl);
UIOutput.make(tableRow, "item-format", i.getFormat());

if (i.getHeight() != null) UIOutput.make(tableRow, "item-height", i.getHeight());
itemGroupString = simplePageBean.getItemGroupString(i, null, true);
UIOutput.make(tableRow, "item-groups", itemGroupString );
if (!blti.objectExists())
entityDeleted = true;
else if (blti.notPublished())
notPublished = true;
}
} else if (i.getType() == SimplePageItem.FORUM) {
UIOutput.make(tableRow, "extra-info");
Expand Down Expand Up @@ -1656,6 +1656,7 @@ else if (forum.notPublished())

} // end of canEditPage


if (i.getType() == SimplePageItem.PAGE) {
UIOutput.make(tableRow, "type", "page");
UIOutput.make(tableRow, "page-next", Boolean.toString(i.getNextPage()));
Expand Down Expand Up @@ -1708,8 +1709,9 @@ else if (lessonEntity.notPublished())
notPublished = true;
break;
case SimplePageItem.BLTI:
if (bltiEntity != null)
lessonEntity = bltiEntity.getEntity(i.getSakaiId());
if (bltiEntity != null) {
lessonEntity = bltiEntity.getEntity(i.getSakaiId());
}
if (lessonEntity != null)
itemGroupString = simplePageBean.getItemGroupString(i, null, true);
if (!lessonEntity.objectExists())
Expand Down Expand Up @@ -1749,6 +1751,10 @@ else if (lessonEntity.notPublished())
else
itemGroupString = messageLocator.getMessage("simplepage.not-published");
}
if ( StringUtils.isNotEmpty(editNote) ) {
if (StringUtils.isEmpty(itemGroupString) ) itemGroupString= "";
itemGroupString = itemGroupString + " " + editNote;
}
if (entityDeleted) {
if (itemGroupString != null)
itemGroupString = itemGroupString + " " +
Expand Down
4 changes: 2 additions & 2 deletions lessonbuilder/tool/src/webapp/js/show-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -3253,9 +3253,9 @@ $(function () {
if (i === 0 && previousTitle){
valueContent = 'value="' + previousTitle + '"';
}
newStuff = newStuff + '<label for="link-title">Link title</label><input id="link-title" class="mm-file-input-names" type="text" size="30" maxlength="255" ' + valueContent + '/></p>';
newStuff = newStuff + '<label for="link-title">' + msg('simplepage.linkTitle') + '</label><input id="link-title" class="mm-file-input-names" type="text" size="30" maxlength="255" ' + valueContent + '/></p>';
} else {
newStuff = newStuff + '<div><label for="link-title"> Custom name for uploaded file [optional]: </label><input id="link-title" class="mm-file-input-names" type="text" size="30" maxlength="255"/></div>';
newStuff = newStuff + '<div><label for="link-title">' + msg('simplepage.addFile_label_name') + '</label><input id="link-title" class="mm-file-input-names" type="text" size="30" maxlength="255"/></div>';
}
newStuff = newStuff + '</p>'
lastInput.after(newStuff);
Expand Down
2 changes: 2 additions & 0 deletions lessonbuilder/tool/src/webapp/templates/ShowPage.html
Original file line number Diff line number Diff line change
Expand Up @@ -3329,6 +3329,8 @@ <h4><span rsf:id="peer-eval-target-name"></span></h4>
<p rsf:id="msg=simplepage.edit" id="simplepage.edit"></p>
<p rsf:id="msg=simplepage.addLink_label_add" id="simplepage.addLink_label_add"></p>
<p rsf:id="msg=simplepage.addLink_label_add_or" id="simplepage.addLink_label_add_or"></p>
<p rsf:id="msg=simplepage.addFile_label_name" id="simplepage.addFile_label_name"></p>
<p rsf:id="msg=simplepage.linkTitle" id="simplepage.linkTitle"></p>
<p rsf:id="msg=simplepage.deletecommentsubmissionexist" id="simplepage.deletecommentsubmissionexist"></p>
<p rsf:id="msg=simplepage.deletestudentsubmissionexist" id="simplepage.deletestudentsubmissionexist"></p>
<p rsf:id="msg=simplepage.delete_page_confirm" id="simplepage.delete_page_confirm"></p>
Expand Down
3 changes: 3 additions & 0 deletions lti/lti-api/src/java/org/sakaiproject/lti/api/LTIService.java
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ public interface LTIService extends LTISubstitutionsFilter {

String validateTool(Map<String, Object> newProps);

// Returns whether or not a tool needs further configuration
boolean isDraft(Map<String, Object> tool);

Object insertTool(Properties newProps, String siteId);

Object insertTool(Map<String, Object> newProps, String siteId);
Expand Down
33 changes: 21 additions & 12 deletions lti/lti-common/src/java/org/sakaiproject/lti/util/SakaiLTIUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ public static String[] postLaunchHTML(Map<String, Object> content, Map<String, O
return postError("<p>" + getRB(rb, "error.tool.partial", "Tool item is incomplete, missing a key and secret.") + "</p>");
}

boolean isLTI13 = isLTI13(tool, content);
boolean isLTI13 = isLTI13(tool);

log.debug("isLTI13={}", isLTI13);

Expand Down Expand Up @@ -1488,7 +1488,7 @@ public static String[] postContentItemSelectionRequest(Long toolKey, Map<String,
// If secret is encrypted, decrypt it
secret = decryptSecret(secret);

boolean isLTI13 = isLTI13(tool, null);
boolean isLTI13 = isLTI13(tool);

log.debug("isLTI13={}", isLTI13);

Expand Down Expand Up @@ -3472,7 +3472,7 @@ public static Map<String, String> deserializeMap(String mapSer) {
}

/**
* Converts a string from a semicolon-separated list of legacy lti roles mapped ot a modern LTI role to a
* Converts a string from a semicolon-separated list of legacy lti roles mapped to a modern LTI role to a
* Map<String, String>. Each role mapping should be of the form:
* Learner=http://purl.imsglobal.org/vocab/lis/v2/membership#Learner
*/
Expand All @@ -3481,19 +3481,28 @@ public static Map<String, String> convertLegacyRoleMapPropToMap(String roleMapPr
}

/**
* Check if we are an LTI 1.3 launch or not
* Check if we are an LTI 1.1 launch or not
*/
public static boolean isLTI13(Map<String, Object> tool, Map<String, Object> content) {
// 0=inherit from tool, 1=LTI 1.1, 2=LTI 1.3
if ( content != null ) {
Long contentLTI13 = Foorm.getLong(content.get(LTIService.LTI13));
if ( contentLTI13.equals(2L)) return true;
if ( contentLTI13.equals(1L)) return false;
}
public static boolean isLTI11(Map<String, Object> tool) {
if ( tool == null ) return false;
Long toolLTI13 = Foorm.getLong(tool.get(LTIService.LTI13));
if ( toolLTI13.equals(LTIService.LTI13_LTI11) ) return true;
if ( toolLTI13.equals(LTIService.LTI13_LTI13) ) return false;
if ( toolLTI13.equals(LTIService.LTI13_BOTH) ) return true;
return true;
}


/**
* Check if we are an LTI 1.3 launch or not
*/
public static boolean isLTI13(Map<String, Object> tool) {
if ( tool == null ) return false;
Long toolLTI13 = Foorm.getLong(tool.get(LTIService.LTI13));
return ! toolLTI13.equals(0L);
if ( toolLTI13.equals(LTIService.LTI13_LTI11) ) return false;
if ( toolLTI13.equals(LTIService.LTI13_LTI13) ) return true;
if ( toolLTI13.equals(LTIService.LTI13_BOTH) ) return true;
return false; // Default of null or other funky value is LTI 1.1
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,28 @@ public String validateTool(Properties newProps) {
return validateTool((Map) newProps);
}

@Override
public boolean isDraft(Map<String, Object> tool) {
boolean retval = true;
if ( tool == null ) return retval;
if ( StringUtils.isEmpty((String) tool.get(LTI_LAUNCH)) ) return true;
if ( SakaiLTIUtil.isLTI11(tool) ) {
String consumerKey = (String) tool.get(LTI_CONSUMERKEY);
String consumerSecret = (String) tool.get(LTI_SECRET);
if ( StringUtils.isNotEmpty(consumerSecret) && StringUtils.isNotEmpty(consumerSecret)
&& (! LTI_SECRET_INCOMPLETE.equals(consumerSecret))
&& (! LTI_SECRET_INCOMPLETE.equals(consumerKey)) ) retval = false;
}

if ( SakaiLTIUtil.isLTI13(tool)
&& StringUtils.isNotEmpty((String) tool.get(LTI13_CLIENT_ID))
&& StringUtils.isNotEmpty((String) tool.get(LTI13_TOOL_KEYSET))
&& StringUtils.isNotEmpty((String) tool.get(LTI13_TOOL_ENDPOINT))
&& StringUtils.isNotEmpty((String) tool.get(LTI13_TOOL_REDIRECT))) retval = false;

return retval;
}

@Override
public String validateTool(Map<String, Object> newProps) {
StringBuffer sb = new StringBuffer();
Expand Down
Loading

0 comments on commit 6b389f3

Please sign in to comment.