From 2b701d0ca28b19215623ee550e4dd906174ad887 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 3 Aug 2016 21:47:32 +0200
Subject: [PATCH] OO-2057: implement extension of the period where a binder is
 editable by overriding begin / end dates

---
 .../portfolio/BinderSecurityCallback.java     |   4 +-
 .../BinderSecurityCallbackFactory.java        |  32 ++++-
 .../org/olat/modules/portfolio/Section.java   |   4 +
 .../olat/modules/portfolio/SectionStatus.java |  14 ++
 .../modules/portfolio/manager/BinderDAO.java  |   8 +-
 .../modules/portfolio/model/SectionImpl.java  |  17 +++
 .../ui/AbstractPageListController.java        |  73 +++++++++-
 .../ui/BinderAssessmentController.java        |  10 +-
 .../ui/BinderPageListController.java          |  11 +-
 .../ui/SectionDatesEditController.java        | 127 ++++++++++++++++++
 .../ui/TableOfContentController.java          | 117 +++++++++++++---
 .../portfolio/ui/_content/page_meta.html      |   2 +-
 .../portfolio/ui/_content/page_row.html       |  13 +-
 .../ui/_i18n/LocalStrings_de.properties       | 100 +++++++-------
 .../ui/_i18n/LocalStrings_en.properties       | 103 +++++++-------
 .../modules/portfolio/ui/model/PageRow.java   |  18 +++
 .../database/mysql/alter_10_x_0_to_11_0_0.sql |   1 +
 .../database/mysql/setupDatabase.sql          |   1 +
 .../oracle/alter_10_x_0_to_11_0_0.sql         |   1 +
 .../database/oracle/setupDatabase.sql         |   1 +
 .../postgresql/alter_10_x_0_to_11_0_0.sql     |   1 +
 .../database/postgresql/setupDatabase.sql     |   1 +
 22 files changed, 511 insertions(+), 148 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/portfolio/ui/SectionDatesEditController.java

diff --git a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java
index 06b37fda24a..55a230ea575 100644
--- a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java
+++ b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallback.java
@@ -47,8 +47,10 @@ public interface BinderSecurityCallback {
 	
 	public boolean canSectionBeginAndEnd();
 	
+	public boolean canCloseSection(Section section);
 	
-	public boolean canAddPage();
+	
+	public boolean canAddPage(Section section);
 	
 	public boolean canEditPage(Page page);
 	
diff --git a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java
index f5e4c177785..a7799c81d8a 100644
--- a/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java
+++ b/src/main/java/org/olat/modules/portfolio/BinderSecurityCallbackFactory.java
@@ -203,6 +203,19 @@ public class BinderSecurityCallbackFactory {
 			return owner && !task;
 		}
 
+		@Override
+		public boolean canCloseSection(Section section) {
+			if(task && rights != null) {
+				for(AccessRights right:rights) {
+					if(PortfolioRoles.coach.equals(right.getRole())
+							&& right.matchElementAndAncestors(section)) {
+						return true;
+					}
+				}
+			}
+			return false;
+		}
+
 		@Override
 		public boolean canSectionBeginAndEnd() {
 			return false;
@@ -219,8 +232,16 @@ public class BinderSecurityCallbackFactory {
 		}
 
 		@Override
-		public boolean canAddPage() {
-			return owner;
+		public boolean canAddPage(Section section) {
+			if(section == null) {
+				return owner;
+			}
+			if(owner) {
+				return section != null
+						&& !SectionStatus.isClosed(section)
+						&& section.getSectionStatus() != SectionStatus.submitted;
+			}
+			return false;
 		}
 
 		/**
@@ -402,6 +423,11 @@ public class BinderSecurityCallbackFactory {
 			return false;
 		}
 
+		@Override
+		public boolean canCloseSection(Section section) {
+			return false;
+		}
+
 		@Override
 		public boolean canSectionBeginAndEnd() {
 			return false;
@@ -418,7 +444,7 @@ public class BinderSecurityCallbackFactory {
 		}
 
 		@Override
-		public boolean canAddPage() {
+		public boolean canAddPage(Section section) {
 			return false;
 		}
 
diff --git a/src/main/java/org/olat/modules/portfolio/Section.java b/src/main/java/org/olat/modules/portfolio/Section.java
index 7cb823ea0f8..4c8c25f0e2a 100644
--- a/src/main/java/org/olat/modules/portfolio/Section.java
+++ b/src/main/java/org/olat/modules/portfolio/Section.java
@@ -50,6 +50,10 @@ public interface Section extends SectionRef, PortfolioElement {
 	
 	public void setEndDate(Date date);
 	
+	public boolean isOverrideBeginEndDates();
+	
+	public void setOverrideBeginEndDates(boolean override);
+	
 	public SectionStatus getSectionStatus();
 	
 	/**
diff --git a/src/main/java/org/olat/modules/portfolio/SectionStatus.java b/src/main/java/org/olat/modules/portfolio/SectionStatus.java
index 228be6c74e5..d339862cbea 100644
--- a/src/main/java/org/olat/modules/portfolio/SectionStatus.java
+++ b/src/main/java/org/olat/modules/portfolio/SectionStatus.java
@@ -19,6 +19,8 @@
  */
 package org.olat.modules.portfolio;
 
+import java.util.Date;
+
 /**
  * 
  * Initial date: 23.06.2016<br>
@@ -57,4 +59,16 @@ public enum SectionStatus {
 		}
 		return false;
 	}
+	
+	public static boolean isClosed(Section section) {
+		if(section.getSectionStatus() == SectionStatus.closed) {
+			return true;
+		}
+
+		Date now = new Date();
+		if(section.getEndDate() != null && section.getEndDate().compareTo(now) < 0) {
+			return true;
+		}
+		return false;
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
index 16f92361592..3f42302b5b8 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
@@ -137,8 +137,10 @@ public class BinderDAO {
 				//sync meta-data of section
 				currentSection.setTitle(templateSection.getTitle());
 				currentSection.setDescription(templateSection.getDescription());
-				currentSection.setBeginDate(templateSection.getBeginDate());
-				currentSection.setEndDate(templateSection.getEndDate());
+				if(!currentSection.isOverrideBeginEndDates()) {
+					currentSection.setBeginDate(templateSection.getBeginDate());
+					currentSection.setEndDate(templateSection.getEndDate());
+				}
 				currentSection = dbInstance.getCurrentEntityManager().merge(currentSection);
 				
 				syncAssignments(templateSection, currentSection);
@@ -192,6 +194,7 @@ public class BinderDAO {
 		section.setDescription(templateSection.getDescription());
 		section.setBeginDate(templateSection.getBeginDate());
 		section.setEndDate(templateSection.getEndDate());
+		section.setOverrideBeginEndDates(false);
 		section.setStatus(SectionStatus.notStarted.name());
 		section.setBinder(binder);
 		section.setTemplateReference(templateSection);
@@ -643,6 +646,7 @@ public class BinderDAO {
 		section.setDescription(description);
 		section.setBeginDate(begin);
 		section.setEndDate(end);
+		section.setOverrideBeginEndDates(false);
 		section.setStatus(SectionStatus.notStarted.name());
 		//force load of the list
 		((BinderImpl)binder).getSections().size();
diff --git a/src/main/java/org/olat/modules/portfolio/model/SectionImpl.java b/src/main/java/org/olat/modules/portfolio/model/SectionImpl.java
index a86ee44041e..30cb3ce500c 100644
--- a/src/main/java/org/olat/modules/portfolio/model/SectionImpl.java
+++ b/src/main/java/org/olat/modules/portfolio/model/SectionImpl.java
@@ -93,6 +93,8 @@ public class SectionImpl implements Persistable, ModifiedInfo, CreateInfo, Secti
 	@Temporal(TemporalType.TIMESTAMP)
 	@Column(name="p_end", nullable=true, insertable=true, updatable=true)
 	private Date endDate;
+	@Column(name="p_override_begin_end", nullable=true, insertable=true, updatable=true)
+	private boolean overrideBeginEndDates;
 
 	@ManyToOne(targetEntity=GroupImpl.class,fetch=FetchType.LAZY,optional=false)
 	@JoinColumn(name="fk_group_id", nullable=false, insertable=true, updatable=false)
@@ -197,22 +199,35 @@ public class SectionImpl implements Persistable, ModifiedInfo, CreateInfo, Secti
 		this.status = status;
 	}
 
+	@Override
 	public Date getBeginDate() {
 		return beginDate;
 	}
 
+	@Override
 	public void setBeginDate(Date beginDate) {
 		this.beginDate = beginDate;
 	}
 
+	@Override
 	public Date getEndDate() {
 		return endDate;
 	}
 
+	@Override
 	public void setEndDate(Date endDate) {
 		this.endDate = endDate;
 	}
 
+	public boolean isOverrideBeginEndDates() {
+		return overrideBeginEndDates;
+	}
+
+	public void setOverrideBeginEndDates(boolean overrideBeginEndDates) {
+		this.overrideBeginEndDates = overrideBeginEndDates;
+	}
+
+	@Override
 	public Group getBaseGroup() {
 		return baseGroup;
 	}
@@ -221,6 +236,7 @@ public class SectionImpl implements Persistable, ModifiedInfo, CreateInfo, Secti
 		this.baseGroup = baseGroup;
 	}
 
+	@Override
 	public Binder getBinder() {
 		return binder;
 	}
@@ -229,6 +245,7 @@ public class SectionImpl implements Persistable, ModifiedInfo, CreateInfo, Secti
 		this.binder = binder;
 	}
 
+	@Override
 	public Section getTemplateReference() {
 		return templateReference;
 	}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java
index 72d0d90ff04..145cdd05bc1 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java
@@ -51,6 +51,8 @@ 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.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
@@ -65,6 +67,7 @@ import org.olat.modules.portfolio.Category;
 import org.olat.modules.portfolio.Page;
 import org.olat.modules.portfolio.PortfolioService;
 import org.olat.modules.portfolio.Section;
+import org.olat.modules.portfolio.SectionStatus;
 import org.olat.modules.portfolio.ui.PageListDataModel.PageCols;
 import org.olat.modules.portfolio.ui.component.TimelineElement;
 import org.olat.modules.portfolio.ui.model.PageAssignmentRow;
@@ -92,6 +95,7 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 	private CloseableModalController cmc;
 	private UserCommentsController commentsCtrl;
 	private AssignmentEditController editAssignmentCtrl;
+	private DialogBoxController confirmCloseSectionCtrl, confirmReopenSectionCtrl;
 	
 	protected int counter;
 	protected final boolean withSections;
@@ -205,6 +209,12 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 		if(pageRow.getOpenFormItem() != null) {
 			components.add(pageRow.getOpenFormItem().getComponent());
 		}
+		if(pageRow.getReopenSectionLink() != null) {
+			components.add(pageRow.getReopenSectionLink().getComponent());
+		}
+		if(pageRow.getCloseSectionLink() != null) {
+			components.add(pageRow.getCloseSectionLink().getComponent());
+		}
 		return components;
 	}
 	
@@ -214,7 +224,8 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 			boolean firstOfSection,
 			Map<OLATResourceable,List<Category>> categorizedElementMap, Map<Long,Long> numberOfCommentsMap) {
 
-		PageRow row = new PageRow(page, page.getSection(), assessmentSection, firstOfSection, config.isAssessable());
+		Section section = page.getSection();
+		PageRow row = new PageRow(page, section, assessmentSection, firstOfSection, config.isAssessable());
 		String openLinkId = "open_" + (++counter);
 		FormLink openLink = uifactory.addFormLink(openLinkId, "open.full", "open.full.page", null, flc, Link.BUTTON_SMALL);
 		openLink.setIconRightCSS("o_icon o_icon_start");
@@ -235,9 +246,19 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 			row.setNumOfComments(0);
 		}
 		
+		if(secCallback.canCloseSection(section)) {
+			if(SectionStatus.isClosed(section)) {
+				FormLink reopenLink = uifactory.addFormLink("ropens_" + (++counter), "reopen.section", "reopen.section", null, flc, Link.BUTTON_SMALL);
+				reopenLink.setUserObject(row);
+				row.setReopenSectionLink(reopenLink);
+			} else {
+				FormLink closeLink = uifactory.addFormLink("closes_" + (++counter), "close.section", "close.section", null, flc, Link.BUTTON_SMALL);
+				closeLink.setUserObject(row);
+				row.setCloseSectionLink(closeLink);
+			}
+		}
+		
 		if(secCallback.canComment(page)) {
-			String commentLinkId = "comment_" + (++counter);
-			
 			String title;
 			if(row.getNumOfComments() == 1) {
 				title = translate("comment.one");
@@ -246,7 +267,7 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 			} else {
 				title = translate("comment.zero");
 			}
-			FormLink commentLink = uifactory.addFormLink(commentLinkId, "comment", title, null, flc, Link.LINK | Link.NONTRANSLATED);
+			FormLink commentLink = uifactory.addFormLink("com_" + (++counter), "comment", title, null, flc, Link.LINK | Link.NONTRANSLATED);
 			commentLink.setCustomEnabledLinkCSS("btn btn-sm o_portfolio_comment");
 			commentLink.setUserObject(row);
 			row.setCommentFormLink(commentLink);
@@ -381,6 +402,16 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 			}
 			cmc.deactivate();
 			cleanUp();
+		} else if(confirmCloseSectionCtrl == source) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				PageRow row = (PageRow)confirmCloseSectionCtrl.getUserObject();
+				doClose(ureq, row);
+			}
+		} else if(confirmReopenSectionCtrl == source) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				PageRow row = (PageRow)confirmReopenSectionCtrl.getUserObject();
+				doReopen(ureq, row);
+			}	
 		} else if(cmc == source) {
 			cleanUp();
 		}
@@ -416,6 +447,12 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 			} else if("comment".equals(cmd)) {
 				PageRow row = (PageRow)link.getUserObject();
 				doComment(ureq, row.getPage());
+			} else if("close.section".equals(cmd)) {
+				PageRow row = (PageRow)link.getUserObject();
+				doConfirmCloseSection(ureq, row);
+			} else if("reopen.section".equals(cmd)) {
+				PageRow row = (PageRow)link.getUserObject();
+				doConfirmReopenSection(ureq, row);
 			} else if("edit.assignment".equals(cmd)) {
 				PageAssignmentRow row = (PageAssignmentRow)link.getUserObject();
 				doEditAssignment(ureq, row);
@@ -435,6 +472,34 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate {
 		//
 	}
 	
+	private void doConfirmCloseSection(UserRequest ureq, PageRow row) {
+		String title = translate("close.section.confirm.title");
+		String text = translate("close.section.confirm.descr", new String[]{ row.getSectionTitle() });
+		confirmCloseSectionCtrl = activateYesNoDialog(ureq, title, text, confirmCloseSectionCtrl);
+		confirmCloseSectionCtrl.setUserObject(row);
+	}
+	
+	private void doClose(UserRequest ureq, PageRow row) {
+		Section section = row.getSection();
+		section = portfolioService.changeSectionStatus(section, SectionStatus.closed, getIdentity());
+		loadModel(null);
+		fireEvent(ureq, Event.CHANGED_EVENT);
+	}
+	
+	private void doConfirmReopenSection(UserRequest ureq, PageRow row) {
+		String title = translate("reopen.section.confirm.title");
+		String text = translate("reopen.section.confirm.descr", new String[]{ row.getSectionTitle() });
+		confirmReopenSectionCtrl = activateYesNoDialog(ureq, title, text, confirmReopenSectionCtrl);
+		confirmReopenSectionCtrl.setUserObject(row);
+	}
+	
+	private void doReopen(UserRequest ureq, PageRow row) {
+		Section section = row.getSection();
+		section = portfolioService.changeSectionStatus(section, SectionStatus.inProgress, getIdentity());
+		loadModel(null);
+		fireEvent(ureq, Event.CHANGED_EVENT);
+	}
+	
 	private void doSwitchTimelineOn() {
 		timelineSwitchOnButton.setVisible(true);
 		timelineSwitchOffButton.setVisible(false);
diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java
index a63d4ab29ba..30c8ab9c23c 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/BinderAssessmentController.java
@@ -164,8 +164,8 @@ public class BinderAssessmentController extends FormBasicController {
 	private void forgeAssessmentSection(AssessmentSectionWrapper row) {
 		AssessmentSection assessmentSection = row.getAssessmentSection();
 
-		SectionStatus status = row.getSection().getSectionStatus();
-		if(status != SectionStatus.closed) {
+		Section section = row.getSection();
+		if(!SectionStatus.isClosed(section)) {
 			//score
 			String pointVal = null;
 			if(assessmentSection != null && assessmentSection.getScore() != null) {
@@ -186,7 +186,7 @@ public class BinderAssessmentController extends FormBasicController {
 			row.setPassedEl(passedEl);
 		}
 
-		if(status == SectionStatus.closed) {
+		if(SectionStatus.isClosed(section)) {
 			FormLink reopenButton = uifactory.addFormLink("reopen" + (++counter), "reopen", "reopen", null, flc, Link.BUTTON);
 			reopenButton.setUserObject(row);
 			row.setButton(reopenButton);
@@ -227,8 +227,8 @@ public class BinderAssessmentController extends FormBasicController {
 		
 		List<AssessmentSectionChange> changes = new ArrayList<>();
 		for(AssessmentSectionWrapper row:rows) {
-			boolean canAssess = secCallback.canAssess(row.getSection());
-			if(canAssess) {
+			Section section = row.getSection();
+			if(secCallback.canAssess(section) && !SectionStatus.isClosed(section)) {
 				BigDecimal score = null;
 				if(withScore) {
 					String value = row.getScoreEl().getValue();
diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java
index 27f838b4e18..cc007b6e76f 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java
@@ -59,7 +59,6 @@ import org.olat.modules.portfolio.CategoryToElement;
 import org.olat.modules.portfolio.Page;
 import org.olat.modules.portfolio.PortfolioRoles;
 import org.olat.modules.portfolio.Section;
-import org.olat.modules.portfolio.SectionStatus;
 import org.olat.modules.portfolio.ui.PageListDataModel.PageCols;
 import org.olat.modules.portfolio.ui.component.TimelinePoint;
 import org.olat.modules.portfolio.ui.model.PageRow;
@@ -100,7 +99,7 @@ public class BinderPageListController extends AbstractPageListController  {
 
 	@Override
 	public void initTools() {
-		if(secCallback.canAddPage()) {
+		if(secCallback.canAddPage(null)) {
 			newEntryLink = LinkFactory.createToolLink("new.page", translate("create.new.page"), this);
 			newEntryLink.setIconLeftCSS("o_icon o_icon-lg o_icon_new_portfolio");
 			stackPanel.addTool(newEntryLink, Align.right);
@@ -197,9 +196,7 @@ public class BinderPageListController extends AbstractPageListController  {
 			PageRow pageRow = forgeRow(page, sectionToAssessmentSectionMap.get(section), sectionToAssignmentMap.get(section),
 					first, categorizedElementMap, numberOfCommentsMap);
 			rows.add(pageRow);
-			if(secCallback.canAddPage() && section != null
-					&& section.getSectionStatus() != SectionStatus.closed
-					&& section.getSectionStatus() != SectionStatus.submitted) {
+			if(secCallback.canAddPage(section)) {
 				FormLink newEntryButton = uifactory.addFormLink("new.entry." + (++counter), "new.entry", "create.new.page", null, flc, Link.BUTTON);
 				newEntryButton.setCustomEnabledLinkCSS("btn btn-primary");
 				newEntryButton.setUserObject(pageRow);
@@ -233,9 +230,7 @@ public class BinderPageListController extends AbstractPageListController  {
 				PageRow pageRow = forgeRow(section, sectionToAssessmentSectionMap.get(section), sectionToAssignmentMap.get(section),
 						true, categorizedElementMap);
 				rows.add(pageRow);
-				if(secCallback.canAddPage() && section != null
-						&& section.getSectionStatus() != SectionStatus.closed
-						&& section.getSectionStatus() != SectionStatus.submitted) {
+				if(secCallback.canAddPage(section)) {
 					FormLink newEntryButton = uifactory.addFormLink("new.entry." + (++counter), "new.entry", "create.new.page", null, flc, Link.BUTTON);
 					newEntryButton.setCustomEnabledLinkCSS("btn btn-primary");
 					newEntryButton.setUserObject(pageRow);
diff --git a/src/main/java/org/olat/modules/portfolio/ui/SectionDatesEditController.java b/src/main/java/org/olat/modules/portfolio/ui/SectionDatesEditController.java
new file mode 100644
index 00000000000..619966f2ef5
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/SectionDatesEditController.java
@@ -0,0 +1,127 @@
+/**
+ * <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.modules.portfolio.ui;
+
+import java.util.Date;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.DateChooser;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.modules.portfolio.BinderSecurityCallback;
+import org.olat.modules.portfolio.PortfolioService;
+import org.olat.modules.portfolio.Section;
+import org.olat.modules.portfolio.SectionStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 03.08.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SectionDatesEditController extends FormBasicController {
+
+	private DateChooser beginDateEl, endDateEl;
+	
+	private Section section;
+	private Object userObject;
+	private BinderSecurityCallback secCallback;
+	
+	@Autowired
+	private PortfolioService portfolioService;
+	
+	public SectionDatesEditController(UserRequest ureq, WindowControl wControl,
+			Section section, BinderSecurityCallback secCallback) {
+		super(ureq, wControl);
+		this.section = section;
+		this.secCallback = secCallback;
+		initForm(ureq);
+	}
+	
+	public Section getSection() {
+		return section;
+	}
+
+	public Object getUserObject() {
+		return userObject;
+	}
+
+	public void setUserObject(Object userObject) {
+		this.userObject = userObject;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		uifactory.addStaticTextElement("title", "title", section.getTitle(), formLayout);
+
+		beginDateEl = uifactory.addDateChooser("begin.date", "begin.date", section.getBeginDate(), formLayout);
+		
+		endDateEl = uifactory.addDateChooser("end.date", "end.date", section.getEndDate(), formLayout);
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		buttonsCont.setRootForm(mainForm);
+		formLayout.add(buttonsCont);
+		if(section != null && section.getKey() != null) {
+			uifactory.addFormSubmitButton("save", buttonsCont);
+		} else {
+			uifactory.addFormSubmitButton("create.section", buttonsCont);
+		}
+		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		
+		return allOk & super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		Section reloadedSection = portfolioService.getSection(section);
+		reloadedSection.setOverrideBeginEndDates(true);
+		reloadedSection.setBeginDate(beginDateEl.getDate());
+		reloadedSection.setEndDate(endDateEl.getDate());
+		section = portfolioService.updateSection(reloadedSection);
+		if(section.getSectionStatus() == SectionStatus.closed
+				&& section.getEndDate() != null
+				&& section.getEndDate().compareTo(new Date()) >= 0) {
+			portfolioService.changeSectionStatus(section, SectionStatus.inProgress, getIdentity());
+		}
+		
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
index eb2ec769725..a88de2b1483 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
@@ -40,6 +40,8 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
@@ -78,7 +80,9 @@ public class TableOfContentController extends BasicController implements TooledC
 	private CloseableModalController cmc;
 	private SectionEditController newSectionCtrl;
 	private SectionEditController editSectionCtrl;
+	private SectionDatesEditController editSectionDatesCtrl;
 	private BinderMetadataEditController binderMetadataCtrl;
+	private DialogBoxController confirmCloseSectionCtrl, confirmReopenSectionCtrl;
 	
 	private PageRunController pageCtrl;
 	private PageMetadataEditController newPageCtrl;
@@ -133,7 +137,7 @@ public class TableOfContentController extends BasicController implements TooledC
 			newSectionButton.setCustomEnabledLinkCSS("btn btn-primary");
 		}
 		
-		if(secCallback.canAddPage()) {
+		if(secCallback.canAddPage(null)) {
 			newEntryLink = LinkFactory.createToolLink("new.page", translate("create.new.page"), this);
 			newEntryLink.setIconLeftCSS("o_icon o_icon-lg o_icon_new_portfolio");
 			stackPanel.addTool(newEntryLink, Align.right);
@@ -179,13 +183,30 @@ public class TableOfContentController extends BasicController implements TooledC
 		SectionRow sectionRow = new SectionRow(section, sectionLink, assessmentSection);
 		sectionLink.setUserObject(sectionRow);
 		
-		if(secCallback.canEditSection()) {
-			Dropdown editDropdown = new Dropdown(sectionId.concat("_down"), null, false, getTranslator());
-			editDropdown.setTranslatedLabel("");
-			editDropdown.setOrientation(DropdownOrientation.right);
-			editDropdown.setIconCSS("o_icon o_icon_actions");
-			mainVC.put(editDropdown.getComponentName(), editDropdown);
+		Dropdown editDropdown = new Dropdown(sectionId.concat("_down"), null, false, getTranslator());
+		editDropdown.setTranslatedLabel("");
+		editDropdown.setOrientation(DropdownOrientation.right);
+		editDropdown.setIconCSS("o_icon o_icon_actions");
+		
+		if(secCallback.canCloseSection(section)) {
+			if(SectionStatus.isClosed(section)) {
+				Link reopenLink = LinkFactory.createLink(sectionId.concat("_ropens"), "reopen.section", "reopen.section", mainVC, this);
+				reopenLink.setUserObject(sectionRow);
+				editDropdown.addComponent(reopenLink);
+			} else {
+				Link closeLink = LinkFactory.createLink(sectionId.concat("_closes"), "close.section", "close.section", mainVC, this);
+				closeLink.setUserObject(sectionRow);
+				editDropdown.addComponent(closeLink);
+			}
+			
+			if(section.getEndDate() != null) {
+				Link overrideDatesLink = LinkFactory.createLink(sectionId.concat("_overd"), "override.dates.section", "override.dates.section", mainVC, this);
+				overrideDatesLink.setUserObject(sectionRow);
+				editDropdown.addComponent(overrideDatesLink);
+			}
+		}
 		
+		if(secCallback.canEditSection()) {
 			Link editSectionLink = LinkFactory.createLink(sectionId.concat("_edit"), "section.edit", "edit_section", mainVC, this);
 			editSectionLink.setIconLeftCSS("o_icon o_icon_edit");
 			editDropdown.addComponent(editSectionLink);
@@ -193,11 +214,15 @@ public class TableOfContentController extends BasicController implements TooledC
 			deleteSectionLink.setIconLeftCSS("o_icon o_icon_delete_item");
 			editDropdown.addComponent(deleteSectionLink);
 			
-			sectionRow.setEditDropdown(editDropdown);
 			editSectionLink.setUserObject(sectionRow);
 			deleteSectionLink.setUserObject(sectionRow);
 		}
 		
+		if(editDropdown.getComponents().iterator().hasNext()) {
+			mainVC.put(editDropdown.getComponentName(), editDropdown);
+			sectionRow.setEditDropdown(editDropdown);
+		}
+		
 		return sectionRow;
 	}
 	
@@ -246,44 +271,48 @@ public class TableOfContentController extends BasicController implements TooledC
 
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
-		if(newSectionCtrl == source) {
+		if(newSectionCtrl == source || editSectionCtrl == source 
+				|| editSectionDatesCtrl == source || newPageCtrl == source) {
 			if(event == Event.DONE_EVENT) {
 				loadModel();
 				fireEvent(ureq, Event.CHANGED_EVENT);
 			}
 			cmc.deactivate();
 			cleanUp();
-		} else if(editSectionCtrl == source) {
+		} else if(binderMetadataCtrl == source) {
 			if(event == Event.DONE_EVENT) {
+				binder = binderMetadataCtrl.getBinder();
 				loadModel();
-				fireEvent(ureq, Event.CHANGED_EVENT);
 			}
 			cmc.deactivate();
 			cleanUp();
-		} else if(newPageCtrl == source) {
-			if(event == Event.DONE_EVENT) {
+		} else if(confirmCloseSectionCtrl == source) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				SectionRow row = (SectionRow)confirmCloseSectionCtrl.getUserObject();
+				doClose(row);
 				loadModel();
+				fireEvent(ureq, Event.CHANGED_EVENT);
 			}
-			cmc.deactivate();
-			cleanUp();
-		} else if(binderMetadataCtrl == source) {
-			if(event == Event.DONE_EVENT) {
-				binder = binderMetadataCtrl.getBinder();
+		} else if(confirmReopenSectionCtrl == source) {
+			if(DialogBoxUIFactory.isYesEvent(event)) {
+				SectionRow row = (SectionRow)confirmReopenSectionCtrl.getUserObject();
+				doReopen(row);
 				loadModel();
-			}
-			cmc.deactivate();
-			cleanUp();
+				fireEvent(ureq, Event.CHANGED_EVENT);
+			}	
 		} else if(cmc == source) {
 			cleanUp();
 		}
 	}
 	
 	private void cleanUp() {
+		removeAsListenerAndDispose(editSectionDatesCtrl);
 		removeAsListenerAndDispose(binderMetadataCtrl);
 		removeAsListenerAndDispose(editSectionCtrl);
 		removeAsListenerAndDispose(newSectionCtrl);
 		removeAsListenerAndDispose(newPageCtrl);
 		removeAsListenerAndDispose(cmc);
+		editSectionDatesCtrl = null;
 		binderMetadataCtrl = null;
 		editSectionCtrl = null;
 		newSectionCtrl = null;
@@ -311,6 +340,15 @@ public class TableOfContentController extends BasicController implements TooledC
 			} else if("open_page".equals(cmd)) {
 				PageRow row = (PageRow)link.getUserObject();
 				doOpenPage(ureq, row.getPage());
+			} else if("reopen.section".equals(cmd)) {
+				SectionRow row = (SectionRow)link.getUserObject();
+				doConfirmReopenSection(ureq, row);
+			} else if("close.section".equals(cmd)) {
+				SectionRow row = (SectionRow)link.getUserObject();
+				doConfirmCloseSection(ureq, row);
+			} else if("override.dates.section".equals(cmd)) {
+				SectionRow row = (SectionRow)link.getUserObject();
+				doOverrideDatesSection(ureq, row);
 			}
 		}
 	}
@@ -381,6 +419,43 @@ public class TableOfContentController extends BasicController implements TooledC
 		cmc.activate();
 	}
 	
+	private void doOverrideDatesSection(UserRequest ureq, SectionRow sectionRow) {
+		if(editSectionDatesCtrl != null) return;
+		
+		editSectionDatesCtrl = new SectionDatesEditController(ureq, getWindowControl(), sectionRow.getSection(), secCallback);
+		editSectionDatesCtrl.setUserObject(sectionRow);
+		listenTo(editSectionDatesCtrl);
+		
+		String title = translate("override.dates.section");
+		cmc = new CloseableModalController(getWindowControl(), null, editSectionDatesCtrl.getInitialComponent(), true, title, true);
+		listenTo(cmc);
+		cmc.activate();
+	}
+	
+	private void doConfirmCloseSection(UserRequest ureq, SectionRow row) {
+		String title = translate("close.section.confirm.title");
+		String text = translate("close.section.confirm.descr", new String[]{ row.getTitle() });
+		confirmCloseSectionCtrl = activateYesNoDialog(ureq, title, text, confirmCloseSectionCtrl);
+		confirmCloseSectionCtrl.setUserObject(row);
+	}
+	
+	private void doClose(SectionRow row) {
+		Section section = row.getSection();
+		section = portfolioService.changeSectionStatus(section, SectionStatus.closed, getIdentity());
+	}
+	
+	private void doConfirmReopenSection(UserRequest ureq, SectionRow row) {
+		String title = translate("reopen.section.confirm.title");
+		String text = translate("reopen.section.confirm.descr", new String[]{ row.getTitle() });
+		confirmReopenSectionCtrl = activateYesNoDialog(ureq, title, text, confirmReopenSectionCtrl);
+		confirmReopenSectionCtrl.setUserObject(row);
+	}
+	
+	private void doReopen(SectionRow row) {
+		Section section = row.getSection();
+		section = portfolioService.changeSectionStatus(section, SectionStatus.inProgress, getIdentity());
+	}
+	
 	public class SectionRow {
 		
 		private final Section section;
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html
index 7d528f5ce71..1769a5f5e50 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html
@@ -74,7 +74,7 @@
 		</div>
 	#end
 	#if($statusEnabled)
-	<div class="o_block">
+	<div class="o_portfolio_status_block o_block">
 		$r.translate("page.status"): $pageStatus
 		
 		#if($r.available("publish"))
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html
index 634810b88ad..07fe63fed5c 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html
@@ -3,8 +3,6 @@
 	<h3>$r.escapeHtml($row.sectionLongTitle) <small><i class="o_icon $row.sectionCssClassStatus"> </i></small></h3>
 	<div class="o_portfolio_section_meta">
 		<div class="clearfix">
-			<span><strong>$r.translate("section.status"): </strong> $r.translate(${row.getSectionStatusI18nKey()})</span>
-
 			#if($r.notNull($row.sectionBeginDate))
 				<span><strong>$r.translate("begin.date"): </strong> $r.formatDate($row.sectionBeginDate)</span>
 			#end
@@ -30,6 +28,17 @@
 			</div>
 		</div>
 		#end
+		
+		<div class="o_portfolio_status_block o_block">
+			<span><strong>$r.translate("section.status"): </strong> $r.translate(${row.getSectionStatusI18nKey()})</span>
+
+			#if($r.isNotNull($row.closeSectionLink))
+				$r.render($row.closeSectionLink)
+			#end
+			#if($r.isNotNull($row.reopenSectionLink))
+				$r.render($row.reopenSectionLink)
+			#end
+		</div>
 	</div>
 	
 	#if($r.isNotNull($row.newEntryLink))
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
index d44c430a079..0233c658993 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
@@ -1,4 +1,4 @@
-#Mon Jul 11 14:16:13 CEST 2016
+#Wed Aug 03 18:07:07 CEST 2016
 access=Zugang
 access.rights=Zugangsrecht hinzuf\u00FCgen
 access.rights.coach=Betreuer
@@ -18,8 +18,8 @@ add.image=Bild hinzuf\u00FCgen
 add.invitation=Einladung hinzuf\u00FCgen
 add.media=Media hinzuf\u00FCgen
 add.member=Mitglied hinzuf\u00FCgen
-add.video=Video hinzuf\u00FCgen
 add.text=Text hinzuf\u00FCgen
+add.video=Video hinzuf\u00FCgen
 artefact.EfficiencyStatement=Leistungnachweis
 artefact.FileResource.BLOG=Blog Eintrag
 artefact.FileResource.WIKI=Wikiseite
@@ -36,13 +36,13 @@ artefact.text=Text
 artefact.title=Titel
 artefact.video=Video
 assignment=Aufgabe
-assignment.title=Titel
-assignment.summary=Zusammenfassung
 assignment.content=Aufgabe
+assignment.document.upload=Dokument
+assignment.summary=Zusammenfassung
+assignment.title=Titel
 assignment.type=Typ
-assignment.type.essay=Freitext
 assignment.type.document=Dokument
-assignment.document.upload=Dokument
+assignment.type.essay=Freitext
 author=Autor
 begin.date=Beginn
 binder.by=von {0}
@@ -55,17 +55,14 @@ binder.title=Portfolio Mappe {0}
 categories=Kategorien
 categories.hint=Kategorien Hinweis
 changes.since=\u00C4nderungen seit
-close=Schliessen
 citation=Zitate
-edition=Edition
-volume=Buchband
-series=Folge
-publication.title=Veröffentlichungstitel
-revision.page=Überarbeiten
+close=Schliessen
+close.confirm.descr=Wollen Sie diesen Eintrag "{0}" schliessen?
+close.confirm.title=Schliessen
 close.page=Schliessen
-issue=Ausgabe
-pages=Seite
-institution=Institution
+close.section=Schliessen
+close.section.confirm.descr=Wollen Sie diesen Bereich "{0}" mit alle Eintr\u00E4ge schliessen?
+close.section.confirm.title=Bereich schliessen
 command.openassessment=Bewertungswerkzeug
 comment.one=1 Kommentar
 comment.several={0} Kommentare
@@ -76,8 +73,8 @@ create.empty.binder=Leere Mappe erstellen
 create.empty.binder.from.course=Mappe f\u00FCr Portfolioaufgabe aus Kurs erstellen
 create.empty.binder.from.template=Mappe basierend auf Vorlage erstellen
 create.new.assignment=Neue Aufgabe
-create.new.assignment.title=Neue Aufgabe erstellen
 create.new.assignment.descr=Neue Aufgabe erlaubt ...
+create.new.assignment.title=Neue Aufgabe erstellen
 create.new.binder=Neue Mappe erstellen
 create.new.binder.descr=Erstellen Sie eine portfolio Mappe um Ihre Eintr\u00E4ge zu strukturieren und zu organisieren und um diese f\u00FCr andere Benutzer zwecks Kommentieren und Bewerten freizugeben.
 create.new.binder.title=Neue Mappe erstellen
@@ -91,8 +88,8 @@ create.page=Neuer Beitrag erstellen
 create.section=Bereich hinzuf\u00FCgen
 create.start.assignment=Neuen Eintrag als Aufgabe erstellen
 creators=Ersteller
-deleted.pages.breadcrump=Papierkorb
 deleted.entries=Papierkorb
+deleted.pages.breadcrump=Papierkorb
 edit.access.rights=Zugangsrechte bearbeiten
 edit.assignment=Aufgabe bearbeiten
 edit.binder.metadata=Metadaten bearbeiten
@@ -100,15 +97,14 @@ edit.last.binder=Letzte benutzte Sammelmappe \u00F6ffnen
 edit.last.entry=Letzte Eintrag bearbeiten
 edit.page=Eintrag bearbeiten
 edit.page.metadata=Metadaten bearbeiten
+edition=Edition
 end.date=Enddatum
-used.in=Verwendet in
+error.invalid.type=Diese Dateityp ist nicht unters\u00FCtzt.
 error.invitation.mail.used=Diese E-Mailadresse wird bereits von einem OpenOLAT-Benutzer verwendet.
 error.mail.invalid=Bitte geben Sie eine g\u00FCltige E-Mailadresse an.
-error.invalid.type=Diese Dateityp ist nicht unters\u00FCtzt.
 fileupload=Titelbild
 filter.show.all=Alle anzeigen
 firstName=Vorname
-reopen.page=Neu eröffnen
 go.to.trash=Go to trash
 goto.media.center=Mediencenter \u00F6ffnen
 goto.my.binders=zu meinen Mappen
@@ -119,11 +115,14 @@ image.align=Richtung
 image.align.background=Als hintergrund Bild benutzen
 image.align.right=Rechts von Zusammenfassung 
 import.artefactV1=Artefakte importieren
+institution=Institution
 invitation.link=Link
 invitation.mail.body=Sie wurden von {1} eingeladen, eine Sammelmappe in OLAT zu betrachten. Sie finden diese unter folgender Adresse\: {0}
 invitation.mail.failure=Fehler beim Versenden der E-Mail. Die eingeladenen Personen konnten nicht per E-Mail benachrichtigt werden. Versuchen Sie es sp\u00E4ter noch einmal oder kontaktieren Sie den Support.
 invitation.mail.subject=Einladung zu einer freigegebenen Sammelmappe
 invitation.mail.success=Die eingeladenen Personen wurden erfolgreich per E-Mail benachrichtigt.
+issue=Ausgabe
+language=Language
 lastName=Name
 mail=Mail
 map.available=$org.olat.course.nodes.portfolio\:map.available
@@ -146,21 +145,19 @@ meta.page.assignment=Hier ist ein Aufgabe
 meta.page.assignment.type=Typ
 meta.section.assignments=<strong>Aufgabe</strong> in diesem Bereich
 meta.section.categories=<strong>Kategorien</strong> in diesem Bereich
-
-mf.sourceType=Typ
 mf.edition=Edition
-mf.volume=Volume
-mf.series=Serien
-mf.publicationTitle=Publication title
+mf.institution=Institution
 mf.issue=Issue
 mf.pages=Pages
-mf.institution=Institution
+mf.publicationTitle=Publication title
+mf.series=Serien
+mf.sourceType=Typ
 mf.sourceType.book=Buch
-mf.sourceType.report=Report
 mf.sourceType.film=Film
 mf.sourceType.journalArticle=Artikel
+mf.sourceType.report=Report
 mf.sourceType.webpage=Webauftritt
-
+mf.volume=Volume
 my.entries=Meine Beitr\u00E4ge
 my.entries.text=Liste aller Beitr\u00E4ge in chronologischer Reihenfolge unabh\u00E4ngig von ihrem Kontext. Dies ist das Herzst\u00FCck Ihrer Portfolioarbeit.
 my.portfolio.binders=Meine Portfolio Mappen
@@ -172,29 +169,28 @@ my.shared.items.text=Die Liste aller Eintr\u00E4ge, die Sie an andere Benutzer f
 new.entry=Neue Eintrag erstellen
 new.section.desc=Beschreibung des Bereiches
 new.section.title=Bereich
-no.map=$org.olat.course.nodes.portfolio\:no.map
 no.binders.template.available=Es steht kein Kursvorlage zu Verf\u00FCgung.
+no.map=$org.olat.course.nodes.portfolio\:no.map
 not.implemented=Nicht implementiert
-notifications.new.comment=Neuer Kommentar zu '{0}' von {1}
 notifications.modified.page=Es wurde eine Seite '{0}' ge\u00E4ndert
 notifications.modified.section=Es wurde ein Bereich '{0}' ge\u00E4ndert
+notifications.new.comment=Neuer Kommentar zu '{0}' von {1}
 notifications.new.page=Es wurde eine neue Seite '{0}' hinzugef\u00FCgt
 notifications.new.section=Neues Bereich '{0}' hinzugef\u00FCgt
 open=\u00D6ffnen
 open.full.page=Den ganzen Eintrag lesen
 open.map=$org.olat.course.nodes.portfolio\:open.map
+override.dates.section=Verl\u00E4ngern
 page.binders=Mappe
 page.sections=Sektion
+page.status=Status
 page.summary=$\:summary
 page.title=$\:title
+pages=Seite
 passed.false=$org.olat.course.assessment\:passed.false
 passed.true=$org.olat.course.assessment\:passed.true
 passed.yourpassed=$org.olat.course.assessment\:passed.yourpassed
 place=Ort
-publisher=Herausgeber
-url=URL
-source=Quelle
-language=Language
 portfolio.assessment=Bewertung
 portfolio.entries=Eintr\u00E4ge
 portfolio.history=\u00C4nderungsprotokoll
@@ -205,47 +201,48 @@ portfolio.publish=Freigabe
 portfolio.root.breadcrump=Portfolio
 portfoliotask=Portfolioaufgabe
 portfoliotask.none=Keine
+publication.title=Ver\u00F6ffentlichungstitel
 publish=Eintrag publizieren
 publish.confirm.descr=Wollen Sie diesen Eintrag "{0}" publizieren?
 publish.confirm.title=Publizieren
-
-close.confirm.descr=Wollen Sie diesen Eintrag "{0}" schliessen?
-close.confirm.title=Schliessen
-
-reopen.confirm.title=Eröffnen
-reopen.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu eröffnen? das wird den Bereich auch eröffnen.
-
-
-revision.confirm.title=Überarbeiten
-revision.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu überarbeiten lassen?
-
 publish.status.title=Freigabe Status der Mappe "{0}"
+publisher=Herausgeber
 quick.links=Schnell Zugriff
 remove=Entfernen
 reopen=Neu \u00F6ffnen
+reopen.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu er\u00F6ffnen? das wird den Bereich auch er\u00F6ffnen.
+reopen.confirm.title=Er\u00F6ffnen
+reopen.page=Neu er\u00F6ffnen
+reopen.section=Neu er\u00F6ffnen
+reopen.section.confirm.descr=Wollen Sie diesen Bereich "{0}" neu er\u00F6ffnen?
+reopen.section.confirm.title=Bereich er\u00F6ffnen
+revision.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu \u00FCberarbeiten lassen?
+revision.confirm.title=\u00DCberarbeiten
+revision.page=\u00DCberarbeiten
 section.delete=Bereich l\u00F6schen
 section.edit=Bereich bearbeiten
-section.paging.previous=Letzte Bereich
+section.paging.all=Alle Eintr\u00E4ge zeigen
 section.paging.next=N\u00E4chste Bereich
-section.paging.with.title=Zum Bereich "{0}"
 section.paging.one=Ein Bereich
-section.paging.all=Alle Eintr\u00E4ge zeigen
+section.paging.previous=Letzte Bereich
+section.paging.with.title=Zum Bereich "{0}"
 section.score=Punkte
 section.status=Status
 section.title=Bereich {0}
 select.mymap=$org.olat.course.nodes.portfolio\:select.mymap
+series=Folge
 shared.with.me=Mit mir geteilt
 shared.with.me.text=Liste aller Mappen, die von anderen Benutzern an mich freigegeben wurden.
+source=Quelle
 status.closed=geschlossen
 status.deleted=gel\u00F6scht
 status.draft=draft
 status.in.progress=in Bearbeitung
 status.in.revision=In revision
-status.inRevision=$:status.in.revision
+status.inRevision=$\:status.in.revision
 status.not.started=nicht gestartet
 status.published=publiziert
 status.submitted=abgegeben
-page.status=Status
 summary=Zusammenfassung
 summary.placeholder=Kurze Zusammenfassung \u00FCber den Inhalt
 table.grading.failed.points=<span class\="o_state o_failed"><i class\="o_icon o_icon_failed"> </i> {0} Punkt(e)</span>
@@ -278,6 +275,9 @@ template.none=Keines
 timeline.switch.off=Timeline
 timeline.switch.on=Timeline
 title=Titel
+url=URL
+used.in=Verwendet in
+volume=Buchband
 warning.binder.synched=Die Portfolio Mappe wurde mit seiner Vorlage synchroniziert.
 warning.portfolio.not.found=Die Portfolio Mappe konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00F6scht.
 warning.template.in.use=Die Vorlage konnte nicht gel\u00F6scht werden weil einige Benutzer es nutzt.
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
index ca0d3a9a07a..0de04ae8b68 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
@@ -1,4 +1,4 @@
-#Mon Jul 11 14:15:59 CEST 2016
+#Wed Aug 03 18:07:31 CEST 2016
 access=Access
 access.rights=Add access rights
 access.rights.coach=Coach
@@ -36,13 +36,13 @@ artefact.text=Text
 artefact.title=Title
 artefact.video=Video
 assignment=Assignment
-assignment.title=Title
-assignment.summary=Summary
 assignment.content=Assignment
+assignment.document.upload=Document
+assignment.summary=Summary
+assignment.title=Title
 assignment.type=Type
-assignment.type.essay=Essay
 assignment.type.document=Document
-assignment.document.upload=Document
+assignment.type.essay=Essay
 author=Author
 begin.date=Begin
 binder.by=by {0}
@@ -55,21 +55,26 @@ binder.title=Portfolio binder {0}
 categories=Categories
 categories.hint=Categories hint
 changes.since=Changes
-close=Close
 citation=Citation
+close=Close
+close.confirm.descr=Do you want to close this entry "{0}"?
+close.confirm.title=Close
+close.page=Close
+close.section=Close
+close.section.confirm.descr=Do you want to close this section "{0}" with all the entries?
+close.section.confirm.title=Close
 command.openassessment=Assessment tool
 comment.one=1 comment
 comment.several={0} comments
 comment.title=Comments
 comment.zero=Still no comments
-reopen.page=Reopen
 create.binder=Create binder
-create.new.assignment=New assignment
-create.new.assignment.title=Create a new assignment
-create.new.assignment.descr=Create a new assignment to assign something to someone
 create.empty.binder=New empty binder
 create.empty.binder.from.course=New binder from course portfolio task
 create.empty.binder.from.template=New binder from template
+create.new.assignment=New assignment
+create.new.assignment.descr=Create a new assignment to assign something to someone
+create.new.assignment.title=Create a new assignment
 create.new.binder=Create new binder
 create.new.binder.descr=Create a new portfolio binder to structure and organize your portfolio entries and make them accessible to other user for commenting and grading.
 create.new.binder.title=Create a new binder
@@ -83,9 +88,8 @@ create.page=Create entry
 create.section=Create section
 create.start.assignment=Create new entry for assignments
 creators=Creators
-deleted.pages.breadcrump=Trash
 deleted.entries=Trash
-page.status=Status
+deleted.pages.breadcrump=Trash
 edit.access.rights=Edit access rights
 edit.assignment=Edit assignment
 edit.binder.metadata=Edit metadata
@@ -93,19 +97,11 @@ edit.last.binder=Edit last used binder
 edit.last.entry=Edit last entry
 edit.page=Edit entry
 edit.page.metadata=Edit metadata
-end.date=End
 edition=Edition
-volume=Volume
-revision.page=Revision
-close.page=Close
-publication.title=Publication title
-series=Series
-issue=Issue
-pages=Pages
-institution=Institution
+end.date=End
+error.invalid.type=This file type is not supported.
 error.invitation.mail.used=This e-mail address is already used by an OpenOLAT user.
 error.mail.invalid=Please provide a valid e-mail address.
-error.invalid.type=This file type is not supported.
 fileupload=Teaser Image
 filter.show.all=Show all
 firstName=First name
@@ -119,12 +115,14 @@ image.align=Align
 image.align.background=Use as full-scale background image
 image.align.right=Embed image in summary on right side
 import.artefactV1=Import artefacts
-used.in=Used in
+institution=Institution
 invitation.link=Link
 invitation.mail.body=You have been invited by {1} to have a look at a binder in OpenOLAT. Please go to\: {0}
 invitation.mail.failure=Error while sending your e-mail. The persons invited could not be notified. Please try again later or contact your support team.
 invitation.mail.subject=Invitation to a binder already released
 invitation.mail.success=The persons invited have been notified successfully via e-mail.
+issue=Issue
+language=Sprache
 lastName=Last name
 mail=E-Mail
 map.available=$org.olat.course.nodes.portfolio\:map.available
@@ -147,21 +145,19 @@ meta.page.assignment=This is an assignment
 meta.page.assignment.type=Type
 meta.section.assignments=<strong>Assignments</strong> in this section
 meta.section.categories=<strong>Categories</strong> in this section
-
-mf.sourceType=Typ
 mf.edition=Edition
-mf.volume=Volume
-mf.series=Serien
-mf.publicationTitle=Publication title
+mf.institution=Institution
 mf.issue=Issue
 mf.pages=Pages
-mf.institution=Institution
+mf.publicationTitle=Publication title
+mf.series=Serien
+mf.sourceType=Typ
 mf.sourceType.book=Book
-mf.sourceType.report=Report
 mf.sourceType.film=Film
 mf.sourceType.journalArticle=Journal article
+mf.sourceType.report=Report
 mf.sourceType.webpage=Webpage
-
+mf.volume=Volume
 my.entries=My entries
 my.entries.text=List all your portfolio entries regardless of their context. This is the heart of your portfolio work.
 my.portfolio.binders=My portfolio binders
@@ -173,29 +169,28 @@ my.shared.items.text=Show all the entries that I shared with other people.
 new.entry=Create new entry
 new.section.desc=Description of the section
 new.section.title=Section
-no.map=$org.olat.course.nodes.portfolio\:no.map
 no.binders.template.available=There isn't any template available from a course.
+no.map=$org.olat.course.nodes.portfolio\:no.map
 not.implemented=Not implemented
-notifications.new.comment=New comment on '{0}' from {1}
 notifications.modified.page=Page '{0}' modified
 notifications.modified.section=Section '{0}' modified
+notifications.new.comment=New comment on '{0}' from {1}
 notifications.new.page=New page '{0}' added
 notifications.new.section=New section '{0}' added
 open=Open
 open.full.page=Read the whole page
 open.map=$org.olat.course.nodes.portfolio\:open.map
+override.dates.section=Extend period
 page.binders=Binder
 page.sections=Section
+page.status=Status
 page.summary=$\:summary
 page.title=$\:title
+pages=Pages
 passed.false=$org.olat.course.assessment\:passed.false
 passed.true=$org.olat.course.assessment\:passed.true
 passed.yourpassed=$org.olat.course.assessment\:passed.yourpassed
 place=Place
-publisher=Publisher
-url=URL
-source=Source
-language=Sprache
 portfolio.assessment=Grading
 portfolio.entries=Entries
 portfolio.history=History
@@ -206,42 +201,45 @@ portfolio.publish=Publish
 portfolio.root.breadcrump=Portfolio
 portfoliotask=Portfolio Task
 portfoliotask.none=None
+publication.title=Publication title
 publish=Publish entry
 publish.confirm.descr=Do you want to publish this entry "{0}"?
 publish.confirm.title=Publish
-
-close.confirm.descr=Do you want to close this entry "{0}"?
-close.confirm.title=Close
-
-reopen.confirm.title=Reopen
-reopen.confirm.descr=Do you want to reopen this entry "{0}"? This will reopen the section too.
-
-revision.confirm.title=Send to revision
-revision.confirm.descr=Do you want to resend this entry "{0}" for revision?
-
 publish.status.title=Publish status of binder "{0}"
+publisher=Publisher
 quick.links=Quick links
 remove=Remove
 reopen=Reopen
+reopen.confirm.descr=Do you want to reopen this entry "{0}"? This will reopen the section too.
+reopen.confirm.title=Reopen entry
+reopen.page=Reopen
+reopen.section=Reopen
+reopen.section.confirm.descr=Do you want to reopen this section "{0}"?
+reopen.section.confirm.title=Reopen section
+revision.confirm.descr=Do you want to resend this entry "{0}" for revision?
+revision.confirm.title=Send to revision
+revision.page=Revision
 section.delete=Delete section
 section.edit=Edit section
-section.paging.previous=Previous
+section.paging.all=Show all entries
 section.paging.next=Next
-section.paging.with.title=Go to section "{0}"
 section.paging.one=One section
-section.paging.all=Show all entries
+section.paging.previous=Previous
+section.paging.with.title=Go to section "{0}"
 section.score=Score
 section.status=Status
 section.title=Section {0}
 select.mymap=$org.olat.course.nodes.portfolio\:select.mymap
+series=Series
 shared.with.me=Shared with me
 shared.with.me.text=Show all the items that are shared with me by other people.
+source=Source
 status.closed=closed
 status.deleted=deleted
 status.draft=Draft
 status.in.progress=in progress
 status.in.revision=In revision
-status.inRevision=$:status.in.revision
+status.inRevision=$\:status.in.revision
 status.not.started=not started
 status.published=published
 status.submitted=submitted
@@ -277,6 +275,9 @@ template.none=None
 timeline.switch.off=Timeline
 timeline.switch.on=Timeline
 title=Title
+url=URL
+used.in=Used in
+volume=Volume
 warning.binder.synched=The binder is synchronized with its template.
 warning.portfolio.not.found=The portfolio cannot be found, probably deleted in the mean time
 warning.template.in.use=The template cannot deleted because some users use it.
diff --git a/src/main/java/org/olat/modules/portfolio/ui/model/PageRow.java b/src/main/java/org/olat/modules/portfolio/ui/model/PageRow.java
index 8fae3e2b6dd..52016c458de 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/model/PageRow.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/model/PageRow.java
@@ -54,6 +54,8 @@ public class PageRow {
 	private Link openLink;
 	private FormLink openFormLink, newFloatingEntryLink, newEntryLink, newAssignmentLink;
 	
+	private FormLink closeSectionLink, reopenSectionLink;
+	
 	private long numOfComments;
 	private Link commentLink;
 	private FormLink commentFormLink;
@@ -283,4 +285,20 @@ public class PageRow {
 	public void setNewAssignmentLink(FormLink newAssignmentLink) {
 		this.newAssignmentLink = newAssignmentLink;
 	}
+
+	public FormLink getCloseSectionLink() {
+		return closeSectionLink;
+	}
+
+	public void setCloseSectionLink(FormLink closeSectionLink) {
+		this.closeSectionLink = closeSectionLink;
+	}
+
+	public FormLink getReopenSectionLink() {
+		return reopenSectionLink;
+	}
+
+	public void setReopenSectionLink(FormLink reopenSectionLink) {
+		this.reopenSectionLink = reopenSectionLink;
+	}
 }
diff --git a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
index da2f8b44e67..644a414e854 100644
--- a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
@@ -144,6 +144,7 @@ create table o_pf_section (
    p_status varchar(32) not null default 'notStarted',
    p_begin datetime,
    p_end datetime,
+   p_override_begin_end bit default 0,
    fk_group_id bigint not null,
    fk_binder_id bigint not null,
    fk_template_reference_id bigint,
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 596d90419c9..1fee1064188 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1613,6 +1613,7 @@ create table o_pf_section (
    p_status varchar(32) not null default 'notStarted',
    p_begin datetime,
    p_end datetime,
+   p_override_begin_end bit default 0,
    fk_group_id bigint not null,
    fk_binder_id bigint not null,
    fk_template_reference_id bigint,
diff --git a/src/main/resources/database/oracle/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/oracle/alter_10_x_0_to_11_0_0.sql
index 7f59ed078a5..ed26e9df8cb 100644
--- a/src/main/resources/database/oracle/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/oracle/alter_10_x_0_to_11_0_0.sql
@@ -156,6 +156,7 @@ create table o_pf_section (
    p_status varchar2(32 char) default 'notStarted' not null,
    p_begin date,
    p_end date,
+   p_override_begin_end number default 0,
    fk_group_id number(20) not null,
    fk_binder_id number(20) not null,
    fk_template_reference_id number(20),
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index ddbc1d0c24c..5b5d4ec9460 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1525,6 +1525,7 @@ create table o_pf_section (
    p_status varchar2(32 char) default 'notStarted' not null,
    p_begin date,
    p_end date,
+   p_override_begin_end number default 0,
    fk_group_id number(20) not null,
    fk_binder_id number(20) not null,
    fk_template_reference_id number(20),
diff --git a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
index cec356ce5ab..97c98e7dd93 100644
--- a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
@@ -156,6 +156,7 @@ create table o_pf_section (
    p_status varchar(32) not null default 'notStarted',
    p_begin timestamp,
    p_end timestamp,
+   p_override_begin_end bool default false,
    fk_group_id int8 not null,
    fk_binder_id int8 not null,
    fk_template_reference_id int8,
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index e5d4db43252..18878295c77 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1495,6 +1495,7 @@ create table o_pf_section (
    p_status varchar(32) not null default 'notStarted',
    p_begin timestamp,
    p_end timestamp,
+   p_override_begin_end bool default false,
    fk_group_id int8 not null,
    fk_binder_id int8 not null,
    fk_template_reference_id int8,
-- 
GitLab