diff --git a/src/main/java/org/olat/core/logging/activity/ActionObject.java b/src/main/java/org/olat/core/logging/activity/ActionObject.java index 9dbe001de9d6a38bc749f5d826725e2ca1c4de89..7ea26cecba6ca55950b951516db3f5dcd8c7e3f7 100644 --- a/src/main/java/org/olat/core/logging/activity/ActionObject.java +++ b/src/main/java/org/olat/core/logging/activity/ActionObject.java @@ -41,6 +41,7 @@ package org.olat.core.logging.activity; public enum ActionObject { bookSection, + blog, calendar, chat, check, diff --git a/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java b/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java index e6831afc3aba86b8519ab7c53218b50efe939280..2fc0190b3b88470f924b2c72fd5d4c7a1486dcc3 100644 --- a/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java +++ b/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java @@ -107,6 +107,10 @@ public class LearningResourceLoggingAction extends BaseLoggingAction { new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.mail).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_EMAIL_DISABLED = new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.remove, ActionObject.mail).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); + public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_BLOG_ENABLED = + new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.blog).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); + public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_BLOG_DISABLED = + new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.remove, ActionObject.blog).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_FORUM_ENABLED = new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.forum).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_FORUM_DISABLED = diff --git a/src/main/java/org/olat/course/config/CourseConfig.java b/src/main/java/org/olat/course/config/CourseConfig.java index 6eceb9f57b2c0bb6f3abd452d39a74719c104797..0fc36c6bc31f6413b34c01b0cf39ae37de42c8d8 100644 --- a/src/main/java/org/olat/course/config/CourseConfig.java +++ b/src/main/java/org/olat/course/config/CourseConfig.java @@ -74,7 +74,7 @@ public class CourseConfig implements Serializable, Cloneable { /** * current config file version */ - private static final transient int CURRENTVERSION = 18; + private static final transient int CURRENTVERSION = 19; public static final transient String KEY_LOGLEVEL_ADMIN = "LOGLEVELADMIN"; public static final transient String KEY_LOGLEVEL_USER = "LOGLEVELUSER"; @@ -103,7 +103,11 @@ public class CourseConfig implements Serializable, Cloneable { public static final transient String PARTICIPANT_LIST_ENABLED = "PARTICIPANT_LIST_ENABLED"; public static final transient String PARTICIPANT_INFO_ENABLED = "PARTICIPANT_INFO_ENABLED"; public static final transient String EMAIL_ENABLED = "EMAIL_ENABLED"; + public static final transient String BLOG_ENABLED = "BLOG_ENABLED"; + public static final transient String BLOG_SOFTKEY = "BLOG_SOFTKEY"; public static final transient String FORUM_ENABLED = "FORUM_ENABLED"; + public static final transient String WIKI_ENABLED = "WIKI_ENABLED"; + public static final transient String WIKI_SOFTKEY = "WIKI_SOFTKEY"; public static final transient String DOCUMENTS_ENABLED = "DOCUMENTS_ENABLED"; public static final transient String KEY_CALENDAR_ENABLED = "KEY_CALENDAR_ENABLED"; @@ -173,7 +177,9 @@ public class CourseConfig implements Serializable, Cloneable { configuration.put(PARTICIPANT_LIST_ENABLED, Boolean.FALSE); configuration.put(PARTICIPANT_INFO_ENABLED, Boolean.FALSE); configuration.put(EMAIL_ENABLED, Boolean.FALSE); + configuration.put(BLOG_ENABLED, Boolean.FALSE); configuration.put(FORUM_ENABLED, Boolean.FALSE); + configuration.put(WIKI_ENABLED, Boolean.FALSE); configuration.put(DOCUMENTS_ENABLED, Boolean.FALSE); configuration.put(NODE_ACCESS_TYPE, NODE_ACCESS_TYPE_DEFAULT); @@ -324,6 +330,15 @@ public class CourseConfig implements Serializable, Cloneable { this.version = 18; } + + if (version == 18) { + if (!configuration.containsKey(BLOG_ENABLED)) + configuration.put(BLOG_ENABLED, Boolean.FALSE); + if (!configuration.containsKey(WIKI_ENABLED)) + configuration.put(WIKI_ENABLED, Boolean.FALSE); + + this.version = 19; + } /* * after resolving the issues, the version number is merged to the @@ -639,6 +654,28 @@ public class CourseConfig implements Serializable, Cloneable { public void setEmailEnabled(boolean b) { configuration.put(EMAIL_ENABLED, Boolean.valueOf(b)); } + + public boolean isBlogEnabled() { + Boolean bool = (Boolean) configuration.get(BLOG_ENABLED); + return bool.booleanValue(); + } + + public void setBlogEnabled(boolean b) { + configuration.put(BLOG_ENABLED, Boolean.valueOf(b)); + } + + public String getBlogSoftKey() { + Object softKey = configuration.get(BLOG_SOFTKEY); + return softKey != null? (String) softKey: null; + } + + public void setBlogSoftKey(String blogSoftKey) { + if (blogSoftKey != null) { + configuration.put(BLOG_SOFTKEY, blogSoftKey); + } else { + configuration.remove(BLOG_SOFTKEY); + } + } public boolean isForumEnabled() { Boolean bool = (Boolean) configuration.get(FORUM_ENABLED); @@ -648,6 +685,27 @@ public class CourseConfig implements Serializable, Cloneable { public void setForumEnabled(boolean b) { configuration.put(FORUM_ENABLED, Boolean.valueOf(b)); } + public boolean isWikiEnabled() { + Boolean bool = (Boolean) configuration.get(WIKI_ENABLED); + return bool.booleanValue(); + } + + public void setWikiEnabled(boolean b) { + configuration.put(WIKI_ENABLED, Boolean.valueOf(b)); + } + + public String getWikiSoftKey() { + Object softKey = configuration.get(WIKI_SOFTKEY); + return softKey != null? (String) softKey: null; + } + + public void setWikiSoftKey(String wikiSoftKey) { + if (wikiSoftKey != null) { + configuration.put(WIKI_SOFTKEY, wikiSoftKey); + } else { + configuration.remove(WIKI_SOFTKEY); + } + } public boolean isDocumentsEnabled() { Boolean bool = (Boolean) configuration.get(DOCUMENTS_ENABLED); @@ -703,7 +761,11 @@ public class CourseConfig implements Serializable, Cloneable { clone.setParticipantListEnabled(isParticipantListEnabled()); clone.setParticipantInfoEnabled(isParticipantInfoEnabled()); clone.setEmailEnabled(isEmailEnabled()); + clone.setBlogEnabled(isBlogEnabled()); + clone.setBlogSoftKey(getBlogSoftKey()); clone.setForumEnabled(isForumEnabled()); + clone.setWikiEnabled(isWikiEnabled()); + clone.setWikiSoftKey(getWikiSoftKey()); clone.setDocumentsEnabled(isDocumentsEnabled()); clone.setNodeAccessType(getNodeAccessType().getType()); return clone; diff --git a/src/main/java/org/olat/course/config/CourseConfigEvent.java b/src/main/java/org/olat/course/config/CourseConfigEvent.java index b06eb4b1f544e0f27101c5e6c2815de603826c57..e3e15a89412b5afdce55aa248baca8f4765e656e 100644 --- a/src/main/java/org/olat/course/config/CourseConfigEvent.java +++ b/src/main/java/org/olat/course/config/CourseConfigEvent.java @@ -63,6 +63,7 @@ public class CourseConfigEvent extends MultiUserEvent { participantList, participantInfo, email, + blog, forum, documents, chat, diff --git a/src/main/java/org/olat/course/config/ui/CourseToolbarController.java b/src/main/java/org/olat/course/config/ui/CourseToolbarController.java index 154e3f53fd02089ed10cd0dc86be74cfcb2f534d..909816f0a5ee553c522f5471122ceb69e16a7090 100644 --- a/src/main/java/org/olat/course/config/ui/CourseToolbarController.java +++ b/src/main/java/org/olat/course/config/ui/CourseToolbarController.java @@ -25,15 +25,18 @@ import org.olat.commons.calendar.ui.events.CalendarGUIModifiedEvent; 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.SelectionElement; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; +import org.olat.core.gui.components.link.Link; 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.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.activity.ILoggingAction; import org.olat.core.logging.activity.LearningResourceLoggingAction; @@ -48,9 +51,12 @@ import org.olat.course.ICourse; import org.olat.course.config.CourseConfig; import org.olat.course.config.CourseConfigEvent; import org.olat.course.config.CourseConfigEvent.CourseConfigType; +import org.olat.fileresource.types.BlogFileResource; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; +import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; +import org.olat.repository.controllers.ReferencableEntriesSearchController; import org.olat.repository.ui.settings.ReloadSettingsEvent; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; @@ -73,20 +79,30 @@ public class CourseToolbarController extends FormBasicController { private SelectionElement participantListEl; private SelectionElement participantInfoEl; private SelectionElement emailEl; + private SelectionElement blogEl; + private FormLayoutContainer blogCont; + private FormLink blogOpenLink; + private FormLink blogSelectLink; private SelectionElement forumEl; private SelectionElement documentsEl; private SelectionElement chatEl; private SelectionElement glossaryEl; + + private CloseableModalController cmc; + private ReferencableEntriesSearchController blogSearchCtrl; private LockResult lockEntry; private final boolean editable; private RepositoryEntry entry; private CourseConfig courseConfig; + private RepositoryEntry blogEntry; @Autowired private UserManager userManager; @Autowired private CalendarModule calendarModule; + @Autowired + private RepositoryManager repositoryManager; public CourseToolbarController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, CourseConfig courseConfig) { @@ -94,6 +110,9 @@ public class CourseToolbarController extends FormBasicController { onValues = new String[] {translate("on")}; this.entry = entry; this.courseConfig = courseConfig; + if (StringHelper.containsNonWhitespace(courseConfig.getBlogSoftKey())) { + blogEntry = repositoryManager.lookupRepositoryEntryBySoftkey(courseConfig.getBlogSoftKey(), false); + } lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker() .acquireLock(entry.getOlatResource(), getIdentity(), CourseFactory.COURSE_EDITOR_LOCK); @@ -182,6 +201,22 @@ public class CourseToolbarController extends FormBasicController { canHideToolbar &= false; } + boolean blogEnabled = courseConfig.isBlogEnabled(); + boolean managedBlog = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.blog); + blogEl = uifactory.addCheckboxesHorizontal("blogIsOn", "chkbx.blog.onoff", formLayout, onKeys, onValues); + blogEl.addActionListener(FormEvent.ONCHANGE); + blogEl.select(onKeys[0], blogEnabled); + blogEl.setEnabled(editable && !managedBlog); + if(managedBlog && blogEnabled) { + canHideToolbar &= false; + } + + blogCont = FormLayoutContainer.createButtonLayout("blogButtons", getTranslator()); + blogCont.setRootForm(mainForm); + formLayout.add(blogCont); + blogOpenLink = uifactory.addFormLink("blog.not.selected", blogCont, Link.LINK); + blogSelectLink = uifactory.addFormLink("blog.select", blogCont, Link.BUTTON_XSMALL); + boolean forumEnabled = courseConfig.isForumEnabled(); boolean managedForum = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.forum); forumEl = uifactory.addCheckboxesHorizontal("forumIsOn", "chkbx.forum.onoff", formLayout, onKeys, onValues); @@ -228,11 +263,37 @@ public class CourseToolbarController extends FormBasicController { FormSubmit saveButton = uifactory.addFormSubmitButton("save", buttonsCont); saveButton.setElementCssClass("o_sel_settings_save"); saveButton.setEnabled(editable); + + updateUI(); + } + + private void updateUI() { + boolean blogEnabled = blogEl.isSelected(0); + blogOpenLink.setVisible(blogEnabled); + blogCont.setVisible(blogEnabled); + blogSelectLink.setVisible(blogEnabled); + if (blogEnabled) { + boolean blogSelected = blogEntry != null; + blogOpenLink.setEnabled(blogSelected); + String blogTitle = blogSelected + ? StringHelper.escapeHtml(blogEntry.getDisplayname()) + : translate("blog.not.selected"); + blogOpenLink.setI18nKey("blog.open", new String[] { blogTitle }); + blogOpenLink.setIconLeftCSS(blogSelected? "o_icon o_icon-fw o_icon_preview": null); + + boolean blogEntryEditable = blogEl.isEnabled() && blogEnabled; + blogSelectLink.setVisible(blogEntryEditable); + blogSelectLink.setI18nKey("blog.select.button", new String[] { translate(blogSelected? "blog.replace": "blog.select")}); + } } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if(toolbarEl == source) { + if (source == blogEl) { + updateUI(); + } else if (source == blogSelectLink) { + doSelectBlog(ureq); + } else if(toolbarEl == source) { if(!toolbarEl.isSelected(0) && isAnyToolSelected()) { showWarning("chkbx.toolbar.off.warning"); } @@ -247,6 +308,7 @@ public class CourseToolbarController extends FormBasicController { || participantListEl.isSelected(0) || participantInfoEl.isSelected(0) || emailEl.isSelected(0) + || blogEl.isSelected(0) || forumEl.isSelected(0) || documentsEl.isSelected(0) || chatEl.isSelected(0) @@ -263,12 +325,52 @@ public class CourseToolbarController extends FormBasicController { participantListEl.setVisible(enabled); participantInfoEl.setVisible(enabled); emailEl.setVisible(enabled); + blogEl.setVisible(enabled); forumEl.setVisible(enabled); documentsEl.setVisible(enabled); chatEl.setVisible(enabled); glossaryEl.setVisible(enabled); } + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == blogSearchCtrl) { + if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { + RepositoryEntry blogEntry = blogSearchCtrl.getSelectedEntry(); + if (blogEntry != null) { + this.blogEntry = blogEntry; + updateUI(); + } + } + cmc.deactivate(); + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(blogSearchCtrl); + removeAsListenerAndDispose(cmc); + blogSearchCtrl = null; + cmc = null; + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + blogCont.clearError(); + boolean blogEnabled = blogEl.isSelected(0); + if (blogEnabled) { + if (blogEntry == null) { + blogCont.setErrorKey("error.no.blog.selected", null); + allOk = false; + } + } + + return allOk & super.validateFormLogic(ureq); + } + @Override protected void formOK(UserRequest ureq) { OLATResourceable courseOres = entry.getOlatResource(); @@ -298,6 +400,13 @@ public class CourseToolbarController extends FormBasicController { boolean updateEmail = courseConfig.isEmailEnabled() != enableEmail; courseConfig.setEmailEnabled(enableEmail && toolbarEnabled); + boolean enableBlog = blogEl.isSelected(0); + boolean updateBlog = courseConfig.isBlogEnabled() != enableBlog; + courseConfig.setBlogEnabled(enableBlog && toolbarEnabled); + boolean blogSelected = enableBlog && blogEntry != null; + String blogSoftKey = blogSelected? blogEntry.getSoftkey(): null;; + courseConfig.setBlogSoftKey(blogSoftKey); + boolean enableForum = forumEl.isSelected(0); boolean updateForum = courseConfig.isForumEnabled() != enableForum; courseConfig.setForumEnabled(enableForum && toolbarEnabled); @@ -368,6 +477,16 @@ public class CourseToolbarController extends FormBasicController { CoordinatorManager.getInstance().getCoordinator().getEventBus() .fireEventToListenersOf(new CourseConfigEvent(CourseConfigType.email, course.getResourceableId()), course); } + + if(updateBlog) { + ILoggingAction loggingAction = enableBlog ? + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_BLOG_ENABLED: + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_BLOG_DISABLED; + ThreadLocalUserActivityLogger.log(loggingAction, getClass()); + + CoordinatorManager.getInstance().getCoordinator().getEventBus() + .fireEventToListenersOf(new CourseConfigEvent(CourseConfigType.blog, course.getResourceableId()), course); + } if(updateForum) { ILoggingAction loggingAction = enableForum ? @@ -416,4 +535,14 @@ public class CourseToolbarController extends FormBasicController { protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } + + private void doSelectBlog(UserRequest ureq) { + blogSearchCtrl = new ReferencableEntriesSearchController(getWindowControl(), ureq, BlogFileResource.TYPE_NAME, + translate("blog.select.titile")); + listenTo(blogSearchCtrl); + cmc = new CloseableModalController(getWindowControl(), translate("close"), + blogSearchCtrl.getInitialComponent(), true, translate("blog.select.title")); + cmc.activate(); + } + } diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties index ad9516f460b09cb3bff7024bca191d2bb1b6adf4..3b8f47c812242fe64d4bab13404bd3d6cdffc2ba 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties @@ -1,4 +1,11 @@ #Thu Aug 21 16:57:07 CEST 2014 +blog.not.selected=Kein Blog ausgew\u00E4hlt +blog.open={0} +blog.replace=Ersetzen +blog.select=Ausw\u00E4hlen +blog.select.button={0} +blog.select.title=Blog ausw\u00E4hlen +chkbx.blog.onoff=Blog chkbx.calendar.onoff=Kurskalender chkbx.chat.onoff=Kurs-Chat chkbx.efficency.onoff=Leistungsnachweis verwenden @@ -22,6 +29,7 @@ command.glossary.remove=Auswahl l\u00F6schen course.log.changed.message=<br>Detaillierte Kurs-Log-Dateien k\u00F6nnen im Archivierungs-Tool heruntergeladen werden.<br><br>Alte Kurs-Log-Dateien (bis und mit OLAT 6.2) stehen im Ablageordner des Kurses zur Verf\u00FCgung. coursefolder=Ablageordner details.options.title=Glossar und Ressourcenordner +error.no.blog.selected=Es ist kein Blog ausgew\u00E4hlt. form.layout.changecustomcss=CSS auswechseln form.layout.choosecustomcss=Eigenes CSS w\u00E4hlen form.layout.choosesystemcss=Standard CSS w\u00E4hlen diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties index 5457db57294c4667c69c35786716687638f7f996..4930a2b5ed57688d22f81f6f0653063a9abee37f 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties @@ -1,4 +1,11 @@ #Fri Jan 21 11:22:00 CET 2011 +blog.not.selected=No blog selected +blog.open={0} +blog.replace=Replace +blog.select=Select +blog.select.button={0} +blog.select.blog=Select blog +chkbx.blog.onoff=Blog chkbx.calendar.onoff=Course calendar chkbx.chat.onoff=Course chat chkbx.search.onoff=Course search @@ -22,6 +29,7 @@ command.glossary.remove=Delete selection course.log.changed.message=<br>Detailed course log files can be downloaded with the archiving tool.<br><br> Older course log files (OLAT 6.2 and earlier versions) are at your disposal in the course's storage folder. coursefolder=Storage folder details.options.title=Glossary and resource folder +error.no.blog.selected=No blog selected. form.layout.changecustomcss=Change CSS form.layout.choosecustomcss=Choose your own CSS form.layout.choosesystemcss=Select default CSS diff --git a/src/main/java/org/olat/course/nodes/feed/blog/BlogToolController.java b/src/main/java/org/olat/course/nodes/feed/blog/BlogToolController.java new file mode 100644 index 0000000000000000000000000000000000000000..81b5d54420eb9839ebe1476c976df00ad59d294e --- /dev/null +++ b/src/main/java/org/olat/course/nodes/feed/blog/BlogToolController.java @@ -0,0 +1,218 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.feed.blog; + +import java.util.List; + +import org.olat.core.commons.services.notifications.SubscriptionContext; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +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.control.generic.messages.MessageController; +import org.olat.core.gui.control.generic.messages.MessageUIFactory; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; +import org.olat.course.CourseModule; +import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.webFeed.FeedSecurityCallback; +import org.olat.modules.webFeed.ui.FeedMainController; +import org.olat.modules.webFeed.ui.blog.BlogUIFactory; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 29 Oct 2019<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class BlogToolController extends BasicController implements Activateable2 { + + public static final String SUBSCRIPTION_SUBIDENTIFIER = "blog"; + + private FeedMainController blogCtrl; + private MessageController noBlogCtrl; + + @Autowired + private RepositoryManager repositoryManager; + + public BlogToolController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv) { + super(ureq, wControl); + + String blogSoftKey = userCourseEnv.getCourseEnvironment().getCourseConfig().getBlogSoftKey(); + RepositoryEntry blogEntry = repositoryManager.lookupRepositoryEntryBySoftkey(blogSoftKey, false); + if (blogEntry != null) { + + String resName = CourseModule.getCourseTypeName(); + Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); + OLATResourceable courseOres = OresHelper.createOLATResourceableInstance(resName, resId); + SubscriptionContext subsContext = new SubscriptionContext(courseOres, SUBSCRIPTION_SUBIDENTIFIER); + + FeedSecurityCallback callback = userCourseEnv.isCourseReadOnly() || ureq.getUserSession().getRoles().isGuestOnly() + ? new ReadOnlyForumCallback() + : new ToolSecurityCallback(userCourseEnv, subsContext); + + Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); + blogCtrl = BlogUIFactory.getInstance(ureq.getLocale()).createMainController(blogEntry.getOlatResource(), + ureq, wControl, callback, courseId, SUBSCRIPTION_SUBIDENTIFIER); + listenTo(blogCtrl); + + putInitialPanel(blogCtrl.getInitialComponent()); + } else { + String title = translate("tool.no.blog.title"); + String text = translate("tool.no.blog.text"); + noBlogCtrl = MessageUIFactory.createInfoMessage(ureq, wControl, title, text); + listenTo(noBlogCtrl); + putInitialPanel(noBlogCtrl.getInitialComponent()); + } + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if (blogCtrl != null) { + blogCtrl.activate(ureq, entries, state); + } + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + @Override + protected void doDispose() { + // + } + + private static class ToolSecurityCallback implements FeedSecurityCallback { + + private final boolean admin; + private final boolean coach; + private SubscriptionContext subscriptionContext; + + private ToolSecurityCallback(UserCourseEnvironment userCourseEnv, SubscriptionContext subscriptionContext) { + this.admin = userCourseEnv.isAdmin(); + this.coach = userCourseEnv.isCoach(); + this.subscriptionContext = subscriptionContext; + } + + @Override + public boolean mayEditMetadata() { + return admin || coach; + } + + @Override + public boolean mayCreateItems() { + return admin || coach; + } + + @Override + public boolean mayEditItems() { + return admin || coach; + } + + @Override + public boolean mayEditOwnItems() { + return true; + } + + @Override + public boolean mayDeleteItems() { + return admin || coach; + } + + @Override + public boolean mayDeleteOwnItems() { + return true; + } + + @Override + public boolean mayViewAllDrafts() { + return admin || coach; + } + + @Override + public SubscriptionContext getSubscriptionContext() { + return subscriptionContext; + } + + @Override + public void setSubscriptionContext(SubscriptionContext subsContext) { + this.subscriptionContext = subsContext; + } + + } + + private static class ReadOnlyForumCallback implements FeedSecurityCallback { + + @Override + public boolean mayEditMetadata() { + return false; + } + + @Override + public boolean mayCreateItems() { + return false; + } + + @Override + public boolean mayEditItems() { + return false; + } + + @Override + public boolean mayEditOwnItems() { + return false; + } + + @Override + public boolean mayDeleteItems() { + return false; + } + + @Override + public boolean mayDeleteOwnItems() { + return false; + } + + @Override + public boolean mayViewAllDrafts() { + return false; + } + + @Override + public SubscriptionContext getSubscriptionContext() { + return null; + } + + @Override + public void setSubscriptionContext(SubscriptionContext subsContext) { + // + } + + } + +} diff --git a/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_de.properties index dfc09acd81cbcff1fed3f092445d51a412a46dab..759dd754708520974abf2b36e43969363a0f5dd0 100644 --- a/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_de.properties @@ -1,12 +1,12 @@ -pane.tab.feed=Blog-Lerninhalt -form.title.choose.feed=Blog ausw\u00E4hlen -chosen.feed=Gew\u00E4hlter Blog -no.feed.chosen=<i>Kein Blog-Lerninhalt ausgew\u00E4hlt</i> - button.change.feed=Blog auswechseln button.choose.feed=Blog w\u00E4hlen button.create.feed=Blog w\u00E4hlen, erstellen oder importieren - +chosen.feed=Gew\u00E4hlter Blog error.no.reference.long=F\u00FCr "{0}" muss in der Konfiguration ein Blog im Tab "Blog-Lerninhalt" ausgew\u00E4hlt werden. error.no.reference.short=Es ist noch kein Blog f\u00FCr "{0}" ausgew\u00E4hlt. error.repository.entry.missing=Der Blog-Lerninhalt, den Sie anzeigen m\u00F6chten, wurde in der Zwischenzeit in der Ablage der Lernressourcen gel\u00F6scht +form.title.choose.feed=Blog ausw\u00E4hlen +no.feed.chosen=<i>Kein Blog-Lerninhalt ausgew\u00E4hlt</i> +pane.tab.feed=Blog-Lerninhalt +tool.no.blog.text=F\u00FCr diesen Kurs ist kein Blog vorhanden. +tool.no.blog.title=Kein Blog vorhanden. diff --git a/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_en.properties index abf17f9cccb1c4b045de44804b66cb5a1442b551..342d6c47fd962d7450be6003d1b97ef912d4e7c0 100644 --- a/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/feed/blog/_i18n/LocalStrings_en.properties @@ -9,3 +9,5 @@ error.repository.entry.missing=The blog learning content you want to see has alr form.title.choose.feed=Select blog no.feed.chosen=<i>No blog learning content selected</i> pane.tab.feed=Blog learning content +tool.no.blog.text=There is no blog available for this course. +tool.no.blog.title=No blog available diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index 47e0615b398ed966d7d61095f8af037cc5bd3016..4f231bf1d94bb3c2b78970314f3c95875c75f1d2 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -107,6 +107,7 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.ENCourseNode; import org.olat.course.nodes.bc.CourseDocumentsController; import org.olat.course.nodes.co.COToolController; +import org.olat.course.nodes.feed.blog.BlogToolController; import org.olat.course.nodes.fo.FOToolController; import org.olat.course.nodes.info.InfoRunController; import org.olat.course.nodes.members.MembersToolRunController; @@ -180,7 +181,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im //my course efficiencyStatementsLink, noteLink, leaveLink, //course tools - learninPathLink, calendarLink, chatLink, participantListLink, participantInfoLink, forumLink, documentsLink, + learninPathLink, calendarLink, chatLink, participantListLink, participantInfoLink, blogLink, forumLink, documentsLink, emailLink, searchLink, //glossary openGlossaryLink, enableGlossaryLink, lecturesLink; @@ -189,6 +190,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private CloseableModalController cmc; private COToolController emailCtrl; + private BlogToolController blogCtrl; private FOToolController forumCtrl; private Controller documentsCtrl; private CourseAreasController areasCtrl; @@ -846,6 +848,12 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im toolbarPanel.addTool(emailLink); } + if(!assessmentLock) { + blogLink = LinkFactory.createToolLink("blog", translate("command.blog"), this, "o_blog_icon"); + blogLink.setVisible(cc.isBlogEnabled()); + toolbarPanel.addTool(blogLink); + } + if(!assessmentLock) { forumLink = LinkFactory.createToolLink("forum", translate("command.forum"), this, "o_fo_icon"); forumLink.setVisible(cc.isForumEnabled()); @@ -990,6 +998,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im doParticipantInfo(ureq); } else if(emailLink == source) { doEmail(ureq); + } else if(blogLink == source) { + doBlog(ureq); } else if(forumLink == source) { doForum(ureq); } else if(documentsLink == source) { @@ -1101,6 +1111,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im case participantList: doParticipantList(ureq); break; case participantInfo: doParticipantInfo(ureq); break; case email: doEmail(ureq); break; + case blog: doBlog(ureq); break; case forum: doForum(ureq); break; case documents: doDocuments(ureq); break; } @@ -1185,6 +1196,14 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im if (emailLink != null && emailLink.isVisible()) { doEmail(ureq); } + } else if("Blog".equalsIgnoreCase(type)) { + if (blogLink != null && blogLink.isVisible()) { + Activateable2 blog = doBlog(ureq); + if (blog != null) { + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + blog.activate(ureq, subEntries, entries.get(0).getTransientState()); + } + } } else if("Forum".equalsIgnoreCase(type)) { if (forumLink != null && forumLink.isVisible()) { doForum(ureq); @@ -1804,6 +1823,23 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im }; } + private BlogToolController doBlog(UserRequest ureq) { + if(delayedClose == Delayed.blog || requestForClose(ureq)) { + removeCustomCSS(); + + OLATResourceable ores = OresHelper.createOLATResourceableType("blog"); + WindowControl swControl = addToHistory(ureq, ores, null); + blogCtrl = new BlogToolController(ureq, swControl, getUserCourseEnvironment()); + + pushController(ureq, translate("command.blog"), blogCtrl); + setActiveTool(blogLink); + currentToolCtr = blogCtrl; + return blogCtrl; + } + delayedClose = Delayed.blog; + return null; + } + private void doForum(UserRequest ureq) { if(delayedClose == Delayed.forum || requestForClose(ureq)) { removeCustomCSS(); @@ -1988,6 +2024,15 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } break; } + case blog: { + if(blogLink != null) { + ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); + CourseConfig cc = course.getCourseEnvironment().getCourseConfig(); + blogLink.setVisible(cc.isBlogEnabled()); + toolbarPanel.setDirty(true); + } + break; + } case forum: { if(forumLink != null) { ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); @@ -2149,6 +2194,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im participantList, participantInfo, email, + blog, forum, documents } diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties index 7276fe1df76893841e4e1f0b6887b2cbf03d1771..ad50c50b88ba72889a36872d3c4d3ac9adb5b09e 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties @@ -3,6 +3,7 @@ command.access=Zugangskonfiguration command.assessment.done=Erledigt command.assessment.mode=Pr\u00FCfungsmodus command.assessment.undone=Unerledigt +command.blog=Blog command.bookmark=Bookmark command.calendar=Kalender command.catalog=Katalogeintr\u00E4ge diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties index 28dee3ed39874308d3c04a9dc040d7ad6520667b..7ba81bcf84bc407ac4271a7f5e2aa39d6f9e64fa 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties @@ -3,6 +3,7 @@ command.access=Access configuration command.assessment.done=Done command.assessment.mode=Assessment mode command.assessment.undone=Undone +command.blog=Blog command.bookmark=Bookmark command.calendar=Calendar command.catalog=Catalogue entries diff --git a/src/main/java/org/olat/modules/webFeed/FeedViewHelper.java b/src/main/java/org/olat/modules/webFeed/FeedViewHelper.java index f3b18512155df915f7e6dcacdde881f4682538c7..97e1006d86ab06ac62e6334562ab05a12fcb0ee2 100644 --- a/src/main/java/org/olat/modules/webFeed/FeedViewHelper.java +++ b/src/main/java/org/olat/modules/webFeed/FeedViewHelper.java @@ -28,12 +28,12 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import org.apache.logging.log4j.Logger; 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.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; @@ -41,6 +41,7 @@ import org.olat.core.util.filter.Filter; import org.olat.core.util.filter.FilterFactory; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseModule; +import org.olat.course.nodes.feed.blog.BlogToolController; import org.olat.modules.webFeed.dispatching.Path; import org.olat.modules.webFeed.manager.FeedManager; import org.olat.modules.webFeed.model.ItemPublishDateComparator; @@ -488,12 +489,19 @@ public class FeedViewHelper { String jumpInLink = null; RepositoryManager resMgr = RepositoryManager.getInstance(); if (courseId != null && nodeId != null) { + + List<ContextEntry> ces = new ArrayList<>(); OLATResourceable oresCourse = OLATResourceManager.getInstance().findResourceable(courseId, CourseModule.getCourseTypeName()); - OLATResourceable oresNode = OresHelper.createOLATResourceableInstance("CourseNode", Long.valueOf(nodeId)); RepositoryEntry repositoryEntry = resMgr.lookupRepositoryEntry(oresCourse, false); - List<ContextEntry> ces = new ArrayList<>(); ces.add(BusinessControlFactory.getInstance().createContextEntry(repositoryEntry)); - ces.add(BusinessControlFactory.getInstance().createContextEntry(oresNode)); + if (BlogToolController.SUBSCRIPTION_SUBIDENTIFIER.equals(nodeId)) { + OLATResourceable oresTool = OresHelper + .createOLATResourceableInstance(BlogToolController.SUBSCRIPTION_SUBIDENTIFIER, Long.valueOf(0)); + ces.add(BusinessControlFactory.getInstance().createContextEntry(oresTool)); + } else { + OLATResourceable oresNode = OresHelper.createOLATResourceableInstance("CourseNode", Long.valueOf(nodeId)); + ces.add(BusinessControlFactory.getInstance().createContextEntry(oresNode)); + } jumpInLink = BusinessControlFactory.getInstance().getAsURIString(ces, false); } else { RepositoryEntry repositoryEntry = resMgr.lookupRepositoryEntry(feed, false); diff --git a/src/main/java/org/olat/modules/webFeed/RSSFeed.java b/src/main/java/org/olat/modules/webFeed/RSSFeed.java index 51ffebf3b10154f822480deeb3ee58c13c8b1b36..8543685708ac14b22842c960d0a44194c9afc45a 100644 --- a/src/main/java/org/olat/modules/webFeed/RSSFeed.java +++ b/src/main/java/org/olat/modules/webFeed/RSSFeed.java @@ -69,7 +69,8 @@ public class RSSFeed extends SyndFeedImpl { strippedDescription = strippedDescription == null? "": strippedDescription; strippedDescription = strippedDescription.replaceAll(" ", " "); setDescription(strippedDescription); - setLink(helper.getJumpInLink(feed, null)); + String link = helper.getJumpInLink(feed, null); + setLink(link); setPublishedDate(feed.getLastModified()); // The image diff --git a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java index acbd3f58fff4b811991829a1328d84f74a1153e6..81c79718d3c7816f91ed6cd07ce8ba2800347f29 100644 --- a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java +++ b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java @@ -39,6 +39,7 @@ import org.olat.core.gui.components.tree.TreeNode; import org.olat.core.gui.control.Event; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.ServletUtil; +import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.id.IdentityEnvironment; import org.olat.core.id.OLATResourceable; @@ -54,7 +55,7 @@ import org.olat.core.util.vfs.VFSMediaResource; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.nodeaccess.NodeAccessService; -import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.feed.blog.BlogToolController; import org.olat.course.run.userview.AccessibleFilter; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; @@ -251,10 +252,15 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { } FeedPathKey key = new FeedPathKey(path.getIdentityKey(), ressourceId, path.getNodeId()); - accessible = validatedUriCache.computeIfAbsent(key, k -> { + if (Settings.isDebuging()) { boolean hasAccess = hasAccess(ureq, feed, path); - return Boolean.valueOf(hasAccess); - }); + accessible = Boolean.valueOf(hasAccess); + } else { + accessible = validatedUriCache.computeIfAbsent(key, k -> { + boolean hasAccess = hasAccess(ureq, feed, path); + return Boolean.valueOf(hasAccess); + }); + } return accessible != null && accessible.booleanValue(); } @@ -288,7 +294,10 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { if (feedLight != null) { lastModifiedMillis = feedLight.getLastModified().getTime(); } - if (sinceModifiedMillis >= (lastModifiedMillis / 1000L) * 1000L) { + boolean sendLastModified = Settings.isDebuging() + ? false + : sinceModifiedMillis >= (lastModifiedMillis / 1000L) * 1000L; + if (sendLastModified) { // Send not modified response response.setDateHeader("last-modified", lastModifiedMillis); try { @@ -348,8 +357,7 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { // A course node is being requested ICourse course = CourseFactory.loadCourse(path.getCourseId()); if(course != null) { - CourseNode node = course.getEditorTreeModel().getCourseNode(path.getNodeId()); - hasAccess = hasAccess(ureq, path, course, node, feed); + hasAccess = hasAccess(ureq, path, course, path.getNodeId(), feed); } } else { // A learning resource is being requested @@ -364,11 +372,11 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { * @param identity * @param token * @param course - * @param node + * @param pathNodeId * @return True if the identity has access to the node in the given course. * False otherwise. */ - private boolean hasAccess(UserRequest ureq, Path path, ICourse course, CourseNode node, OLATResourceable feed) { + private boolean hasAccess(UserRequest ureq, Path path, ICourse course, String pathNodeId, OLATResourceable feed) { RepositoryEntry entry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); if (allowsGuestAccess(entry)) { return true; @@ -391,6 +399,9 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { boolean hasAccess = false; if(identity != null && roles != null && reSecurity != null) { + String courseNodeId = BlogToolController.SUBSCRIPTION_SUBIDENTIFIER.equals(pathNodeId) + ? course.getRunStructure().getRootNode().getIdent() + : pathNodeId; IdentityEnvironment ienv = new IdentityEnvironment(identity, roles); UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment(), null, null, null, null, reSecurity.isCourseCoach() || reSecurity.isGroupCoach(), reSecurity.isEntryAdmin(), reSecurity.isCourseParticipant() || reSecurity.isGroupParticipant(), @@ -400,7 +411,7 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener { TreeNode treeNode = nodeAccessService.getCourseTreeModelBuilder(userCourseEnv) .withFilter(AccessibleFilter.create()) .build() - .getNodeById(node.getIdent()); + .getNodeById(courseNodeId); if (treeNode != null && treeNode.isAccessible()) { hasAccess = true; } diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java b/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java index 04b5c7ef34d6759146195cd75d16424e40091510..aeff7e57b5c3aa097818e5f04e3d923d519204eb 100644 --- a/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java +++ b/src/main/java/org/olat/modules/webFeed/manager/FeedNotificationsHandler.java @@ -24,6 +24,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import org.apache.logging.log4j.Logger; import org.olat.core.commons.services.commentAndRating.CommentAndRatingService; import org.olat.core.commons.services.commentAndRating.model.UserComment; import org.olat.core.commons.services.notifications.NotificationsHandler; @@ -37,7 +38,6 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.gui.util.CSSHelper; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.BusinessControlFactory; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; @@ -45,6 +45,7 @@ import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.feed.blog.BlogToolController; import org.olat.modules.webFeed.Feed; import org.olat.modules.webFeed.Item; import org.olat.modules.webFeed.ui.FeedMainController; @@ -96,7 +97,7 @@ public abstract class FeedNotificationsHandler implements NotificationsHandler { if("CourseModule".equals(p.getResName())) { ICourse course = CourseFactory.loadCourse(re); CourseNode node = course.getRunStructure().getNode(p.getSubidentifier()); - if(node == null) { + if(node == null && !BlogToolController.SUBSCRIPTION_SUBIDENTIFIER.equals(p.getSubidentifier())) { notificationsManager.deactivate(p); return notificationsManager.getNoSubscriptionInfo(); } diff --git a/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java b/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java index 7a614c4b3a2295258fc05e676fdc5039ce7ca1ae..963191a90b44db1dcb7be88f14f168691998006e 100644 --- a/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java +++ b/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java @@ -50,6 +50,7 @@ public enum RepositoryEntryManagedFlag { participantList(settings, all), participantInfo(settings, all), email(settings, all), + blog(settings, all), forum(settings, all), documents(settings, all), chat(settings,all),