From 1c51666e7306b71d64d8cab766d26879b44cf76e Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Thu, 15 May 2014 08:58:35 +0200 Subject: [PATCH] OO-990: mostly fix of the authoring GUI, and unit tests, integrate the demo course to the test resource --- pom.xml | 20 ++-- .../org/olat/commons/servlets/RSSServlet.java | 4 +- .../ui/UserCommentsAndRatingsController.java | 4 +- .../notifications/PersonalRSSFeed.java | 2 +- .../model/NoSubscriptionInfo.java | 16 +--- .../stack/BreadcrumbedStackedPanel.java | 2 +- .../olat/core/id/context/HistoryManager.java | 1 + .../org/olat/core/util/mail/MailHelper.java | 5 +- .../olat/core/util/prefs/db/DbStorage.java | 6 +- .../java/org/olat/course/CourseFactory.java | 10 +- .../org/olat/course/PersistingCourseImpl.java | 2 +- .../EfficiencyStatementManager.java | 51 +++++----- .../org/olat/course/editor/PublishStep01.java | 6 +- .../course/nodes/PortfolioCourseNode.java | 9 +- .../repository/handlers/QTISurveyHandler.java | 59 ++++-------- .../repository/handlers/QTITestHandler.java | 12 +-- .../AfterLoginInterceptionController.java | 6 +- .../qpool/ui/QuestionListController.java | 18 ++-- .../portfolio/manager/EPStructureManager.java | 12 +-- .../ui/_i18n/LocalStrings_ar.properties | 2 + .../ui/_i18n/LocalStrings_de.properties | 4 +- .../ui/_i18n/LocalStrings_en.properties | 2 + .../ui/_i18n/LocalStrings_fr.properties | 2 + .../ui/_i18n/LocalStrings_it.properties | 2 + .../ui/_i18n/LocalStrings_jp.properties | 2 + .../ui/_i18n/LocalStrings_nl_NL.properties | 2 + .../ui/_i18n/LocalStrings_pl.properties | 2 + .../ui/_i18n/LocalStrings_pt_BR.properties | 2 + .../ui/_i18n/LocalStrings_zh_CN.properties | 2 + .../org/olat/repository/RepositoryEntry.java | 3 +- .../olat/repository/RepositoryManager.java | 28 +++--- .../ReferencableEntriesSearchController.java | 53 ++++++----- .../RepositorySearchController.java | 26 ++---- .../repository/controllers/SearchForm.java | 23 +++-- .../controllers/_content/results.html | 24 +++++ .../{ => controllers}/_content/search.html | 0 .../olat/repository/handlers/BlogHandler.java | 8 +- .../repository/handlers/CourseHandler.java | 8 +- .../repository/handlers/GlossaryHandler.java | 7 +- .../repository/handlers/ImsCPHandler.java | 11 +-- .../repository/handlers/PodcastHandler.java | 10 +- .../repository/handlers/PortfolioHandler.java | 28 +++--- .../handlers/RepositoryHandler.java | 3 +- .../handlers/RepositoryHandlerFactory.java | 24 ++++- .../repository/handlers/SCORMCPHandler.java | 12 +-- .../handlers/SharedFolderHandler.java | 13 +-- .../handlers/WebDocumentHandler.java | 54 +++++------ .../olat/repository/handlers/WikiHandler.java | 12 +-- .../org/olat/repository/handlers/package.html | 4 - .../manager/RepositoryEntryStatisticsDAO.java | 6 ++ ...RepositoryEntryAccessColumnDescriptor.java | 4 +- .../ui/author/AuthorListController.java | 36 +++++--- .../ui/author/AuthoringEntryDataModel.java | 2 +- .../AuthoringEntryDetailsController.java | 10 +- .../CreateRepositoryEntryController.java | 26 +----- .../ImportRepositoryEntryController.java | 31 +------ .../repository/ui/author/PropPupForm.java | 3 + .../RepositoryEditDescriptionController.java | 2 - .../ui/AccessConfigurationController.java | 19 ++-- .../repository/RepositoryEntriesResource.java | 4 +- .../service/indexer/IndexWriterHolder.java | 8 +- .../database/mysql/setupDatabase.sql | 2 +- .../core/id/context/HistoryManagerTest.java | 3 +- .../assessment/AssessmentManagerTest.java | 87 ++++++++++-------- .../auditing/UserNodeAuditManagerTest.java | 8 +- .../olat/course/condition/ConditionTest.java | 4 +- .../ProjectBrokerManagerTest.java | 3 +- .../java/org/olat/portfolio/EPImportTest.java | 11 ++- .../repository/RepositoryManagerTest.java | 10 +- .../RepositoryEntryStatisticsDAOTest.java | 4 +- .../java/org/olat/restapi/UserMgmtTest.java | 3 +- .../java/org/olat/test/JunitTestHelper.java | 67 ++++++-------- .../olat/test/_spring/demoCourseExport.xml | 18 ---- src/test/java/org/olat/test/_spring/readme | 2 - .../test/file_resources/Demo-Kurs-7.1.zip | Bin 0 -> 60957 bytes 75 files changed, 468 insertions(+), 523 deletions(-) create mode 100644 src/main/java/org/olat/repository/controllers/_content/results.html rename src/main/java/org/olat/repository/{ => controllers}/_content/search.html (100%) delete mode 100644 src/main/java/org/olat/repository/handlers/package.html delete mode 100644 src/test/java/org/olat/test/_spring/demoCourseExport.xml delete mode 100644 src/test/java/org/olat/test/_spring/readme create mode 100644 src/test/java/org/olat/test/file_resources/Demo-Kurs-7.1.zip diff --git a/pom.xml b/pom.xml index ac7886f018e..6665c43951e 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ <org.mysql.version>5.1.29</org.mysql.version> <org.postgresql.version>9.3-1100-jdbc41</org.postgresql.version> <org.infinispan.version>6.0.1.Final</org.infinispan.version> - <lucene.version>4.5.1</lucene.version> + <lucene.version>4.8.0</lucene.version> <!-- properties for testing and Q&A --> <!-- by default no tests are executed so far (April 2011). Use appropriate profiles and properties on the command line --> @@ -1095,7 +1095,7 @@ <id>central</id> <name>Maven Repository Switchboard</name> <layout>default</layout> - <url>http://repo1.maven.org/maven2</url> + <url>http://central.maven.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> @@ -1683,7 +1683,7 @@ <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> - <version>1.8.4</version> + <version>1.8.5</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> @@ -2174,13 +2174,13 @@ <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> - <version>1.0.0.Final</version> + <version>1.0.9.Final</version> <scope>test</scope> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> - <version>1.0.0.Final</version> + <version>1.0.9.Final</version> <scope>test</scope> </dependency> @@ -2273,17 +2273,15 @@ <version>2.9</version> </plugin> <!-- Javadoc --> - - <!-- <reportSets> <reportSet> <reports> <report>javadoc</report> --> <!-- Note: leave this line commented out if unit tests are not to be documented <report>test-javadoc</report>report> --> <!-- </reports> </reportSet> </reportSets> </plugin> --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jxr-plugin</artifactId> - <version>2.3</version> - </plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jxr-plugin</artifactId> + <version>2.3</version> + </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>cobertura-maven-plugin</artifactId> diff --git a/src/main/java/org/olat/commons/servlets/RSSServlet.java b/src/main/java/org/olat/commons/servlets/RSSServlet.java index 196cedb6e5f..5b874f0efac 100644 --- a/src/main/java/org/olat/commons/servlets/RSSServlet.java +++ b/src/main/java/org/olat/commons/servlets/RSSServlet.java @@ -212,8 +212,6 @@ public class RSSServlet extends HttpServlet { } // create rss feed for user notifications - SyndFeed feed = new PersonalRSSFeed(identity, idToken); - //TODO implements some caching - return feed; + return new PersonalRSSFeed(identity); } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java index 42444297165..caa011ddf5b 100644 --- a/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java +++ b/src/main/java/org/olat/core/commons/services/commentAndRating/ui/UserCommentsAndRatingsController.java @@ -168,7 +168,7 @@ public class UserCommentsAndRatingsController extends BasicController implements * * @param ureq */ - public void collapseComments(UserRequest ureq) { + void collapseComments() { if (!canExpandToFullView) { throw new AssertException("Can not collapse messages when controller initialized as not expandable"); } userCommentsAndRatingsVC.remove(commentsCtr.getInitialComponent()); removeAsListenerAndDispose(commentsCtr); @@ -236,7 +236,7 @@ public class UserCommentsAndRatingsController extends BasicController implements if (canExpandToFullView) { if (isExpanded) { // Collapse - collapseComments(ureq); + collapseComments(); } else { // Expand now expandComments(ureq); diff --git a/src/main/java/org/olat/core/commons/services/notifications/PersonalRSSFeed.java b/src/main/java/org/olat/core/commons/services/notifications/PersonalRSSFeed.java index c443b19c619..a4079f26009 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/PersonalRSSFeed.java +++ b/src/main/java/org/olat/core/commons/services/notifications/PersonalRSSFeed.java @@ -63,7 +63,7 @@ public class PersonalRSSFeed extends SyndFeedImpl { * @param identity The users identity * @param token The users RSS-authentication token */ - public PersonalRSSFeed(Identity identity, String token) { + public PersonalRSSFeed(Identity identity) { super(); setFeedType("rss_2.0"); setEncoding(RSSServlet.DEFAULT_ENCODING); diff --git a/src/main/java/org/olat/core/commons/services/notifications/model/NoSubscriptionInfo.java b/src/main/java/org/olat/core/commons/services/notifications/model/NoSubscriptionInfo.java index 858de5333c1..eaf8d3f66a5 100644 --- a/src/main/java/org/olat/core/commons/services/notifications/model/NoSubscriptionInfo.java +++ b/src/main/java/org/olat/core/commons/services/notifications/model/NoSubscriptionInfo.java @@ -25,6 +25,8 @@ package org.olat.core.commons.services.notifications.model; +import java.util.Locale; + import org.olat.core.commons.services.notifications.SubscriptionInfo; /** @@ -38,23 +40,16 @@ import org.olat.core.commons.services.notifications.SubscriptionInfo; */ public class NoSubscriptionInfo extends SubscriptionInfo { - /** - * - */ public NoSubscriptionInfo() { super(null, null, null, null); } - /** - * @see org.olat.core.commons.services.notifications.SubscriptionInfo#getSpecificInfo(java.lang.String) - */ - public String getSpecificInfo(String mimeType) { + @Override + public String getSpecificInfo(String mimeType, Locale locale) { return ""; } - /** - * @see org.olat.core.commons.services.notifications.SubscriptionInfo#hasNews() - */ + @Override public boolean hasNews() { return false; } @@ -68,6 +63,5 @@ public class NoSubscriptionInfo extends SubscriptionInfo { public String getCustomUrl() { return null; } - } diff --git a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java index 3abe3cedee1..adec8f63db5 100644 --- a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java +++ b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java @@ -76,7 +76,7 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Bre // Add back link before the bread crumbs, when pressed delegates click to current bread-crumb - 1 closeLink = LinkFactory.createCustomLink("close", "close", null, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS, null, this); closeLink.setIconLeftCSS("o_icon o_icon_close_tab"); - closeLink.setCustomDisplayText(translator.translate("doclose")); + closeLink.setCustomDisplayText(translator.translate("close")); closeLink.setAccessKey("x"); // allow navigation using keyboard } diff --git a/src/main/java/org/olat/core/id/context/HistoryManager.java b/src/main/java/org/olat/core/id/context/HistoryManager.java index 583e5793b56..fd641af6c7e 100644 --- a/src/main/java/org/olat/core/id/context/HistoryManager.java +++ b/src/main/java/org/olat/core/id/context/HistoryManager.java @@ -65,6 +65,7 @@ public class HistoryManager extends BasicManager { historyReadStream.omitField(RepositoryEntry.class, "participantGroup"); historyReadStream.omitField(RepositoryEntry.class, "tutorGroup"); historyReadStream.omitField(RepositoryEntry.class, "metaDataElements"); + historyReadStream.alias("org.olat.core.util.resource.OresHelper$1", Resourceable.class); historyReadStream.alias("org.olat.core.util.resource.OresHelper$2", Resourceable.class); historyReadStream.alias("org.olat.core.util.resource.OresHelper$3", Resourceable.class); diff --git a/src/main/java/org/olat/core/util/mail/MailHelper.java b/src/main/java/org/olat/core/util/mail/MailHelper.java index 4726711c640..440cda4f91f 100644 --- a/src/main/java/org/olat/core/util/mail/MailHelper.java +++ b/src/main/java/org/olat/core/util/mail/MailHelper.java @@ -71,7 +71,10 @@ public class MailHelper { } public static String getMailFooter(MailBundle bundle) { - return getMailFooter(bundle.getFromId()); + if(bundle.getFromId() != null) { + return getMailFooter(bundle.getFromId()); + } + return getMailFooter(I18nModule.getDefaultLocale()); } diff --git a/src/main/java/org/olat/core/util/prefs/db/DbStorage.java b/src/main/java/org/olat/core/util/prefs/db/DbStorage.java index d5ec81d572b..994aee976cd 100644 --- a/src/main/java/org/olat/core/util/prefs/db/DbStorage.java +++ b/src/main/java/org/olat/core/util/prefs/db/DbStorage.java @@ -116,7 +116,7 @@ public class DbStorage extends LogDelegator implements PreferencesStorage{ private DbPrefs getPreferencesForProperty(Identity identity, Property guiProperty) { DbPrefs prefs; try { - prefs = createDbPrefsFrom(identity, guiProperty, guiProperty.getTextValue()); + prefs = createDbPrefsFrom(identity, guiProperty.getTextValue()); } catch (Exception e) { prefs = doGuiPrefsMigration( guiProperty, identity); } @@ -130,7 +130,7 @@ public class DbStorage extends LogDelegator implements PreferencesStorage{ return prefs; } - private DbPrefs createDbPrefsFrom(Identity identity, Property guiProperty, String textValue) { + private DbPrefs createDbPrefsFrom(Identity identity, String textValue) { DbPrefs prefs = (DbPrefs) xstream.fromXML(textValue); prefs.setIdentity(identity); // reset transient value return prefs; @@ -140,7 +140,7 @@ public class DbStorage extends LogDelegator implements PreferencesStorage{ String migratedTextValue = doCalendarRefactoringMigration(guiProperty.getTextValue()); // add new migration methode here try { - return createDbPrefsFrom(identity, guiProperty, migratedTextValue); + return createDbPrefsFrom(identity, migratedTextValue); } catch (Exception e) { // Migration failed => return empty db-prefs return createEmptyDbPrefs(identity,false); diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java index e82f4c620ed..ff3a7d6d91d 100644 --- a/src/main/java/org/olat/course/CourseFactory.java +++ b/src/main/java/org/olat/course/CourseFactory.java @@ -294,19 +294,11 @@ public class CourseFactory extends BasicManager { OLATResourceable courseResourceable = OresHelper.createOLATResourceableInstance(PersistingCourseImpl.class, resourceableId); course = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(courseResourceable, new SyncerCallback<PersistingCourseImpl>() { public PersistingCourseImpl execute() { - PersistingCourseImpl theCourse = null; - theCourse = getCourseFromCache(resourceableId); + PersistingCourseImpl theCourse = getCourseFromCache(resourceableId); if (theCourse == null) { - long startTime = 0; - long endTime = 0; - if (log.isDebug()) startTime = System.currentTimeMillis(); theCourse = new PersistingCourseImpl(resourceableId); theCourse.load(); - if (log.isDebug()) endTime = System.currentTimeMillis(); putCourseInCache(resourceableId, theCourse); - long diff = 0; - if (log.isDebug()) diff = Long.valueOf(endTime - startTime); - if (log.isDebug()) log.debug("[[" + resourceableId + "[[" + diff + "[[" + theCourse.getCourseTitle()); } return theCourse; } diff --git a/src/main/java/org/olat/course/PersistingCourseImpl.java b/src/main/java/org/olat/course/PersistingCourseImpl.java index 656700a9f86..26c9f60dcbf 100644 --- a/src/main/java/org/olat/course/PersistingCourseImpl.java +++ b/src/main/java/org/olat/course/PersistingCourseImpl.java @@ -126,7 +126,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ // prepare filesystem and set course base path and course folder paths prepareFilesystem(); courseConfig = CourseConfigManagerImpl.getInstance().loadConfigFor(this); // load or init defaults - courseEnvironment = new CourseEnvironmentImpl(this); + courseEnvironment = new CourseEnvironmentImpl(this); } diff --git a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java index c03e1e59ba2..0329bc61641 100644 --- a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java +++ b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java @@ -34,8 +34,6 @@ import java.util.List; import java.util.Map; import org.olat.core.commons.persistence.DB; -import org.olat.core.commons.persistence.DBFactory; -import org.olat.core.commons.persistence.DBQuery; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.manager.BasicManager; @@ -281,10 +279,11 @@ public class EfficiencyStatementManager extends BasicManager implements UserData sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") .append(" where statement.identity.key=:identityKey and statement.courseRepoKey=:repoKey"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("identityKey", identity.getKey()); - query.setLong("repoKey", courseRepoEntryKey); - List<UserEfficiencyStatementImpl> statement = query.list(); + List<UserEfficiencyStatementImpl> statement = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), UserEfficiencyStatementImpl.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("repoKey", courseRepoEntryKey) + .getResultList(); if(statement.isEmpty()) { return null; } @@ -301,10 +300,11 @@ public class EfficiencyStatementManager extends BasicManager implements UserData sb.append("select statement from ").append(UserEfficiencyStatementLight.class.getName()).append(" as statement ") .append(" where statement.identity.key=:identityKey and statement.courseRepoKey=:repoKey"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("identityKey", identity.getKey()); - query.setLong("repoKey", courseRepoEntryKey); - List<UserEfficiencyStatement> statement = query.list(); + List<UserEfficiencyStatement> statement = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), UserEfficiencyStatement.class) + .setParameter("identityKey", identity.getKey()) + .setParameter("repoKey", courseRepoEntryKey) + .getResultList(); if(statement.isEmpty()) { return null; } @@ -321,9 +321,10 @@ public class EfficiencyStatementManager extends BasicManager implements UserData sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") .append(" where statement.key=:key"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("key", key); - List<UserEfficiencyStatementImpl> statement = query.list(); + List<UserEfficiencyStatementImpl> statement = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), UserEfficiencyStatementImpl.class) + .setParameter("key", key) + .getResultList(); if(statement.isEmpty()) { return null; } @@ -426,15 +427,14 @@ public class EfficiencyStatementManager extends BasicManager implements UserData protected List<EfficiencyStatement> findEfficiencyStatements(Identity identity) { List<EfficiencyStatement> efficiencyStatements = new ArrayList<EfficiencyStatement>(); try { - dbInstance = DBFactory.getInstance(); - StringBuilder sb = new StringBuilder(); sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") .append(" where statement.identity.key=:identityKey"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("identityKey", identity.getKey()); - List<UserEfficiencyStatementImpl> statements = query.list(); + List<UserEfficiencyStatementImpl> statements = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), UserEfficiencyStatementImpl.class) + .setParameter("identityKey", identity.getKey()) + .getResultList(); for(UserEfficiencyStatementImpl statement:statements) { EfficiencyStatement s = (EfficiencyStatement)xstream.fromXML(statement.getStatementXml()); efficiencyStatements.add(s); @@ -474,10 +474,10 @@ public class EfficiencyStatementManager extends BasicManager implements UserData sb.append("select distinct(statement.identity) from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") .append(" where statement.courseRepoKey=:repoKey"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("repoKey", courseRepoEntryKey); - List<Identity> identities = query.list(); - return identities; + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Identity.class) + .setParameter("repoKey", courseRepoEntryKey) + .getResultList(); } catch (Exception e) { logError("findIdentitiesWithEfficiencyStatements: " + courseRepoEntryKey, e); return Collections.emptyList(); @@ -495,9 +495,10 @@ public class EfficiencyStatementManager extends BasicManager implements UserData sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ") .append(" where statement.courseRepoKey=:repoKey"); - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("repoKey", courseRepoEntryKey); - List<UserEfficiencyStatementImpl> statements = query.list(); + List<UserEfficiencyStatementImpl> statements = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), UserEfficiencyStatementImpl.class) + .setParameter("repoKey", courseRepoEntryKey) + .getResultList(); for(UserEfficiencyStatementImpl statement:statements) { dbInstance.deleteObject(statement); } diff --git a/src/main/java/org/olat/course/editor/PublishStep01.java b/src/main/java/org/olat/course/editor/PublishStep01.java index 7e212089cd1..740ebfc551b 100644 --- a/src/main/java/org/olat/course/editor/PublishStep01.java +++ b/src/main/java/org/olat/course/editor/PublishStep01.java @@ -48,7 +48,7 @@ import org.olat.course.ICourse; import org.olat.login.LoginModule; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryModule; -import org.olat.repository.ui.author.PropPupForm; +import org.olat.repository.RepositoryService; /** * Description:<br> @@ -129,9 +129,9 @@ class PublishStep01 extends BasicStep { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - Translator pt = Util.createPackageTranslator(PropPupForm.class, getLocale(), getTranslator()); + Translator pt = Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator()); - FormItemContainer fic = FormLayoutContainer.createCustomFormLayout("access", pt, this.velocity_root+"/publish_courseaccess.html"); + FormItemContainer fic = FormLayoutContainer.createCustomFormLayout("access", pt, velocity_root + "/publish_courseaccess.html"); formLayout.add(fic); List<String> keyList = new ArrayList<String>(); diff --git a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java index cfb3478500a..0497e41d0d3 100644 --- a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java +++ b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java @@ -56,7 +56,9 @@ import org.olat.course.run.userview.NodeEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.portfolio.EPTemplateMapResource; +import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.manager.EPStructureManager; +import org.olat.portfolio.model.structel.PortfolioStructure; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryImportExport; import org.olat.repository.RepositoryManager; @@ -426,8 +428,11 @@ public class PortfolioCourseNode extends AbstractAccessableCourseNode implements RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(EPTemplateMapResource.TYPE_NAME); RepositoryEntry re = handler.importResource(owner, rie.getDisplayName(), rie.getDescription(), false, locale, rie.importGetExportedFile(), null); - //TODO missing map - PortfolioCourseNodeEditController.setReference(re, null, getModuleConfiguration()); + if(re != null) { + EPFrontendManager ePFMgr = CoreSpringFactory.getImpl(EPFrontendManager.class); + PortfolioStructure map = ePFMgr.loadPortfolioStructure(re.getOlatResource()); + PortfolioCourseNodeEditController.setReference(re, map, getModuleConfiguration()); + } } } } \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java index cad6852aa4a..1726e062078 100644 --- a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java +++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java @@ -26,7 +26,6 @@ package org.olat.ims.qti.repository.handlers; import java.io.File; -import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -68,18 +67,6 @@ import de.bps.onyx.plugin.run.OnyxRunController; * */ public class QTISurveyHandler extends QTIHandler { - private static final boolean LAUNCHEABLE = true; - private static final boolean DOWNLOADEABLE = true; - private static final boolean EDITABLE = true; - - static List<String> supportedTypes; - - /** - * Default constructor. - */ - public QTISurveyHandler() { - super(); - } @Override public boolean isCreate() { @@ -108,43 +95,30 @@ public class QTISurveyHandler extends QTIHandler { return super.importResource(initialAuthor, displayname, description, new SurveyFileResource(), file, filename); } - /** - * @see org.olat.repository.handlers.RepositoryHandler#getSupportedTypes() - */ - public List<String> getSupportedTypes() { - return supportedTypes; + @Override + public String getSupportedType() { + return SurveyFileResource.TYPE_NAME; } - static { // initialize supported types - supportedTypes = new ArrayList<String>(1); - supportedTypes.add(SurveyFileResource.TYPE_NAME); - } - - /** - * @see org.olat.repository.handlers.RepositoryHandler#supportsLaunch() - */ + @Override public boolean supportsLaunch(RepositoryEntry repoEntry) { - return LAUNCHEABLE; + return true; } - /** - * @see org.olat.repository.handlers.RepositoryHandler#supportsDownload() - */ + + @Override public boolean supportsDownload(RepositoryEntry repoEntry) { - return DOWNLOADEABLE; + return true; } - /** - * @see org.olat.repository.handlers.RepositoryHandler#supportsEdit() - */ + + @Override public boolean supportsEdit(RepositoryEntry repoEntry) { if (OnyxModule.isOnyxTest(repoEntry.getOlatResource())) { return false; } - return EDITABLE; + return true; } - /** - * @see org.olat.repository.handlers.RepositoryHandler#getCreateWizardController(org.olat.core.id.OLATResourceable, org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl) - */ + @Override public StepsMainRunController createWizardController(OLATResourceable res, UserRequest ureq, WindowControl wControl) { throw new AssertException("Trying to get wizard where no creation wizard is provided for this type."); } @@ -174,9 +148,6 @@ public class QTISurveyHandler extends QTIHandler { return layoutCtr; } - /** - * @see org.olat.repository.handlers.RepositoryHandler#getEditorController(org.olat.core.id.OLATResourceable org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl) - */ @Override public Controller createEditorController(RepositoryEntry re, UserRequest ureq, WindowControl wControl) { OLATResource res = re.getOlatResource(); @@ -199,11 +170,13 @@ public class QTISurveyHandler extends QTIHandler { return null; } } - + + @Override protected String getDeletedFilePrefix() { return "del_qtisurvey_"; } - + + @Override public WizardCloseResourceController createCloseResourceController(UserRequest ureq, WindowControl wControl, RepositoryEntry repositoryEntry) { throw new AssertException("not implemented"); } diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java index 785f7e81ab5..5837e7b100d 100644 --- a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java +++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java @@ -26,7 +26,6 @@ package org.olat.ims.qti.repository.handlers; import java.io.File; -import java.util.Collections; import java.util.List; import java.util.Locale; @@ -68,13 +67,6 @@ import de.bps.onyx.plugin.run.OnyxRunController; * */ public class QTITestHandler extends QTIHandler { - - private static List<String> supportedTypes = Collections.singletonList(TestFileResource.TYPE_NAME); - - /** - * Default construcotr. - */ - public QTITestHandler() { super(); } @Override public boolean isCreate() { @@ -104,8 +96,8 @@ public class QTITestHandler extends QTIHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return TestFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/login/AfterLoginInterceptionController.java b/src/main/java/org/olat/login/AfterLoginInterceptionController.java index d87eafb5a31..3170b4acf34 100644 --- a/src/main/java/org/olat/login/AfterLoginInterceptionController.java +++ b/src/main/java/org/olat/login/AfterLoginInterceptionController.java @@ -153,7 +153,7 @@ public class AfterLoginInterceptionController extends BasicController { listenTo(wiz); // get first Ctrl into Wizard - putControllerToPanel(ureq, wControl, 0); + putControllerToPanel(0); vC.put("actualPanel", actualPanel); cmc = new CloseableModalController(getWindowControl(), translate("close"), vC, true, translate("runonce.title"), false); @@ -201,7 +201,7 @@ public class AfterLoginInterceptionController extends BasicController { * @param wControl * @param ctrNr */ - private void putControllerToPanel(UserRequest ureq, WindowControl wControl, int ctrNr) { + private void putControllerToPanel(int ctrNr) { if (aftctrls.get(ctrNr) == null) return; actualCtrNr = ctrNr; wiz.setCurStep(ctrNr + 1); @@ -277,7 +277,7 @@ public class AfterLoginInterceptionController extends BasicController { */ private void activateNextOrCloseModal(UserRequest ureq){ if ((actualCtrNr + 1) < aftctrls.size()) { - putControllerToPanel(ureq, getWindowControl(), actualCtrNr + 1); + putControllerToPanel(actualCtrNr + 1); } else { removeAsListenerAndDispose(actCtrl); cmc.deactivate(); diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java index 1a6baf9138f..e47f6973dfc 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java @@ -80,6 +80,7 @@ import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.ui.author.CreateRepositoryEntryController; import org.olat.search.service.indexer.LifeFullIndexer; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -122,15 +123,16 @@ public class QuestionListController extends AbstractItemListController implement private ReferencableEntriesSearchController importTestCtrl; private QuestionItemCollection itemCollection; - - private final LifeFullIndexer lifeFullIndexer; - private final RepositoryManager repositoryManager; + + @Autowired + private LifeFullIndexer lifeFullIndexer; + @Autowired + private RepositoryManager repositoryManager; + @Autowired + private RepositoryHandlerFactory repositoryHandlerFactory; public QuestionListController(UserRequest ureq, WindowControl wControl, QuestionItemsSource source, String key) { super(ureq, wControl, source, key); - - lifeFullIndexer = CoreSpringFactory.getImpl(LifeFullIndexer.class); - repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class); } @Override @@ -639,8 +641,8 @@ public class QuestionListController extends AbstractItemListController implement removeAsListenerAndDispose(addController); String type = TestFileResource.TYPE_NAME; - RepositoryHandler handler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(type); - addController = new CreateRepositoryEntryController(ureq, getWindowControl(), type, handler); + RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type); + addController = new CreateRepositoryEntryController(ureq, getWindowControl(), handler); addController.setUserObject(new QItemList(items)); listenTo(addController); cmc = new CloseableModalController(getWindowControl(), translate("close"), addController.getInitialComponent()); diff --git a/src/main/java/org/olat/portfolio/manager/EPStructureManager.java b/src/main/java/org/olat/portfolio/manager/EPStructureManager.java index 96c2bc52dfb..38ff0314b25 100755 --- a/src/main/java/org/olat/portfolio/manager/EPStructureManager.java +++ b/src/main/java/org/olat/portfolio/manager/EPStructureManager.java @@ -1541,13 +1541,13 @@ public class EPStructureManager extends BasicManager { StringBuilder sb = new StringBuilder(); sb.append("select element from ").append(EPStructureElement.class.getName()).append(" element") .append(" left join fetch element.olatResource as oRes") - .append(" left join fetch element.group as baseGroup"); + .append(" left join fetch element.group as baseGroup") + .append(" where element.key=:key");; - DBQuery query = dbInstance.createQuery(sb.toString()); - query.setLong("key", key); - - @SuppressWarnings("unchecked") - List<PortfolioStructure> resources = query.list(); + List<PortfolioStructure> resources = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), PortfolioStructure.class) + .setParameter("key", key) + .getResultList(); // if not found, it is an empty list if (resources.isEmpty()) return null; return resources.get(0); diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_ar.properties index f02902fad10..e20b126fdd2 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_ar.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_ar.properties @@ -40,6 +40,8 @@ othermaps.title=$\:admin.menu.title - $\:othermaps.menu.title portfolio.intro=\u0645\u0646 \u062E\u0644\u0627\u0644 \u0647\u0630\u0647 \u064A\u0645\u0643\u0646\u0643 \u062A\u0646\u0634\u064A\u0637 \u0623\u0648 \u0625\u064A\u0642\u0627\u0641 \u062A\u0646\u0634\u064A\u0637 \u0648\u0638\u064A\u0641\u0629 \u0627\u0644\u0628\u0648\u0631\u062A\u0641\u0648\u0644\u064A\u0648 \u0641\u0649 \u0623\u0648\u0644\u0627\u062A portfolio.module.enabled=\u062A\u0646\u0634\u064A\u0637 \u0627\u0644\u0628\u0648\u0631\u062A\u0641\u0648\u0644\u064A\u0648 portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=\u0639\u0631\u0636\: view.mode.details=\u062A\u0641\u0627\u0635\u064A\u0644 view.mode.table=\u062C\u062F\u0648\u0644 diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_de.properties index dbf9c0c338f..c3ac415340a 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_de.properties @@ -69,8 +69,8 @@ othermaps.intro=$\:othermaps.menu.title.alt othermap.title=$\:admin.menu.title - Mappe othermap.intro=$\:othermaps.menu.title.alt -site.title=ePortfolio - +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title viewTab.all=Artefakte viewTab.browse=Tag-Browser viewTab.search=Suche diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_en.properties index 72602daad4c..c0aa0f9757f 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_en.properties @@ -56,6 +56,8 @@ portfolio.intro=With this you can (de)activate the entire ePortfolio functionali portfolio.module.change.warning=OLAT needs to be restarted to activate your changes throughout the system. portfolio.module.enabled=Activate ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=View\: view.mode.details=Details view.mode.table=Table diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_fr.properties index dd810faf63e..e2f741614a2 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_fr.properties @@ -56,6 +56,8 @@ portfolio.intro=Toutes les fonctions de l'ePortfolio peuvent \u00EAtre activ\u00 portfolio.module.change.warning=Afin que les changements soient activ\u00E9s, vous devez red\u00E9marrer OpenOLAT. portfolio.module.enabled=Activer ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=Affichage\: view.mode.details=D\u00E9tails view.mode.table=Tableau diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_it.properties index 122fce4a45d..3210b87fc8c 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_it.properties @@ -55,6 +55,8 @@ othermaps.title=$\:admin.menu.title - $\:othermaps.menu.title portfolio.intro=Tutte le funzioni dell'ePortfolio possono essere attivate o disattivate. portfolio.module.enabled=Attivare ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=Visualizzazione\: view.mode.details=Dettagli view.mode.table=Tabella diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_jp.properties index 0be404ee7f6..4bbd61c25f5 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_jp.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_jp.properties @@ -54,6 +54,8 @@ othermaps.title=$\:admin.menu.title - $\:othermaps.menu.title portfolio.intro=\u3053\u308C\u306B\u3088\u308A\u3001\u3042\u306A\u305F\u306FOLAT\u5185\u306Ee\u30DD\u30FC\u30C8\u30D5\u30A9\u30EA\u30AA\u6A5F\u80FD\u3092\u6709\u52B9\u307E\u305F\u306F\u7121\u52B9\u306B\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 portfolio.module.enabled=e\u30DD\u30FC\u30C8\u30D5\u30A9\u30EA\u30AA\u3092\u6709\u52B9\u5316\u3059\u308B portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=\u30D3\u30E5\u30FC\: view.mode.details=\u8A73\u7D30 view.mode.table=\u30C6\u30FC\u30D6\u30EB diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_nl_NL.properties index 5f6be12a537..0cae4c495d4 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_nl_NL.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_nl_NL.properties @@ -55,6 +55,8 @@ othermaps.title=$\:admin.menu.title - $\:othermaps.menu.title portfolio.intro=Hiermee kunt u de gehele ePortfolio functionaliteit in OLAT (de)activeren. portfolio.module.enabled=Activeer ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=View\: view.mode.details=Details view.mode.table=Tabel diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pl.properties index 89ae0816b4d..faf58a361d0 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pl.properties @@ -41,6 +41,8 @@ portfolio.intro=Mo\u017Cesz tu w\u0142\u0105czy\u0107 lub wy\u0142\u0105czy\u010 portfolio.module.change.warning=Nale\u017Cy zrestartowa\u0107 OLAT, \u017Ceby aktywowa\u0107 zmiany w systemie. portfolio.module.enabled=W\u0142\u0105cz ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=Widok\: view.mode.details=Szczeg\u00F3\u0142y view.mode.table=Tabela diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pt_BR.properties index 74e18e6a5b5..b2eef955edf 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_pt_BR.properties @@ -56,6 +56,8 @@ portfolio.intro=Com isso voc\u00EA pode (des)ativar a funcionalidade ePortfolio portfolio.module.change.warning=OLAT precisa ser reiniciado para ativar as suas altera\u00E7\u00F5es ao longo do sistema. portfolio.module.enabled=Ativar ePortfolio portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=Visualizar\: view.mode.details=Detalhes view.mode.table=Tabela diff --git a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_zh_CN.properties index f8ffff39529..2fc9658334e 100644 --- a/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/portfolio/ui/_i18n/LocalStrings_zh_CN.properties @@ -55,6 +55,8 @@ othermaps.title=$\:admin.menu.title - $\:othermaps.menu.title portfolio.intro=\u901A\u8FC7\u6B64\u529F\u80FD\uFF0C\u60A8\u53EF\u4EE5\uFF08\u64A4\u9500\uFF09\u6FC0\u6D3BOLAT\u4E2D\u7684\u6574\u4E2A\u7535\u5B50\u6587\u6863\u7684\u529F\u80FD\u3002 portfolio.module.enabled=\u6FC0\u6D3B\u7535\u5B50\u6863\u6848 portfolio.title=$\:admin.menu.title +site.title=$\:admin.menu.title +site.title.alt=$\:admin.menu.title view.mode=\u67E5\u770B\u65B9\u5F0F\uFF1A view.mode.details=\u8BE6\u7EC6\u5185\u5BB9 view.mode.table=\u8868\u683C\u663E\u793A diff --git a/src/main/java/org/olat/repository/RepositoryEntry.java b/src/main/java/org/olat/repository/RepositoryEntry.java index 87787bab5c2..a340c04b1c2 100644 --- a/src/main/java/org/olat/repository/RepositoryEntry.java +++ b/src/main/java/org/olat/repository/RepositoryEntry.java @@ -197,8 +197,9 @@ public class RepositoryEntry implements CreateInfo, Persistable , RepositoryEntr * @param softkey */ public void setSoftkey(String softkey) { - if (softkey.length() > 36) + if (softkey.length() > 36) { throw new AssertException("Trying to set a softkey which is too long..."); + } this.softkey = softkey; } diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java index 11d22005b96..d0873bf20f2 100644 --- a/src/main/java/org/olat/repository/RepositoryManager.java +++ b/src/main/java/org/olat/repository/RepositoryManager.java @@ -36,9 +36,9 @@ import java.util.List; import java.util.Map; import javax.persistence.LockModeType; +import javax.persistence.Query; import javax.persistence.TypedQuery; -import org.hibernate.type.StandardBasicTypes; import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.Group; @@ -1168,23 +1168,23 @@ public class RepositoryManager extends BasicManager { } public int countGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params) { - DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(params, false, true); - Number count = (Number)dbQuery.uniqueResult(); + Query dbQuery = createGenericANDQueryWithRolesRestriction(params, false, true); + Number count = (Number)dbQuery.getSingleResult(); return count.intValue(); } public List<RepositoryEntry> genericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, int firstResult, int maxResults, boolean orderBy) { - DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(params, orderBy, false); + Query dbQuery = createGenericANDQueryWithRolesRestriction(params, orderBy, false); dbQuery.setFirstResult(firstResult); if(maxResults > 0) { dbQuery.setMaxResults(maxResults); } - List<RepositoryEntry> res = dbQuery.list(); + List<RepositoryEntry> res = dbQuery.getResultList(); return res; } - private DBQuery createGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, boolean orderBy, boolean count) { + private Query createGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, boolean orderBy, boolean count) { String displayName = params.getDisplayName(); String author = params.getAuthor(); String desc = params.getDesc(); @@ -1241,20 +1241,20 @@ public class RepositoryManager extends BasicManager { .append(")))"); } else if (params.isOnlyOwnedResources()) { - query.append(" where v.access>0 and exists (select rel from repoentrytogroup as rel, bgroup as baseGroup, bgroupmember as membership ") + query.append(" where (v.access>0 and exists (select rel from repoentrytogroup as rel, bgroup as baseGroup, bgroupmember as membership ") .append(" where rel.entry=v and rel.group=baseGroup and membership.group=baseGroup") .append(" and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'") - .append(" )"); + .append(" ))"); setIdentity = true; } else if (params.isOnlyExplicitMember()) { - query.append(" where v.access>=").append(RepositoryEntry.ACC_USERS) + query.append(" where (v.access>=").append(RepositoryEntry.ACC_USERS) .append(" or (") .append(" v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true") .append(" and exists (select rel from repoentrytogroup as rel, bgroup as baseGroup, bgroupmember as membership ") .append(" where rel.entry=v and rel.group=baseGroup and membership.group=baseGroup and membership.identity.key=:identityKey ") .append(" and membership.role in ('").append(GroupRoles.owner.name()).append("','").append(GroupRoles.coach.name()).append("','").append(GroupRoles.participant.name()).append("')") .append(" )") - .append(" )"); + .append(" ))"); setIdentity = true; } else { @@ -1333,8 +1333,8 @@ public class RepositoryManager extends BasicManager { if(!count && orderBy) { query.append(" order by v.displayname, v.key ASC"); } - - DBQuery dbQuery = dbInstance.createQuery(query.toString()); + + Query dbQuery = dbInstance.getCurrentEntityManager().createQuery(query.toString()); if(institut) { dbQuery.setParameter("institution", institution); } @@ -1351,10 +1351,10 @@ public class RepositoryManager extends BasicManager { dbQuery.setParameter("desc", desc); } if (var_resourcetypes) { - dbQuery.setParameterList("resourcetypes", resourceTypes, StandardBasicTypes.STRING); + dbQuery.setParameter("resourcetypes", resourceTypes); } if(params.getRepositoryEntryKeys() != null && !params.getRepositoryEntryKeys().isEmpty()) { - dbQuery.setParameterList("entryKeys", params.getRepositoryEntryKeys()); + dbQuery.setParameter("entryKeys", params.getRepositoryEntryKeys()); } if(StringHelper.containsNonWhitespace(params.getExternalId())) { dbQuery.setParameter("externalId", params.getExternalId()); diff --git a/src/main/java/org/olat/repository/controllers/ReferencableEntriesSearchController.java b/src/main/java/org/olat/repository/controllers/ReferencableEntriesSearchController.java index 4979f0e9ed0..ef7851879a4 100644 --- a/src/main/java/org/olat/repository/controllers/ReferencableEntriesSearchController.java +++ b/src/main/java/org/olat/repository/controllers/ReferencableEntriesSearchController.java @@ -32,6 +32,7 @@ import java.util.List; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.segmentedview.SegmentViewComponent; @@ -55,13 +56,14 @@ import org.olat.ims.qti.fileresource.SurveyFileResource; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.portfolio.EPTemplateMapResource; import org.olat.repository.RepositoryEntry; -import org.olat.repository.RepositoryManager; +import org.olat.repository.RepositoryService; import org.olat.repository.controllers.RepositorySearchController.Can; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.ui.RepositoryTableModel; import org.olat.repository.ui.author.CreateRepositoryEntryController; import org.olat.repository.ui.author.ImportRepositoryEntryController; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -91,7 +93,10 @@ public class ReferencableEntriesSearchController extends BasicController { private SegmentViewComponent segmentView; private Link myEntriesLink, allEntriesLink, searchEntriesLink, adminEntriesLink; - private Link createRessourceButton, importRessourceButton; + private Link importRessourceButton; + private Component createRessourceCmp; + private List<Link> createRessourceButtons; + private CreateRepositoryEntryController createController; private ImportRepositoryEntryController importController; private CloseableModalController cmc; @@ -104,10 +109,12 @@ public class ReferencableEntriesSearchController extends BasicController { private final Can canBe; private Object userObject; + + @Autowired + private RepositoryHandlerFactory repositoryHandlerFactory; public ReferencableEntriesSearchController(WindowControl wControl, UserRequest ureq, String limitType, String commandLabel) { - this(wControl, ureq, new String[]{limitType}, null, commandLabel, true, true, true, false, false, Can.referenceable); - setBasePackage(RepositoryManager.class); + this(wControl, ureq, new String[]{ limitType }, null, commandLabel, true, true, true, false, false, Can.referenceable); } public ReferencableEntriesSearchController(WindowControl wControl, UserRequest ureq, String[] limitTypes, String commandLabel) { @@ -129,7 +136,7 @@ public class ReferencableEntriesSearchController extends BasicController { this.canImport = canImport; this.canCreate = canCreate; this.limitTypes = limitTypes; - setBasePackage(RepositoryManager.class); + setBasePackage(RepositoryService.class); mainVC = createVelocityContainer("referencableSearch"); if(limitTypes != null && limitTypes.length == 1 && limitTypes[0] != null) { @@ -142,8 +149,21 @@ public class ReferencableEntriesSearchController extends BasicController { // do instantiate buttons if (canCreate && isCreateButtonVisible()) { - createRessourceButton = LinkFactory.createButtonSmall("cmd.create.ressource", mainVC, this); - createRessourceButton.setElementCssClass("o_sel_repo_popup_create_resource"); + if(limitTypes != null && limitTypes.length == 1) { + Link createButton = LinkFactory.createButtonSmall("cmd.create.ressource", mainVC, this); + createButton.setElementCssClass("o_sel_repo_popup_create_resource"); + RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(limitTypes[0]); + createButton.setUserObject(handler); + createRessourceCmp = createButton; + } else if(limitTypes != null && limitTypes.length > 1) { + Dropdown dropdown = new Dropdown("cmd.create.ressource", "cmd.create.ressource", false, getTranslator()); + for(String limitType:limitTypes) { + RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(limitType); + Link createLink = LinkFactory.createLink(handler.getSupportedType(), getTranslator(), this); + dropdown.addComponent(createLink); + } + createRessourceCmp = dropdown; + } } if (canImport && isImportButtonVisible()) { importRessourceButton = LinkFactory.createButtonSmall("cmd.import.ressource", mainVC, this); @@ -263,11 +283,7 @@ public class ReferencableEntriesSearchController extends BasicController { return selectedRepositoryEntries; } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Component source, Event event) { if(source == segmentView) { if(event instanceof SegmentViewEvent) { @@ -294,11 +310,10 @@ public class ReferencableEntriesSearchController extends BasicController { searchCtr.displayAdminSearchForm(); } } - } else if(source == createRessourceButton) { + } else if(source == createRessourceCmp || createRessourceButtons.contains(source)) { removeAsListenerAndDispose(createController); - String type = null; - RepositoryHandler handler = null; - createController = new CreateRepositoryEntryController(ureq, getWindowControl(), type, handler); + RepositoryHandler handler = (RepositoryHandler)((Link)source).getUserObject(); + createController = new CreateRepositoryEntryController(ureq, getWindowControl(), handler); listenTo(createController); removeAsListenerAndDispose(cmc); @@ -322,11 +337,7 @@ public class ReferencableEntriesSearchController extends BasicController { } } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ + @Override public void event(UserRequest ureq, Controller source, Event event) { String cmd = event.getCommand(); if (source == searchCtr) { diff --git a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java index e8d0ea0d436..b9c84435e51 100644 --- a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java +++ b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java @@ -50,7 +50,6 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.generic.dtabs.Activateable2; -import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.id.UserConstants; @@ -59,6 +58,7 @@ import org.olat.core.id.context.StateEntry; import org.olat.core.util.Util; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.RepositoryService; import org.olat.repository.model.SearchRepositoryEntryParameters; import org.olat.repository.ui.RepositoryTableModel; @@ -79,10 +79,9 @@ import org.olat.repository.ui.RepositoryTableModel; */ public class RepositorySearchController extends BasicController implements Activateable2 { - private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(RepositoryManager.class); + private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(RepositorySearchController.class); protected VelocityContainer vc; - protected Translator translator; protected RepositoryTableModel repoTableModel; protected SearchForm searchForm; protected TableController tableCtr; @@ -106,8 +105,7 @@ public class RepositorySearchController extends BasicController implements Activ */ public RepositorySearchController(String selectButtonLabel, UserRequest ureq, WindowControl myWControl, boolean withCancel, boolean enableDirectLaunch, boolean multiSelect) { - //fxdiff VCRP-10: repository search with type filter - super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale())); + super(ureq, myWControl, Util.createPackageTranslator(RepositoryService.class, ureq.getLocale())); init(selectButtonLabel, ureq, withCancel, enableDirectLaunch, multiSelect, new String[]{}, null); } @@ -127,8 +125,7 @@ public class RepositorySearchController extends BasicController implements Activ public RepositorySearchController(String selectButtonLabel, UserRequest ureq, WindowControl myWControl, boolean withCancel, boolean enableDirectLaunch, boolean multiSelect, String[] limitTypes, RepositoryEntryFilter filter) { - //fxdiff VCRP-10: repository search with type filter - super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale())); + super(ureq, myWControl, Util.createPackageTranslator(RepositoryService.class, ureq.getLocale())); init(selectButtonLabel, ureq, withCancel, enableDirectLaunch, multiSelect, limitTypes, filter); } @@ -136,18 +133,16 @@ public class RepositorySearchController extends BasicController implements Activ * @param myWControl */ public RepositorySearchController(UserRequest ureq, WindowControl myWControl) { - //fxdiff VCRP-10: repository search with type filter - super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale())); + super(ureq, myWControl, Util.createPackageTranslator(RepositoryService.class, ureq.getLocale())); } private void init(String selectButtonLabel, UserRequest ureq, boolean withCancel, boolean enableDirectLaunch, boolean multiSelect, String[] limitTypes, RepositoryEntryFilter filter) { this.filter = filter; - translator = Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()); Roles roles = ureq.getUserSession().getRoles(); - vc = new VelocityContainer("reposearch", VELOCITY_ROOT + "/search.html", translator, this); + vc = new VelocityContainer("reposearch", VELOCITY_ROOT + "/search.html", getTranslator(), this); removeAsListenerAndDispose(searchForm); searchForm = new SearchForm(ureq, getWindowControl(), withCancel, roles.isOLATAdmin(), limitTypes); @@ -161,17 +156,16 @@ public class RepositorySearchController extends BasicController implements Activ tableConfig.setPreferencesOffered(true, "repositorySearchResult_v2"); } - //fxdiff VCRP-10: repository search with type filter - String filterTitle = translator.translate("search.filter.type"); - String noFilterOption = translator.translate("search.filter.showAll"); - tableCtr = new TableController(tableConfig, ureq, getWindowControl(), null, null, filterTitle, noFilterOption, true, translator); + String filterTitle = translate("search.filter.type"); + String noFilterOption = translate("search.filter.showAll"); + tableCtr = new TableController(tableConfig, ureq, getWindowControl(), null, null, filterTitle, noFilterOption, true, getTranslator()); if(multiSelect) { tableCtr.setMultiSelect(multiSelect); tableCtr.addLabeledMultiSelectAction(selectButtonLabel, "mselect"); } listenTo(tableCtr); - repoTableModel = new RepositoryTableModel(translator); + repoTableModel = new RepositoryTableModel(getTranslator()); ColumnDescriptor sortCol = repoTableModel.addColumnDescriptors(tableCtr, selectButtonLabel, enableDirectLaunch); tableCtr.setTableDataModel(repoTableModel); tableCtr.setSortColumn(sortCol, true); diff --git a/src/main/java/org/olat/repository/controllers/SearchForm.java b/src/main/java/org/olat/repository/controllers/SearchForm.java index d9e06e3b529..1eade49a472 100644 --- a/src/main/java/org/olat/repository/controllers/SearchForm.java +++ b/src/main/java/org/olat/repository/controllers/SearchForm.java @@ -47,6 +47,7 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.logging.AssertException; +import org.olat.core.util.Util; import org.olat.course.CourseModule; import org.olat.fileresource.types.AnimationFileResource; import org.olat.fileresource.types.BlogFileResource; @@ -68,6 +69,7 @@ import org.olat.ims.qti.fileresource.SurveyFileResource; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.portfolio.EPTemplateMapResource; import org.olat.repository.RepositoryModule; +import org.olat.repository.RepositoryService; /** * Initial Date: 08.07.2003 @@ -113,6 +115,12 @@ public class SearchForm extends FormBasicController{ } } + public SearchForm(UserRequest ureq, WindowControl wControl, boolean withCancel, boolean isAdmin, String[] limitTypes) { + this(ureq, wControl, withCancel, isAdmin); + this.limitTypes = limitTypes; + update(); + } + /** * Generic search form. * @param name Internal form name. @@ -121,18 +129,15 @@ public class SearchForm extends FormBasicController{ * @param isAdmin Is calling identity an administrator? If yes, allow search by ID * @param limitTypes Limit searches to specific types. */ - public SearchForm(UserRequest ureq, WindowControl wControl, boolean withCancel, boolean isAdmin) { + private SearchForm(UserRequest ureq, WindowControl wControl, boolean withCancel, boolean isAdmin) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator())); + this.withCancel = withCancel; this.isAdmin = isAdmin; managedEnabled = CoreSpringFactory.getImpl(RepositoryModule.class).isManagedRepositoryEntries(); initForm(ureq); } - public SearchForm(UserRequest ureq, WindowControl wControl, boolean withCancel, boolean isAdmin, String[] limitTypes) { - this(ureq, wControl, withCancel, isAdmin); - this.limitTypes = limitTypes; - update(); - } @Override protected boolean validateFormLogic(UserRequest ureq) { @@ -148,7 +153,9 @@ public class SearchForm extends FormBasicController{ /** * @return Is ID field available? */ - public boolean hasId() { return (id != null && !id.isEmpty()); } + public boolean hasId() { + return (id != null && !id.isEmpty()); + } /** * @return Return value of ID field. @@ -182,7 +189,7 @@ public class SearchForm extends FormBasicController{ } /** - * @return Descritpion field value. + * @return Description field value. */ public String getDescription() { return description.getValue(); diff --git a/src/main/java/org/olat/repository/controllers/_content/results.html b/src/main/java/org/olat/repository/controllers/_content/results.html new file mode 100644 index 00000000000..776fa38221e --- /dev/null +++ b/src/main/java/org/olat/repository/controllers/_content/results.html @@ -0,0 +1,24 @@ +#if ($withBack) + $r.render("backLink") + <br /> + <br /> +#end +#if ($isGuest) + <div class="b_warning" >${r.translate("filtered.first")}${r.render("repo.login")}${r.translate("filtered.second")}</div> +#end +$r.render("repotable") +#if ($hasResults) + <div class="b_xsmall">$r.translate("table.header.access.desc")</div> + #if ($withCancel) + <p> + $r.render("cancel") + <p> + #end +#else + <br /> + #if ($withCancel) + <p> + $r.render("cancel") + <p> + #end +#end diff --git a/src/main/java/org/olat/repository/_content/search.html b/src/main/java/org/olat/repository/controllers/_content/search.html similarity index 100% rename from src/main/java/org/olat/repository/_content/search.html rename to src/main/java/org/olat/repository/controllers/_content/search.html diff --git a/src/main/java/org/olat/repository/handlers/BlogHandler.java b/src/main/java/org/olat/repository/handlers/BlogHandler.java index 7b5a3a37003..b0ee44eda83 100644 --- a/src/main/java/org/olat/repository/handlers/BlogHandler.java +++ b/src/main/java/org/olat/repository/handlers/BlogHandler.java @@ -20,8 +20,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -74,8 +72,6 @@ import org.olat.resource.references.ReferenceManager; // Loads of parameters are unused public class BlogHandler implements RepositoryHandler { - private static final List<String> supportedTypes = Collections.singletonList(BlogFileResource.TYPE_NAME); - @Override public boolean isCreate() { return true; @@ -200,8 +196,8 @@ public class BlogHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return BlogFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/CourseHandler.java b/src/main/java/org/olat/repository/handlers/CourseHandler.java index 6a578c39cbe..e2aee84ad9a 100644 --- a/src/main/java/org/olat/repository/handlers/CourseHandler.java +++ b/src/main/java/org/olat/repository/handlers/CourseHandler.java @@ -33,8 +33,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.UUID; @@ -132,8 +130,6 @@ public class CourseHandler implements RepositoryHandler { public static final String EDITOR_XML = "editortreemodel.xml"; private static final OLog log = Tracing.createLoggerFor(CourseHandler.class); - - private static final List<String> supportedTypes = Collections.singletonList(CourseModule.getCourseTypeName()); @Override public boolean isCreate() { @@ -445,8 +441,8 @@ public class CourseHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return CourseModule.getCourseTypeName(); } @Override diff --git a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java index 80e5f9f3c72..a88f97e7d3a 100644 --- a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java +++ b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java @@ -26,8 +26,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Properties; @@ -82,7 +80,6 @@ import org.olat.resource.references.ReferenceManager; */ public class GlossaryHandler implements RepositoryHandler { - private static final List<String> supportedTypes = Collections.singletonList(GlossaryResource.TYPE_NAME); public static final String PROCESS_CREATENEW = "cn"; public static final String PROCESS_UPLOAD = "pu"; @@ -154,8 +151,8 @@ public class GlossaryHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return GlossaryResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java index 282f9440f8f..45b0fb268c6 100644 --- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java +++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java @@ -26,8 +26,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.admin.quota.QuotaConstants; @@ -90,11 +88,6 @@ public class ImsCPHandler extends FileHandler { private static final OLog log = Tracing.createLoggerFor(ImsCPHandler.class); - public static final String PROCESS_CREATENEW = "new"; - public static final String PROCESS_IMPORT = "add"; - - private static final List<String> supportedTypes = Collections.singletonList(ImsCPFileResource.TYPE_NAME); - @Override public boolean isCreate() { return true; @@ -204,8 +197,8 @@ public class ImsCPHandler extends FileHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return ImsCPFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/PodcastHandler.java b/src/main/java/org/olat/repository/handlers/PodcastHandler.java index ad7026d1e6a..58d04ea109d 100644 --- a/src/main/java/org/olat/repository/handlers/PodcastHandler.java +++ b/src/main/java/org/olat/repository/handlers/PodcastHandler.java @@ -20,8 +20,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -73,10 +71,6 @@ import org.olat.resource.references.ReferenceManager; */ // Loads of parameters are unused public class PodcastHandler implements RepositoryHandler { - public static final String PROCESS_CREATENEW = "create_new"; - public static final String PROCESS_UPLOAD = "upload"; - - private static final List<String> supportedTypes = Collections.singletonList(PodcastFileResource.TYPE_NAME); @Override public boolean isCreate() { @@ -200,8 +194,8 @@ public class PodcastHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return PodcastFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java index 1602daf15ae..ef3b9cf2493 100644 --- a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java +++ b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java @@ -22,8 +22,6 @@ package org.olat.repository.handlers; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -84,11 +82,6 @@ import de.bps.onyx.plugin.StreamMediaResource; public class PortfolioHandler implements RepositoryHandler { private static final OLog log = Tracing.createLoggerFor(PortfolioHandler.class); - public static final String PROCESS_CREATENEW = "create_new"; - public static final String PROCESS_UPLOAD = "upload"; - - private static final List<String> supportedTypes = Collections.singletonList(EPTemplateMapResource.TYPE_NAME); - @Override public boolean isCreate() { return true; @@ -133,7 +126,16 @@ public class PortfolioHandler implements RepositoryHandler { @Override public RepositoryEntry importResource(Identity initialAuthor, String displayname, String description, boolean withReferences, Locale locale, File file, String filename) { - return null; + EPFrontendManager ePFMgr = CoreSpringFactory.getImpl(EPFrontendManager.class); + EPStructureManager eSTMgr = CoreSpringFactory.getImpl(EPStructureManager.class); + + PortfolioStructure structure = EPXStreamHandler.getAsObject(file, false); + OLATResource resource = eSTMgr.createPortfolioMapTemplateResource(); + RepositoryEntry re = CoreSpringFactory.getImpl(RepositoryService.class) + .create(initialAuthor, "", displayname, description, resource, RepositoryEntry.ACC_OWNERS); + + ePFMgr.importPortfolioMapTemplate(structure, resource); + return re; } @Override @@ -243,7 +245,7 @@ public class PortfolioHandler implements RepositoryHandler { @Override public MainLayoutController createLaunchController(RepositoryEntry re, UserRequest ureq, WindowControl wControl) { - EPFrontendManager ePFMgr = (EPFrontendManager) CoreSpringFactory.getBean("epFrontendManager"); + EPFrontendManager ePFMgr = CoreSpringFactory.getImpl(EPFrontendManager.class); PortfolioStructureMap map = (PortfolioStructureMap)ePFMgr.loadPortfolioStructure(re.getOlatResource()); EPSecurityCallback secCallback = EPSecurityCallbackFactory.getSecurityCallback(ureq, map, ePFMgr); Controller epCtr = EPUIFactory.createPortfolioStructureMapController(ureq, wControl, map, secCallback); @@ -252,14 +254,12 @@ public class PortfolioHandler implements RepositoryHandler { layoutCtr.addActivateableDelegate((Activateable2)epCtr); } layoutCtr.addDisposableChildController(epCtr); - //fxdiff VCRP-1: access control of learn resources - RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, re, layoutCtr); - return wrapper; + return new RepositoryMainAccessControllerWrapper(ureq, wControl, re, layoutCtr); } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return EPTemplateMapResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java index 7a30061a5cd..8676234caaf 100644 --- a/src/main/java/org/olat/repository/handlers/RepositoryHandler.java +++ b/src/main/java/org/olat/repository/handlers/RepositoryHandler.java @@ -26,7 +26,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.List; import java.util.Locale; import org.olat.core.gui.UserRequest; @@ -58,7 +57,7 @@ public interface RepositoryHandler { /** * @return Return the typeNames of OLATResourceable this Handler can handle. */ - public List<String> getSupportedTypes(); + public String getSupportedType(); /** * This resource support creation within OpenOLAT. diff --git a/src/main/java/org/olat/repository/handlers/RepositoryHandlerFactory.java b/src/main/java/org/olat/repository/handlers/RepositoryHandlerFactory.java index 95773cdb594..6f91ecc6abc 100644 --- a/src/main/java/org/olat/repository/handlers/RepositoryHandlerFactory.java +++ b/src/main/java/org/olat/repository/handlers/RepositoryHandlerFactory.java @@ -32,6 +32,15 @@ import java.util.Set; import org.olat.core.CoreSpringFactory; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.AssertException; +import org.olat.fileresource.types.AnimationFileResource; +import org.olat.fileresource.types.DocFileResource; +import org.olat.fileresource.types.FileResource; +import org.olat.fileresource.types.ImageFileResource; +import org.olat.fileresource.types.MovieFileResource; +import org.olat.fileresource.types.PdfFileResource; +import org.olat.fileresource.types.PowerpointFileResource; +import org.olat.fileresource.types.SoundFileResource; +import org.olat.fileresource.types.XlsFileResource; import org.olat.repository.RepositoryEntry; import org.springframework.stereotype.Service; @@ -50,7 +59,6 @@ public class RepositoryHandlerFactory { static { handlerMap = new HashMap<String, RepositoryHandler>(21); - registerHandler(new WebDocumentHandler()); registerHandler(new ImsCPHandler()); registerHandler(new SCORMCPHandler()); registerHandler(new CourseHandler()); @@ -60,12 +68,20 @@ public class RepositoryHandlerFactory { registerHandler(new BlogHandler()); registerHandler(new GlossaryHandler()); registerHandler(new PortfolioHandler()); + + registerHandler(new WebDocumentHandler(FileResource.GENERIC_TYPE_NAME)); + registerHandler(new WebDocumentHandler(DocFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(XlsFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(PowerpointFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(PdfFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(SoundFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(MovieFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(AnimationFileResource.TYPE_NAME)); + registerHandler(new WebDocumentHandler(ImageFileResource.TYPE_NAME)); } public static void registerHandler(RepositoryHandler handler) { - for (String type : handler.getSupportedTypes()) { - handlerMap.put(type, handler); - } + handlerMap.put(handler.getSupportedType(), handler); } public static RepositoryHandlerFactory getInstance() { diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java index ecbf68b3fa2..425940dd16e 100644 --- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java +++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java @@ -26,8 +26,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -70,12 +68,6 @@ import org.olat.util.logging.activity.LoggingResourceable; * */ public class SCORMCPHandler extends FileHandler { - - private static final List<String> supportedTypes = Collections.singletonList(ScormCPFileResource.TYPE_NAME); - - public SCORMCPHandler() { - // - } @Override public boolean isCreate() { @@ -166,8 +158,8 @@ public class SCORMCPHandler extends FileHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return ScormCPFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java index 28978aa7ee8..29ae4255ea7 100644 --- a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java +++ b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java @@ -26,8 +26,6 @@ package org.olat.repository.handlers; import java.io.File; -import java.util.Collections; -import java.util.List; import java.util.Locale; import org.olat.basesecurity.GroupRoles; @@ -77,13 +75,6 @@ import org.olat.resource.references.ReferenceManager; * @author gnaegi */ public class SharedFolderHandler implements RepositoryHandler { - - private static final List<String> supportedTypes = Collections.singletonList(SharedFolderFileResource.TYPE_NAME); - - /** - * Comment for <code>PROCESS_CREATENEW</code> - */ - public static final String PROCESS_CREATENEW = "cn"; @Override public boolean isCreate() { @@ -139,8 +130,8 @@ public class SharedFolderHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return SharedFolderFileResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java index 9d515bcd313..c3e2ba9dccd 100644 --- a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java +++ b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java @@ -29,8 +29,6 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import org.olat.core.CoreSpringFactory; @@ -78,18 +76,10 @@ import org.olat.resource.OLATResourceManager; public class WebDocumentHandler extends FileHandler { private static final OLog log = Tracing.createLoggerFor(WebDocumentHandler.class); - private static final List<String> supportedTypes; - static { // initialize supported types - supportedTypes = new ArrayList<String>(10); - supportedTypes.add(FileResource.GENERIC_TYPE_NAME); - supportedTypes.add(DocFileResource.TYPE_NAME); - supportedTypes.add(XlsFileResource.TYPE_NAME); - supportedTypes.add(PowerpointFileResource.TYPE_NAME); - supportedTypes.add(PdfFileResource.TYPE_NAME); - supportedTypes.add(SoundFileResource.TYPE_NAME); - supportedTypes.add(MovieFileResource.TYPE_NAME); - supportedTypes.add(AnimationFileResource.TYPE_NAME); - supportedTypes.add(ImageFileResource.TYPE_NAME); + private final String supportedType; + + public WebDocumentHandler(String type) { + supportedType = type; } @Override @@ -121,21 +111,21 @@ public class WebDocumentHandler extends FileHandler { ResourceEvaluation eval = new ResourceEvaluation(false); String extension = FileUtils.getFileSuffix(filename); if(StringHelper.containsNonWhitespace(extension)) { - if (DocFileResource.validate(filename)) { + if (DocFileResource.TYPE_NAME.equals(supportedType) && DocFileResource.validate(filename)) { eval.setValid(true); - } else if (XlsFileResource.validate(filename)) { + } else if (XlsFileResource.TYPE_NAME.equals(supportedType) && XlsFileResource.validate(filename)) { eval.setValid(true); - } else if (PowerpointFileResource.validate(filename)) { + } else if (PowerpointFileResource.TYPE_NAME.equals(supportedType) && PowerpointFileResource.validate(filename)) { eval.setValid(true); - } else if (PdfFileResource.validate(filename)) { + } else if (PdfFileResource.TYPE_NAME.equals(supportedType) && PdfFileResource.validate(filename)) { eval.setValid(true); - } else if (ImageFileResource.validate(filename)) { + } else if (ImageFileResource.TYPE_NAME.equals(supportedType) && ImageFileResource.validate(filename)) { eval.setValid(true); - } else if (MovieFileResource.validate(filename)) { + } else if (MovieFileResource.TYPE_NAME.equals(supportedType) && MovieFileResource.validate(filename)) { eval.setValid(true); - } else if (SoundFileResource.validate(filename)) { + } else if (SoundFileResource.TYPE_NAME.equals(supportedType) && SoundFileResource.validate(filename)) { eval.setValid(true); - } else if (AnimationFileResource.validate(filename)) { + } else if (AnimationFileResource.TYPE_NAME.equals(supportedType) && AnimationFileResource.validate(filename)) { eval.setValid(true); } } @@ -147,21 +137,21 @@ public class WebDocumentHandler extends FileHandler { Locale locale, File file, String filename) { FileResource ores; - if (DocFileResource.validate(filename)) { + if (DocFileResource.TYPE_NAME.equals(supportedType) && DocFileResource.validate(filename)) { ores = new DocFileResource(); - } else if (XlsFileResource.validate(filename)) { + } else if (XlsFileResource.TYPE_NAME.equals(supportedType) && XlsFileResource.validate(filename)) { ores = new XlsFileResource(); - } else if (PowerpointFileResource.validate(filename)) { + } else if (PowerpointFileResource.TYPE_NAME.equals(supportedType) && PowerpointFileResource.validate(filename)) { ores = new PowerpointFileResource(); - } else if (PdfFileResource.validate(filename)) { + } else if (PdfFileResource.TYPE_NAME.equals(supportedType) && PdfFileResource.validate(filename)) { ores = new PdfFileResource(); - } else if (ImageFileResource.validate(filename)) { + } else if (ImageFileResource.TYPE_NAME.equals(supportedType) && ImageFileResource.validate(filename)) { ores = new ImageFileResource(); - } else if (MovieFileResource.validate(filename)) { + } else if (MovieFileResource.TYPE_NAME.equals(supportedType) && MovieFileResource.validate(filename)) { ores = new MovieFileResource(); - } else if (SoundFileResource.validate(filename)) { + } else if (SoundFileResource.TYPE_NAME.equals(supportedType) && SoundFileResource.validate(filename)) { ores = new SoundFileResource(); - } else if (AnimationFileResource.validate(filename)) { + } else if (AnimationFileResource.TYPE_NAME.equals(supportedType) && AnimationFileResource.validate(filename)) { ores = new AnimationFileResource(); } else { return null; @@ -200,8 +190,8 @@ public class WebDocumentHandler extends FileHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return supportedType; } @Override diff --git a/src/main/java/org/olat/repository/handlers/WikiHandler.java b/src/main/java/org/olat/repository/handlers/WikiHandler.java index 83cd35fa202..a510ac66ca1 100644 --- a/src/main/java/org/olat/repository/handlers/WikiHandler.java +++ b/src/main/java/org/olat/repository/handlers/WikiHandler.java @@ -29,7 +29,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; import java.util.List; import java.util.Locale; @@ -98,14 +97,7 @@ import org.olat.resource.references.ReferenceManager; public class WikiHandler implements RepositoryHandler { private static final OLog log = Tracing.createLoggerFor(WikiHandler.class); - private static final List<String> supportedTypes = Collections.singletonList(WikiResource.TYPE_NAME); - /** - * Comment for <code>PROCESS_CREATENEW</code> - */ - public static final String PROCESS_CREATENEW = "cn"; - public static final String PROCESS_UPLOAD = "pu"; - @Override public boolean isCreate() { return true; @@ -203,8 +195,8 @@ public class WikiHandler implements RepositoryHandler { } @Override - public List<String> getSupportedTypes() { - return supportedTypes; + public String getSupportedType() { + return WikiResource.TYPE_NAME; } @Override diff --git a/src/main/java/org/olat/repository/handlers/package.html b/src/main/java/org/olat/repository/handlers/package.html deleted file mode 100644 index 9475ca9fd75..00000000000 --- a/src/main/java/org/olat/repository/handlers/package.html +++ /dev/null @@ -1,4 +0,0 @@ -<html><body> -<h3>Repository handlers</h3> -<p></p> -</body></html> diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java index 317b21c6f23..5459cc0992a 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java @@ -139,6 +139,12 @@ public class RepositoryEntryStatisticsDAO implements UserRatingsDelegate, UserCo } private RepositoryEntryStatistics loadStatisticsForUpdate(OLATResourceable repositoryEntryRes) { + if(repositoryEntryRes instanceof RepositoryEntry) { + RepositoryEntry re = (RepositoryEntry)repositoryEntryRes; + dbInstance.getCurrentEntityManager().detach(re); + dbInstance.getCurrentEntityManager().detach(re.getStatistics()); + } + StringBuilder sb = new StringBuilder(); sb.append("select stats from ").append(RepositoryEntryStatistics.class.getName()).append(" as stats") .append(" where stats.key in (select v.statistics.key from ").append(RepositoryEntry.class.getName()).append(" as v where v.key=:key)"); diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryAccessColumnDescriptor.java b/src/main/java/org/olat/repository/ui/RepositoryEntryAccessColumnDescriptor.java index 7c59346826d..5214df3b0c1 100644 --- a/src/main/java/org/olat/repository/ui/RepositoryEntryAccessColumnDescriptor.java +++ b/src/main/java/org/olat/repository/ui/RepositoryEntryAccessColumnDescriptor.java @@ -49,7 +49,6 @@ public class RepositoryEntryAccessColumnDescriptor implements CustomCellRenderer public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) { if(val instanceof RepositoryEntry) { RepositoryEntry re = (RepositoryEntry)val; - //fxdiff VCRP-1,2: access control of resources if(re.isMembersOnly()) { sb.append(translator.translate("table.header.access.membersonly")); } else { @@ -70,8 +69,7 @@ public class RepositoryEntryAccessColumnDescriptor implements CustomCellRenderer sb.append(translator.translate("table.header.access.guest")); } break; - } - default: + } default: // OLAT-6272 in case of broken repo entries with no access code // return error instead of nothing sb.append("ERROR"); diff --git a/src/main/java/org/olat/repository/ui/author/AuthorListController.java b/src/main/java/org/olat/repository/ui/author/AuthorListController.java index ece913a71d1..b2a4377a342 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthorListController.java +++ b/src/main/java/org/olat/repository/ui/author/AuthorListController.java @@ -62,6 +62,7 @@ import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; @@ -134,7 +135,7 @@ public class AuthorListController extends FormBasicController implements Activat for(String type:types) { RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type); if(handler != null && handler.isCreate()) { - addCreateLink(type, createDropdown); + addCreateLink(handler, createDropdown); } } @@ -154,9 +155,9 @@ public class AuthorListController extends FormBasicController implements Activat return super.getTranslator(); } - private void addCreateLink(String type, Dropdown dropdown) { - Link createLink = LinkFactory.createLink(type, getTranslator(), this); - createLink.setUserObject(type); + private void addCreateLink(RepositoryHandler handler, Dropdown dropdown) { + Link createLink = LinkFactory.createLink(handler.getSupportedType(), getTranslator(), this); + createLink.setUserObject(handler); dropdown.addComponent(createLink); } @@ -249,10 +250,9 @@ public class AuthorListController extends FormBasicController implements Activat if(importLink == source) { doImport(ureq); } else if(source instanceof Link && ((Link)source).getUserObject() instanceof String) { - String type = (String)((Link)source).getUserObject(); - RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type); + RepositoryHandler handler = (RepositoryHandler)((Link)source).getUserObject(); if(handler != null) { - doCreate(ureq, type, handler); + doCreate(ureq, handler); } } super.event(ureq, source, event); @@ -265,7 +265,7 @@ public class AuthorListController extends FormBasicController implements Activat } else if(createCtrl == source) { cmc.deactivate(); if(Event.DONE_EVENT.equals(event)) { - doOpenDetails(ureq, createCtrl.getAddedEntry()); + doOpenDetailsSettings(ureq, createCtrl.getAddedEntry()); cleanUp(); } else if(CreateRepositoryEntryController.CREATION_WIZARD.equals(event)) { doPostCreateWizard(ureq, createCtrl.getAddedEntry(), createCtrl.getHandler()); @@ -275,7 +275,7 @@ public class AuthorListController extends FormBasicController implements Activat } else if(importCtrl == source) { cmc.deactivate(); if(Event.DONE_EVENT.equals(event)) { - doOpenDetails(ureq, importCtrl.getImportedEntry()); + doOpenDetailsSettings(ureq, importCtrl.getImportedEntry()); cleanUp(); } else { cleanUp(); @@ -285,7 +285,7 @@ public class AuthorListController extends FormBasicController implements Activat getWindowControl().pop(); RepositoryEntry newEntry = (RepositoryEntry)wizardCtrl.getRunContext().get("authoringNewEntry"); cleanUp(); - doOpenDetails(ureq, newEntry); + doOpenDetailsSettings(ureq, newEntry); } } else if(searchCtrl == source) { if(event instanceof SearchEvent) { @@ -400,6 +400,18 @@ public class AuthorListController extends FormBasicController implements Activat return detailsCtrl; } + private AuthoringEntryDetailsController doOpenDetailsSettings(UserRequest ureq, RepositoryEntryRef entry) { + RepositoryEntryAuthorView view = repositoryService.loadAuthorView(getIdentity(), entry); + String fullnameAuthor = ""; + AuthoringEntryRow row = new AuthoringEntryRow(view, fullnameAuthor); + detailsCtrl = doOpenDetails(ureq, row); + + ContextEntry editEntry = BusinessControlFactory.getInstance().createContextEntry(AuthoringEntryDetailsController.EDIT_SETTINGS_ORES); + List<ContextEntry> entries = Collections.singletonList(editEntry); + detailsCtrl.activate(ureq, entries, null); + return detailsCtrl; + } + private void doImport(UserRequest ureq) { if(importCtrl != null) return; @@ -415,11 +427,11 @@ public class AuthorListController extends FormBasicController implements Activat cmc.activate(); } - private void doCreate(UserRequest ureq, String type, RepositoryHandler handler) { + private void doCreate(UserRequest ureq, RepositoryHandler handler) { if(createCtrl != null) return; removeAsListenerAndDispose(createCtrl); - createCtrl = new CreateRepositoryEntryController(ureq, getWindowControl(), type, handler); + createCtrl = new CreateRepositoryEntryController(ureq, getWindowControl(), handler); listenTo(createCtrl); removeAsListenerAndDispose(cmc); diff --git a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java index 5c192435914..1193684ecd5 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java +++ b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDataModel.java @@ -91,7 +91,7 @@ class AuthoringEntryDataModel extends DefaultFlexiTableDataSourceModel<Authoring displayName("cif.displayname"), author("table.header.author"), authors("table.header.author"), - access("table.header.author"), + access("table.header.access"), creationDate("table.header.date"), lastUsage("table.header.lastusage"), mark("table.header.mark"); diff --git a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDetailsController.java b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDetailsController.java index 77ea17e048e..0f4b5a5bb49 100644 --- a/src/main/java/org/olat/repository/ui/author/AuthoringEntryDetailsController.java +++ b/src/main/java/org/olat/repository/ui/author/AuthoringEntryDetailsController.java @@ -107,6 +107,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class AuthoringEntryDetailsController extends FormBasicController implements Activateable2 { + public static final OLATResourceable EDIT_SETTINGS_ORES = OresHelper.createOLATResourceableInstance("Settings", 0l); + private FormLink markLink, startLink; private Link editLink, launchLink, @@ -423,7 +425,13 @@ public class AuthoringEntryDetailsController extends FormBasicController impleme @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - // + if(entries == null || entries.isEmpty()) return; + + ContextEntry entry = entries.get(0); + String segment = entry.getOLATResourceable().getResourceableTypeName(); + if(EDIT_SETTINGS_ORES.getResourceableTypeName().equals(segment)) { + doEditSettings(ureq); + } } @Override diff --git a/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java b/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java index 163346a94ec..a503cac69e9 100644 --- a/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java +++ b/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java @@ -24,7 +24,6 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FormLink; -import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -56,18 +55,15 @@ public class CreateRepositoryEntryController extends FormBasicController { private FormLink wizardButton; private TextElement displaynameEl; - private RichTextElement descriptionEl; private RepositoryEntry addedEntry; - private final String type; private final RepositoryHandler handler; private Object userObject; - public CreateRepositoryEntryController(UserRequest ureq, WindowControl wControl, String type, RepositoryHandler handler) { + public CreateRepositoryEntryController(UserRequest ureq, WindowControl wControl, RepositoryHandler handler) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(RepositoryManager.class, getLocale(), getTranslator())); - this.type = type; this.handler = handler; initForm(ureq); } @@ -91,8 +87,8 @@ public class CreateRepositoryEntryController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { String typeName; - if (type != null) { - typeName = NewControllerFactory.translateResourceableTypeName(type, getLocale()); + if (handler != null) { + typeName = NewControllerFactory.translateResourceableTypeName(handler.getSupportedType(), getLocale()); } else { typeName = translate("cif.type.na"); } @@ -101,11 +97,6 @@ public class CreateRepositoryEntryController extends FormBasicController { displaynameEl = uifactory.addTextElement("cif.displayname", "cif.displayname", 100, "", formLayout); displaynameEl.setDisplaySize(30); displaynameEl.setMandatory(true); - - descriptionEl = uifactory.addRichTextElementForStringData("cif.description", "cif.description", - "", 10, -1, false, null, null, formLayout, ureq.getUserSession(), getWindowControl()); - descriptionEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); - descriptionEl.setMandatory(true); FormLayoutContainer buttonContainer = FormLayoutContainer.createButtonLayout("buttonContainer", getTranslator()); formLayout.add("buttonContainer", buttonContainer); @@ -137,14 +128,6 @@ public class CreateRepositoryEntryController extends FormBasicController { displaynameEl.clearError(); } - // Check for empty description - if (!StringHelper.containsNonWhitespace(descriptionEl.getValue())) { - descriptionEl.setErrorKey("cif.error.description.empty", new String[] {}); - allOk = false; - } else { - descriptionEl.clearError(); - } - return allOk & super.validateFormLogic(ureq); } @@ -173,9 +156,8 @@ public class CreateRepositoryEntryController extends FormBasicController { private void doCreate() { String displayname = displaynameEl.getValue(); - String description = descriptionEl.getValue(); - addedEntry = handler.createResource(getIdentity(), displayname, description, getLocale()); + addedEntry = handler.createResource(getIdentity(), displayname, "", getLocale()); ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CREATE, getClass(), LoggingResourceable.wrap(addedEntry, OlatResourceableType.genRepoEntry)); diff --git a/src/main/java/org/olat/repository/ui/author/ImportRepositoryEntryController.java b/src/main/java/org/olat/repository/ui/author/ImportRepositoryEntryController.java index 00303f913ee..298b40d69f0 100644 --- a/src/main/java/org/olat/repository/ui/author/ImportRepositoryEntryController.java +++ b/src/main/java/org/olat/repository/ui/author/ImportRepositoryEntryController.java @@ -27,7 +27,6 @@ import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; -import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.SpacerElement; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; @@ -46,7 +45,6 @@ import org.olat.core.util.Util; import org.olat.fileresource.types.ResourceEvaluation; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; -import org.olat.repository.controllers.EntryChangedEvent; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.util.logging.activity.LoggingResourceable; @@ -68,7 +66,6 @@ public class ImportRepositoryEntryController extends FormBasicController { private FileElement uploadFileEl; private StaticTextElement typeEl; private TextElement displaynameEl; - private RichTextElement descriptionEl; private MultipleSelectionElement referencesEl; private final static String[] refKeys = new String[]{ "checked" }; @@ -102,12 +99,6 @@ public class ImportRepositoryEntryController extends FormBasicController { String[] refValues = new String[]{ "" }; referencesEl = uifactory.addCheckboxesHorizontal("references", "references", formLayout, refKeys, refValues, null); referencesEl.setVisible(false); - - descriptionEl = uifactory.addRichTextElementForStringData("cif.description", "cif.description", - "", 10, -1, false, null, null, formLayout, ureq.getUserSession(), getWindowControl()); - descriptionEl.getEditorConfiguration().setFileBrowserUploadRelPath("media"); - descriptionEl.setMandatory(true); - descriptionEl.setVisible(false); FormLayoutContainer buttonContainer = FormLayoutContainer.createButtonLayout("buttonContainer", getTranslator()); formLayout.add("buttonContainer", buttonContainer); @@ -144,7 +135,6 @@ public class ImportRepositoryEntryController extends FormBasicController { if(handlerForUploadedResource != null) { doImport(); fireEvent(ureq, Event.DONE_EVENT); - fireEvent(ureq, new EntryChangedEvent(importedEntry, EntryChangedEvent.ADDED)); } } @@ -165,14 +155,6 @@ public class ImportRepositoryEntryController extends FormBasicController { } else { displaynameEl.clearError(); } - - // Check for empty description - if (!StringHelper.containsNonWhitespace(descriptionEl.getValue())) { - descriptionEl.setErrorKey("cif.error.description.empty", new String[] {}); - allOk = false; - } else { - descriptionEl.clearError(); - } return allOk & handlerForUploadedResource != null & super.validateFormLogic(ureq); } @@ -181,12 +163,11 @@ public class ImportRepositoryEntryController extends FormBasicController { if(handlerForUploadedResource == null) return; String displayname = displaynameEl.getValue(); - String description = descriptionEl.getValue(); File uploadedFile = uploadFileEl.getUploadFile(); String uploadedFilename = uploadFileEl.getUploadFileName(); boolean withReferences = referencesEl.isAtLeastSelected(1); - importedEntry = handlerForUploadedResource.importResource(getIdentity(), displayname, description, + importedEntry = handlerForUploadedResource.importResource(getIdentity(), displayname, "", withReferences, getLocale(), uploadedFile, uploadedFilename); ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CREATE, getClass(), @@ -201,17 +182,17 @@ public class ImportRepositoryEntryController extends FormBasicController { RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type); ResourceEvaluation eval = handler.acceptImport(uploadedFile, uploadedFilename); if(eval != null && eval.isValid()) { - updateResourceInfos(eval, type, handler); + updateResourceInfos(eval, handler); break; } } } - private void updateResourceInfos(ResourceEvaluation eval, String type, RepositoryHandler handler) { + private void updateResourceInfos(ResourceEvaluation eval, RepositoryHandler handler) { handlerForUploadedResource = handler; typeEl.setVisible(true); - if (type != null) { // add image and typename code - String tName = NewControllerFactory.translateResourceableTypeName(type, getLocale()); + if (handler != null) { // add image and typename code + String tName = NewControllerFactory.translateResourceableTypeName(handler.getSupportedType(), getLocale()); typeEl.setValue(tName); } else { typeEl.setValue(translate("cif.type.na")); @@ -222,8 +203,6 @@ public class ImportRepositoryEntryController extends FormBasicController { if(eval.isReferences()) { referencesEl.select(refKeys[0], true); } - descriptionEl.setVisible(true); - descriptionEl.setValue(eval.getDescription()); importButton.setEnabled(handler != null); } } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/ui/author/PropPupForm.java b/src/main/java/org/olat/repository/ui/author/PropPupForm.java index 70e279448df..513063cb947 100644 --- a/src/main/java/org/olat/repository/ui/author/PropPupForm.java +++ b/src/main/java/org/olat/repository/ui/author/PropPupForm.java @@ -38,12 +38,14 @@ import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.Util; import org.olat.fileresource.types.ScormCPFileResource; import org.olat.ims.qti.fileresource.SurveyFileResource; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.login.LoginModule; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; +import org.olat.repository.RepositoryService; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; @@ -76,6 +78,7 @@ public class PropPupForm extends FormBasicController { */ public PropPupForm(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) { super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator())); this.entry = entry; String typeName = entry.getOlatResource().getResourceableTypeName(); diff --git a/src/main/java/org/olat/repository/ui/author/RepositoryEditDescriptionController.java b/src/main/java/org/olat/repository/ui/author/RepositoryEditDescriptionController.java index 21285047c09..d6ed91a4e81 100644 --- a/src/main/java/org/olat/repository/ui/author/RepositoryEditDescriptionController.java +++ b/src/main/java/org/olat/repository/ui/author/RepositoryEditDescriptionController.java @@ -378,9 +378,7 @@ public class RepositoryEditDescriptionController extends FormBasicController { flc.setDirty(true); } } else if (source == deleteImage) { - VFSLeaf img = repositoryManager.getImage(repositoryEntry); - if(fileUpload.getUploadFile() != null) { fileUpload.reset(); diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java index e1618ff233e..b9dd93279fb 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java @@ -26,7 +26,6 @@ import java.util.Date; import java.util.List; import java.util.Map; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; @@ -52,6 +51,7 @@ import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.Offer; import org.olat.resource.accesscontrol.model.OfferAccess; import org.olat.resource.accesscontrol.model.OfferImpl; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -67,8 +67,6 @@ public class AccessConfigurationController extends FormBasicController { private List<FormLink> addMethods = new ArrayList<FormLink>(); private final String displayName; private final OLATResource resource; - private final AccessControlModule acModule; - private final ACService acService; private CloseableModalController cmc; private FormLayoutContainer confControllerContainer; @@ -81,6 +79,11 @@ public class AccessConfigurationController extends FormBasicController { private boolean allowPaymentMethod; private final boolean editable; + @Autowired + private ACService acService; + @Autowired + private AccessControlModule acModule; + public AccessConfigurationController(UserRequest ureq, WindowControl wControl, OLATResource resource, String displayName, boolean allowPaymentMethod, boolean editable) { super(ureq, wControl, "access_configuration"); @@ -88,8 +91,6 @@ public class AccessConfigurationController extends FormBasicController { this.resource = resource; this.displayName = displayName; this.allowPaymentMethod = allowPaymentMethod; - acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule"); - acService = CoreSpringFactory.getImpl(ACService.class); embbed = false; this.editable = editable; emptyConfigGrantsFullAccess = true; @@ -105,8 +106,6 @@ public class AccessConfigurationController extends FormBasicController { this.resource = resource; this.displayName = displayName; this.allowPaymentMethod = allowPaymentMethod; - acModule = CoreSpringFactory.getImpl(AccessControlModule.class); - acService = CoreSpringFactory.getImpl(ACService.class); embbed = true; emptyConfigGrantsFullAccess = false; @@ -116,10 +115,6 @@ public class AccessConfigurationController extends FormBasicController { public int getNumOfBookingConfigurations() { return confControllers.size(); } - - public FormItem getInitialFormItem() { - return flc; - } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { @@ -134,7 +129,7 @@ public class AccessConfigurationController extends FormBasicController { String title = handler.getMethodName(getLocale()); FormLink add = uifactory.addFormLink("create." + handler.getType(), title, null, formLayout, Link.LINK | Link.NONTRANSLATED); add.setUserObject(method); - add.setIconLeftCSS((method.getMethodCssClass() + "_icon").intern()); + add.setIconLeftCSS( ("o_icon " + method.getMethodCssClass() + "_icon o_icon-lg").intern()); addMethods.add(add); formLayout.add(add.getName(), add); } diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java index 35b41e2f156..9960690469f 100644 --- a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java +++ b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java @@ -342,7 +342,9 @@ public class RepositoryEntriesResource { RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); OLATResource ores = OLATResourceManager.getInstance().findOrPersistResourceable(newResource); RepositoryEntry addedEntry = repositoryService.create(identity, resourcename, displayname, null, ores, 0); - addedEntry.setSoftkey(softkey); + if(StringHelper.containsNonWhitespace(softkey)) { + addedEntry.setSoftkey(softkey); + } //TODO repository // Do set access for owner at the end, because unfinished course should be invisible diff --git a/src/main/java/org/olat/search/service/indexer/IndexWriterHolder.java b/src/main/java/org/olat/search/service/indexer/IndexWriterHolder.java index cecb97430f3..51b300b075a 100644 --- a/src/main/java/org/olat/search/service/indexer/IndexWriterHolder.java +++ b/src/main/java/org/olat/search/service/indexer/IndexWriterHolder.java @@ -82,12 +82,12 @@ public class IndexWriterHolder { int used = counter.decrementAndGet(); if(used == 0) { long start = System.currentTimeMillis(); - indexWriter.commit(); - indexWriter.close(); - writerRef = null; + //indexWriter.commit(); + //indexWriter.close(); + //writerRef = null; log.info("Close writer takes (ms): " + (System.currentTimeMillis() - start)); } - } catch (IOException e) { + } catch (Exception e) { log.error("", e); } } diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 922c672b572..746c65f4536 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -295,7 +295,7 @@ create table if not exists o_repositoryentry ( version mediumint unsigned not null, lastmodified datetime, creationdate datetime, - softkey varchar(30) not null unique, + softkey varchar(36) not null unique, external_id varchar(64), external_ref varchar(64), managed_flags varchar(255), diff --git a/src/test/java/org/olat/core/id/context/HistoryManagerTest.java b/src/test/java/org/olat/core/id/context/HistoryManagerTest.java index 5d2d09e2233..34580a65860 100644 --- a/src/test/java/org/olat/core/id/context/HistoryManagerTest.java +++ b/src/test/java/org/olat/core/id/context/HistoryManagerTest.java @@ -28,6 +28,7 @@ import java.net.URL; import junit.framework.Assert; +import org.junit.Ignore; import org.junit.Test; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -103,7 +104,7 @@ public class HistoryManagerTest extends OlatTestCase { * @throws IOException * @throws URISyntaxException */ - @Test + @Test @Ignore public void testRead_v83_repoMetadaElements() throws IOException, URISyntaxException { URL xmlUrl = HistoryManagerTest.class.getResource("resume_ver83b.xml"); assertNotNull(xmlUrl); diff --git a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java index dce14e941d7..5c147b5cb12 100644 --- a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java +++ b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java @@ -40,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.olat.core.commons.persistence.DBFactory; @@ -51,6 +52,7 @@ import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; import org.olat.course.CourseModule; import org.olat.course.ICourse; +import org.olat.course.config.CourseConfig; import org.olat.course.nodes.AssessableCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.ScoreEvaluation; @@ -60,6 +62,7 @@ import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -83,24 +86,33 @@ public class AssessmentManagerTest extends OlatTestCase { private final Boolean passed = Boolean.TRUE; private final Boolean fullyAssessed = Boolean.TRUE; + @Autowired + private EfficiencyStatementManager efficiencyStatementManager; + @Before public void setUp() throws Exception { try { log.info("setUp start ------------------------"); - tutor = JunitTestHelper.createAndPersistIdentityAsUser("junit_tutor_" + UUID.randomUUID().toString().replace("-", "")); - student = JunitTestHelper.createAndPersistIdentityAsUser("junit_student_" + UUID.randomUUID().toString().replace("-", "")); + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("junit_auth-" + UUID.randomUUID().toString()); + tutor = JunitTestHelper.createAndPersistIdentityAsUser("junit_tutor-" + UUID.randomUUID().toString()); + student = JunitTestHelper.createAndPersistIdentityAsUser("junit_student-" + UUID.randomUUID().toString()); - //import "Demo course" into the bcroot_junittest - RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(); + //import "Demo course" into the bcroot_junittest + RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(author); Long resourceableId = repositoryEntry.getOlatResource().getResourceableId(); System.out.println("Demo course imported - resourceableId: " + resourceableId); course = CourseFactory.loadCourse(resourceableId); DBFactory.getInstance().closeSession(); - course.getCourseEnvironment().getCourseConfig().setEfficencyStatementIsEnabled(true); + CourseConfig config = course.getCourseEnvironment().getCourseConfig(); + config.setEfficencyStatementIsEnabled(true); + CourseFactory.setCourseConfig(course.getResourceableId(), config); + course = CourseFactory.loadCourse(resourceableId); + config = course.getCourseEnvironment().getCourseConfig(); + Assert.assertTrue(config.isEfficencyStatementEnabled()); log.info("setUp done ------------------------"); } catch (RuntimeException e) { @@ -149,39 +161,39 @@ public class AssessmentManagerTest extends OlatTestCase { UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment()); boolean incrementAttempts = true; //assessableCourseNode.updateUserScoreEvaluation(scoreEvaluation, userCourseEnv, tutor, incrementAttempts); //alternative - assessmentManager.saveScoreEvaluation(assessableCourseNode, tutor, student, scoreEvaluation, userCourseEnv, incrementAttempts); - DBFactory.getInstance().closeSession(); - //the attempts mut have been incremented - //assertEquals(attempts, assessableCourseNode.getUserAttempts(userCourseEnv)); //alternative - assertEquals(attempts, assessmentManager.getNodeAttempts(assessableCourseNode, student)); - + assessmentManager.saveScoreEvaluation(assessableCourseNode, tutor, student, scoreEvaluation, userCourseEnv, incrementAttempts); + DBFactory.getInstance().closeSession(); + //the attempts mut have been incremented + //assertEquals(attempts, assessableCourseNode.getUserAttempts(userCourseEnv)); //alternative + assertEquals(attempts, assessmentManager.getNodeAttempts(assessableCourseNode, student)); + assessmentManager.saveNodeCoachComment(assessableCourseNode, student, coachComment); //assessableCourseNode.updateUserCoachComment(coachComment, userCourseEnv); //alternative - assessmentManager.saveNodeComment(assessableCourseNode, tutor, student, userComment); + assessmentManager.saveNodeComment(assessableCourseNode, tutor, student, userComment); //assessableCourseNode.updateUserUserComment(userComment, userCourseEnv, tutor); //alternative - attempts++; - assessmentManager.saveNodeAttempts(assessableCourseNode, tutor, student, attempts); - assertEquals(attempts, assessmentManager.getNodeAttempts(assessableCourseNode, student)); + attempts++; + assessmentManager.saveNodeAttempts(assessableCourseNode, tutor, student, attempts); + assertEquals(attempts, assessmentManager.getNodeAttempts(assessableCourseNode, student)); //assessableCourseNode.updateUserAttempts(attempts, userCourseEnv, tutor); //alternative - - assertEquals(score, assessmentManager.getNodeScore(assessableCourseNode, student)); - assertEquals(passed, assessmentManager.getNodePassed(assessableCourseNode, student)); - assertEquals(assessmentID, assessmentManager.getAssessmentID(assessableCourseNode, student)); - - assertEquals(coachComment, assessmentManager.getNodeCoachComment(assessableCourseNode, student)); - assertEquals(userComment, assessmentManager.getNodeComment(assessableCourseNode, student)); - - System.out.println("Finish testing AssessmentManager read/write methods"); - - checkEfficiencyStatementManager(); - assertNotNull("no course at the end of test",course); - try { - course = CourseFactory.loadCourse(course.getResourceableId()); - } catch (Exception ex ) { - fail("Could not load course at the end of test Exception=" + ex); - } + + assertEquals(score, assessmentManager.getNodeScore(assessableCourseNode, student)); + assertEquals(passed, assessmentManager.getNodePassed(assessableCourseNode, student)); + assertEquals(assessmentID, assessmentManager.getAssessmentID(assessableCourseNode, student)); + + assertEquals(coachComment, assessmentManager.getNodeCoachComment(assessableCourseNode, student)); + assertEquals(userComment, assessmentManager.getNodeComment(assessableCourseNode, student)); + + System.out.println("Finish testing AssessmentManager read/write methods"); + + checkEfficiencyStatementManager(); + assertNotNull("no course at the end of test",course); + try { + course = CourseFactory.loadCourse(course.getResourceableId()); + } catch (Exception ex ) { + fail("Could not load course at the end of test Exception=" + ex); + } assertNotNull("no course after loadCourse", course); } @@ -201,10 +213,8 @@ public class AssessmentManagerTest extends OlatTestCase { RepositoryEntry courseRepositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry( OresHelper.createOLATResourceableInstance(CourseModule.class, courseResId), false); assertNotNull(courseRepositoryEntry); - // check the stored EfficiencyStatement + // check the stored EfficiencyStatement EfficiencyStatement efficiencyStatement = checkEfficiencyStatement(courseRepositoryEntry); - - EfficiencyStatementManager efficiencyStatementManager = EfficiencyStatementManager.getInstance(); //force the storing of the efficiencyStatement - this is usually done only at Learnresource/modify properties/Efficiency statement (ON) efficiencyStatementManager.updateEfficiencyStatements(course, identitiyList); DBFactory.getInstance().closeSession(); @@ -254,9 +264,9 @@ public class AssessmentManagerTest extends OlatTestCase { * @return */ private EfficiencyStatement checkEfficiencyStatement(RepositoryEntry courseRepositoryEntry) { - EfficiencyStatementManager efficiencyStatementManager = EfficiencyStatementManager.getInstance(); - //check the stored EfficiencyStatement - EfficiencyStatement efficiencyStatement = efficiencyStatementManager.getUserEfficiencyStatement(courseRepositoryEntry.getKey(), student); + //check the stored EfficiencyStatement + EfficiencyStatement efficiencyStatement = efficiencyStatementManager + .getUserEfficiencyStatement(courseRepositoryEntry.getKey(), student); assertNotNull(efficiencyStatement); List<Map<String,Object>> assessmentNodes = efficiencyStatement.getAssessmentNodes(); Iterator<Map<String,Object>> listIterator = assessmentNodes.iterator(); @@ -274,5 +284,4 @@ public class AssessmentManagerTest extends OlatTestCase { assertEquals(passed,efficiencyStatementManager.getPassed(assessableCourseNode.getIdent(), efficiencyStatement)); return efficiencyStatement; } - } diff --git a/src/test/java/org/olat/course/auditing/UserNodeAuditManagerTest.java b/src/test/java/org/olat/course/auditing/UserNodeAuditManagerTest.java index b20ca4cfe25..ab237c00e23 100644 --- a/src/test/java/org/olat/course/auditing/UserNodeAuditManagerTest.java +++ b/src/test/java/org/olat/course/auditing/UserNodeAuditManagerTest.java @@ -30,9 +30,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.UUID; + import org.junit.Before; import org.junit.Test; import org.olat.core.commons.persistence.DBFactory; +import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.course.CourseFactory; @@ -56,8 +59,9 @@ public class UserNodeAuditManagerTest extends OlatTestCase { try { log.info("setUp start ------------------------"); - //import "Demo course" into the bcroot_junittest - RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(); + //import "Demo course" into the bcroot_junittest + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("auth-" + UUID.randomUUID().toString()); + RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(author); Long resourceableId = repositoryEntry.getOlatResource().getResourceableId(); System.out.println("Demo course imported - resourceableId: " + resourceableId); diff --git a/src/test/java/org/olat/course/condition/ConditionTest.java b/src/test/java/org/olat/course/condition/ConditionTest.java index 5e6d8bfe2cc..49e0aaf819a 100644 --- a/src/test/java/org/olat/course/condition/ConditionTest.java +++ b/src/test/java/org/olat/course/condition/ConditionTest.java @@ -20,6 +20,7 @@ package org.olat.course.condition; import java.util.Collection; +import java.util.UUID; import junit.framework.Assert; @@ -84,9 +85,10 @@ public class ConditionTest extends OlatTestCase { } private UserCourseEnvironment getUserDemoCourseEnvironment() { + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("junit_auth-" + UUID.randomUUID().toString()); Identity id = JunitTestHelper.createAndPersistIdentityAsUser("condition"); Roles roles = new Roles(false, false, false, false, false, false, false); - RepositoryEntry re = JunitTestHelper.deployDemoCourse(); + RepositoryEntry re = JunitTestHelper.deployDemoCourse(author); ICourse course = CourseFactory.loadCourse(re.getOlatResource()); IdentityEnvironment identityEnv = new IdentityEnvironment(id, roles); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(identityEnv, course.getCourseEnvironment()); diff --git a/src/test/java/org/olat/course/nodes/projectbroker/ProjectBrokerManagerTest.java b/src/test/java/org/olat/course/nodes/projectbroker/ProjectBrokerManagerTest.java index 43345f56c7c..c28c65ae5db 100644 --- a/src/test/java/org/olat/course/nodes/projectbroker/ProjectBrokerManagerTest.java +++ b/src/test/java/org/olat/course/nodes/projectbroker/ProjectBrokerManagerTest.java @@ -94,7 +94,8 @@ public class ProjectBrokerManagerTest extends OlatTestCase { id2 = JunitTestHelper.createAndPersistIdentityAsUser("project-id2-" + UUID.randomUUID().toString()); if (resourceableId == null) { - RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(); + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("project-auth-" + UUID.randomUUID().toString()); + RepositoryEntry repositoryEntry = JunitTestHelper.deployDemoCourse(author); resourceableId = repositoryEntry.getOlatResource().getResourceableId(); System.out.println("Demo course imported - resourceableId: " + resourceableId); } diff --git a/src/test/java/org/olat/portfolio/EPImportTest.java b/src/test/java/org/olat/portfolio/EPImportTest.java index 039953b9ce4..962bc94b852 100644 --- a/src/test/java/org/olat/portfolio/EPImportTest.java +++ b/src/test/java/org/olat/portfolio/EPImportTest.java @@ -29,10 +29,14 @@ import junit.framework.Assert; import org.junit.Test; import org.olat.core.commons.persistence.DB; +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.resource.OresHelper; import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.manager.EPXStreamHandler; import org.olat.portfolio.model.structel.PortfolioStructure; import org.olat.portfolio.model.structel.PortfolioStructureMap; +import org.olat.resource.OLATResource; +import org.olat.resource.OLATResourceManager; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -47,6 +51,8 @@ public class EPImportTest extends OlatTestCase { @Autowired private DB dbInstance; @Autowired + private OLATResourceManager resourceManager; + @Autowired private EPFrontendManager epFrontendManager; @@ -55,9 +61,12 @@ public class EPImportTest extends OlatTestCase { URL mapUrl = EPImportTest.class.getResource("map_81.xml.zip"); assertNotNull(mapUrl); File mapFile = new File(mapUrl.toURI()); + + OLATResourceable ores = OresHelper.createOLATResourceableType("EPMapTemplate"); + OLATResource resource = resourceManager.createAndPersistOLATResourceInstance(ores); //import the map PortfolioStructure rootStructure = EPXStreamHandler.getAsObject(mapFile, false); - PortfolioStructureMap importedMap = epFrontendManager.importPortfolioMapTemplate(rootStructure, null); + PortfolioStructureMap importedMap = epFrontendManager.importPortfolioMapTemplate(rootStructure, resource); Assert.assertNotNull(importedMap); dbInstance.commitAndCloseSession(); } diff --git a/src/test/java/org/olat/repository/RepositoryManagerTest.java b/src/test/java/org/olat/repository/RepositoryManagerTest.java index 162715a85c8..a73bcd18ec4 100644 --- a/src/test/java/org/olat/repository/RepositoryManagerTest.java +++ b/src/test/java/org/olat/repository/RepositoryManagerTest.java @@ -866,10 +866,12 @@ public class RepositoryManagerTest extends OlatTestCase { dbInstance.commitAndCloseSession(); //check - Roles roles = new Roles(false, false, false, false, false, true, false); - boolean institutionMgr1 = repositoryManager.isInstitutionalRessourceManagerFor(owner1, roles, re); - boolean institutionMgr2 = repositoryManager.isInstitutionalRessourceManagerFor(owner2, roles, re); - boolean institutionMgr3 = repositoryManager.isInstitutionalRessourceManagerFor(part3, roles, re); + Roles rolesOwner1 = securityManager.getRoles(owner1); + Roles rolesOwner2 = securityManager.getRoles(owner2); + Roles rolesPart3 = securityManager.getRoles(part3); + boolean institutionMgr1 = repositoryManager.isInstitutionalRessourceManagerFor(owner1, rolesOwner1, re); + boolean institutionMgr2 = repositoryManager.isInstitutionalRessourceManagerFor(owner2, rolesOwner2, re); + boolean institutionMgr3 = repositoryManager.isInstitutionalRessourceManagerFor(part3, rolesPart3, re); Assert.assertTrue(institutionMgr1); Assert.assertFalse(institutionMgr2); diff --git a/src/test/java/org/olat/repository/manager/RepositoryEntryStatisticsDAOTest.java b/src/test/java/org/olat/repository/manager/RepositoryEntryStatisticsDAOTest.java index 629db4b0eb0..d5f664eaa6a 100644 --- a/src/test/java/org/olat/repository/manager/RepositoryEntryStatisticsDAOTest.java +++ b/src/test/java/org/olat/repository/manager/RepositoryEntryStatisticsDAOTest.java @@ -209,7 +209,9 @@ public class RepositoryEntryStatisticsDAOTest extends OlatTestCase { log.info("testIncrementDownloadCounter finished"); } - + /** + * Test concurrent increment of the launch counter + */ @Test public void concurrentIncrementLaunchCounter() { final List<Exception> exceptionHolder = Collections.synchronizedList(new ArrayList<Exception>(1)); diff --git a/src/test/java/org/olat/restapi/UserMgmtTest.java b/src/test/java/org/olat/restapi/UserMgmtTest.java index 888c7d182e7..3ffe417a110 100644 --- a/src/test/java/org/olat/restapi/UserMgmtTest.java +++ b/src/test/java/org/olat/restapi/UserMgmtTest.java @@ -241,7 +241,8 @@ public class UserMgmtTest extends OlatJerseyTestCase { dbInstance.commitAndCloseSession(); //prepare some courses - RepositoryEntry entry = JunitTestHelper.deployDemoCourse(); + Identity author = JunitTestHelper.createAndPersistIdentityAsUser("auth-" + UUID.randomUUID().toString()); + RepositoryEntry entry = JunitTestHelper.deployDemoCourse(author); if (!repositoryService.hasRole(id1, entry, GroupRoles.participant.name())){ repositoryService.addRole(id1, entry, GroupRoles.participant.name()); } diff --git a/src/test/java/org/olat/test/JunitTestHelper.java b/src/test/java/org/olat/test/JunitTestHelper.java index b88467250a6..d40ea03f8e0 100644 --- a/src/test/java/org/olat/test/JunitTestHelper.java +++ b/src/test/java/org/olat/test/JunitTestHelper.java @@ -28,7 +28,9 @@ */ package org.olat.test; -import java.util.List; +import java.io.File; +import java.net.URL; +import java.util.Locale; import java.util.Random; import java.util.UUID; @@ -42,20 +44,21 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Roles; import org.olat.core.id.User; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; -import org.olat.course.DeployableCourseExport; -import org.olat.properties.Property; -import org.olat.properties.PropertyManager; +import org.olat.course.CourseModule; +import org.olat.course.ICourse; import org.olat.repository.RepositoryEntry; -import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; +import org.olat.repository.handlers.RepositoryHandler; +import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.user.UserManager; -import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Description:<br> @@ -70,6 +73,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; */ public class JunitTestHelper { + private static final OLog log = Tracing.createLoggerFor(JunitTestHelper.class); + public static final String PWD = "A6B7C8"; private static final Random randomResId = new Random(); @@ -190,44 +195,24 @@ public class JunitTestHelper { * Deploys/imports the "Demo Course". * @return the created RepositoryEntry */ - public static RepositoryEntry deployDemoCourse() { - + public static RepositoryEntry deployDemoCourse(Identity initialAuthor) { + String displayname = "Demo-Kurs-7.1"; + String description = ""; + RepositoryEntry re = null; - PropertyManager propertyManager = PropertyManager.getInstance(); - List<Property> l = propertyManager.findProperties(null, null, null, "_o3_", "deployedCourses"); - if (l.size() > 0) { - re = RepositoryManager.getInstance().lookupRepositoryEntry(l.get(0).getLongValue()); - if (re != null) { - //try to load it - try { - CourseFactory.loadCourse(re.getOlatResource()); - return re; - } catch(Exception ex) { - propertyManager.deleteProperties(null, null, null, "_o3_", "deployedCourses"); - RepositoryManager.getInstance().deleteRepositoryEntry(re); - } - } - } - - ClassPathXmlApplicationContext beanContext = null; try { - createAndPersistIdentityAsAdmin("administrator"); - beanContext = new ClassPathXmlApplicationContext("/org/olat/test/_spring/demoCourseExport.xml"); - DeployableCourseExport export = (DeployableCourseExport)beanContext.getBean("demoCourse"); - if (!export.getDeployableCourseZipFile().exists()) { - //do not throw exception as users may upload bad file - System.out.println("Cannot deploy course from file: " + export.getIdentifier()); - return null; - } - re = CourseFactory.deployCourseFromZIP(export.getDeployableCourseZipFile(), 4); - if (re != null) { - Property prop = propertyManager.createPropertyInstance(null, null, null, "_o3_", "deployedCourses", export.getVersion(), re.getKey(), export.getIdentifier(), null); - propertyManager.saveProperty(prop); - } - } finally { - beanContext.close(); + URL courseUrl = JunitTestHelper.class.getResource("file_resources/Demo-Kurs-7.1.zip"); + File courseFile = new File(courseUrl.toURI()); + + RepositoryHandler courseHandler = RepositoryHandlerFactory.getInstance() + .getRepositoryHandler(CourseModule.getCourseTypeName()); + re = courseHandler.importResource(initialAuthor, displayname, description, true, Locale.ENGLISH, courseFile, null); + + ICourse course = CourseFactory.loadCourse(re.getOlatResource()); + CourseFactory.publishCourse(course, RepositoryEntry.ACC_USERS, false, initialAuthor, Locale.ENGLISH); + } catch (Exception e) { + log.error("", e); } return re; } - } diff --git a/src/test/java/org/olat/test/_spring/demoCourseExport.xml b/src/test/java/org/olat/test/_spring/demoCourseExport.xml deleted file mode 100644 index 4de7af91f4e..00000000000 --- a/src/test/java/org/olat/test/_spring/demoCourseExport.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - - -<bean id="demoCourse" class="org.olat.course.DeployableCourseExport"> - <property name="courseUrl" value="http://nexus.openolat.org/nexus/content/repositories/openolat-snapshots/org/openolat/course/Demo-Kurs/7.1-SNAPSHOT/Demo-Kurs-7.1-SNAPSHOT.zip" /> - <property name="identifier" value="Demo Kurs" /> - <property name="version" value="1" /> -</bean> - -</beans> \ No newline at end of file diff --git a/src/test/java/org/olat/test/_spring/readme b/src/test/java/org/olat/test/_spring/readme deleted file mode 100644 index 7a7f170f29c..00000000000 --- a/src/test/java/org/olat/test/_spring/readme +++ /dev/null @@ -1,2 +0,0 @@ -Do not name the spring context files xyzContext.xml otherwise they may get loaded when olat starts. See web.xml for all -generic names which are searched on the classpath. \ No newline at end of file diff --git a/src/test/java/org/olat/test/file_resources/Demo-Kurs-7.1.zip b/src/test/java/org/olat/test/file_resources/Demo-Kurs-7.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..74d45cf865e346b5a167012347ea3fcd50d855df GIT binary patch literal 60957 zcmagF1CT9Um;PC{ZQFL$E!((d+qP}jE!(zj+qP|E?)&w0|9igap4sQ@jEu-wCnDGL ztjwKf{Zd{E7z70X;_pYoPLL1azYPQc1OOphX9q`PAzK?0b5lAuYbzBs7=S;ij!Nq) z5;9MKC;&x@6BYvu2%RU?QP+PqG@&B`sijC3IrO+gGo$uLV+7*)sZ-u>DtKUIHf9@n z%}rS^FKL8KY&}ssC84wClpg(V6bPKHo3m_6%vA0>#8@K923OIrNpY%WYz5xM*tH|i z5a)=)$OQPO6Z6TDVvh2>^Iv{*>_A$O0u-B(>zxdWN;vJhB`;3Hm8=unEz={SK5&>q z>J~#zR2Ym+pf{84y*(hKV^v0D4;?-yi1ot*?L@w<p++kuliKUl(fG)!--}ooMkNS} zMavUNaP(`knkguI#n)%vS@K~SzNm%wJ;DV#G595ZVC}B>oI3nLugrgF{hW(w_`=`B zp&RDVl~0~~@|6?qkIa4D3~m9r!IhT+hsYmQghB=c02l%S0FeKiV5onk_1_Z=`!~Uc z|4Oilt(B3n1O2~e_n*-JSsUDc4>h+jv30Q4cQUuNp)+&(e+y+DHzoU5sGyraZlOb= z+c?Nif`oVejf&Lcu>=qt=_VU$gD!S#g-2)hSaA`9W63VZ8)-7KrmpJW9=}2pq(NWg zR4a_ZqM+}1#)49hnBCM5*{Q<{m`A(nqsgu+%Y#yP>Je)bO1lyAFWO5pgr{vqz6o4- zX|A_^>B@>Nm*xhH9oE{JQf(Ce$nT#yaiyl=kdl@Ql7UJ1tAHsri$v<gKfo+cBWXyc zRiN0<yVx#|lEVly;L-4A9f(!@Qc8xk$iA`UxktJdf83zc*QVMbD5AA~ed8yTK^+(V z>=w#oSG^R9R-?Nbb}x8$F&kh>CNC&VhK|PD9;t>^#wNQhMT{crF9*a$v-Oroz&fR$ zJPC&L-i3$h)=*346R+0X0kG)6Y~iJUj73rir4fn{a(RRON6PVRRVmiLQcnM!|GOT@ zfAugnGIz3daB?s<wzf4gw)&sS<x2a)VS}UoyGPDnvZ$D;soCo7ni<dbEm=J$oIHC~ zqWoD73W*R(jHDD$fLh_|;4<SfGRwvfg`S8~F&Rlc{~1Y	tH`q`PKri{oQNb%jt) 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^ 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 literal 0 HcmV?d00001 -- GitLab