From e2d04e92287e712c57d2a03db42ba23c5adbbf41 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 24 Jul 2018 20:04:00 +0200
Subject: [PATCH] OO-3296: apply organisation permissions to quota

---
 .../olat/admin/quota/DeleteQuotaEvent.java    |  39 +++++
 .../quota/GenericQuotaEditController.java     | 131 ++++++++-------
 .../quota/GenericQuotaViewController.java     |  14 +-
 .../org/olat/admin/quota/QuotaController.java | 134 ++++++++-------
 .../java/org/olat/admin/quota/QuotaForm.java  |  86 +++++++---
 .../olat/admin/quota/QuotaManagerImpl.java    | 113 +++++++++++--
 .../org/olat/admin/quota/_content/edit.html   |   5 +-
 .../org/olat/admin/quota/_content/index.html  |   7 +-
 .../olat/admin/user/UserAdminController.java  |   3 +-
 .../collaboration/CollaborationTools.java     |   5 +-
 .../CollaborationToolsSettingsController.java |  11 +-
 .../bc/BriefcaseWebDAVMergeSource.java        |   3 +-
 .../modules/bc/FolderRunController.java       |   9 +-
 .../modules/bc/commands/CmdEditQuota.java     |  20 +--
 .../bc/commands/FolderCommandFactory.java     |   2 +-
 .../org/olat/core/util/vfs/QuotaManager.java  |  27 ++-
 .../vfs/callbacks/FullAccessCallback.java     |  21 ++-
 .../FullAccessWithQuotaCallback.java          |  15 +-
 .../util/vfs/callbacks/ReadOnlyCallback.java  |  40 ++---
 .../nodes/pf/manager/CountingCallback.java    |   2 +-
 .../ProjectBrokerCourseEditorController.java  |  32 +---
 .../ta/DropboxScoringViewController.java      | 156 ++++++++++--------
 .../nodes/ta/TACourseNodeEditController.java  |  40 ++---
 .../wizard/BGConfigToolsStepController.java   |   4 +-
 .../olat/ims/cp/ui/CPRuntimeController.java   |   3 +-
 .../webFeed/ui/FeedRuntimeController.java     |   2 +-
 .../org/olat/repository/RepositoryEntry.java  |   3 +-
 .../SharedFolderSecurityCallback.java         |  38 ++---
 28 files changed, 573 insertions(+), 392 deletions(-)
 create mode 100644 src/main/java/org/olat/admin/quota/DeleteQuotaEvent.java

diff --git a/src/main/java/org/olat/admin/quota/DeleteQuotaEvent.java b/src/main/java/org/olat/admin/quota/DeleteQuotaEvent.java
new file mode 100644
index 00000000000..a3566c16740
--- /dev/null
+++ b/src/main/java/org/olat/admin/quota/DeleteQuotaEvent.java
@@ -0,0 +1,39 @@
+/**
+ * <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.admin.quota;
+
+import org.olat.core.gui.control.Event;
+
+/**
+ * 
+ * Initial date: 24 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class DeleteQuotaEvent extends Event {
+
+	private static final long serialVersionUID = 825951705192059820L;
+	public static final String DELETE_QUOTA = "delete-quota";
+	
+	public DeleteQuotaEvent() {
+		super(DELETE_QUOTA);
+	}
+
+}
diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
index 2c44ccc8e5f..d67ea85b462 100644
--- a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
+++ b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
@@ -25,9 +25,6 @@
 
 package org.olat.admin.quota;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -37,9 +34,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.id.OrganisationRef;
 import org.olat.core.logging.AssertException;
-import org.olat.core.logging.OLATSecurityException;
 import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,13 +54,13 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 class GenericQuotaEditController extends BasicController {
 
-	private VelocityContainer myContent;
 	private QuotaForm quotaForm;
-	
+	private Link addQuotaButton;
+	private VelocityContainer myContent;
+
 	private Quota currentQuota;
-	private Link delQuotaButton;
-	
-	private List<OrganisationRef> organisations;
+	private final boolean canEditQuota;
+	private final boolean withCancel;
 	
 	@Autowired
 	private QuotaManager quotaManager;
@@ -81,21 +76,20 @@ class GenericQuotaEditController extends BasicController {
 	 * @param wControl
 	 * @param quotaPath The path for which the quota should be edited
 	 */
-	GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath, List<? extends OrganisationRef> organisations) {
+	GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath,
+			boolean embedded, boolean withCancel) {
 		super(ureq, wControl);
+		this.withCancel = withCancel;
 
-		this.organisations = organisations == null ? null : new ArrayList<>(organisations);
-		
-		// check if quota foqf.cannot.del.defaultr this path already exists
 		currentQuota = quotaManager.getCustomQuota(relPath);
-		// init velocity context
-		initMyContent(ureq);
 		if (currentQuota == null) {
-			currentQuota = quotaManager.createQuota(relPath, null, null);
-			myContent.contextPut("editQuota", Boolean.FALSE);			
-		} else {
-			initQuotaForm(ureq, currentQuota);			
+			currentQuota = quotaManager.createQuota(relPath, null, null);		
 		}
+		canEditQuota = quotaManager.hasQuotaEditRights(ureq.getIdentity(), ureq.getUserSession().getRoles(), currentQuota);
+
+		initMyContent();
+		initQuotaForm(ureq, currentQuota, canEditQuota);
+		myContent.contextPut("withLegend", Boolean.valueOf(embedded));
 		putInitialPanel(myContent);
 	}
 
@@ -106,20 +100,15 @@ class GenericQuotaEditController extends BasicController {
 	 * @param wControl
 	 * @param quota The existing quota or null. If null, a new quota is generated
 	 */
-	public GenericQuotaEditController(UserRequest ureq, WindowControl wControl, Quota quota) {
+	public GenericQuotaEditController(UserRequest ureq, WindowControl wControl, Quota quota, boolean withLegend) {
 		super(ureq, wControl);
+		withCancel = true;
+		currentQuota = quota;
+		canEditQuota = quotaManager.hasQuotaEditRights(ureq.getIdentity(), ureq.getUserSession().getRoles(), currentQuota);
 		
-		initMyContent(ureq);
-		
-		// start with neq quota if quota is empty
-		if (quota == null) {
-			currentQuota = quotaManager.createQuota(null, null, null);
-			myContent.contextPut("isEmptyQuota", true);
-		} else {
-			currentQuota = quota;
-		}
-		initQuotaForm(ureq, currentQuota);
-		
+		initMyContent();
+		initQuotaForm(ureq, currentQuota, canEditQuota);
+		myContent.contextPut("withLegend", Boolean.valueOf(withLegend));
 		putInitialPanel(myContent);
 	}
 
@@ -132,25 +121,24 @@ class GenericQuotaEditController extends BasicController {
 	 */
 	public GenericQuotaEditController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
-		
-		initMyContent(ureq);
-		
-		// start with new quota
+		withCancel = true;
+		canEditQuota = true;	
 		currentQuota = quotaManager.createQuota(null, null, null);
-		myContent.contextPut("isEmptyQuota", true);
-		initQuotaForm(ureq, currentQuota);
-		
+
+		// start with new quota
+		initMyContent();
+		initQuotaForm(ureq, currentQuota, false);
+		myContent.contextPut("isEmptyQuota", Boolean.TRUE);
+		myContent.contextPut("withLegend", Boolean.FALSE);
 		putInitialPanel(myContent);
 	}
 
-	private void initMyContent(UserRequest ureq) {
-		if (!quotaManager.hasQuotaEditRights(ureq.getIdentity(), ureq.getUserSession().getRoles(), organisations)) {
-			throw new OLATSecurityException("Insufficient permissions to access QuotaController");
-		}
-
+	private void initMyContent() {
 		myContent = createVelocityContainer("edit");
-		LinkFactory.createButtonSmall("qf.new", myContent, this);
-		delQuotaButton = LinkFactory.createButtonSmall("qf.del", myContent, this);
+		
+		if(canEditQuota) {
+			addQuotaButton = LinkFactory.createButtonSmall("qf.new", myContent, this);
+		}
 		
 		myContent.contextPut("users", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_USERS));
 		myContent.contextPut("powerusers", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_POWER));
@@ -159,14 +147,13 @@ class GenericQuotaEditController extends BasicController {
 		myContent.contextPut("coursefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_COURSE));
 		myContent.contextPut("nodefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_NODES));
 		myContent.contextPut("feeds", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS));
-		
 	}
 	
-	private void initQuotaForm(UserRequest ureq, Quota quota) {
+	private void initQuotaForm(UserRequest ureq, Quota quota, boolean withDelete) {
 		if (quotaForm != null) {
 			removeAsListenerAndDispose(quotaForm);
 		}
-		quotaForm = new QuotaForm(ureq, getWindowControl(), quota, true);
+		quotaForm = new QuotaForm(ureq, getWindowControl(), quota, canEditQuota, withDelete, withCancel);
 		listenTo(quotaForm);
 		myContent.put("quotaform", quotaForm.getInitialComponent());
 		myContent.contextPut("editQuota", Boolean.TRUE);
@@ -174,27 +161,20 @@ class GenericQuotaEditController extends BasicController {
 
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
-		initQuotaForm(ureq, currentQuota);
-		if (source == delQuotaButton){
-			boolean deleted = quotaManager.deleteCustomQuota(currentQuota);
-			if (deleted) {
-				myContent.remove(quotaForm.getInitialComponent());
-				myContent.contextPut("editQuota", Boolean.FALSE);
-				showInfo("qf.deleted", currentQuota.getPath());
-				fireEvent(ureq, Event.CHANGED_EVENT);
-			} else {
-				showError("qf.cannot.del.default");
-			}
-		}	
+		if(source == addQuotaButton) {
+			doAddQuota(ureq);
+		}
 	}
 	
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == quotaForm) {
 			if (event == Event.DONE_EVENT) {
-				currentQuota = quotaManager.createQuota(quotaForm.getPath(), new Long(quotaForm.getQuotaKB()), new Long(quotaForm.getULLimit()));
-				quotaManager.setCustomQuotaKB(currentQuota);
-				fireEvent(ureq, Event.CHANGED_EVENT);
+				doSaveQuota(ureq);
+			} else if(event == Event.CANCELLED_EVENT) {
+				fireEvent(ureq, event);
+			} else if(event instanceof DeleteQuotaEvent) {
+				doDelete(ureq);
 			}
 		}
 	}
@@ -205,6 +185,29 @@ class GenericQuotaEditController extends BasicController {
 		}
 		return currentQuota;
 	}
+	
+	private void doAddQuota(UserRequest ureq) {
+		initQuotaForm(ureq, currentQuota, canEditQuota);
+	}
+	
+	private void doSaveQuota(UserRequest ureq) {
+		currentQuota = quotaManager.createQuota(quotaForm.getPath(),
+				Long.valueOf(quotaForm.getQuotaKB()), Long.valueOf(quotaForm.getULLimit()));
+		quotaManager.setCustomQuotaKB(currentQuota);
+		fireEvent(ureq, Event.CHANGED_EVENT);
+	}
+	
+	private void doDelete(UserRequest ureq) {
+		boolean deleted = quotaManager.deleteCustomQuota(currentQuota);
+		if (deleted) {
+			myContent.remove(quotaForm.getInitialComponent());
+			myContent.contextPut("editQuota", Boolean.FALSE);
+			showInfo("qf.deleted", currentQuota.getPath());
+			fireEvent(ureq, Event.CHANGED_EVENT);
+		} else {
+			showError("qf.cannot.del.default");
+		}
+	}
 		
 	@Override
 	protected void doDispose() {
diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
index 806ff7fb24f..704192ecc68 100644
--- a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
+++ b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
@@ -74,7 +74,7 @@ public class GenericQuotaViewController extends BasicController {
 			initQuotaForm(ureq, currentQuota);			
 		}
 		myContent.contextPut("editQuota", Boolean.FALSE);	
-	  putInitialPanel(myContent);
+		putInitialPanel(myContent);
 	}
 	
 	public void setNotEnoughPrivilegeMessage() {
@@ -97,22 +97,18 @@ public class GenericQuotaViewController extends BasicController {
 		if (quotaForm != null) {
 			removeAsListenerAndDispose(quotaForm);
 		}
-		quotaForm = new QuotaForm(ureq, getWindowControl(), quota, false);
+		quotaForm = new QuotaForm(ureq, getWindowControl(), quota, false, false, false);
 		listenTo(quotaForm);
 		myContent.put("quotaform", quotaForm.getInitialComponent());
 		myContent.contextPut("editQuota", Boolean.TRUE);
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		//
 	}
-		
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
+	
+	@Override
 	protected void doDispose() {
 		//
 	}
diff --git a/src/main/java/org/olat/admin/quota/QuotaController.java b/src/main/java/org/olat/admin/quota/QuotaController.java
index a6e27cfbeb6..3de15be5b98 100644
--- a/src/main/java/org/olat/admin/quota/QuotaController.java
+++ b/src/main/java/org/olat/admin/quota/QuotaController.java
@@ -29,7 +29,6 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
-import org.olat.core.gui.components.panel.Panel;
 import org.olat.core.gui.components.table.ColumnDescriptor;
 import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
@@ -43,7 +42,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.logging.OLATSecurityException;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
@@ -57,15 +56,15 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author Felix Jost
  */
 public class QuotaController extends BasicController {
-
-	private VelocityContainer myContent;
+	
+	private Link addQuotaButton;
+	private final VelocityContainer myContent;
 	private QuotaTableModel quotaTableModel;
 
-	private GenericQuotaEditController quotaEditCtr;
-	private Panel main;
 	private TableController tableCtr;
-	private Link addQuotaButton;
-	
+	private CloseableModalController cmc;
+	private GenericQuotaEditController quotaEditCtr;
+
 	@Autowired
 	private QuotaManager quotaManager;
 
@@ -75,15 +74,13 @@ public class QuotaController extends BasicController {
 	 */
 	public QuotaController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
+		myContent = createVelocityContainer("index");
 
 		UserSession usess = ureq.getUserSession();
-		if (!usess.getRoles().isAdministrator() && !usess.getRoles().isSystemAdmin()) {//TODO quota roles
-			throw new OLATSecurityException("Insufficient permissions to access QuotaController");
-		}
-
-		main = new Panel("quotamain");
-		myContent = createVelocityContainer("index");
+		boolean isAdministrator = usess.getRoles().isAdministrator() || usess.getRoles().isSystemAdmin();
+		
 		addQuotaButton = LinkFactory.createButton("qf.new", myContent, this);
+		addQuotaButton.setVisible(isAdministrator);
 
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
@@ -96,26 +93,20 @@ public class QuotaController extends BasicController {
 				ColumnDescriptor.ALIGNMENT_LEFT, new QuotaByteRenderer()));
 		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.limit", 2, null, getLocale(),
 				ColumnDescriptor.ALIGNMENT_LEFT, new QuotaByteRenderer()));
-		tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.edit", "table.action", translate("edit")));
-		tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.del", "table.action", translate("delete")));
+		if(isAdministrator) {
+			tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.edit", "table.action", translate("edit")));
+			tableCtr.addColumnDescriptor(new StaticColumnDescriptor("qf.del", "table.action", translate("delete")));
+		}
 		tableCtr.setTableDataModel(quotaTableModel);
 		
 		myContent.put("quotatable", tableCtr.getInitialComponent());
-		main.setContent(myContent);
-
-		putInitialPanel(main);
+		putInitialPanel(myContent);
 	}
 
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(source == addQuotaButton){
-			// clean up old controller first
-			if (quotaEditCtr != null) removeAsListenerAndDispose(quotaEditCtr);
-			// start edit workflow in dedicated quota edit controller
-			removeAsListenerAndDispose(quotaEditCtr);
-			quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl());
-			listenTo(quotaEditCtr);
-			main.setContent(quotaEditCtr.getInitialComponent());
+			doAddQuota(ureq);
 		}
 	}
 
@@ -126,38 +117,67 @@ public class QuotaController extends BasicController {
 				quotaTableModel.setObjects(quotaManager.listCustomQuotasKB());
 				tableCtr.setTableDataModel(quotaTableModel);
 			}
-			// else cancel event. in any case set content to list
-			main.setContent(myContent);
-		}
-
-		if (source == tableCtr && event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
-				TableEvent te = (TableEvent)event;
-				Quota q = quotaTableModel.getRowData(te.getRowId());
-				if (te.getActionId().equals("qf.edit")) {
-					// clean up old controller first
-					// start edit workflow in dedicated quota edit controller
-					removeAsListenerAndDispose(quotaEditCtr);
-					quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl(), q);
-					listenTo(quotaEditCtr);
-					main.setContent(quotaEditCtr.getInitialComponent());
-
-				} else if (te.getActionId().equals("qf.del")) {
-					// try to delete quota
-					boolean deleted = quotaManager.deleteCustomQuota(q);
-					if (deleted) {
-						quotaTableModel.setObjects(quotaManager.listCustomQuotasKB());
-						tableCtr.setTableDataModel(quotaTableModel);
-						showInfo("qf.deleted", q.getPath());
-					} else {
-						// default quotas can not be deleted
-						showError("qf.cannot.del.default");
-					}
-				}
+			cmc.deactivate();
+			cleanUp();
+		} else if (source == cmc) {
+			cleanUp();
+		} else if (source == tableCtr && event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
+			TableEvent te = (TableEvent)event;
+			Quota q = quotaTableModel.getRowData(te.getRowId());
+			if (te.getActionId().equals("qf.edit")) {
+				doEditQuota(ureq, q);
+			} else if (te.getActionId().equals("qf.del")) {
+				// try to delete quota
+				doDeleteQuota(q);
 			}
 		}
-
-		@Override
-		protected void doDispose() {
-			//
+	}
+	
+	private void cleanUp() {
+		removeAsListenerAndDispose(quotaEditCtr);
+		removeAsListenerAndDispose(cmc);
+		quotaEditCtr = null;
+		cmc = null;
+	}
+	
+	private void doDeleteQuota(Quota q) {
+		boolean deleted = quotaManager.deleteCustomQuota(q);
+		if (deleted) {
+			quotaTableModel.setObjects(quotaManager.listCustomQuotasKB());
+			tableCtr.setTableDataModel(quotaTableModel);
+			showInfo("qf.deleted", q.getPath());
+		} else {
+			// default quotas can not be deleted
+			showError("qf.cannot.del.default");
 		}
 	}
+	
+	private void doEditQuota(UserRequest ureq, Quota q) {
+		if(quotaEditCtr != null) return;
+		
+		quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl(), q, false);
+		listenTo(quotaEditCtr);
+		
+		cmc = new CloseableModalController(getWindowControl(), "close", quotaEditCtr.getInitialComponent(), true, translate("qf.edit"));
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void doAddQuota(UserRequest ureq) {
+		if(quotaEditCtr != null) return;
+		
+		// start edit workflow in dedicated quota edit controller
+		removeAsListenerAndDispose(quotaEditCtr);
+		quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl());
+		listenTo(quotaEditCtr);
+		
+		cmc = new CloseableModalController(getWindowControl(), "close", quotaEditCtr.getInitialComponent(), true, translate("qf.new"));
+		cmc.activate();
+		listenTo(cmc);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/quota/QuotaForm.java b/src/main/java/org/olat/admin/quota/QuotaForm.java
index 33d88caa8b6..6387b8f7623 100644
--- a/src/main/java/org/olat/admin/quota/QuotaForm.java
+++ b/src/main/java/org/olat/admin/quota/QuotaForm.java
@@ -27,10 +27,14 @@ package org.olat.admin.quota;
 
 import org.olat.core.commons.modules.bc.FolderConfig;
 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.IntegerElement;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+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;
@@ -46,11 +50,14 @@ import org.springframework.beans.factory.annotation.Autowired;
 public class QuotaForm extends FormBasicController {
 
 	private TextElement path;
-	private IntegerElement quotaKB;
-	private IntegerElement ulLimitKB;
+	private TextElement quotaKB;
+	private TextElement ulLimitKB;
+	private FormLink deleteButton;
 	
 	private Quota quota;
 	private final boolean editable;
+	private final boolean deletable;
+	private final boolean cancelable;
 	
 	@Autowired
 	private QuotaManager quotaManager;
@@ -59,10 +66,13 @@ public class QuotaForm extends FormBasicController {
 	 * @param name component name of form
 	 * @param quota the quota used to initialize the form or null if empty form is used
 	 */
-	public QuotaForm(UserRequest ureq, WindowControl wControl, Quota quota, boolean editable) {
+	public QuotaForm(UserRequest ureq, WindowControl wControl, Quota quota,
+			boolean editable, boolean deletable, boolean cancelable) {
 		super(ureq, wControl);
 		this.quota = quota;
 		this.editable = editable;
+		this.deletable = deletable;
+		this.cancelable = cancelable;
 		initForm(ureq);
 	}
 
@@ -87,26 +97,13 @@ public class QuotaForm extends FormBasicController {
 		return ulLimitKB.getValue();
 	}
 
-	@Override
-	protected void formOK(UserRequest ureq) {
-		fireEvent(ureq, Event.DONE_EVENT);
-	}
-	
-	@Override
-	protected boolean validateFormLogic (UserRequest ureq) {
-		if (!quotaManager.isValidQuotaPath(path.getValue())) {
-			path.setErrorKey("qf.error.path.invalid", null);
-			return false;	
-		}
-		return true;
-	}
-
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		
 		if (quota != null && quota.getPath() != null && !quota.getPath().equals("")) {
 			path = uifactory.addTextElement("qf_path", "qf.path", 255, quota.getPath(), formLayout);
-			if (quota != null) path.setEnabled(false);
+			if (quota != null) {
+				path.setEnabled(false);
+			}
 		} else {
 			path = uifactory.addTextElement("qf_path", "qf.path", 255, "", formLayout);
 			path.setNotEmptyCheck("qf.error.path.invalid");
@@ -115,24 +112,63 @@ public class QuotaForm extends FormBasicController {
 		path.setEnabled(editable);
 		
 		if (quota != null && quota.getQuotaKB() != null) {
-			quotaKB = uifactory.addIntegerElement("qf_quota", "qf.quota", quota.getQuotaKB().intValue(), formLayout);
+			quotaKB = uifactory.addTextElement("qf_quota", "qf.quota", 16, String.valueOf(quota.getQuotaKB()), formLayout);
 		} else {	
-			quotaKB = uifactory.addIntegerElement("qf_quota", "qf.quota",(int)FolderConfig.getDefaultQuotaKB() , formLayout);
+			quotaKB = uifactory.addTextElement("qf_quota", "qf.quota", 16, String.valueOf(FolderConfig.getDefaultQuotaKB()), formLayout);
 		}
 		quotaKB.setMandatory(true);
 		quotaKB.setEnabled(editable);
 		
 		if (quota != null && quota.getUlLimitKB() != null) {
-			ulLimitKB = uifactory.addIntegerElement("qf_limit", "qf.limit", quota.getUlLimitKB().intValue(), formLayout);
+			ulLimitKB = uifactory.addTextElement("qf_limit", "qf.limit", 16, String.valueOf(quota.getUlLimitKB()), formLayout);
 		} else {
-			ulLimitKB = uifactory.addIntegerElement("qf_limit", "qf.limit",(int)FolderConfig.getLimitULKB() , formLayout);
+			ulLimitKB = uifactory.addTextElement("qf_limit", "qf.limit", 16, String.valueOf(FolderConfig.getLimitULKB()), formLayout);
 		}
 		ulLimitKB.setMandatory(true);
 		ulLimitKB.setEnabled(editable);
 		
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonLayout);
+		
+		if(cancelable) {
+			uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
+		}
 		if(editable) {
-			uifactory.addFormSubmitButton("submit", formLayout);
+			uifactory.addFormSubmitButton("submit", buttonLayout);
 		}
+		if(editable && deletable) {
+			deleteButton = uifactory.addFormLink("qf.del", buttonLayout, Link.BUTTON);
+		}
+	}
+
+	@Override
+	protected boolean validateFormLogic (UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		if (!quotaManager.isValidQuotaPath(path.getValue())) {
+			path.setErrorKey("qf.error.path.invalid", null);
+			allOk &= false;	
+		}
+		
+		return allOk;
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == deleteButton) {
+			fireEvent(ureq, new DeleteQuotaEvent());
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+	
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
index d0834e5067f..c41be22ad2f 100644
--- a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
+++ b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
@@ -32,6 +32,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.persistence.DB;
@@ -52,6 +53,9 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
+import org.olat.repository.RepositoryEntryRef;
+import org.olat.repository.manager.RepositoryEntryRelationDAO;
+import org.olat.repository.model.RepositoryEntryRefImpl;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
 import org.springframework.beans.factory.InitializingBean;
@@ -78,14 +82,14 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	@Autowired
 	private DB dbInstance;
 	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
 	private PropertyManager propertyManager;
 	@Autowired
 	private OLATResourceManager resourceManager;
-	
+	@Autowired
+	private RepositoryEntryRelationDAO repositoryEntryRelationDao;
 
-	/**
-	 * @see org.olat.core.util.vfs.QuotaManager#createQuota(java.lang.String, java.lang.Long, java.lang.Long)
-	 */
 	@Override
 	public Quota createQuota(String path, Long quotaKB, Long ulLimitKB) {
 		return new QuotaImpl(path, quotaKB, ulLimitKB);
@@ -238,8 +242,7 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	@Override
 	public List<Quota> listCustomQuotasKB() {
 		List<Quota> results = new ArrayList<>();
-		PropertyManager pm = PropertyManager.getInstance();
-		List<Property> props = pm.listProperties(null, null, quotaResource, QUOTA_CATEGORY, null);
+		List<Property> props = propertyManager.listProperties(null, null, quotaResource, QUOTA_CATEGORY, null);
 		if (props == null || props.isEmpty()) return results;
 		for (Iterator<Property> iter = props.iterator(); iter.hasNext();) {
 			Property prop = iter.next();
@@ -290,7 +293,7 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	 */
 	@Override
 	public Quota getDefaultQuotaDependingOnRole(Identity identity, Roles roles) {
-		if (isPowerUser(roles)) {//TODO quota roles
+		if (isPowerUser(roles)) {
 			return getDefaultQuotaPowerUsers();
 		}
 		return getDefaultQuotaUsers();
@@ -307,7 +310,6 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	public Quota getCustomQuotaOrDefaultDependingOnRole(Identity identity, Roles roles, String relPath) {
 		Quota quota = getCustomQuota(relPath);
 		if (quota == null) { // no custom quota
-			//TODO quota roles
 			Quota defQuota = isPowerUser(roles) ? getDefaultQuotaPowerUsers() : getDefaultQuotaUsers();
 			return createQuota(relPath, defQuota.getQuotaKB(), defQuota.getUlLimitKB());
 		}
@@ -389,9 +391,10 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	}
 
 	@Override
-	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, List<? extends OrganisationRef> resourceOwnerships) {
+	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath,
+			boolean withLegend, boolean withCancel) {
 		try {
-			return new GenericQuotaEditController(ureq, wControl, relPath, resourceOwnerships);
+			return new GenericQuotaEditController(ureq, wControl, relPath, withLegend, withCancel);
 		} catch (OLATSecurityException e) {
 			log.warn("Try to access the quota editor without enough privilege", e);
 			GenericQuotaViewController viewCtrl = new GenericQuotaViewController(ureq, wControl, relPath);
@@ -404,6 +407,96 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
 	public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath) {
 		return new GenericQuotaViewController(ureq, wControl, relPath);
 	}
+	
+	@Override
+	public boolean hasMinimalRolesToEditquota(Roles roles) {
+		return roles.isAdministrator() || roles.isSystemAdmin()
+				|| roles.isRolesManager() || roles.isUserManager()
+				|| roles.isLearnResourceManager();
+	}
+
+	@Override
+	public boolean hasQuotaEditRights(Identity identity, Roles roles, Quota quota) {
+		if(identity == null || roles == null || quota == null || quota.getPath() == null) {
+			return false;
+		}
+
+		String path = quota.getPath();
+		if(path.startsWith("::DEFAULT")) {
+			return roles.isSystemAdmin();
+		} else if(path.startsWith("/cts/folders/BusinessGroup/")) {
+			return roles.isSystemAdmin() || roles.isAdministrator();
+		} else if(path.startsWith("/repository/")) {
+			return canEditRepositoryResources(path, identity, roles);
+		} else if(path.startsWith("/course/")) {
+			return canEditRepositoryResources(path, identity, roles) ;
+		} else if(path.startsWith("/homes/")) {
+			return canEditUser(path, roles);
+		}
+		
+		return roles.isSystemAdmin();
+	}
+	
+	private boolean canEditUser(String path, Roles roles) {
+		if(!roles.isAdministrator() && !roles.isSystemAdmin() && !roles.isRolesManager() && !roles.isUserManager()) {
+			return false;
+		}
+		
+		try {
+			int start = "/homes/".length();
+			int index = path.indexOf('/', start + 1);
+			if(index >= 0 && start < path.length()) {
+				String username = path.substring(start, index);
+				Identity editedIdentity = securityManager.findIdentityByName(username);
+				Roles editedRoles = securityManager.getRoles(editedIdentity);
+				return (roles.isAdministrator() && roles.isManagerOf(OrganisationRoles.administrator, editedRoles))
+						|| (roles.isSystemAdmin() && roles.isManagerOf(OrganisationRoles.sysadmin, editedRoles))
+						|| (roles.isRolesManager() && roles.isManagerOf(OrganisationRoles.rolesmanager, editedRoles))
+						|| (roles.isUserManager() && roles.isManagerOf(OrganisationRoles.usermanager, editedRoles));
+			}
+			return false;
+		} catch (NumberFormatException e) {
+			log.error("Cannot parse this quota path: " + path, e);
+			return false;
+		}
+	}
+	
+	private boolean canEditRepositoryResources(String path, Identity identity, Roles roles) {
+		if(!roles.isAdministrator() && !roles.isSystemAdmin() && !roles.isLearnResourceManager()) {
+			return false;
+		}
+		
+		try {
+			int start = path.indexOf('/', 2) + 1;
+			int index = path.indexOf('/', start + 1);
+			if(index == -1) {
+				index = path.length();
+			}
+			if(start >= 0 && start <= path.length() && index >= 0 && index <= path.length()) {
+				String resIdString = path.substring(start, index);
+				Long resId = Long.valueOf(resIdString);
+				RepositoryEntryRef re = getRepositoryEntryKey(resId);
+				return re != null && repositoryEntryRelationDao.hasRole(identity, re, true,
+						OrganisationRoles.administrator.name(), OrganisationRoles.sysadmin.name(), OrganisationRoles.learnresourcemanager.name());
+			}
+			return false;
+		} catch (NumberFormatException e) {
+			log.error("Cannot parse this quota path: " + path, e);
+			return false;
+		}
+	}
+	
+	private RepositoryEntryRef getRepositoryEntryKey(Long resId) {
+		String query = "select v.key from repositoryentry v inner join v.olatResource as ores where ores.resId=:resId";
+		List<Long> keys = dbInstance.getCurrentEntityManager()
+				.createQuery(query, Long.class)
+				.setParameter("resId", resId)
+				.getResultList();
+		if(!keys.isEmpty()) {
+			return new RepositoryEntryRefImpl(keys.get(0));
+		}
+		return null;
+	}
 
 	@Override
 	public boolean hasQuotaEditRights(Identity identity, Roles roles, List<OrganisationRef> organisationOwnerships) {
diff --git a/src/main/java/org/olat/admin/quota/_content/edit.html b/src/main/java/org/olat/admin/quota/_content/edit.html
index 6a0d2a36381..4e4b10a13e9 100644
--- a/src/main/java/org/olat/admin/quota/_content/edit.html
+++ b/src/main/java/org/olat/admin/quota/_content/edit.html
@@ -1,12 +1,11 @@
 #if($editQuota)
 	<fieldset class="clearfix">
+		#if($r.isTrue($withLegend))
 		<legend>$r.translate("qf.edit")</legend>
+		#end
 		#if($r.isNotNull($notEnoughPrivilege) && $notEnoughPrivilege)
 		<div class="o_warning">$r.translate("warning.qd.not.enough.privilege")</div>
 		#end
-		#if(!$isEmptyQuota)
-		<div class="o_button_group o_button_group_right">$r.render("qf.del")</div>
-		#end
 		$r.render("quotaform")
 	</fieldset>
 #else
diff --git a/src/main/java/org/olat/admin/quota/_content/index.html b/src/main/java/org/olat/admin/quota/_content/index.html
index ddfb10734f2..a146efaea1c 100644
--- a/src/main/java/org/olat/admin/quota/_content/index.html
+++ b/src/main/java/org/olat/admin/quota/_content/index.html
@@ -1,8 +1,9 @@
 <fieldset>
 	<legend>$r.translate("qf.title")</legend>
-	<div class="btn-toolbar"><div class="pull-right">
+	#if($r.available("qf.new"))
+	<div class="o_button_group o_button_group_right">
 		$r.render("qf.new")
-	</div></div>
-	<h5 class="clearfix">$r.translate("qf.list")</h5>
+	</div>
+	#end
 	$r.render("quotatable")
 </fieldset>
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/user/UserAdminController.java b/src/main/java/org/olat/admin/user/UserAdminController.java
index cc63c1ca0b9..5e2caf1d5b3 100644
--- a/src/main/java/org/olat/admin/user/UserAdminController.java
+++ b/src/main/java/org/olat/admin/user/UserAdminController.java
@@ -439,8 +439,7 @@ public class UserAdminController extends BasicController implements Activateable
 		if (isUserManagerOf || isRolesManagerOf || isAdminOf) {
 			userTabP.addTab(translate(NLS_EDIT_UQUOTA),  uureq -> {
 				String relPath = FolderConfig.getUserHomes() + "/" + identity.getName();
-				List<Organisation> identityOrganisations = organisationService.getOrganisations(identity, OrganisationRoles.values());
-				quotaCtr = quotaManager.getQuotaEditorInstance(uureq, getWindowControl(), relPath, identityOrganisations);
+				quotaCtr = quotaManager.getQuotaEditorInstance(uureq, getWindowControl(), relPath, true, false);
 				return quotaCtr.getInitialComponent();
 			});
 		}
diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index f2068175604..3fc0dc87e2f 100644
--- a/src/main/java/org/olat/collaboration/CollaborationTools.java
+++ b/src/main/java/org/olat/collaboration/CollaborationTools.java
@@ -399,14 +399,15 @@ public class CollaborationTools implements Serializable {
 	 * Return the root VFS container with security callback set
 	 * @return
 	 */
-	public OlatRootFolderImpl getSecuredFolder(BusinessGroup businessGroup, SubscriptionContext subsContext, Identity identity, boolean isAdmin) {
+	public OlatRootFolderImpl getSecuredFolder(BusinessGroup businessGroup, SubscriptionContext subsContext,
+			Identity identity, boolean isBusinessGroupAdmin) {
 		if(!isToolEnabled(CollaborationTools.TOOL_FOLDER)) {
 			return null;
 		}
 
 		boolean writeAccess;
 		boolean isOwner = CoreSpringFactory.getImpl(BusinessGroupService.class).hasRoles(identity, businessGroup, GroupRoles.coach.name());
-		if (!(isAdmin || isOwner)) {
+		if (!(isBusinessGroupAdmin || isOwner)) {
 				// check if participants have read/write access
 			int folderAccess = CollaborationTools.FOLDER_ACCESS_ALL;
 			Long lFolderAccess = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroup).lookupFolderAccess();
diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
index ea942bbbd57..53e40475e80 100644
--- a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
+++ b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
@@ -43,6 +43,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.util.UserSession;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.QuotaManager;
@@ -103,12 +104,14 @@ public class CollaborationToolsSettingsController extends BasicController {
 			vc_collabtools.contextPut("newsToolEnabled", Boolean.FALSE);
 		}
 		
-		if (ureq.getUserSession().getRoles().isAdministrator()) {//TODO quota roles
+		UserSession usess = ureq.getUserSession();
+		
+		if (usess.getRoles().isAdministrator() || usess.getRoles().isSystemAdmin()) {
 			vc_collabtools.contextPut("isOlatAdmin", Boolean.TRUE);
 			if(managed) {
 				quotaCtr = quotaManager.getQuotaViewInstance(ureq, getWindowControl(), collabTools.getFolderRelPath());
 			} else {
-				quotaCtr = quotaManager.getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), null);
+				quotaCtr = quotaManager.getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), true, false);
 			}
 			listenTo(quotaCtr);
 		} else {
@@ -137,7 +140,7 @@ public class CollaborationToolsSettingsController extends BasicController {
 		// update quota form: only show when enabled
 		if (collabTools.isToolEnabled(CollaborationTools.TOOL_FOLDER)) {
 			vc_collabtools.contextPut("folderToolEnabled", Boolean.TRUE);
-			if(ureq.getUserSession().getRoles().isAdministrator()) {//TODO quota roles
+			if(usess.getRoles().isAdministrator() || usess.getRoles().isSystemAdmin()) {
 				vc_collabtools.put("quota", quotaCtr.getInitialComponent());
 			}
 			vc_collabtools.contextPut("folderToolEnabled", Boolean.TRUE);
@@ -238,7 +241,7 @@ public class CollaborationToolsSettingsController extends BasicController {
 				folderForm.setEnabled(!managed);
 				listenTo(folderForm);
 				vc_collabtools.put("folderform", folderForm.getInitialComponent());
-				if (ureq.getUserSession().getRoles().isAdministrator()) {//TODO quota roles
+				if (ureq.getUserSession().getRoles().isAdministrator()) {
 					vc_collabtools.put("quota", quotaCtr.getInitialComponent());
 				}
 			} else {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
index 101e9f52f01..fc4ec8531ff 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
@@ -85,8 +85,7 @@ public class BriefcaseWebDAVMergeSource  extends MergeSource {
 			QuotaManager qm = CoreSpringFactory.getImpl(QuotaManager.class);
 			String path = PersonalFolderManager.getRootPathFor(identity);
 			Quota quota = qm.getCustomQuotaOrDefaultDependingOnRole(identity, roles, path);
-			FullAccessWithQuotaCallback secCallback = new FullAccessWithQuotaCallback(quota);
-			setLocalSecurityCallback(secCallback);
+			setLocalSecurityCallback(new FullAccessWithQuotaCallback(quota));
 		}
 		return super.getLocalSecurityCallback();
 	}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
index 62b651509af..992bab1cf81 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FolderRunController.java
@@ -75,6 +75,7 @@ import org.olat.core.util.UserSession;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.OlatRelPathImpl;
 import org.olat.core.util.vfs.Quota;
+import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSContainerMapper;
 import org.olat.core.util.vfs.VFSItem;
@@ -119,6 +120,8 @@ public class FolderRunController extends BasicController implements Activateable
 	
 	@Autowired
 	private SearchModule searchModule;
+	@Autowired
+	private QuotaManager quotaManager;
 
 	/**
 	 * Default Constructor, results in showing users personal folder, used by Spring
@@ -504,10 +507,12 @@ public class FolderRunController extends BasicController implements Activateable
 		} 
 		
 		Boolean newEditQuota = Boolean.FALSE;
-		if (usess.getRoles().isAdministrator() || usess.getRoles().isLearnResourceManager()) {//TODO quota roles
+		if (quotaManager.hasMinimalRolesToEditquota(usess.getRoles())) {
 			// Only sys admins or institutonal resource managers can have the quota button
 			Quota q = VFSManager.isTopLevelQuotaContainer(folderComponent.getCurrentContainer());
-			newEditQuota = (q == null)? Boolean.FALSE : Boolean.TRUE;
+			if(q != null) {
+				newEditQuota = quotaManager.hasQuotaEditRights(ureq.getIdentity(), usess.getRoles(), q);
+			}
 		}
 
 		Boolean currentEditQuota = (Boolean) folderContainer.contextGet("editQuota");
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
index ce3ff8d69bb..989274ac438 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
@@ -26,15 +26,17 @@
 
 package org.olat.core.commons.modules.bc.commands;
 
+import org.olat.admin.quota.QuotaController;
 import org.olat.core.commons.modules.bc.components.FolderComponent;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.ControllerEventListener;
-import org.olat.core.gui.control.DefaultController;
 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.translator.Translator;
+import org.olat.core.util.Util;
 import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.VFSContainer;
@@ -42,7 +44,7 @@ import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
 import org.springframework.beans.factory.annotation.Autowired;
 
-public class CmdEditQuota extends DefaultController implements FolderCommand, ControllerEventListener {
+public class CmdEditQuota extends BasicController implements FolderCommand, ControllerEventListener {
 
 	private int status = FolderCommandStatus.STATUS_SUCCESS;
 	private Controller quotaEditController;
@@ -51,8 +53,8 @@ public class CmdEditQuota extends DefaultController implements FolderCommand, Co
 	@Autowired
 	private QuotaManager quotaManager;
 	
-	protected CmdEditQuota(WindowControl wControl) {
-		super(wControl);
+	protected CmdEditQuota(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, Util.createPackageTranslator(QuotaController.class, ureq.getLocale()));
 	}
 
 	@Override
@@ -67,10 +69,11 @@ public class CmdEditQuota extends DefaultController implements FolderCommand, Co
 		// cleanup old controller first
 		if (quotaEditController != null) quotaEditController.dispose();
 		// create a edit controller
-		quotaEditController = quotaManager.getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath(), null);//TODO quota roles
+		quotaEditController = quotaManager.getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath(),
+				false, true);
 		quotaEditController.addControllerListener(this);
 		if (quotaEditController != null) {
-			setInitialComponent(quotaEditController.getInitialComponent());
+			putInitialPanel(quotaEditController.getInitialComponent());
 			return this;
 		}
 		// do nothing, quota can't be edited
@@ -90,12 +93,9 @@ public class CmdEditQuota extends DefaultController implements FolderCommand, Co
 	
 	@Override
 	public String getModalTitle() {
-		return null;
+		return translate("qf.edit");
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.ControllerEventListener#dispatchEvent(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
-	 */
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == quotaEditController) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java b/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java
index a4e015cf985..4605816b77a 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/FolderCommandFactory.java
@@ -79,7 +79,7 @@ public class FolderCommandFactory {
 		else if (command.equals(COMMAND_SERV_THUMBNAIL)) cmd = new CmdServeThumbnailResource();
 		else if (command.equals(COMMAND_EDIT)) cmd = new CmdEditMeta(ureq, wControl);
 		else if (command.equals(COMMAND_EDIT_CONTENT)) cmd = new CmdEditContent(ureq, wControl);
-		else if (command.equals(COMMAND_EDIT_QUOTA)) cmd = new CmdEditQuota(wControl);
+		else if (command.equals(COMMAND_EDIT_QUOTA)) cmd = new CmdEditQuota(ureq, wControl);
 		else if (command.equals(COMMAND_DEL)) cmd = new CmdDelete(ureq, wControl);
 		else if (command.equals(COMMAND_MAIL)) {
 			AutoCreator controllerCreator = (AutoCreator)CoreSpringFactory.getBean("sendDocumentByEMailControllerCreator");
diff --git a/src/main/java/org/olat/core/util/vfs/QuotaManager.java b/src/main/java/org/olat/core/util/vfs/QuotaManager.java
index df19a437f7e..477967fc3c9 100644
--- a/src/main/java/org/olat/core/util/vfs/QuotaManager.java
+++ b/src/main/java/org/olat/core/util/vfs/QuotaManager.java
@@ -148,13 +148,34 @@ public interface QuotaManager {
 	 * </ul>
 	 * @param ureq
 	 * @param wControl
-	 * @param relPath
+	 * @param relPath Path of the quota
+	 * @param withLegend Add the title as legend of the form
+	 * @param withCancel Add a cancel button
 	 * @return
 	 */
-	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, List<? extends OrganisationRef> resourceOwnership);
+	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath,
+			boolean withLegend, boolean withCancel);
 	
 	public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath);
 	
+	/**
+	 * Check quickly if the user has the minimal roles to edit some quota.
+	 * To check permission on a specific quota, use the method below.
+	 * 
+	 * @param roles
+	 * @return
+	 */
+	public boolean hasMinimalRolesToEditquota(Roles roles);
+	
+	/**
+	 * Check if a user has the rights to launch the quota editor tool
+	 * 
+	 * @param identity The identity that requests to change a quota
+	 * @return true: user is allowed to launch quota editor ; false: user is not
+	 *         allowed to launch quota editor
+	 */
+	public boolean hasQuotaEditRights(Identity identity, Roles roles, Quota quota);
+	
 	/**
 	 * Check if a user has the rights to launch the quota editor tool
 	 * 
@@ -162,5 +183,5 @@ public interface QuotaManager {
 	 * @return true: user is allowed to launch quota editor ; false: user is not
 	 *         allowed to launch quota editor
 	 */
-	public boolean hasQuotaEditRights(Identity identity, Roles roles, List<OrganisationRef> resourceOwnership);
+	public boolean hasQuotaEditRights(Identity identity, Roles roles, List<OrganisationRef> owners);
 }
diff --git a/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessCallback.java b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessCallback.java
index 3f9183af4db..e6ededfa5ef 100644
--- a/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessCallback.java
+++ b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessCallback.java
@@ -30,11 +30,13 @@ import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.util.vfs.Quota;
 
 public class FullAccessCallback implements VFSSecurityCallback {
-
+	
+	@Override
 	public boolean canRead() {
 		return true;
 	}
-
+	
+	@Override
 	public boolean canWrite() {
 		return true;
 	}
@@ -43,31 +45,38 @@ public class FullAccessCallback implements VFSSecurityCallback {
 	public boolean canCreateFolder() {
 		return true;
 	}
-
+	
+	@Override
 	public boolean canDelete() {
 		return true;
 	}
-
+	
+	@Override
 	public boolean canList() {
 		return true;
 	}
-
+	
+	@Override
 	public boolean canCopy() {
 		return true;
 	}
 	
+	@Override
 	public boolean canDeleteRevisionsPermanently() {
 		return true;
 	}
 
+	@Override
 	public Quota getQuota() {
 		return null;
 	}
-
+	
+	@Override
 	public void setQuota(Quota quota) {
 		// nothing to do here.
 	}
 	
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithQuotaCallback.java b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithQuotaCallback.java
index 7256c183c9d..d5c2f50931c 100644
--- a/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithQuotaCallback.java
+++ b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithQuotaCallback.java
@@ -42,11 +42,13 @@ public class FullAccessWithQuotaCallback implements VFSSecurityCallback {
 	public FullAccessWithQuotaCallback(Quota quota) {
 		this.quota = quota;
 	}
-	
+
+	@Override
 	public boolean canRead() {
 		return true;
 	}
 
+	@Override
 	public boolean canWrite() {
 		return true;
 	}
@@ -56,30 +58,37 @@ public class FullAccessWithQuotaCallback implements VFSSecurityCallback {
 		return true;
 	}
 
+	@Override
 	public boolean canDelete() {
 		return true;
 	}
 
+	@Override
 	public boolean canList() {
 		return true;
 	}
 
+	@Override
 	public boolean canCopy() {
 		return true;
 	}
-	
+
+	@Override
 	public boolean canDeleteRevisionsPermanently() {
 		return true;
 	}
 
+	@Override
 	public Quota getQuota() {
 		return quota;
 	}
 
+	@Override
 	public void setQuota(Quota quota) {
 		this.quota = quota;
 	}
-	
+
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return subContext;
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/callbacks/ReadOnlyCallback.java b/src/main/java/org/olat/core/util/vfs/callbacks/ReadOnlyCallback.java
index 4e57b61d18a..607047b018c 100644
--- a/src/main/java/org/olat/core/util/vfs/callbacks/ReadOnlyCallback.java
+++ b/src/main/java/org/olat/core/util/vfs/callbacks/ReadOnlyCallback.java
@@ -31,23 +31,17 @@ import org.olat.core.util.vfs.Quota;
 
 public class ReadOnlyCallback implements VFSSecurityCallback {
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canList(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canList() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canRead(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canRead() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canWrite(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canWrite() {
 		return false;
 	}
@@ -57,44 +51,32 @@ public class ReadOnlyCallback implements VFSSecurityCallback {
 		return false;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDelete(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canDelete() {
 		return false;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canCopy()
-	 */
+	@Override
 	public boolean canCopy() {
 		return false;
 	}
-	
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canDeleteRevisionsPermanently()
-	 */
+
+	@Override
 	public boolean canDeleteRevisionsPermanently() {
 		return false;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getQuotaKB(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public Quota getQuota() {
 		return null;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#setQuota(org.olat.admin.quota.Quota)
-	 */
+	@Override
 	public void setQuota(Quota quota) {
 		// nothing to do here.
 	}
-	
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getSubscriptionContext()
-	 */
+
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
diff --git a/src/main/java/org/olat/course/nodes/pf/manager/CountingCallback.java b/src/main/java/org/olat/course/nodes/pf/manager/CountingCallback.java
index 4800bcc0637..121ce465943 100644
--- a/src/main/java/org/olat/course/nodes/pf/manager/CountingCallback.java
+++ b/src/main/java/org/olat/course/nodes/pf/manager/CountingCallback.java
@@ -112,7 +112,7 @@ public class CountingCallback implements VFSSecurityCallback {
 
 	@Override
 	public void setQuota(Quota quota) {
-		
+		//
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java
index 1d286ed0eff..40b3980a5dd 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java
@@ -405,16 +405,12 @@ class FolderCallback implements VFSSecurityCallback {
 		this.folderQuota = folderQuota;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canRead(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canRead() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canWrite(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canWrite() {
 		return !folderLocked;
 	}
@@ -424,44 +420,32 @@ class FolderCallback implements VFSSecurityCallback {
 		return !folderLocked;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDelete(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canDelete() {
 		return !folderLocked;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canList(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canList() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canCopy()
-	 */
+	@Override
 	public boolean canCopy() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getQuotaKB(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public Quota getQuota() {
 		return folderQuota;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#setQuota(org.olat.admin.quota.Quota)
-	 */
+	@Override
 	public void setQuota(Quota quota) {
 		folderQuota = quota;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getSubscriptionContext()
-	 */
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
index 6885027bd39..68674005749 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
@@ -403,45 +403,52 @@ public class DropboxScoringViewController extends BasicController {
 
 class ReadOnlyAndDeleteCallback implements VFSSecurityCallback {
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canList(org.olat.modules.bc.Path)
-	 */
-	public boolean canList() { return true; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canRead(org.olat.modules.bc.Path)
-	 */
-	public boolean canRead() { return true; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canWrite(org.olat.modules.bc.Path)
-	 */
-	public boolean canWrite() { return false; }
 	@Override
-	public boolean canCreateFolder() { return false; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDelete(org.olat.modules.bc.Path)
-	 */
-	public boolean canDelete() { return true; }
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canCopy()
-	 */
-	public boolean canCopy() { return true; }
-	
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDeleteRevisionsPermanently()
-	 */
-	public boolean canDeleteRevisionsPermanently() { return false; }
+	public boolean canList() {
+		return true;
+	}
+
+	@Override
+	public boolean canRead() {
+		return true;
+	}
+
+	@Override
+	public boolean canWrite() {
+		return false;
 	
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getQuotaKB(org.olat.modules.bc.Path)
-	 */
-	public Quota getQuota() { return null; }
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#setQuota(org.olat.admin.quota.Quota)
-	 */
-	public void setQuota(Quota quota) {}
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getSubscriptionContext()
-	 */
+	}
+	@Override
+	public boolean canCreateFolder() {
+		return false;
+	}
+
+	@Override
+	public boolean canDelete() {
+		return true;
+	}
+
+	@Override
+	public boolean canCopy() {
+		return true;
+	}
+
+	@Override
+	public boolean canDeleteRevisionsPermanently() {
+		return false;
+	}
+
+	@Override
+	public Quota getQuota() {
+		return null;
+	}
+
+	@Override
+	public void setQuota(Quota quota) {
+		//
+	}
+
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
@@ -460,48 +467,55 @@ class ReturnboxFullAccessCallback implements VFSSecurityCallback {
 			quota = quotaManager.createQuota(relPath, defQuota.getQuotaKB(), defQuota.getUlLimitKB());
 		}
 	}
+
+	@Override
+	public boolean canList() {
+		return true;
+	}
+
+	@Override
+	public boolean canRead() {
+		return true;
+	}
+
+	@Override
+	public boolean canWrite() {
+		return true;
+	}
 	
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canList(org.olat.modules.bc.Path)
-	 */
-	public boolean canList() { return true; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canRead(org.olat.modules.bc.Path)
-	 */
-	public boolean canRead() { return true; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canWrite(org.olat.modules.bc.Path)
-	 */
-	public boolean canWrite() { return true; }
 	@Override
-	public boolean canCreateFolder() { return true; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDelete(org.olat.modules.bc.Path)
-	 */
-	public boolean canDelete() { return true; }
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canCopy()
-	 */
-	public boolean canCopy() { return true; }
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canDeleteRevisionsPermanently()
-	 */
-	public boolean canDeleteRevisionsPermanently() { return false; }
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getQuotaKB(org.olat.modules.bc.Path)
-	 */
+	public boolean canCreateFolder() {
+		return true;
+	}
+
+	@Override
+	public boolean canDelete() {
+		return true;
+	}
+
+	@Override
+	public boolean canCopy() {
+		return true;
+	}
+
+	@Override
+	public boolean canDeleteRevisionsPermanently() {
+		return false;
+	}
+	
+	
+
+	@Override
 	public Quota getQuota() {
 		return quota;
 	}
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#setQuota(org.olat.admin.quota.Quota)
-	 */
+
+	@Override
 	public void setQuota(Quota quota) {
 		this.quota = quota;
 	}
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getSubscriptionContext()
-	 */
+
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return subscriptionContext;
 	} 
diff --git a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
index a498e6a49d2..12bbd560876 100644
--- a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
+++ b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java
@@ -558,7 +558,7 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr
 	 */
 	private List<Identity> removeAssignedTask(ICourse course, String task) {	
 		//identities to be notified
-		List<Identity> identityList = new ArrayList<Identity>();
+		List<Identity> identityList = new ArrayList<>();
 		CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();				
 		List<Property> properties = cpm.listCourseNodeProperties(node, null, null, TaskController.PROP_ASSIGNED);
 		if(properties!=null && properties.size()>0) {
@@ -627,16 +627,12 @@ class TaskFolderCallback implements VFSSecurityCallback {
 		this.folderQuota = folderQuota;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canRead(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canRead() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canWrite(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canWrite() {
 		return !folderLocked;
 	}
@@ -646,51 +642,37 @@ class TaskFolderCallback implements VFSSecurityCallback {
 		return false;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canDelete(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canDelete() {
 		return !folderLocked;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#canList(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public boolean canList() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canCopy()
-	 */
+	@Override
 	public boolean canCopy() {
 		return true;
 	}
-	
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canDeleteRevisionsPermanently()
-	 */
+
+	@Override
 	public boolean canDeleteRevisionsPermanently() {
 		return false;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getQuotaKB(org.olat.modules.bc.Path)
-	 */
+	@Override
 	public Quota getQuota() {
 		return folderQuota;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#setQuota(org.olat.admin.quota.Quota)
-	 */
+	@Override
 	public void setQuota(Quota quota) {
 		folderQuota = quota;
 	}
 
-	/**
-	 * @see org.olat.modules.bc.callbacks.SecurityCallback#getSubscriptionContext()
-	 */
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
diff --git a/src/main/java/org/olat/group/ui/wizard/BGConfigToolsStepController.java b/src/main/java/org/olat/group/ui/wizard/BGConfigToolsStepController.java
index 011e66aed41..9c673c6d1c9 100644
--- a/src/main/java/org/olat/group/ui/wizard/BGConfigToolsStepController.java
+++ b/src/main/java/org/olat/group/ui/wizard/BGConfigToolsStepController.java
@@ -117,7 +117,7 @@ public class BGConfigToolsStepController extends StepFormBasicController {
 				config.folderCtrl.getInitialFormItem().setVisible(false);
 				
 				//add quota configuration for admin only
-				if(roles.isAdministrator()) {//TODO quota roles
+				if(quotaManager.hasMinimalRolesToEditquota(roles)) {
 					Quota quota = quotaManager.createQuota(null, null, null);
 					config.quotaCtrl = new BGConfigQuotaController(ureq, getWindowControl(), quota, mainForm);
 					config.configContainer.add("quota", config.quotaCtrl.getInitialFormItem());
@@ -171,7 +171,7 @@ public class BGConfigToolsStepController extends StepFormBasicController {
 				} else if (tool.equals(CollaborationTools.TOOL_FOLDER)) {
 					configuration.setFolderAccess(config.folderCtrl.getFolderAccess());
 					//only admin are allowed to configure quota
-					if(roles.isAdministrator() && config.quotaCtrl != null) {//TODO quota roles
+					if(quotaManager.hasMinimalRolesToEditquota(roles) && config.quotaCtrl != null) {
 						Long quotaKB = config.quotaCtrl.getQuotaKB();
 						Long ulLimit = config.quotaCtrl.getULLimit();
 						Quota quota = quotaManager.createQuota(null, quotaKB, ulLimit);
diff --git a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
index caf86ffcff3..ecf1709c6f5 100644
--- a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
+++ b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
@@ -129,7 +129,8 @@ public class CPRuntimeController extends RepositoryEntryRuntimeController {
 			OLATResource resource = entry.getOlatResource();
 			OlatRootFolderImpl cpRoot = FileResourceManager.getInstance().unzipContainerResource(resource);
 			WindowControl bwControl = getSubWindowControl("Quota");
-			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath(), getOrganisations());
+			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath(),
+					true, false);
 			pushController(ureq, translate("tab.quota.edit"), quotaCtrl);
 			setActiveTool(quotaLink);
 		}
diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
index 6ce1ddd2aec..330a4ffb3e2 100644
--- a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
+++ b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
@@ -98,7 +98,7 @@ public class FeedRuntimeController extends RepositoryEntryRuntimeController {
 			RepositoryEntry entry = getRepositoryEntry();
 			OlatRootFolderImpl feedRoot = FileResourceManager.getInstance().getFileResourceRootImpl(entry.getOlatResource());
 			WindowControl bwControl = getSubWindowControl("Quota");
-			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath(), getOrganisations());
+			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath(), true, false);
 			pushController(ureq, translate("tab.quota.edit"), quotaCtrl);
 			setActiveTool(quotaLink);
 		}
diff --git a/src/main/java/org/olat/repository/RepositoryEntry.java b/src/main/java/org/olat/repository/RepositoryEntry.java
index 1b8d339d068..60d7abe2d78 100644
--- a/src/main/java/org/olat/repository/RepositoryEntry.java
+++ b/src/main/java/org/olat/repository/RepositoryEntry.java
@@ -78,8 +78,7 @@ import org.olat.resource.OLATResourceImpl;
 	@NamedQuery(name="loadRepositoryEntryByResourceKey", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where ores.key = :resourceKey"),
 	@NamedQuery(name="loadRepositoryEntryByResourceId", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where ores.resId=:resId and ores.resName=:resName"),
 	@NamedQuery(name="loadRepositoryEntryByResourceIds", query="select v from repositoryentry as v inner join fetch v.olatResource as ores inner join fetch v.statistics as statistics left join fetch v.lifecycle as lifecycle where ores.resId in (:resIds) and ores.resName=:resName"),
-	
-	
+
 	@NamedQuery(name="getDisplayNameByResourceKey", query="select v.displayname from repositoryentry v where v.olatResource.key=:resKey"),
 	@NamedQuery(name="getDisplayNameByOlatResourceRedId", query="select v.displayname from repositoryentry v inner join v.olatResource as ores where ores.resId=:resid"),
 	@NamedQuery(name="getDisplayNameByRepositoryEntryKey", query="select v.displayname from repositoryentry v where v.key=:reKey")
diff --git a/src/main/java/org/olat/repository/SharedFolderSecurityCallback.java b/src/main/java/org/olat/repository/SharedFolderSecurityCallback.java
index 1de74d2e70b..2f12a066192 100644
--- a/src/main/java/org/olat/repository/SharedFolderSecurityCallback.java
+++ b/src/main/java/org/olat/repository/SharedFolderSecurityCallback.java
@@ -50,16 +50,12 @@ public class SharedFolderSecurityCallback implements VFSSecurityCallback {
 		this.relPath = relPath;
 	}
 
-	/**
-	 * @return boolean
-	 */
+	@Override
 	public boolean canRead() {
 		return true;
 	}
 
-	/**
-	 * @return boolean
-	 */
+	@Override
 	public boolean canWrite() {
 		return true;
 	}
@@ -69,36 +65,27 @@ public class SharedFolderSecurityCallback implements VFSSecurityCallback {
 		return true;
 	}
 
-	/**
-	 * @return boolean
-	 */
+	@Override
 	public boolean canDelete() {
 		return true;
 	}
-	/**
-	 * @return boolean
-	 */
+
+	@Override
 	public boolean canList() {
 		return true;
 	}
 
-	/**
-	 * @return boolean
-	 */
+	@Override
 	public boolean canCopy() {
 		return true;
 	}
-	
-	/**
-	 * @see org.olat.core.util.vfs.callbacks.VFSSecurityCallback#canDeleteRevisionsPermanently()
-	 */
+
+	@Override
 	public boolean canDeleteRevisionsPermanently() {
 		return true;
 	}
 
-	/**
-	 * @return boolean
-	 */
+	@Override
 	public Quota getQuota() {
 		if(sharedFolderQuota == null) {
 			initSharedFolderQuota(relPath);
@@ -106,13 +93,12 @@ public class SharedFolderSecurityCallback implements VFSSecurityCallback {
 		return sharedFolderQuota;
 	}
 
+	@Override
 	public void setQuota(Quota quota) {
 		sharedFolderQuota = quota;
 	}
-	
-	/**
-	 * @return boolean
-	 */
+
+	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return null;
 	}
-- 
GitLab