use of org.olat.course.tree.CourseEditorTreeNode in project openolat by klemens.
the class CourseEditorEnvImpl method checkFolderNodes.
private List<StatusDescription> checkFolderNodes(INode rootNode, ICourse course, List<StatusDescription> descriptions) {
List<StatusDescription> descriptionsI = descriptions;
Visitor visitor = new Visitor() {
@Override
public void visit(INode node) {
CourseEditorTreeNode courseNode = (CourseEditorTreeNode) course.getEditorTreeModel().getNodeById(node.getIdent());
if (!courseNode.isDeleted() && courseNode.getCourseNode() instanceof BCCourseNode) {
BCCourseNode bcNode = (BCCourseNode) courseNode.getCourseNode();
if (bcNode.isSharedFolder()) {
String translPackage = Util.getPackageName(BCCourseNodeEditController.class);
StatusDescription status = new StatusDescription(StatusDescription.ERROR, "warning.no.sharedfolder", "warning.no.sharedfolder", null, translPackage);
status.setDescriptionForUnit(bcNode.getIdent());
// set which pane is affected by error
status.setActivateableViewIdentifier(BCCourseNodeEditController.PANE_TAB_FOLDER);
descriptionsI.add(status);
}
}
}
};
TreeVisitor v = new TreeVisitor(visitor, rootNode, false);
v.visitAll();
return descriptionsI;
}
use of org.olat.course.tree.CourseEditorTreeNode in project openolat by klemens.
the class PublishProcess method testPublishSet.
/**
* can only be called after createPublishSetFor method. The method calculates the
* resulting runstructure, and checks them against error and warning messages.
* These are returned as a list of StatusDescriptions.<br>
* If status ok -> apply the publish set -> this changes the course effectively
*
* @param locale
* @return
*/
public PublishSetInformations testPublishSet(Locale locale) {
// check for valid references to tests, resource folder, wiki
List<StatusDescription> damagedRefsInsertedNodes = checkRefs(editorModelInsertedNodes);
if (damagedRefsInsertedNodes.size() > 0) {
// abort testing as a blocking error found!
StatusDescription[] status = new StatusDescription[damagedRefsInsertedNodes.size()];
status = damagedRefsInsertedNodes.toArray(status);
return new PublishSetInformations(status);
}
List<StatusDescription> damagedRefsModifiedNodes = checkRefs(editorModelModifiedNodes);
if (damagedRefsModifiedNodes.size() > 0) {
// abort testing as a blocking error found
StatusDescription[] status = new StatusDescription[damagedRefsModifiedNodes.size()];
status = damagedRefsModifiedNodes.toArray(status);
return new PublishSetInformations(status);
}
CourseNode clonedCourseNode = (CourseNode) ObjectCloner.deepCopy(resultingCourseRun.getRootNode());
CourseEditorTreeNode clonedRoot = new CourseEditorTreeNode(clonedCourseNode);
convertInCourseEditorTreeNode(clonedRoot, clonedCourseNode);
// Do remove all children after convertInCourseEditorTreeNode
clonedCourseNode.removeAllChildren();
CourseEditorTreeModel cloneCETM = new CourseEditorTreeModel();
cloneCETM.setRootNode(clonedRoot);
/*
* now we have the cloned editor tree synchronized with the pre-published
* runstructure. The cloned editor tree is used within a new
* CourseEditorEnvironment which is placed in a new Editor User Course
* Session for evaluation only. This is like opening the runstructure in a
* virtual course editor for using the validation facilities of the editor
* environment.
*/
CourseEditorEnv tmpCEV = new CourseEditorEnvImpl(cloneCETM, course.getCourseEnvironment().getCourseGroupManager(), locale);
// the resulting object is not needed, but constructor makes
// initializations within tmpCEV!! thus important step.
new EditorUserCourseEnvironmentImpl(tmpCEV, null);
//
tmpCEV.setCurrentCourseNodeId(cloneCETM.getRootNode().getIdent());
tmpCEV.validateCourse();
StatusDescription[] status = tmpCEV.getCourseStatus();
// check if the resulting course contains cycles.
Set<String> nodesInCycle = tmpCEV.listCycles();
if (nodesInCycle.size() > 0) {
// there are nodes generating cylces -> error! this is not a publishable
// set!
StringBuilder sb = new StringBuilder();
for (String id : nodesInCycle) {
String title = editorTreeModel.getCourseEditorNodeById(id).getTitle();
sb.append("<b>").append(title).append("</b> ").append("(id:").append(id).append(")<br>");
}
StatusDescription sd = new StatusDescription(ValidationStatus.ERROR, "pbl.error.cycles", "pbl.error.cycles", new String[] { sb.toString() }, PACKAGE);
status = new StatusDescription[] { sd };
} else {
/*
* these are now status description as they are helpful in the editor
* context. The same errors in the publish context have a kind of
* different meaning --- Let the nodes explain what it means in publish
* mode.
*/
for (int i = 0; i < status.length; i++) {
StatusDescription description = status[i];
String nodeId = description.getDescriptionForUnit();
CourseNode cn = cloneCETM.getCourseNode(nodeId);
status[i] = cn.explainThisDuringPublish(description);
}
}
List<StatusDescription> updateNotifications = testUpdateSet(tmpCEV);
return new PublishSetInformations(status, updateNotifications);
}
use of org.olat.course.tree.CourseEditorTreeNode in project openolat by klemens.
the class PublishProcess method assemblePublishConfirmation.
String assemblePublishConfirmation() {
List<String> nodeIdsToPublish = originalNodeIdsToPublish;
StringBuilder msg = new StringBuilder();
OLATResourceable courseRunOres = OresHelper.createOLATResourceableInstance(RunMainController.ORES_TYPE_COURSE_RUN, repositoryEntry.getOlatResource().getResourceableId());
// -1: Remove myself from list
int cnt = CoordinatorManager.getInstance().getCoordinator().getEventBus().getListeningIdentityCntFor(courseRunOres) - 1;
if (cnt > 0) {
msg.append(translate("pbl.confirm.users", String.valueOf(cnt)));
} else {
msg.append(translator.translate("pbl.confirm"));
}
if (nodeIdsToPublish != null && nodeIdsToPublish.size() > 0) {
msg.append("<ul class='list-unstyled'>");
CourseEditorTreeModel cetm = course.getEditorTreeModel();
for (int i = 0; i < nodeIdsToPublish.size(); i++) {
msg.append("<li>");
String nodeId = nodeIdsToPublish.get(i);
CourseEditorTreeNode cetn = (CourseEditorTreeNode) cetm.getNodeById(nodeId);
CourseNode cn = cetm.getCourseNode(nodeId);
if (cetn.isDeleted() && !cetn.isNewnode()) {
msg.append("<i class='o_icon o_icon_delete_item'> </i> ");
} else {
CourseNodeConfiguration nodeConfig = CourseNodeFactory.getInstance().getCourseNodeConfigurationEvenForDisabledBB(cn.getType());
if (nodeConfig != null) {
msg.append("<i class='o_icon ").append(nodeConfig.getIconCSSClass()).append("'> </i> ");
}
}
msg.append(cn.getShortTitle()).append("</li>");
}
msg.append("</ul>");
}
return msg.toString();
}
use of org.olat.course.tree.CourseEditorTreeNode in project openolat by klemens.
the class PublishProcess method applyPublishSet.
/**
* @param identity
* @param locale
* @param newCourse Optimization for new courses, it doesn't call upddateOnPublish of inserted/updated course nodes
*/
public void applyPublishSet(Identity identity, Locale locale, boolean newCourse) {
// the active runstructure and the new created runstructure
Structure existingCourseRun = course.getRunStructure();
EventBus orec = CoordinatorManager.getInstance().getCoordinator().getEventBus();
/*
* use book keeping lists for publish event
*/
Set<String> deletedCourseNodeIds = new HashSet<String>();
if (editorModelDeletedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelDeletedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
deletedCourseNodeIds.add(cn.getIdent());
}
}
Set<String> insertedCourseNodeIds = new HashSet<String>();
if (editorModelInsertedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelInsertedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
insertedCourseNodeIds.add(cn.getIdent());
}
}
Set<String> modifiedCourseNodeIds = new HashSet<String>();
if (editorModelModifiedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelModifiedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
modifiedCourseNodeIds.add(cn.getIdent());
}
}
/*
* broadcast PRE PUBLISH event that a publish will take place
*/
PublishEvent beforePublish = new PublishEvent(course, identity);
beforePublish.setDeletedCourseNodeIds(deletedCourseNodeIds);
beforePublish.setInsertedCourseNodeIds(insertedCourseNodeIds);
beforePublish.setModifiedCourseNodeIds(modifiedCourseNodeIds);
beforePublish.setState(PublishEvent.PRE_PUBLISH);
// old course structure accessible
orec.fireEventToListenersOf(beforePublish, course);
/*
* TODO:pb: discuss with fj: listeners could add information to
* beforePublish event such as a right to veto or add identities who is
* currently in the course, thus stopping the publishing author from
* publishing! i.e. if people are in a test or something like this.... we
* could the ask here beforePublish.accepted() and proceed only in this
* case.
*/
//
/*
* remove new nodes which were marked as delete and deletion is published.
*/
UserManager um = UserManager.getInstance();
String charset = um.getUserCharset(identity);
if (editorModelDeletedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelDeletedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
CourseNode oldCn = existingCourseRun.getNode(cetn.getIdent());
// null
if (oldCn != null) {
if (!(cn.getIdent().equals(oldCn.getIdent()))) {
throw new AssertException("deleted cn.getIdent != oldCn.getIdent");
}
}
cetn.removeFromParent();
if (!cetn.isNewnode() && oldCn != null) {
// only clean up and archive of nodes which were already in run
// save data, remove references
deleteRefs(oldCn);
archiveDeletedNode(identity, cn, oldCn, locale, charset);
// 2) delete all user data
oldCn.cleanupOnDelete(course);
}
}
}
/*
* mark modified ones as no longer dirty
*/
if (editorModelModifiedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelModifiedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
CourseNode oldCn = existingCourseRun.getNode(cetn.getIdent());
// null
if (oldCn != null) {
if (!(cn.getIdent().equals(oldCn.getIdent()))) {
throw new AssertException("deleted cn.getIdent != oldCn.getIdent");
}
}
cetn.setDirty(false);
//
updateRefs(cn, oldCn);
}
}
/*
* mark newly published ones is no longer new and dirty
*/
if (editorModelInsertedNodes.size() > 0) {
for (Iterator<CourseEditorTreeNode> iter = editorModelInsertedNodes.iterator(); iter.hasNext(); ) {
CourseEditorTreeNode cetn = iter.next();
CourseNode cn = cetn.getCourseNode();
CourseNode oldCn = existingCourseRun.getNode(cetn.getIdent());
if (oldCn != null) {
throw new AssertException("new node has an oldCN??");
}
cetn.setDirty(false);
cetn.setNewnode(false);
//
updateRefs(cn, null);
}
}
/*
* saving
*/
long pubtimestamp = System.currentTimeMillis();
editorTreeModel.setLatestPublishTimestamp(pubtimestamp);
// set the new runstructure and save it.
existingCourseRun.setRootNode(resultingCourseRun.getRootNode());
CourseFactory.saveCourse(course.getResourceableId());
// on old course, apply update to published nodes
if (!newCourse) {
for (CourseEditorTreeNode cetn : editorModelInsertedNodes) {
cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
}
for (CourseEditorTreeNode cetn : editorModelModifiedNodes) {
cetn.getCourseNode().updateOnPublish(locale, course, identity, publishEvents);
}
}
// commit all changes before sending an event
DBFactory.getInstance().commitAndCloseSession();
/*
* broadcast event
*/
PublishEvent publishEvent = new PublishEvent(course, identity);
publishEvent.setDeletedCourseNodeIds(deletedCourseNodeIds);
publishEvent.setInsertedCourseNodeIds(insertedCourseNodeIds);
publishEvent.setModifiedCourseNodeIds(modifiedCourseNodeIds);
// new course structure accessible
// CourseFactory is one listener, which removes the course from the
// cache.
orec.fireEventToListenersOf(publishEvent, course);
/*
* END NEW STYLE PUBLISH
*/
}
use of org.olat.course.tree.CourseEditorTreeNode in project OpenOLAT by OpenOLAT.
the class CourseHandler method importResource.
@Override
public RepositoryEntry importResource(Identity initialAuthor, String initialAuthorAlt, String displayname, String description, boolean withReferences, Locale locale, File file, String filename) {
OLATResource newCourseResource = OLATResourceManager.getInstance().createOLATResourceInstance(CourseModule.class);
ICourse course = CourseFactory.importCourseFromZip(newCourseResource, file);
// cfc.release();
if (course == null) {
return null;
}
RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
RepositoryEntry re = repositoryService.create(initialAuthor, null, "", displayname, description, newCourseResource, RepositoryEntry.ACC_OWNERS);
DBFactory.getInstance().commit();
// create empty run structure
course = CourseFactory.openCourseEditSession(course.getResourceableId());
Structure runStructure = course.getRunStructure();
runStructure.getRootNode().removeAllChildren();
CourseFactory.saveCourse(course.getResourceableId());
// import references
CourseEditorTreeNode rootNode = (CourseEditorTreeNode) course.getEditorTreeModel().getRootNode();
importReferences(rootNode, course, initialAuthor, locale, withReferences);
if (withReferences && course.getCourseConfig().hasCustomSharedFolder()) {
importSharedFolder(course, initialAuthor);
}
if (withReferences && course.getCourseConfig().hasGlossary()) {
importGlossary(course, initialAuthor);
}
// create group management / import groups
CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
File fImportBaseDirectory = course.getCourseExportDataDir().getBasefile();
CourseEnvironmentMapper envMapper = cgm.importCourseBusinessGroups(fImportBaseDirectory);
envMapper.setAuthor(initialAuthor);
// upgrade course
course = CourseFactory.loadCourse(cgm.getCourseResource());
course.postImport(fImportBaseDirectory, envMapper);
// rename root nodes, but only when user modified the course title
boolean doUpdateTitle = true;
File repoConfigXml = new File(fImportBaseDirectory, "repo.xml");
if (repoConfigXml.exists()) {
RepositoryEntryImport importConfig;
try {
importConfig = RepositoryEntryImportExport.getConfiguration(new FileInputStream(repoConfigXml));
if (importConfig != null) {
if (displayname.equals(importConfig.getDisplayname())) {
// do not update if title was not modified during import
// user does not expect to have an updated title and there is a chance
// the root node title is not the same as the course title
doUpdateTitle = false;
}
}
} catch (FileNotFoundException e) {
// ignore
}
}
if (doUpdateTitle) {
// do not use truncate!
course.getRunStructure().getRootNode().setShortTitle(Formatter.truncateOnly(displayname, 25));
course.getRunStructure().getRootNode().setLongTitle(displayname);
}
// course.saveRunStructure();
CourseEditorTreeNode editorRootNode = ((CourseEditorTreeNode) course.getEditorTreeModel().getRootNode());
// do not use truncate!
editorRootNode.getCourseNode().setShortTitle(Formatter.truncateOnly(displayname, 25));
editorRootNode.getCourseNode().setLongTitle(displayname);
// mark entire structure as dirty/new so the user can re-publish
markDirtyNewRecursively(editorRootNode);
// root has already been created during export. Unmark it.
editorRootNode.setNewnode(false);
// save and close edit session
CourseFactory.saveCourse(course.getResourceableId());
CourseFactory.closeCourseEditSession(course.getResourceableId(), true);
RepositoryEntryImportExport imp = new RepositoryEntryImportExport(fImportBaseDirectory);
if (imp.anyExportedPropertiesAvailable()) {
re = imp.importContent(re, getMediaContainer(re));
}
// import reminders
importReminders(re, fImportBaseDirectory, envMapper, initialAuthor);
// clean up export folder
cleanExportAfterImport(fImportBaseDirectory);
return re;
}
Aggregations