diff --git a/src/main/java/org/olat/core/configuration/AbstractSpringModule.java b/src/main/java/org/olat/core/configuration/AbstractSpringModule.java index 1c7d64c6986115cd3564139dc24a1f28c7a459c7..4859bdce0e59c3a9722d3c1a5e00f7deb3783d02 100644 --- a/src/main/java/org/olat/core/configuration/AbstractSpringModule.java +++ b/src/main/java/org/olat/core/configuration/AbstractSpringModule.java @@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.olat.core.gui.control.Event; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.springframework.beans.factory.DisposableBean; @@ -99,6 +100,9 @@ public abstract class AbstractSpringModule implements GenericEventListener, Init @Override public void afterPropertiesSet() { + if (!StringHelper.containsNonWhitespace(userDataDirectory)) { + userDataDirectory = System.getProperty("java.io.tmpdir") + "/olatdata"; + } moduleConfigProperties.setUserDataDirectory(userDataDirectory); moduleConfigProperties.init(); initDefaultProperties(); diff --git a/src/main/java/org/olat/ims/qti/qpool/QTI12ItemFactory.java b/src/main/java/org/olat/ims/qti/qpool/QTI12ItemFactory.java index 0645b197e2cb7b74f9a2b67aa9d0bc070909cfec..14d93f248b1df63165043d7df934cdf935be49de 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTI12ItemFactory.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTI12ItemFactory.java @@ -44,6 +44,11 @@ public class QTI12ItemFactory implements QItemFactory { public QTI12ItemFactory(Type type) { this.type = type; } + + @Override + public String getType() { + return "qti12_".concat(type.name()); + } @Override public String getLabel(Locale locale) { @@ -61,8 +66,7 @@ public class QTI12ItemFactory implements QItemFactory { @Override public QuestionItem createItem(Identity owner, String title, Locale locale) { QTIQPoolServiceProvider spi = CoreSpringFactory.getImpl(QTIQPoolServiceProvider.class); - QuestionItem newItem = spi.createItem(owner, type, title, locale); - return newItem; + return spi.createItem(owner, type, title, locale); } public enum Type { diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21AssessmentItemFactory.java b/src/main/java/org/olat/ims/qti21/pool/QTI21AssessmentItemFactory.java index af8dfaf19d8681698feef51da8c230c7f7dfc69b..55d451bcf4429593032793b65b00ffbb9ec5dd64 100644 --- a/src/main/java/org/olat/ims/qti21/pool/QTI21AssessmentItemFactory.java +++ b/src/main/java/org/olat/ims/qti21/pool/QTI21AssessmentItemFactory.java @@ -43,6 +43,11 @@ public class QTI21AssessmentItemFactory implements QItemFactory { public QTI21AssessmentItemFactory(QTI21QuestionType type) { this.type = type; } + + @Override + public String getType() { + return "qti21_".concat(type.name()); + } @Override public String getLabel(Locale locale) { diff --git a/src/main/java/org/olat/modules/qpool/QItemFactory.java b/src/main/java/org/olat/modules/qpool/QItemFactory.java index 138ac1d9c1caa6b130dca6d87bd33c7ec5531515..8293bc404c39379578962505a8d5c45f2ff2004e 100644 --- a/src/main/java/org/olat/modules/qpool/QItemFactory.java +++ b/src/main/java/org/olat/modules/qpool/QItemFactory.java @@ -31,6 +31,8 @@ import org.olat.core.id.Identity; */ public interface QItemFactory { + public String getType(); + public String getLabel(Locale locale); public QuestionItem createItem(Identity owner, String title, Locale locale); diff --git a/src/main/java/org/olat/modules/qpool/site/QuestionPoolSite.java b/src/main/java/org/olat/modules/qpool/site/QuestionPoolSite.java index 64ffbcc5720c16f08b4347eb4676318bc111b823..b967c5862bd18d6caf76abf7773463c5d9f5eae4 100644 --- a/src/main/java/org/olat/modules/qpool/site/QuestionPoolSite.java +++ b/src/main/java/org/olat/modules/qpool/site/QuestionPoolSite.java @@ -67,8 +67,7 @@ public class QuestionPoolSite extends AbstractSiteInstance { OLATResourceable ores = OresHelper.createOLATResourceableInstance("QPool", 0l); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ureq, ores, new StateSite(this), wControl, true); - MainLayoutController c = new QuestionPoolSiteMainController(ureq, bwControl); - return c; + return new QuestionPoolSiteMainController(ureq, bwControl); } @Override diff --git a/src/main/java/org/olat/modules/qpool/ui/NewItemOptionsController.java b/src/main/java/org/olat/modules/qpool/ui/NewItemOptionsController.java index 696753f3295f4e483ba73d8466c44b8cc2e876d3..be794ba96b2e29315bff10d1e3a75e7e5b7a16b8 100644 --- a/src/main/java/org/olat/modules/qpool/ui/NewItemOptionsController.java +++ b/src/main/java/org/olat/modules/qpool/ui/NewItemOptionsController.java @@ -85,8 +85,10 @@ public class NewItemOptionsController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_new_item_form"); //title titleEl = uifactory.addTextElement("general.title", "general.title", 128, "", formLayout); + titleEl.setElementCssClass("o_sel_item_title"); //type List<QItemFactory> factories = new ArrayList<>(); @@ -100,7 +102,7 @@ public class NewItemOptionsController extends FormBasicController { String[] typeKeys = new String[factories.size()]; String[] valueKeys = new String[factories.size()]; for(QItemFactory factory:factories) { - String typeKey = "item.type." + count; + String typeKey = factory.getType(); typeKeys[count] = typeKey; keyToFactoryMap.put(typeKey, factory); valueKeys[count] = factory.getLabel(getLocale()); @@ -108,6 +110,7 @@ public class NewItemOptionsController extends FormBasicController { } typeEl = uifactory.addDropdownSingleselect("question.type", "menu.admin.types", formLayout, typeKeys, valueKeys, null); + typeEl.setElementCssClass("o_sel_item_type"); //subject taxonomyLevelEl = uifactory.addDropdownSingleselect("process.start.review.taxonomy.level", formLayout, @@ -121,6 +124,7 @@ public class NewItemOptionsController extends FormBasicController { } } taxonomyLevelEl.setVisible(qPoolSecurityCallback.canUseTaxonomy()); + taxonomyLevelEl.setElementCssClass("o_sel_item_taxonomy_level"); FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonLayout.setRootForm(mainForm); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java index 103c40ca91f3abfc27bda5827444ace4fe8b6007..09cb270809a0911d8681ed8bf99be7037805af4e 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolMainEditorController.java @@ -117,6 +117,7 @@ public class QuestionPoolMainEditorController extends BasicController implements content = new Panel("list"); columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, content, "qpool"); + columnLayoutCtr.addCssClassToMain("o_qpool"); doSelectControllerTreeNode(ureq, treeModel.getMyNode(), null, null); putInitialPanel(columnLayoutCtr.getInitialComponent()); diff --git a/src/main/java/org/olat/modules/qpool/ui/ReviewController.java b/src/main/java/org/olat/modules/qpool/ui/ReviewController.java index 44d63127375ad5894700166e002f7c73bee992ae..7b32bca76fd7014dded56df31af62d5e10a53df1 100644 --- a/src/main/java/org/olat/modules/qpool/ui/ReviewController.java +++ b/src/main/java/org/olat/modules/qpool/ui/ReviewController.java @@ -56,6 +56,7 @@ public class ReviewController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormDescription("process.rating.description"); + formLayout.setElementCssClass("o_sel_qpool_review_form"); ratingEl = uifactory.addRatingItem("process.rating", "process.rating", 0f, 5, true, formLayout); diff --git a/src/main/java/org/olat/modules/qpool/ui/ReviewStartController.java b/src/main/java/org/olat/modules/qpool/ui/ReviewStartController.java index 9e7092b1d4acafb9388cbce9d1ea47d92b1315fe..1a74e80d66f8fdfac37951078bc375c0c65e6bfb 100644 --- a/src/main/java/org/olat/modules/qpool/ui/ReviewStartController.java +++ b/src/main/java/org/olat/modules/qpool/ui/ReviewStartController.java @@ -66,6 +66,7 @@ public class ReviewStartController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_qpool_confirm_start_form"); setFormDescription("process.start.review.description", new String[] {item.getTitle()}); qpoolTaxonomyTreeBuilder.loadTaxonomyLevelsSelection(getIdentity(), false, ignoreCompetences); diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QuestionPoolAdminConfigurationController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QuestionPoolAdminConfigurationController.java index 2c797ec56183abc58bc6027830e52ecdd19d5637..3c836752b568850709f91aedf3cc596322007a0a 100644 --- a/src/main/java/org/olat/modules/qpool/ui/admin/QuestionPoolAdminConfigurationController.java +++ b/src/main/java/org/olat/modules/qpool/ui/admin/QuestionPoolAdminConfigurationController.java @@ -103,6 +103,7 @@ public class QuestionPoolAdminConfigurationController extends FormBasicControlle @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FormLayoutContainer moduleCont = FormLayoutContainer.createDefaultFormLayout("module", getTranslator()); + moduleCont.setElementCssClass("o_sel_qpool_configuration"); moduleCont.setFormTitle(translate("admin.configuration.title")); moduleCont.setRootForm(mainForm); formLayout.add("module", moduleCont); @@ -110,6 +111,7 @@ public class QuestionPoolAdminConfigurationController extends FormBasicControlle String[] onValues = new String[] { translate("on") }; reviewProcessEnabledEl = uifactory.addCheckboxesHorizontal("review.process.enabled", moduleCont, onKeys, onValues); reviewProcessEnabledEl.addActionListener(FormEvent.ONCHANGE); + reviewProcessEnabledEl.setElementCssClass("o_sel_qpool_review_process"); if (qpoolModule.isReviewProcessEnabled()) { reviewProcessEnabledEl.select(onKeys[0], true); } @@ -196,6 +198,7 @@ public class QuestionPoolAdminConfigurationController extends FormBasicControlle poolManagerRightsEl.select(POOL_MANAGER_EDUCATIONAL_CONTEXT, qpoolModule.isPoolAdminAllowedToConfigEducationalContext()); FormLayoutContainer buttonsWrapperCont = FormLayoutContainer.createDefaultFormLayout("global", getTranslator()); + buttonsWrapperCont.setElementCssClass("o_sel_qpool_buttons"); buttonsWrapperCont.setRootForm(mainForm); formLayout.add("buttonsWrapper", buttonsWrapperCont); FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessActivationController.java b/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessActivationController.java index d9d3cc37da71aed166804e1c0c3f730941b4e1c9..fe95a61f6d16dd317e9f0d0296bb010706fb2c1e 100644 --- a/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessActivationController.java +++ b/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessActivationController.java @@ -51,10 +51,12 @@ public class ReviewProcessActivationController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_qpool_reset_status_form"); uifactory.addStaticTextElement("description", "", translate("review.process.confirm.enable.description"), formLayout); String[] resetValues = new String[] { translate("reset.status") }; resetStatusaEl = uifactory.addCheckboxesHorizontal("reset.status", "", formLayout, resetKeys, resetValues); + resetStatusaEl.setElementCssClass("o_sel_qpool_reset_status"); FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); formLayout.add("buttons", buttonLayout); diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessAdminController.java index d89019ebfa1b45ba1d5fdc2b2c6728fb6aff47e7..068f7542c1d80b5393d6e4d5672c4c95e4937904 100644 --- a/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessAdminController.java +++ b/src/main/java/org/olat/modules/qpool/ui/admin/ReviewProcessAdminController.java @@ -67,6 +67,7 @@ public class ReviewProcessAdminController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_qpool_review_process_admin"); setFormTitle("admin.review.process.title"); // decision provider @@ -98,6 +99,7 @@ public class ReviewProcessAdminController extends FormBasicController { String numberOfRatings = Integer.toString(qpoolModule.getReviewDecisionNumberOfRatings()); numberOfRatingsEl = uifactory.addTextElement("number.of.ratings", 5, numberOfRatings, formLayout); + numberOfRatingsEl.setElementCssClass("o_sel_qpool_num_of_reviews"); numberOfRatingsEl.setMandatory(true); numberOfRatingsEl.setDisplaySize(5); @@ -112,6 +114,7 @@ public class ReviewProcessAdminController extends FormBasicController { translate(FINAL_VISIBILITY_MANAGER), translate(FINAL_VISIBILITY_MANAGER_TEACHER)}; finalVisibilityEl = uifactory.addDropdownSingleselect("final.visibility", formLayout, finalVisibilityKeys, finalVisibilityValues); + finalVisibilityEl.setElementCssClass("o_sel_qpool_final_visibility"); String selectedKey = qpoolModule.isFinalVisibleTeach()? FINAL_VISIBILITY_MANAGER_TEACHER: FINAL_VISIBILITY_MANAGER; finalVisibilityEl.select(selectedKey, true); diff --git a/src/main/java/org/olat/modules/qpool/ui/tree/QuestionPoolMenuTreeModel.java b/src/main/java/org/olat/modules/qpool/ui/tree/QuestionPoolMenuTreeModel.java index 244cdc15ca8edc0f1e3252fd23d98f5c6806de71..fedaa516fe55d8f7c57a89aa40208ad866e3bfe8 100644 --- a/src/main/java/org/olat/modules/qpool/ui/tree/QuestionPoolMenuTreeModel.java +++ b/src/main/java/org/olat/modules/qpool/ui/tree/QuestionPoolMenuTreeModel.java @@ -295,6 +295,7 @@ public class QuestionPoolMenuTreeModel extends GenericTreeModel implements DnDTr if(!taxonomyLevels.isEmpty()) { reviewNode = new GenericTreeNode(translator.translate("menu.review")); reviewNode.setTitle(translator.translate("menu.review")); + reviewNode.setCssClass("o_sel_qpool_review_taxonomy_levels"); rootNode.addChild(reviewNode); for(TaxonomyLevel taxonomyLevel:taxonomyLevels) { diff --git a/src/main/java/org/olat/modules/taxonomy/ui/EditTaxonomyLevelController.java b/src/main/java/org/olat/modules/taxonomy/ui/EditTaxonomyLevelController.java index b26668a01baa1096b725f8509c30448b827cc32c..7f550ac2565f86f451a718590f08756c90c51ec4 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/EditTaxonomyLevelController.java +++ b/src/main/java/org/olat/modules/taxonomy/ui/EditTaxonomyLevelController.java @@ -121,6 +121,8 @@ public class EditTaxonomyLevelController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + formLayout.setElementCssClass("o_sel_taxonomy_level_form"); + if(level == null || level.getKey() == null) { String[] pathKeys; String[] pathValues; @@ -141,10 +143,12 @@ public class EditTaxonomyLevelController extends FormBasicController { String identifier = level == null ? "" : level.getIdentifier(); identifierEl = uifactory.addTextElement("level.identifier", "level.identifier", 255, identifier, formLayout); identifierEl.setEnabled(!TaxonomyLevelManagedFlag.isManaged(level, TaxonomyLevelManagedFlag.identifier)); + identifierEl.setElementCssClass("o_sel_taxonomy_level_identifier"); identifierEl.setMandatory(true); String displayName = level == null ? "" : level.getDisplayName(); displayNameEl = uifactory.addTextElement("level.displayname", "level.displayname", 255, displayName, formLayout); + displayNameEl.setElementCssClass("o_sel_taxonomy_level_name"); displayNameEl.setMandatory(true); displayNameEl.setEnabled(!TaxonomyLevelManagedFlag.isManaged(level, TaxonomyLevelManagedFlag.displayName)); if(!StringHelper.containsNonWhitespace(displayName)) { diff --git a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelCompetenceController.java b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelCompetenceController.java index bc27acac2cf27667f843e78024d7eb116bb38c1a..d2b796f23b6455e458699b12b37e8817a15a1903 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelCompetenceController.java +++ b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelCompetenceController.java @@ -126,6 +126,7 @@ public class TaxonomyLevelCompetenceController extends FormBasicController { || !TaxonomyLevelManagedFlag.isManaged(taxonomyLevel, TaxonomyLevelManagedFlag.haveCompetence) || !TaxonomyLevelManagedFlag.isManaged(taxonomyLevel, TaxonomyLevelManagedFlag.targetCompetence)) { addCompetencesButton = uifactory.addFormLink("add.competences", formLayout, Link.BUTTON); + addCompetencesButton.setElementCssClass("o_sel_competence_add"); removeCompetencesButton = uifactory.addFormLink("delete", formLayout, Link.BUTTON); multiSelect = true; } @@ -216,7 +217,7 @@ public class TaxonomyLevelCompetenceController extends FormBasicController { } else if (event instanceof MultiIdentityChosenEvent) { MultiIdentityChosenEvent multiEvent = (MultiIdentityChosenEvent)event; List<Identity> toAdd = multiEvent.getChosenIdentities(); - if(toAdd.size() > 0) { + if(!toAdd.isEmpty()) { doAddCompetence(toAdd, (TaxonomyCompetenceTypes)userSearchCtrl.getUserObject()); loadModel(); } diff --git a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelOverviewController.java b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelOverviewController.java index 3b57a959d98f3b0a8ffb4446b8f96cb52c6d381e..b46495bbb62fc50e89725cf60f50e93cbd0e3c8c 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelOverviewController.java +++ b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyLevelOverviewController.java @@ -26,7 +26,6 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.tabbedpane.TabCreator; import org.olat.core.gui.components.tabbedpane.TabbedPane; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; @@ -86,6 +85,7 @@ public class TaxonomyLevelOverviewController extends BasicController implements actionButton.setIconLeftCSS("o_icon o_icon_actions"); tabPane = new TabbedPane("tabs", ureq.getLocale()); + tabPane.setElementCssClass("o_sel_taxonomy_level_tabs"); tabPane.addListener(this); metadataCtrl = new EditTaxonomyLevelController(ureq, getWindowControl(), taxonomyLevel); @@ -100,22 +100,16 @@ public class TaxonomyLevelOverviewController extends BasicController implements } private void initTabPane() { - tabPane.addTab(translate("taxonomy.level.competences"), new TabCreator() { - @Override - public Component create(UserRequest uureq) { - competencesCtrl = new TaxonomyLevelCompetenceController(uureq, getWindowControl(), taxonomyLevel); - listenTo(competencesCtrl); - return competencesCtrl.getInitialComponent(); - } + tabPane.addTab(translate("taxonomy.level.competences"), uureq -> { + competencesCtrl = new TaxonomyLevelCompetenceController(uureq, getWindowControl(), taxonomyLevel); + listenTo(competencesCtrl); + return competencesCtrl.getInitialComponent(); }); - tabPane.addTab(translate("taxonomy.level.relations"), new TabCreator() { - @Override - public Component create(UserRequest uureq) { - relationsCtrl = new TaxonomyLevelRelationsController(uureq, getWindowControl(), taxonomyLevel); - listenTo(relationsCtrl); - return relationsCtrl.getInitialComponent(); - } + tabPane.addTab(translate("taxonomy.level.relations"), uureq -> { + relationsCtrl = new TaxonomyLevelRelationsController(uureq, getWindowControl(), taxonomyLevel); + listenTo(relationsCtrl); + return relationsCtrl.getInitialComponent(); }); } diff --git a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyOverviewController.java b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyOverviewController.java index bf9750840485e23b900d4e4c6363025e77fbed5a..bb677709a69db8bbebc2e6ae84bdbae6fbf60727 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyOverviewController.java +++ b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyOverviewController.java @@ -69,14 +69,18 @@ public class TaxonomyOverviewController extends BasicController implements Bread segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); metadataLink = LinkFactory.createLink("taxonomy.metadata", mainVC, this); + metadataLink.setElementCssClass("o_sel_taxonomy_metadata"); segmentView.addSegment(metadataLink, true); doOpenMetadata(ureq); typesLink = LinkFactory.createLink("taxonomy.types", mainVC, this); + typesLink.setElementCssClass("o_sel_taxonomy_types"); segmentView.addSegment(typesLink, false); levelsLink = LinkFactory.createLink("taxonomy.levels", mainVC, this); + levelsLink.setElementCssClass("o_sel_taxonomy_levels"); segmentView.addSegment(levelsLink, false); lostFoundLink = LinkFactory.createLink("taxonomy.lost.found", mainVC, this); + lostFoundLink.setElementCssClass("o_sel_taxonomy_lost_found"); segmentView.addSegment(lostFoundLink, false); putInitialPanel(mainVC); diff --git a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyTreeTableController.java b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyTreeTableController.java index 773385b24765dec0e0307d73e0cb7ee0c6c80516..fc855ece13c6c8a8ab33c7356bc64aa2c4fa18dd 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyTreeTableController.java +++ b/src/main/java/org/olat/modules/taxonomy/ui/TaxonomyTreeTableController.java @@ -120,6 +120,7 @@ public class TaxonomyTreeTableController extends FormBasicController implements protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { newLevelButton = uifactory.addFormLink("add.taxonomy.level", formLayout, Link.BUTTON); + newLevelButton.setElementCssClass("o_sel_taxonomy_new_level"); deleteButton = uifactory.addFormLink("delete", formLayout, Link.BUTTON); mergeButton = uifactory.addFormLink("merge.taxonomy.level", formLayout, Link.BUTTON); typeButton = uifactory.addFormLink("type.taxonomy.level", formLayout, Link.BUTTON); diff --git a/src/main/java/org/olat/modules/taxonomy/ui/_content/admin_taxonomy_levels.html b/src/main/java/org/olat/modules/taxonomy/ui/_content/admin_taxonomy_levels.html index 6f81943b9f145f5eaf8b9246b68c8d3ac217d317..c2ba20b7d7534cc09471e8d842f1cf6a63233951 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/_content/admin_taxonomy_levels.html +++ b/src/main/java/org/olat/modules/taxonomy/ui/_content/admin_taxonomy_levels.html @@ -1,20 +1,22 @@ -#if($r.available("add.taxonomy.level")) -<div class="o_button_group o_button_group_right"> - $r.render("add.taxonomy.level") -</div> -#end -$r.render("table") -<div class="o_button_group"> - #if($r.available("type.taxonomy.level")) - $r.render("type.taxonomy.level") - #end - #if($r.available("move.taxonomy.level")) - $r.render("move.taxonomy.level") - #end - #if($r.available("merge.taxonomy.level")) - $r.render("merge.taxonomy.level") - #end - #if($r.available("delete")) - $r.render("delete") +<div class="o_sel_taxonomy_levels_tree"> + #if($r.available("add.taxonomy.level")) + <div class="o_button_group o_button_group_right"> + $r.render("add.taxonomy.level") + </div> #end + $r.render("table") + <div class="o_button_group"> + #if($r.available("type.taxonomy.level")) + $r.render("type.taxonomy.level") + #end + #if($r.available("move.taxonomy.level")) + $r.render("move.taxonomy.level") + #end + #if($r.available("merge.taxonomy.level")) + $r.render("merge.taxonomy.level") + #end + #if($r.available("delete")) + $r.render("delete") + #end + </div> </div> diff --git a/src/main/java/org/olat/modules/taxonomy/ui/_content/level_competences.html b/src/main/java/org/olat/modules/taxonomy/ui/_content/level_competences.html index f02de4b506a215b2a356d08a785db34e0049d492..2a3369ae282a282ba20d9e319d309ae9523fd4ae 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/_content/level_competences.html +++ b/src/main/java/org/olat/modules/taxonomy/ui/_content/level_competences.html @@ -1,11 +1,13 @@ -#if($r.available("add.competences")) -<div class="o_button_group o_button_group_right"> - $r.render("add.competences") -</div> -#end -$r.render("table") -#if($r.available("delete")) -<div class="o_button_group"> - $r.render("delete") -</div> -#end \ No newline at end of file +<div class="o_sel_taxonomy_level_competences"> + #if($r.available("add.competences")) + <div class="o_button_group o_button_group_right"> + $r.render("add.competences") + </div> + #end + $r.render("table") + #if($r.available("delete")) + <div class="o_button_group"> + $r.render("delete") + </div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/taxonomy/ui/_content/taxonomy_level_overview.html b/src/main/java/org/olat/modules/taxonomy/ui/_content/taxonomy_level_overview.html index 45179c50e9812241e7a15569f3e37dead47ef2a2..536b360613d76780554c74d3ac36bb423dacc3a1 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/_content/taxonomy_level_overview.html +++ b/src/main/java/org/olat/modules/taxonomy/ui/_content/taxonomy_level_overview.html @@ -3,7 +3,7 @@ $r.render("actions") </div> #end -<div class="o_form form-horizontal clearfix"> +<div class="o_form form-horizontal o_sel_taxonomy_level_overview clearfix"> <div class="form-group clearfix"> <div> <label class="control-label col-sm-3" for="tax_level_key">$r.translate("taxonomy.level.key")</label> diff --git a/src/main/java/org/olat/modules/taxonomy/ui/_content/tools.html b/src/main/java/org/olat/modules/taxonomy/ui/_content/tools.html index ee364a66e1151caa279c872f06410e111e07e20d..6115e224832012d01a121f0febb05960dd3e7617 100644 --- a/src/main/java/org/olat/modules/taxonomy/ui/_content/tools.html +++ b/src/main/java/org/olat/modules/taxonomy/ui/_content/tools.html @@ -1,4 +1,4 @@ -<ul class="o_dropdown list-unstyled"> +<ul class="o_dropdown list-unstyled o_sel_tools"> #foreach($link in $links) #if($link == "-") <li class="divider"></li> diff --git a/src/test/java/org/olat/restapi/RepositoryEntryResourceTest.java b/src/test/java/org/olat/restapi/RepositoryEntryResourceTest.java index ac8253425f1a3dacfe1b5c5b956a9280bba5a07f..b9417e6027defb722f77969826b9648a9d698ebb 100644 --- a/src/test/java/org/olat/restapi/RepositoryEntryResourceTest.java +++ b/src/test/java/org/olat/restapi/RepositoryEntryResourceTest.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.restapi; import java.io.File; diff --git a/src/test/java/org/olat/selenium/QuestionPoolTest.java b/src/test/java/org/olat/selenium/QuestionPoolTest.java new file mode 100644 index 0000000000000000000000000000000000000000..52839020b0807fbe7b4bfba9f4dec1d6c5ccf122 --- /dev/null +++ b/src/test/java/org/olat/selenium/QuestionPoolTest.java @@ -0,0 +1,174 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.UUID; + +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.arquillian.graphene.page.InitialPage; +import org.jboss.arquillian.graphene.page.Page; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.olat.ims.qti21.model.QTI21QuestionType; +import org.olat.modules.taxonomy.TaxonomyCompetenceTypes; +import org.olat.selenium.page.LoginPage; +import org.olat.selenium.page.NavigationPage; +import org.olat.selenium.page.core.AdministrationPage; +import org.olat.selenium.page.qpool.QuestionPoolPage; +import org.olat.selenium.page.user.UserToolsPage; +import org.olat.test.rest.UserRestClient; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.WebDriver; + +/** + * Test the question pool. + * + * + * Initial date: 27 avr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@RunWith(Arquillian.class) +public class QuestionPoolTest extends Deployments { + + @Drone + private WebDriver browser; + @ArquillianResource + private URL deploymentUrl; + @Page + private NavigationPage navBar; + + /** + * Smoke test: an author create a QTI 2.1 question, + * a single choice one. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void questionPool(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + UserVO author = new UserRestClient(deploymentUrl).createAuthor("Lili"); + + loginPage + .loginAs(author.getLogin(), author.getPassword()) + .resume(); + + String questionTitle = "SC-" + UUID.randomUUID(); + QuestionPoolPage questionPool = navBar.assertOnNavigationPage() + .openQuestionPool(); + questionPool + .selectMyQuestions() + .newQuestion(questionTitle, QTI21QuestionType.sc) + .clickToolbarBack() + .assertQuestionInList(questionTitle, QTI21QuestionType.sc.name()); + } + + /** + * An administrator set up the review process. A question need + * 1 review with more than 2 stars. Than it checks that the taxonomy + * for the question pool as an "At least one" taxonomy level.<br> + * An author create a question. A reviewer reviews the question + * and give it 4 stars. The author see the result. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void reviewProcess(@InitialPage LoginPage loginPage) + throws IOException, URISyntaxException { + + UserVO reviewer = new UserRestClient(deploymentUrl).createAuthor("Albert"); + + loginPage + .loginAs("administrator", "openolat") + .resume(); + AdministrationPage administration = new NavigationPage(browser) + .openAdministration(); + // configure the review process + administration + .openQuestionPool() + .enableReviews() + .reviewsConfiguration(1, 2); + // configure the taxonomy + administration + .openTaxonomy() + .selectTaxonomy("QPOOL") + .selectTaxonomyTree() + .atLeastOneLevel("at-least-one", "At least one") + .selectTaxonomyLevel("at-least-one") + .selectCompetence() + .addCompetence(reviewer, TaxonomyCompetenceTypes.teach); + + new UserToolsPage(browser).logout(); + + // author create a question + UserVO author = new UserRestClient(deploymentUrl).createAuthor("Leila"); + + loginPage + .loginAs(author.getLogin(), author.getPassword()) + .resume(); + + String questionTitle = "SC-" + UUID.randomUUID(); + QuestionPoolPage questionPool = navBar.assertOnNavigationPage() + .openQuestionPool(); + questionPool + .selectMyQuestions() + .newQuestion(questionTitle, QTI21QuestionType.sc) + .startReviewProcess() + .clickToolbarBack() + .assertQuestionInList(questionTitle, QTI21QuestionType.sc.name()); + // author log out + new UserToolsPage(browser).logout(); + + // reviewer make its job + loginPage + .loginAs(reviewer.getLogin(), reviewer.getPassword()) + .resume(); + navBar.assertOnNavigationPage() + .openQuestionPool() + .selectTaxonomyLevel("At least one") + .selectQuestionInList(questionTitle) + .assessQuestion(4) + .assertFinalOnQuestion(); + + new UserToolsPage(browser).logout(); + + // author come to see the result + loginPage + .loginAs(author.getLogin(), author.getPassword()) + .resume(); + navBar.assertOnNavigationPage() + .openQuestionPool() + .selectMyQuestions() + .assertFinalQuestionInList(questionTitle); + } + +} diff --git a/src/test/java/org/olat/selenium/page/NavigationPage.java b/src/test/java/org/olat/selenium/page/NavigationPage.java index 2b17a70d6b37e48271d68d0b3df8eb0620248c56..b6bfcdb5b827e1dbf0401728c452622ec99de8d7 100644 --- a/src/test/java/org/olat/selenium/page/NavigationPage.java +++ b/src/test/java/org/olat/selenium/page/NavigationPage.java @@ -27,6 +27,7 @@ import org.olat.selenium.page.core.AdministrationPage; import org.olat.selenium.page.course.MyCoursesPage; import org.olat.selenium.page.graphene.OOGraphene; import org.olat.selenium.page.group.GroupsPage; +import org.olat.selenium.page.qpool.QuestionPoolPage; import org.olat.selenium.page.repository.AuthoringEnvPage; import org.olat.selenium.page.repository.CatalogAdminPage; import org.olat.selenium.page.repository.CatalogPage; @@ -47,6 +48,7 @@ public class NavigationPage { private static final By navigationSitesBy = By.cssSelector("ul.o_navbar_sites"); private static final By authoringEnvTabBy = By.cssSelector("li.o_site_author_env > a"); + private static final By questionPoolTabBy = By.cssSelector("li.o_site_qpool > a"); private static final By portalBy = By.cssSelector("li.o_site_portal > a"); private static final By myCoursesBy = By.cssSelector("li.o_site_repository > a"); private static final By userManagementBy = By.cssSelector("li.o_site_useradmin > a"); @@ -83,6 +85,12 @@ public class NavigationPage { return new AuthoringEnvPage(browser); } + public QuestionPoolPage openQuestionPool() { + navigate(questionPoolTabBy); + return new QuestionPoolPage(browser) + .assertOnQuestionPool(); + } + public PortalPage openPortal() { navigate(portalBy); return new PortalPage(browser); diff --git a/src/test/java/org/olat/selenium/page/core/AdministrationPage.java b/src/test/java/org/olat/selenium/page/core/AdministrationPage.java index b7aa74cf1a86fb2ad9662e2894bc826ac28cb196..ea7d3b6ab3f8f182be60b8fcaeadf9bdf2dd0583 100644 --- a/src/test/java/org/olat/selenium/page/core/AdministrationPage.java +++ b/src/test/java/org/olat/selenium/page/core/AdministrationPage.java @@ -24,6 +24,8 @@ import java.util.List; import org.junit.Assert; import org.olat.selenium.page.graphene.OOGraphene; import org.olat.selenium.page.lecture.LectureAdminSettingsPage; +import org.olat.selenium.page.qpool.QuestionPoolAdminPage; +import org.olat.selenium.page.taxonomy.TaxonomyAdminPage; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -163,4 +165,24 @@ public class AdministrationPage { OOGraphene.waitElement(licenseAdminBy, browser); return new LicensesAdminstrationPage(browser); } + + public QuestionPoolAdminPage openQuestionPool() { + selectAssessment(); + + By poolBy = By.cssSelector(".o_sel_qpool span.o_tree_level_label_leaf>a"); + browser.findElement(poolBy).click(); + OOGraphene.waitBusy(browser); + + return new QuestionPoolAdminPage(browser).assertOnConfiguration(); + } + + public TaxonomyAdminPage openTaxonomy() { + selectModules(); + + By taxonomyBy = By.cssSelector(".o_sel_taxonomy span.o_tree_level_label_leaf>a"); + browser.findElement(taxonomyBy).click(); + OOGraphene.waitBusy(browser); + + return new TaxonomyAdminPage(browser).assertOnTaxonomyList(); + } } diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionPoolAdminPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionPoolAdminPage.java new file mode 100644 index 0000000000000000000000000000000000000000..5f2685ff06d5be90351ee31a6c301342f07aee29 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/qpool/QuestionPoolAdminPage.java @@ -0,0 +1,96 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.qpool; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 27 avr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QuestionPoolAdminPage { + + private final WebDriver browser; + + public QuestionPoolAdminPage(WebDriver browser) { + this.browser = browser; + } + + public QuestionPoolAdminPage assertOnConfiguration() { + By configBy = By.className("o_sel_qpool_configuration"); + OOGraphene.waitElement(configBy, browser); + return this; + } + + public QuestionPoolAdminPage enableReviews() { + assertOnConfiguration(); + + By reviewBy = By.cssSelector(".o_sel_qpool_configuration .o_sel_qpool_review_process input[type='checkbox']"); + WebElement reviewEl = browser.findElement(reviewBy); + String checked = reviewEl.getAttribute("checked"); + if(checked == null) { + OOGraphene.check(reviewEl, Boolean.TRUE); + OOGraphene.waitModalDialog(browser); + + //don't reset the status + By statusBy = By.cssSelector("fieldset.o_sel_qpool_reset_status_form .o_sel_qpool_reset_status input[type='checkbox']"); + WebElement statusEl = browser.findElement(statusBy); + OOGraphene.check(statusEl, Boolean.TRUE); + + //engage review process + By confirmBy = By.cssSelector("fieldset.o_sel_qpool_reset_status_form button.btn-primary"); + browser.findElement(confirmBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialogDisappears(browser); + + By saveConfigurationBy = By.cssSelector(".o_sel_qpool_buttons button.btn-primary"); + browser.findElement(saveConfigurationBy).click(); + OOGraphene.waitBusy(browser); + } + return this; + } + + public QuestionPoolAdminPage reviewsConfiguration(int numOfReviews, int numOfStars) { + By reviewBy = By.xpath("//div[contains(@class,'o_segments')]/a[contains(@onclick,'segment.review.process')]"); + browser.findElement(reviewBy).click(); + OOGraphene.waitBusy(browser); + + By numOfReviewsBy = By.cssSelector("fieldset.o_sel_qpool_review_process_admin .o_sel_qpool_num_of_reviews input[type='text']"); + OOGraphene.waitElement(numOfReviewsBy, browser); + WebElement numOfReviewEl = browser.findElement(numOfReviewsBy); + numOfReviewEl.clear(); + numOfReviewEl.sendKeys(Integer.toString(numOfReviews)); + + By numOfStarsBy = By.xpath("//div[contains(@class,'o_rating')]/div[contains(@class,'o_rating_items')]/a[" + numOfStars + "]"); + browser.findElement(numOfStarsBy).click(); + OOGraphene.waitBusy(browser); + + By saveBy = By.cssSelector("fieldset.o_sel_qpool_review_process_admin button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionPoolPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionPoolPage.java new file mode 100644 index 0000000000000000000000000000000000000000..b383e6e2570b58f67fc5ae6c50eaa0e8190d7f7a --- /dev/null +++ b/src/test/java/org/olat/selenium/page/qpool/QuestionPoolPage.java @@ -0,0 +1,183 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.qpool; + +import org.olat.ims.qti21.model.QTI21QuestionType; +import org.olat.selenium.page.NavigationPage; +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; + +/** + * + * Initial date: 26 avr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QuestionPoolPage { + + private final WebDriver browser; + + public QuestionPoolPage(WebDriver browser) { + this.browser = browser; + } + + public QuestionPoolPage assertOnQuestionPool() { + By mainBy = By.className("o_qpool"); + OOGraphene.waitElement(mainBy, browser); + return this; + } + + /** + * Select the node my questions. + * + * @return Itself + */ + public QuestionPoolPage selectMyQuestions() { + By myQuestionsBy = By.xpath("//div[contains(@class,'o_tree')]/ul[@class='o_tree_l0']//a[i[contains(@class,'o_sel_qpool_my_items')]]"); + OOGraphene.waitElement(myQuestionsBy, browser); + browser.findElement(myQuestionsBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitElement(By.id("qitems"), browser); + return this; + } + + /** + * Select a node in the review process. + * + * @param name The name of the taxonomy level + * @return Itself + */ + public QuestionPoolPage selectTaxonomyLevel(String name) { + By leafBy = By.xpath("//li[contains(@class,'o_sel_qpool_review_taxonomy_levels')]/ul/li/div[contains(@class,'o_tree_l1')]/span/a[contains(@onclick,'ctncl')][span[text()[contains(.,'" + name + "')]]]"); + OOGraphene.waitElement(leafBy, browser); + browser.findElement(leafBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + /** + * Select a question in a list. + * + * @param title The title of the question + * @return Itself + */ + public QuestionPoolPage selectQuestionInList(String title) { + By rowBy = By.xpath("//div[contains(@class,'o_table_flexi')]//tr[td[text()[contains(.,'" + title + "')]]]/td/a[contains(@href,'select-item')]"); + OOGraphene.waitElement(rowBy, browser); + browser.findElement(rowBy).click(); + OOGraphene.waitBusy(browser); + return this; + } + + public QuestionPoolPage assessQuestion(int numOfStars) { + By assessmentBy = By.xpath("//div[contains(@class,'o_instruction')]/div[@class='o_button_group']/a[contains(@onclick,'process.activate.review')]"); + OOGraphene.waitElement(assessmentBy, browser); + browser.findElement(assessmentBy).click(); + OOGraphene.waitModalDialog(browser); + + By numOfStarsBy = By.xpath("//fieldset[contains(@class,'o_sel_qpool_review_form')]//div[contains(@class,'o_rating')]/div[contains(@class,'o_rating_items')]/a[" + numOfStars + "]"); + OOGraphene.waitElement(numOfStarsBy, browser); + browser.findElement(numOfStarsBy).click(); + OOGraphene.waitBusy(browser); + + By saveBy = By.cssSelector("div.modal-content fieldset.o_sel_qpool_review_form button.btn.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialogDisappears(browser); + return this; + } + + public QuestionPoolPage newQuestion(String title, QTI21QuestionType type) { + By newQuestionBy = By.xpath("//a[i[contains(@class,'o_icon_qitem_new')]]"); + browser.findElement(newQuestionBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialog(browser); + + By titleBy = By.cssSelector("fieldset.o_sel_new_item_form div.o_sel_item_title input[type='text']"); + browser.findElement(titleBy).sendKeys(title); + + By typeBy = By.cssSelector("fieldset.o_sel_new_item_form div.o_sel_item_type select"); + WebElement typeEl = browser.findElement(typeBy); + new Select(typeEl).selectByValue("qti21_" + type.name()); + + By saveBy = By.cssSelector("fieldset.o_sel_new_item_form button.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialogDisappears(browser); + + By assessmentItemBy = By.cssSelector("ul.o_sel_assessment_item_config"); + OOGraphene.waitElement(assessmentItemBy, browser); + return this; + } + + /** + * Start the process, confirm with the first taxonomy level found. + * + * @return Itself + */ + public QuestionPoolPage startReviewProcess() { + By startProcessBy = By.xpath("//div[contains(@class,'o_button_group')]/a[contains(@onclick,'process.activate.start.review')]"); + browser.findElement(startProcessBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialog(browser); + + By confirmBy = By.cssSelector("fieldset.o_sel_qpool_confirm_start_form button.btn.btn-primary"); + OOGraphene.waitElement(confirmBy, browser); + browser.findElement(confirmBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialogDisappears(browser); + return this; + } + + public QuestionPoolPage assertQuestionInList(String title, String type) { + By rowBy = By.xpath("//div[contains(@class,'o_table_flexi')]//tr[td[text()='" + type + "']]/td[text()[contains(.,'" + title + "')]]"); + OOGraphene.waitElement(rowBy, browser); + return this; + } + + /** + * Check if the mark "Final" is visible in the toolbar. + * + * @return Itself + */ + public QuestionPoolPage assertFinalOnQuestion() { + By finalBy = By.cssSelector("li.o_tool a.o_qpool_tools_status.o_qpool_status_finalVersion"); + OOGraphene.waitElement(finalBy, browser); + return this; + } + + public QuestionPoolPage assertFinalQuestionInList(String title) { + By rowBy = By.xpath("//div[contains(@class,'o_table_flexi')]//tr[td/div/span[contains(@class,'o_qpool_status_finalVersion_light')]]/td[text()[contains(.,'" + title + "')]]"); + OOGraphene.waitElement(rowBy, browser); + return this; + } + + public QuestionPoolPage clickToolbarBack() { + browser.findElement(NavigationPage.toolbarBackBy).click(); + OOGraphene.waitBusy(browser); + + By tableBy = By.cssSelector("div.o_table_flexi.o_rendertype_classic"); + OOGraphene.waitElement(tableBy, browser); + return this; + } +} diff --git a/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyAdminPage.java b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyAdminPage.java new file mode 100644 index 0000000000000000000000000000000000000000..2a72c1a02671bf674112a3f1c988d948bf40d87f --- /dev/null +++ b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyAdminPage.java @@ -0,0 +1,53 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.taxonomy; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 11 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TaxonomyAdminPage { + + private final WebDriver browser; + + public TaxonomyAdminPage(WebDriver browser) { + this.browser = browser; + } + + public TaxonomyAdminPage assertOnTaxonomyList() { + By taxonomyListBy = By.className("o_taxonomy_listing"); + OOGraphene.waitElement(taxonomyListBy, browser); + return this; + } + + public TaxonomyPage selectTaxonomy(String identifier) { + By selectBy = By.xpath("//div[@class='o_taxonomy_row'][div/div/h4/small[text()[contains(.,'" + identifier + "')]]]/div/div[@class='panel-body']/div[@class='pull-right']/a"); + browser.findElement(selectBy).click(); + OOGraphene.waitBusy(browser); + return new TaxonomyPage(browser); + } + +} diff --git a/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyLevelPage.java b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyLevelPage.java new file mode 100644 index 0000000000000000000000000000000000000000..fc269250e3af3addd4fd4ed10ed9db2a770f01b0 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyLevelPage.java @@ -0,0 +1,101 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.taxonomy; + +import java.util.List; + +import org.junit.Assert; +import org.olat.modules.taxonomy.TaxonomyCompetenceTypes; +import org.olat.selenium.page.graphene.OOGraphene; +import org.olat.selenium.page.group.MembersWizardPage; +import org.olat.user.restapi.UserVO; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 22 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TaxonomyLevelPage { + + private final WebDriver browser; + + public TaxonomyLevelPage(WebDriver browser) { + this.browser = browser; + } + + public TaxonomyLevelPage assertOnTaxonomyLevel() { + By overviewBy = By.cssSelector("div.o_sel_taxonomy_level_overview"); + OOGraphene.waitElement(overviewBy, browser); + return this; + } + + public TaxonomyLevelPage selectCompetence() { + By configBy = By.className("o_sel_taxonomy_level_competences"); + return selectTab(configBy); + } + + public TaxonomyLevelPage addCompetence(UserVO user, TaxonomyCompetenceTypes competence) { + // open callout + By addCompetenceBy = By.cssSelector("a.o_sel_competence_add"); + browser.findElement(addCompetenceBy).click(); + OOGraphene.waitBusy(browser); + //choose competence + OOGraphene.waitElement(By.cssSelector("div.popover-content ul.o_sel_tools"), browser); + By competenceBy = By.xpath("//ul[contains(@class,'o_sel_tools')]/li/a[contains(@onclick,'add.competence." + competence + "')]"); + browser.findElement(competenceBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialog(browser); + + MembersWizardPage members = new MembersWizardPage(browser); + members.searchMember(user, true); + OOGraphene.waitBusy(browser); + + By chooseBy = By.xpath("//fieldset[@class='o_sel_usersearch_searchform']//div[@class='o_table_buttons']/button[@name='msc']"); + browser.findElement(chooseBy).click(); + OOGraphene.waitModalDialogDisappears(browser); + + return this; + } + + private TaxonomyLevelPage selectTab(By tabBy) { + By tabLinkBy = By.cssSelector("ul.o_sel_taxonomy_level_tabs>li>a"); + List<WebElement> tabLinks = browser.findElements(tabLinkBy); + + boolean found = false; + a_a: + for(WebElement tabLink:tabLinks) { + tabLink.click(); + OOGraphene.waitBusy(browser); + List<WebElement> chooseRepoEntry = browser.findElements(tabBy); + if(chooseRepoEntry.size() > 0) { + found = true; + break a_a; + } + } + + Assert.assertTrue("Found the tab", found); + return this; + } + +} diff --git a/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyPage.java b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyPage.java new file mode 100644 index 0000000000000000000000000000000000000000..e941f3f36c1ca00944edbbfa538efee60d79d56c --- /dev/null +++ b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyPage.java @@ -0,0 +1,52 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.taxonomy; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +/** + * + * Initial date: 11 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TaxonomyPage { + + private final WebDriver browser; + + public TaxonomyPage(WebDriver browser) { + this.browser = browser; + } + + /** + * Select the tab to manage the taxonomy levels. + * + * @return The taxonomy tree page + */ + public TaxonomyTreePage selectTaxonomyTree() { + By selectLevelsBy = By.cssSelector("a.o_sel_taxonomy_levels"); + OOGraphene.waitElement(selectLevelsBy, browser); + browser.findElement(selectLevelsBy).click(); + return new TaxonomyTreePage(browser).assertOnTaxonomyTree(); + } + +} diff --git a/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyTreePage.java b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyTreePage.java new file mode 100644 index 0000000000000000000000000000000000000000..4adc6985025307f695ba2da0ced299687c84d937 --- /dev/null +++ b/src/test/java/org/olat/selenium/page/taxonomy/TaxonomyTreePage.java @@ -0,0 +1,89 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.selenium.page.taxonomy; + +import java.util.List; + +import org.olat.selenium.page.graphene.OOGraphene; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +/** + * + * Initial date: 11 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class TaxonomyTreePage { + + private final WebDriver browser; + + public TaxonomyTreePage(WebDriver browser) { + this.browser = browser; + } + + public TaxonomyTreePage assertOnTaxonomyTree() { + By levelsTreeBy = By.className("o_sel_taxonomy_levels_tree"); + OOGraphene.waitElement(levelsTreeBy, browser); + return this; + } + + /** + * Check if there is at least one level. If not, create one. + * + * @return Itself + */ + public TaxonomyTreePage atLeastOneLevel(String identifier, String name) { + By tableBy = By.xpath("//div[contains(@class,'o_sel_taxonomy_levels_tree')]//table//tr/td[text()[contains(.,'" + identifier + "')]]"); + List<WebElement> tableEls = browser.findElements(tableBy); + if(tableEls.isEmpty()) { + newLevel(identifier, name); + } + return this; + } + + public TaxonomyLevelPage selectTaxonomyLevel(String identifier) { + By selectBy = By.xpath("//div[contains(@class,'o_sel_taxonomy_levels_tree')]//table//tr[td[text()[contains(.,'" + identifier + "')]]]/td/a[contains(@href,'select')]"); + browser.findElement(selectBy).click(); + OOGraphene.waitBusy(browser); + return new TaxonomyLevelPage(browser).assertOnTaxonomyLevel(); + } + + public TaxonomyTreePage newLevel(String identifier, String name) { + By newLevelBy = By.cssSelector("div.o_sel_taxonomy_levels_tree a.o_sel_taxonomy_new_level"); + browser.findElement(newLevelBy).click(); + OOGraphene.waitModalDialog(browser); + + By identifierBy = By.cssSelector("div.o_sel_taxonomy_level_identifier input[type='text']"); + OOGraphene.waitElement(identifierBy, browser); + browser.findElement(identifierBy).sendKeys(identifier); + + By nameBy = By.cssSelector("div.o_sel_taxonomy_level_name input[type='text']"); + browser.findElement(nameBy).sendKeys(name); + + By saveBy = By.cssSelector("fieldset.o_sel_taxonomy_level_form button.btn.btn-primary"); + browser.findElement(saveBy).click(); + OOGraphene.waitBusy(browser); + OOGraphene.waitModalDialogDisappears(browser); + return this; + } + +} diff --git a/src/test/java/org/olat/test/rest/UserRestClient.java b/src/test/java/org/olat/test/rest/UserRestClient.java index 24d1f9d9b8b512c5b51dac3b294b2b869ba8df2b..2189df8b3afb40f5704d021bd77a98e7e014dbad 100644 --- a/src/test/java/org/olat/test/rest/UserRestClient.java +++ b/src/test/java/org/olat/test/rest/UserRestClient.java @@ -97,14 +97,22 @@ public class UserRestClient { RolesVO roles = new RolesVO(); roles.setAuthor(true); + updateRoles(restConnection, user, roles); + + restConnection.shutdown(); + return user; + } + + public UserVO createPoolManager(String name) + throws IOException, URISyntaxException { + RestConnection restConnection = new RestConnection(deploymentUrl); + assertTrue(restConnection.login(username, password)); - //update roles of author - URI request = getUsersURIBuilder().path(user.getKey().toString()).path("roles").build(); - HttpPost method = restConnection.createPost(request, MediaType.APPLICATION_JSON); - restConnection.addJsonEntity(method, roles); - HttpResponse response = restConnection.execute(method); - Assert.assertEquals(200, response.getStatusLine().getStatusCode()); - EntityUtils.consume(response.getEntity()); + UserVO user = createUser(restConnection, name, "Auth"); + + RolesVO roles = new RolesVO(); + roles.setPoolAdmin(true); + updateRoles(restConnection, user, roles); restConnection.shutdown(); return user; @@ -144,6 +152,20 @@ public class UserRestClient { return current; } + /** + * Update roles + */ + private void updateRoles(RestConnection restConnection, UserVO user, RolesVO roles) + throws URISyntaxException, IOException { + //update roles of pool manager + URI request = getUsersURIBuilder().path(user.getKey().toString()).path("roles").build(); + HttpPost method = restConnection.createPost(request, MediaType.APPLICATION_JSON); + restConnection.addJsonEntity(method, roles); + HttpResponse response = restConnection.execute(method); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + EntityUtils.consume(response.getEntity()); + } + private UriBuilder getUsersURIBuilder() throws URISyntaxException { return UriBuilder.fromUri(deploymentUrl.toURI()).path("restapi").path("users");