Skip to content
Snippets Groups Projects
Commit fb86dc2c authored by srosse's avatar srosse
Browse files

Merge remote-tracking branch 'origin/OpenOLAT_12.5'

parents 35807f58 4fb313b6
No related branches found
No related tags found
No related merge requests found
Showing
with 51 additions and 65 deletions
...@@ -146,6 +146,7 @@ class GenericQuotaEditController extends BasicController { ...@@ -146,6 +146,7 @@ class GenericQuotaEditController extends BasicController {
myContent.contextPut("repository", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_REPO)); myContent.contextPut("repository", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_REPO));
myContent.contextPut("coursefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_COURSE)); myContent.contextPut("coursefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_COURSE));
myContent.contextPut("nodefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_NODES)); myContent.contextPut("nodefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_NODES));
myContent.contextPut("pfNodefolder", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_PFNODES));
myContent.contextPut("feeds", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS)); myContent.contextPut("feeds", quotaManager.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS));
} }
......
...@@ -35,6 +35,7 @@ public class QuotaConstants { ...@@ -35,6 +35,7 @@ public class QuotaConstants {
public static final String IDENTIFIER_DEFAULT_REPO = IDENTIFIER_DEFAULT + "REPOSITORY"; public static final String IDENTIFIER_DEFAULT_REPO = IDENTIFIER_DEFAULT + "REPOSITORY";
public static final String IDENTIFIER_DEFAULT_COURSE = IDENTIFIER_DEFAULT + "COURSEFOLDERS"; public static final String IDENTIFIER_DEFAULT_COURSE = IDENTIFIER_DEFAULT + "COURSEFOLDERS";
public static final String IDENTIFIER_DEFAULT_NODES = IDENTIFIER_DEFAULT + "NODEFOLDERS"; public static final String IDENTIFIER_DEFAULT_NODES = IDENTIFIER_DEFAULT + "NODEFOLDERS";
public static final String IDENTIFIER_DEFAULT_PFNODES = IDENTIFIER_DEFAULT + "NODEPARTFOLDERS";
public static final String IDENTIFIER_DEFAULT_FEEDS = IDENTIFIER_DEFAULT + "BLOGSPODCASTS"; public static final String IDENTIFIER_DEFAULT_FEEDS = IDENTIFIER_DEFAULT + "BLOGSPODCASTS";
} }
...@@ -116,6 +116,8 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean { ...@@ -116,6 +116,8 @@ public class QuotaManagerImpl implements QuotaManager, InitializingBean {
defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_COURSE, defaultQuotaCourseFolder); defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_COURSE, defaultQuotaCourseFolder);
Quota defaultQuotaNodeFolder = initDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_NODES); Quota defaultQuotaNodeFolder = initDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_NODES);
defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_NODES, defaultQuotaNodeFolder); defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_NODES, defaultQuotaNodeFolder);
Quota defaultQuotaPfNodeFolder = initDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_PFNODES);
defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_PFNODES, defaultQuotaPfNodeFolder);
Quota defaultQuotaFeed = initDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS); Quota defaultQuotaFeed = initDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS);
defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS, defaultQuotaFeed); defaultQuotas.put(QuotaConstants.IDENTIFIER_DEFAULT_FEEDS, defaultQuotaFeed);
} }
......
...@@ -56,6 +56,11 @@ ...@@ -56,6 +56,11 @@
<tr><td>$r.translate("qd.nodefolder")</td><td>$r.formatBytes($nodefolderQuotaBytes) ($nodefolder.getQuotaKB())</td> <tr><td>$r.translate("qd.nodefolder")</td><td>$r.formatBytes($nodefolderQuotaBytes) ($nodefolder.getQuotaKB())</td>
#set ($nodefolderUlLimitBytes = $nodefolder.getUlLimitKB() * 1000) #set ($nodefolderUlLimitBytes = $nodefolder.getUlLimitKB() * 1000)
<td>$r.formatBytes($nodefolderUlLimitBytes) ($nodefolder.getUlLimitKB())</td></tr> <td>$r.formatBytes($nodefolderUlLimitBytes) ($nodefolder.getUlLimitKB())</td></tr>
#set ($pfNodefolderQuotaBytes = $pfNodefolder.getQuotaKB() * 1000)
<tr><td>$r.translate("qd.pfnodefolder")</td><td>$r.formatBytes($pfNodefolderQuotaBytes) ($pfNodefolder.getQuotaKB())</td>
#set ($pfNodefolderUlLimitBytes = $pfNodefolder.getUlLimitKB() * 1000)
<td>$r.formatBytes($pfNodefolderUlLimitBytes) ($pfNodefolder.getUlLimitKB())</td></tr>
#set ($feedsQuotaBytes = $feeds.getQuotaKB() * 1000) #set ($feedsQuotaBytes = $feeds.getQuotaKB() * 1000)
<tr><td>$r.translate("qd.feeds")</td><td>$r.formatBytes($feedsQuotaBytes) ($feeds.getQuotaKB())</td> <tr><td>$r.translate("qd.feeds")</td><td>$r.formatBytes($feedsQuotaBytes) ($feeds.getQuotaKB())</td>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
qd.coursefolder=Kursordner qd.coursefolder=Kursordner
qd.groups=Gruppen qd.groups=Gruppen
qd.nodefolder=Kursbausteine qd.nodefolder=Kursbausteine
qd.pfnodefolder=Teilnehmer Ordner Kursbausteine
qd.powerusers=Poweruser (Autoren) qd.powerusers=Poweruser (Autoren)
qd.repository=Lernressourcen qd.repository=Lernressourcen
qd.title=Default Quotas qd.title=Default Quotas
......
...@@ -3,6 +3,7 @@ qd.coursefolder=Course folder ...@@ -3,6 +3,7 @@ qd.coursefolder=Course folder
qd.feeds=Blogs and podcasts qd.feeds=Blogs and podcasts
qd.groups=Groups qd.groups=Groups
qd.nodefolder=Course elements qd.nodefolder=Course elements
qd.pfnodefolder=Participant folder course elements
qd.powerusers=Power user (authors) qd.powerusers=Power user (authors)
qd.repository=Learning resources qd.repository=Learning resources
qd.title=Default quotas qd.title=Default quotas
......
...@@ -124,7 +124,7 @@ public class CmdUpload extends BasicController implements FolderCommand { ...@@ -124,7 +124,7 @@ public class CmdUpload extends BasicController implements FolderCommand {
if (inheritingContainer != null) { if (inheritingContainer != null) {
secCallback = inheritingContainer.getLocalSecurityCallback(); secCallback = inheritingContainer.getLocalSecurityCallback();
actualUsage = VFSManager.getUsageKB(inheritingContainer); actualUsage = VFSManager.getUsageKB(inheritingContainer);
ubar.setActual(actualUsage/ 1024); ubar.setActual(actualUsage / 1024f);
if (inheritingContainer.getLocalSecurityCallback().getQuota() != null) { if (inheritingContainer.getLocalSecurityCallback().getQuota() != null) {
quotaKB = secCallback.getQuota().getQuotaKB().longValue(); quotaKB = secCallback.getQuota().getQuotaKB().longValue();
uploadLimitKB = (int) secCallback.getQuota().getUlLimitKB().longValue(); uploadLimitKB = (int) secCallback.getQuota().getUlLimitKB().longValue();
......
...@@ -257,7 +257,7 @@ public class PFManager { ...@@ -257,7 +257,7 @@ public class PFManager {
* @param dropbox * @param dropbox
* @return the VFSSecurityCallback * @return the VFSSecurityCallback
*/ */
private VFSSecurityCallback calculateCallback (CourseEnvironment courseEnv, PFCourseNode pfNode, VFSContainer dropbox, boolean webdav) { private VFSSecurityCallback calculateCallback(CourseEnvironment courseEnv, String quotaPath, PFCourseNode pfNode, VFSContainer dropbox, boolean webdav) {
VFSSecurityCallback callback; VFSSecurityCallback callback;
SubscriptionContext folderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode); SubscriptionContext folderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode);
int count = countFiles(dropbox); int count = countFiles(dropbox);
...@@ -271,9 +271,9 @@ public class PFManager { ...@@ -271,9 +271,9 @@ public class PFManager {
} else if (limitCount && alterFile) { } else if (limitCount && alterFile) {
callback = new ReadDeleteCallback(folderSubContext); callback = new ReadDeleteCallback(folderSubContext);
} else if (!limitCount && !alterFile) { } else if (!limitCount && !alterFile) {
callback = new ReadWriteCallback(folderSubContext); callback = new ReadWriteCallback(folderSubContext, quotaPath);
} else { } else {
callback = new ReadWriteDeleteCallback(folderSubContext); callback = new ReadWriteDeleteCallback(folderSubContext, quotaPath);
} }
return callback; return callback;
} }
...@@ -312,6 +312,7 @@ public class PFManager { ...@@ -312,6 +312,7 @@ public class PFManager {
Translator translator = Util.createPackageTranslator(PFRunController.class, locale); Translator translator = Util.createPackageTranslator(PFRunController.class, locale);
SubscriptionContext subsContext = CourseModule.createSubscriptionContext(courseEnv, pfNode); SubscriptionContext subsContext = CourseModule.createSubscriptionContext(courseEnv, pfNode);
String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER; String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER;
String quotaPath = path + "/" + pfNode.getIdent();
VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null); VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null);
VirtualContainer namedCourseFolder = new VirtualContainer(identity.getName()); VirtualContainer namedCourseFolder = new VirtualContainer(identity.getName());
Path relPath = Paths.get(pfNode.getIdent(), getIdFolderName(identity)); Path relPath = Paths.get(pfNode.getIdent(), getIdFolderName(identity));
...@@ -323,7 +324,7 @@ public class PFManager { ...@@ -323,7 +324,7 @@ public class PFManager {
dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(subsContext)); dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(subsContext));
} else { } else {
VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity); VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity);
VFSSecurityCallback callback = calculateCallback(courseEnv, pfNode, dropbox, true); VFSSecurityCallback callback = calculateCallback(courseEnv, quotaPath, pfNode, dropbox, true);
dropContainer.setLocalSecurityCallback(callback); dropContainer.setLocalSecurityCallback(callback);
} }
namedCourseFolder.addItem(dropContainer); namedCourseFolder.addItem(dropContainer);
...@@ -349,8 +350,10 @@ public class PFManager { ...@@ -349,8 +350,10 @@ public class PFManager {
Locale locale = I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage()); Locale locale = I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage());
Translator translator = Util.createPackageTranslator(PFRunController.class, locale); Translator translator = Util.createPackageTranslator(PFRunController.class, locale);
SubscriptionContext nodefolderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode); SubscriptionContext nodefolderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode);
List<Identity> participants = getParticipants(identity, courseEnv, admin); List<Identity> participants = getParticipants(identity, courseEnv, admin);
String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER; String courseContainerRelPath = courseEnv.getCourseBaseContainer().getRelPath();
String path = courseContainerRelPath + "/" + FILENAME_PARTICIPANTFOLDER;
String quotaPath = path + "/" + pfNode.getIdent();
VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null); VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null);
VirtualContainer namedCourseFolder = new VirtualContainer(translator.translate("participant.folder")); VirtualContainer namedCourseFolder = new VirtualContainer(translator.translate("participant.folder"));
for (Identity participant : participants) { for (Identity participant : participants) {
...@@ -366,7 +369,7 @@ public class PFManager { ...@@ -366,7 +369,7 @@ public class PFManager {
//if coach is also participant, can user his/her webdav folder with participant rights //if coach is also participant, can user his/her webdav folder with participant rights
if (identity.equals(participant)){ if (identity.equals(participant)){
VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity); VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity);
VFSSecurityCallback callback = calculateCallback(courseEnv, pfNode, dropbox, true); VFSSecurityCallback callback = calculateCallback(courseEnv, quotaPath, pfNode, dropbox, true);
dropContainer.setLocalSecurityCallback(callback); dropContainer.setLocalSecurityCallback(callback);
} else { } else {
dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext)); dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext));
...@@ -377,7 +380,7 @@ public class PFManager { ...@@ -377,7 +380,7 @@ public class PFManager {
if (pfNode.hasCoachBoxConfigured()){ if (pfNode.hasCoachBoxConfigured()){
VFSContainer returnContainer = new NamedContainerImpl(translator.translate("return.box"), VFSContainer returnContainer = new NamedContainerImpl(translator.translate("return.box"),
VFSManager.resolveOrCreateContainerFromPath(userBaseContainer, FILENAME_RETURNBOX)); VFSManager.resolveOrCreateContainerFromPath(userBaseContainer, FILENAME_RETURNBOX));
returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext)); returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext, quotaPath));
participantFolder.addItem(returnContainer); participantFolder.addItem(returnContainer);
} }
} }
...@@ -401,6 +404,7 @@ public class PFManager { ...@@ -401,6 +404,7 @@ public class PFManager {
participants = new ArrayList<>(new HashSet<>(participants)); participants = new ArrayList<>(new HashSet<>(participants));
String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER; String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER;
String quotaPath = path + "/" + pfNode.getIdent();
VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null); VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null);
VirtualContainer namedCourseFolder = new VirtualContainer(translator.translate("participant.folder")); VirtualContainer namedCourseFolder = new VirtualContainer(translator.translate("participant.folder"));
for (Identity participant : participants) { for (Identity participant : participants) {
...@@ -421,7 +425,7 @@ public class PFManager { ...@@ -421,7 +425,7 @@ public class PFManager {
if (pfNode.hasCoachBoxConfigured()){ if (pfNode.hasCoachBoxConfigured()){
VFSContainer returnContainer = new NamedContainerImpl(translator.translate("return.box"), VFSContainer returnContainer = new NamedContainerImpl(translator.translate("return.box"),
VFSManager.resolveOrCreateContainerFromPath(userBaseContainer, FILENAME_RETURNBOX)); VFSManager.resolveOrCreateContainerFromPath(userBaseContainer, FILENAME_RETURNBOX));
returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext)); returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext, quotaPath));
participantFolder.addItem(returnContainer); participantFolder.addItem(returnContainer);
} }
} }
...@@ -445,6 +449,7 @@ public class PFManager { ...@@ -445,6 +449,7 @@ public class PFManager {
SubscriptionContext nodefolderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode); SubscriptionContext nodefolderSubContext = CourseModule.createSubscriptionContext(courseEnv, pfNode);
String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER; String path = courseEnv.getCourseBaseContainer().getRelPath() + "/" + FILENAME_PARTICIPANTFOLDER;
String quotaPath = path + "/" + pfNode.getIdent();
VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null); VFSContainer courseElementBaseContainer = new OlatRootFolderImpl(path, null);
Path relPath = Paths.get(pfNode.getIdent(), getIdFolderName(identity)); Path relPath = Paths.get(pfNode.getIdent(), getIdFolderName(identity));
...@@ -479,10 +484,10 @@ public class PFManager { ...@@ -479,10 +484,10 @@ public class PFManager {
} else { } else {
if (isCoach) { if (isCoach) {
dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext)); dropContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext));
returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext)); returnContainer.setLocalSecurityCallback(new ReadWriteDeleteCallback(nodefolderSubContext, quotaPath));
} else { } else {
VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity); VFSContainer dropbox = resolveOrCreateDropFolder(courseEnv, pfNode, identity);
VFSSecurityCallback callback = calculateCallback(courseEnv, pfNode, dropbox, false); VFSSecurityCallback callback = calculateCallback(courseEnv, path, pfNode, dropbox, false);
dropContainer.setLocalSecurityCallback(callback); dropContainer.setLocalSecurityCallback(callback);
returnContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext)); returnContainer.setLocalSecurityCallback(new ReadOnlyCallback(nodefolderSubContext));
} }
......
...@@ -19,8 +19,11 @@ ...@@ -19,8 +19,11 @@
*/ */
package org.olat.course.nodes.pf.manager; package org.olat.course.nodes.pf.manager;
import org.olat.admin.quota.QuotaConstants;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.util.vfs.Quota; import org.olat.core.util.vfs.Quota;
import org.olat.core.util.vfs.QuotaManager;
import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
/** /**
* *
...@@ -30,10 +33,15 @@ import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; ...@@ -30,10 +33,15 @@ import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
public class ReadWriteCallback implements VFSSecurityCallback { public class ReadWriteCallback implements VFSSecurityCallback {
private SubscriptionContext subsContext; private SubscriptionContext subsContext;
private Quota quota;
private final String folderPath;
private final String defaultQuota;
public ReadWriteCallback(SubscriptionContext subsContext) { public ReadWriteCallback(SubscriptionContext subsContext, String folderPath) {
super(); super();
this.subsContext = subsContext; this.subsContext = subsContext;
this.folderPath = folderPath;
this.defaultQuota = QuotaConstants.IDENTIFIER_DEFAULT_PFNODES;
} }
@Override @Override
...@@ -73,13 +81,21 @@ public class ReadWriteCallback implements VFSSecurityCallback { ...@@ -73,13 +81,21 @@ public class ReadWriteCallback implements VFSSecurityCallback {
@Override @Override
public Quota getQuota() { public Quota getQuota() {
return null; if(quota == null) {
QuotaManager qm = CoreSpringFactory.getImpl(QuotaManager.class);
Quota q = qm.getCustomQuota(folderPath);
if (q == null) {
Quota defQuota = qm.getDefaultQuota(defaultQuota);
q = qm.createQuota(folderPath, defQuota.getQuotaKB(), defQuota.getUlLimitKB());
}
setQuota(q);
}
return quota;
} }
@Override @Override
public void setQuota(Quota quota) { public void setQuota(Quota quota) {
this.quota = quota;
} }
@Override @Override
......
...@@ -20,35 +20,15 @@ ...@@ -20,35 +20,15 @@
package org.olat.course.nodes.pf.manager; package org.olat.course.nodes.pf.manager;
import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.util.vfs.Quota;
import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
/** /**
* *
* @author Fabian Kiefer, fabian.kiefer@frentix.com, http://www.frentix.com * @author Fabian Kiefer, fabian.kiefer@frentix.com, http://www.frentix.com
* *
*/ */
public class ReadWriteDeleteCallback implements VFSSecurityCallback { public class ReadWriteDeleteCallback extends ReadWriteCallback {
private SubscriptionContext subsContext; public ReadWriteDeleteCallback(SubscriptionContext subsContext, String folderPath) {
super(subsContext, folderPath);
public ReadWriteDeleteCallback(SubscriptionContext subsContext) {
super();
this.subsContext = subsContext;
}
@Override
public boolean canRead() {
return true;
}
@Override
public boolean canWrite() {
return true;
}
@Override
public boolean canCreateFolder() {
return true;
} }
@Override @Override
...@@ -56,34 +36,8 @@ public class ReadWriteDeleteCallback implements VFSSecurityCallback { ...@@ -56,34 +36,8 @@ public class ReadWriteDeleteCallback implements VFSSecurityCallback {
return true; return true;
} }
@Override
public boolean canList() {
return true;
}
@Override
public boolean canCopy() {
return true;
}
@Override @Override
public boolean canDeleteRevisionsPermanently() { public boolean canDeleteRevisionsPermanently() {
return false; return false;
} }
@Override
public Quota getQuota() {
return null;
}
@Override
public void setQuota(Quota quota) {
}
@Override
public SubscriptionContext getSubscriptionContext() {
return subsContext;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment