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

SAK-50927 CC+Archive Lessons cross-server import has stack trace #13246

Merged
merged 1 commit into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ protected void processLti(String fileName, String siteId, StringBuilder results,
}
Long contentId = ltiService.getId(content);
if ( contentId > 0 ) {
content.put("TOOL_IMPORT", tool);
content.put(LTIService.TOOL_IMPORT_MAP, tool);
ltiContentItems.put(contentId, content);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ public SecurityAdvice isAllowed(String userId, String function, String reference
securityService.pushAdvisor(mergeAdvisor);

merge("0134937b-ce16-440c-80a6-fb088d79e5ad", (Element)doc.getFirstChild().getFirstChild(), "/tmp/archive", "45d48248-ba23-4829-914a-7219c3ced2dd", null, null, null);

} catch (Exception e) {
log.info(e.getMessage(), e);
} finally {
Expand Down Expand Up @@ -730,7 +731,7 @@ public String getLabel() {
}

// the pages are already made. this adds the elements
private boolean makePage(Element element, String oldServer, String siteId, String fromSiteId, Map<Long,Long> pageMap, Map<Long,Long> itemMap, Map<String,String> entityMap) {
private boolean makePage(Element element, String oldServer, String siteId, String fromSiteId, Map<Long,Long> pageMap, Map<Long,Long> itemMap, Map<String,String> entityMap, Map<Long, Map<String, Object>> ltiContentItems) {

String oldSiteId = element.getAttribute("siteid");
String oldPageIdString = element.getAttribute("pageid");
Expand All @@ -748,6 +749,14 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin
} catch (Exception impossible) {};
}

Site fromSite = null;
try {
fromSite = siteService.getSite(fromSiteId);
} catch (Exception impossible) {
fromSite = null;
};
boolean isSameServer = fromSite != null;

NodeList allChildrenNodes = element.getChildNodes();
int length = allChildrenNodes.getLength();
for (int i = 0; i < length; i++) {
Expand Down Expand Up @@ -775,16 +784,73 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin
else
log.warn("sakaiId not recognized: {}", sakaiId);
} else if (type == SimplePageItem.BLTI) {
try {
// We need to import the BLTI tool to the new site and update the sakaiid
String[] bltiId = sakaiId.split("/");
Long ltiContentId = Long.valueOf(bltiId[2]);
Map<String, Object> ltiContent = ltiService.getContentDao(ltiContentId, oldSiteId, securityService.isSuperUser());
String newSakaiId = copyLTIContent(ltiContent, siteId, oldSiteId);
if ( newSakaiId != null ) sakaiId = newSakaiId;
} catch (Exception e) {
log.warn("Unable to import LTI tool to new site: {}", e);
}
// We need to import the BLTI tool to the new site and update the sakaiid
if (sakaiId == null || !sakaiId.startsWith("/blti/")) {
log.warn("Invalid BLTI sakaiId format: {}", sakaiId);
continue;
}
String[] bltiId = sakaiId.split("/");
Long ltiContentId = NumberUtils.toLong(bltiId[2]);
if (ltiContentId < 1) {
log.warn("Invalid BLTI sakaiId format: {}", sakaiId);
continue;
}
if ( isSameServer ) {
try {
Map<String, Object> ltiContent = ltiService.getContentDao(ltiContentId, oldSiteId, securityService.isSuperUser());
String newSakaiId = copyLTIContent(ltiContent, siteId, oldSiteId);
if ( newSakaiId != null ) sakaiId = newSakaiId;
} catch (Exception e) {
log.warn("Unable to import LTI tool to new site: {}", e);
continue;
}
} else {
if ( ltiContentItems == null ) {
log.warn("Unable to look up LTI content item with ID: {}", ltiContentId);
continue;
}
Map<String, Object> ltiContentItem = ltiContentItems.get(ltiContentId);
if (ltiContentItem == null) {
log.warn("Unable to find LTI content item with ID: {}", ltiContentId);
continue;
}

// Lets find the right tool to assiociate with if it is already installed
Long ltiToolId = null;
String launchUrl = ltiContentItem.get(LTIService.LTI_LAUNCH).toString();
String toolBaseUrl = SakaiLTIUtil.stripOffQuery(launchUrl);
List<Map<String,Object>> tools = ltiService.getTools(null,null,0,0, siteId);
Map<String, Object> ltiTool = SakaiLTIUtil.findBestToolMatch(launchUrl, null, tools);
if ( ltiTool != null ) ltiToolId = ltiService.getId(ltiTool);

// If no matching tool, lets get a tool from the import XML if provided
// or make a stub tool from the content data
if ( ltiToolId == null ) {
ltiTool = (Map<String, Object>) ltiContentItem.get(LTIService.TOOL_IMPORT_MAP);
if (ltiTool == null) {
log.debug("Creating LTI11 Stub Tool for {}", toolBaseUrl);
ltiTool = ltiService.createStubLTI11Tool(toolBaseUrl, ltiContentItem.get(LTIService.LTI_TITLE).toString());
}
Object toolResult = ltiService.insertTool(ltiTool, siteId);
if (!(toolResult instanceof Long)) {
log.warn("Unable to add LTI tool to new site: {}", toolResult);
continue;
} else {
ltiToolId = (Long) toolResult;
}
}
// Now store the content item with the toolId
ltiContentItem.put(LTIService.LTI_TOOL_ID, ltiToolId);
Object contentResult = ltiService.insertContent(ltiContentItem, siteId);
if (!(contentResult instanceof Long)) {
log.warn("Unable to import LTI content to new site: {}", contentResult);
continue;
} else {
ltiContentId = (Long) contentResult;
sakaiId = "/blti/" + ltiContentId;
log.debug("Created new content item: {}", sakaiId);
}
}
} else if (type == SimplePageItem.TEXT) {
String html = itemElement.getAttribute("html");
// TODO: SAK-46983 - Check carefully
Expand Down Expand Up @@ -1140,14 +1206,19 @@ public String fixUrls(String s, String oldServer, String siteId, String fromSite
return convertHtmlContent(context, htmlWithAttachments, null, itemMap);
}

public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans,
Set userListAllowImport) {
return merge(siteId, root, archivePath, fromSiteId, attachmentNames, userIdTrans, userListAllowImport, null);
// Externally used for zip import
@Override
public String merge(String siteId, Element root, String archivePath, String fromSiteId, String creatorId, Map<String, String> attachmentNames,
Map<Long, Map<String, Object>> ltiContentItems, Map<String, String> userIdTrans, Set<String> userListAllowImport) {
return merge(siteId, root, archivePath, fromSiteId, creatorId, attachmentNames, ltiContentItems, userIdTrans, userListAllowImport, null);
}

public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans,
Set userListAllowImport, Map<String, String> entityMap)
// Internally used for both site copy and zip import
public String merge(String siteId, Element root, String archivePath, String fromSiteId, String creatorId, Map attachmentNames,
Map<Long, Map<String, Object>> ltiContentItems, Map userIdTrans, Set userListAllowImport, Map<String, String> entityMap)
{
log.debug("Lessons Merge siteId={} fromSiteId={} creatorId={}", siteId, fromSiteId, creatorId);

StringBuilder results = new StringBuilder();
// map old to new page ids
Map <Long,Long> pageMap = new HashMap<Long,Long>();
Expand Down Expand Up @@ -1231,7 +1302,8 @@ public String merge(String siteId, Element root, String archivePath, String from
Long oldPageId = Long.valueOf(pageElement.getAttribute("pageid"));
pageElementMap.put(oldPageId, pageElement);

if (makePage(pageElement, oldServer, siteId, fromSiteId, pageMap, itemMap, entityMap))
if (makePage(pageElement, oldServer, siteId, fromSiteId, pageMap, itemMap, entityMap, ltiContentItems))

needFix = true;
}
}
Expand Down Expand Up @@ -1543,7 +1615,8 @@ public Map<String,String> transferCopyEntitiesImpl(String fromContext, String to

stack.pop();

merge(toContext, (Element)doc.getFirstChild().getFirstChild(), "/tmp/archive", fromContext, null, null, null, entityMap);
String creatorId = sessionManager.getCurrentSessionUserId();
merge(toContext, (Element)doc.getFirstChild().getFirstChild(), "/tmp/archive", fromContext, creatorId, null, null, null, null, entityMap);

ToolSession session = sessionManager.getCurrentToolSession();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,9 @@ public interface LTIService extends LTISubstitutionsFilter {

// Checksum for import and export
String SAKAI_TOOL_CHECKSUM = "sakai_tool_checksum";
String ARCHIVE_LTI_CONTENT_TAG = "sakai-lti-content";
String ARCHIVE_LTI_CONTENT_TAG = "sakai-lti-content";
String ARCHIVE_LTI_TOOL_TAG = "sakai-lti-tool";
String TOOL_IMPORT_MAP = "TOOL_IMPORT";

/**
* Indicate if the current logged in user has the maintain role in a site
Expand Down Expand Up @@ -351,6 +352,10 @@ public interface LTIService extends LTISubstitutionsFilter {
// Returns whether or not a tool needs further configuration
boolean isDraft(Map<String, Object> tool);

Map<String, Object> createStubLTI11Tool(String toolBaseUrl, String title);

Properties convertToProperties(Map<String, Object> map);

Object insertTool(Properties newProps, String siteId);

Object insertTool(Map<String, Object> newProps, String siteId);
Expand Down Expand Up @@ -473,6 +478,8 @@ public interface LTIService extends LTISubstitutionsFilter {

Object insertContent(Properties newProps, String siteId);

Object insertContent(Map<String, Object> newProps, String siteId);

Object insertContentDao(Properties newProps, String siteId);

Object insertContentDao(Properties newProps, String siteId, boolean isAdminRole, boolean isMaintainRole);
Expand Down
64 changes: 30 additions & 34 deletions lti/lti-impl/src/java/org/sakaiproject/lti/impl/BaseLTIService.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import java.lang.StringBuffer;

Expand All @@ -40,7 +39,6 @@
import org.json.simple.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.cover.ComponentManager;
Expand All @@ -64,7 +62,7 @@
import org.tsugi.lti.LTIUtil;

import lombok.extern.slf4j.Slf4j;

import lombok.Setter;
/**
* <p>
* Implements the LTIService, all but a Storage model.
Expand Down Expand Up @@ -135,34 +133,11 @@ public void setEventTrackingService(EventTrackingService service) {
m_eventTrackingService = service;
}

/**
*
*/
protected SecurityService securityService = null;
/**
*
*/
protected SiteService siteService = null;
/**
*
*/
@Setter protected SecurityService securityService = null;

/**
*
*/
protected ServerConfigurationService serverConfigurationService;
@Setter protected SiteService siteService = null;

/**
* Pull in any necessary services using factory pattern
*/
protected void getServices() {
if (securityService == null)
securityService = ComponentManager.get(SecurityService.class);
if (siteService == null)
siteService = ComponentManager.get(SiteService.class);
if (serverConfigurationService == null)
serverConfigurationService = ComponentManager.get(ServerConfigurationService.class);
}
@Setter protected ServerConfigurationService serverConfigurationService;

/**********************************************************************************************************************************************************************************************************************************************************
* Init and Destroy
Expand All @@ -179,8 +154,6 @@ public void init() {
log.warn("init(): ", t);
}

getServices();

// Check to see if all out properties are defined
ArrayList<String> strings = foorm.checkI18NStrings(LTIService.TOOL_MODEL, rb);
for (String str : strings) {
Expand Down Expand Up @@ -493,7 +466,7 @@ public boolean isDraft(Map<String, Object> tool) {
}

if ( SakaiLTIUtil.isLTI13(tool)
&& StringUtils.isNotEmpty((String) tool.get(LTI13_CLIENT_ID))
&& 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;
Expand Down Expand Up @@ -704,6 +677,25 @@ public String validateContent(Map<String, Object> newProps) {
return null;
}

@Override
public Map<String,Object> createStubLTI11Tool(String toolBaseUrl, String title) {
Map<String, Object> retval = new HashMap ();
retval.put(LTIService.LTI_LAUNCH,toolBaseUrl);
retval.put(LTIService.LTI_TITLE, title);
retval.put(LTIService.LTI_CONSUMERKEY, LTIService.LTI_SECRET_INCOMPLETE);
retval.put(LTIService.LTI_SECRET, LTIService.LTI_SECRET_INCOMPLETE);
retval.put(LTIService.LTI_ALLOWOUTCOMES, "1");
retval.put(LTIService.LTI_SENDNAME, "1");
retval.put(LTIService.LTI_SENDEMAILADDR, "1");
retval.put(LTIService.LTI_NEWPAGE, "2");
return retval;
}

@Override
public Properties convertToProperties(Map<String, Object> map) {
return Foorm.convertToProperties(map);
}

@Override
public Object insertContent(Properties newProps, String siteId) {
if ( newProps.getProperty(LTIService.LTI_PLACEMENTSECRET) == null ) {
Expand All @@ -712,6 +704,11 @@ public Object insertContent(Properties newProps, String siteId) {
return insertContentDao(newProps, siteId, isAdmin(siteId), isMaintain(siteId));
}

@Override
public Object insertContent(Map<String, Object> newMap, String siteId) {
return insertContent(convertToProperties(newMap), siteId);
}

@Override
public Object insertContentDao(Properties newProps, String siteId) {
if ( newProps.getProperty(LTIService.LTI_PLACEMENTSECRET) == null ) {
Expand Down Expand Up @@ -1144,7 +1141,7 @@ public Long mergeContentFromImport(Element element, String siteId) {
Long toolId = Foorm.getLongNull(theTool.get(LTIService.LTI_ID));
log.debug("Matched toolId={} for launchUrl={}", toolId, launchUrl);
content.put(LTIService.LTI_TOOL_ID, toolId.intValue());
Object result = this.insertContent(Foorm.convertToProperties(content), siteId);
Object result = this.insertContent(convertToProperties(content), siteId);
if ( ! (result instanceof Long) ) {
log.info("Could not insert content {}", result);
return null;
Expand All @@ -1160,7 +1157,6 @@ public Long mergeContentFromImport(Element element, String siteId) {
return contentKey;
}
}

}

@Override
Expand Down
3 changes: 3 additions & 0 deletions lti/lti-impl/src/webapp/WEB-INF/components.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<property name="usageSessionService"><ref bean="org.sakaiproject.event.api.UsageSessionService"/></property>
<property name="userDirectoryService"><ref bean="org.sakaiproject.user.api.UserDirectoryService"/></property>
<property name="sessionManager"><ref bean="org.sakaiproject.tool.api.SessionManager"/></property>
<property name="serverConfigurationService"><ref bean="org.sakaiproject.component.api.ServerConfigurationService"/></property>
<property name="siteService"><ref bean="org.sakaiproject.site.api.SiteService"/></property>
<property name="securityService"><ref bean="org.sakaiproject.authz.api.SecurityService"/></property>
<property name="autoDdl"><value>${auto.ddl}</value></property>
</bean>

Expand Down
Loading