From ff33354837e5cc7d3fdf98f8092a9a274733abdc Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Mon, 17 Jun 2019 17:30:15 +0200
Subject: [PATCH] OO-3887: option to share selectively the documents of a
 meeting

---
 .../adobeconnect/AdobeConnectManager.java     |   2 +
 .../adobeconnect/AdobeConnectMeeting.java     |   5 +
 .../manager/AdobeConnectManagerImpl.java      |   9 ++
 .../model/AdobeConnectMeetingImpl.java        |  44 +++++++
 .../adobeconnect/model/AdobeConnectSco.java   |  17 +++
 .../ui/AdobeConnectContentRow.java            |  19 ++-
 .../ui/AdobeConnectContentTableModel.java     |  10 ++
 .../ui/AdobeConnectMeetingController.java     |  83 +++++++++---
 .../AdobeConnectShareDocumentsController.java | 123 ++++++++++++++++++
 .../adobeconnect/ui/_content/meeting.html     |  12 +-
 .../ui/_content/share_documents.html          |   5 +
 .../ui/_i18n/LocalStrings_de.properties       |   4 +
 .../ui/_i18n/LocalStrings_en.properties       |   5 +
 .../database/mysql/alter_13_2_x_to_14_0_0.sql |   1 +
 .../database/mysql/setupDatabase.sql          |   1 +
 .../oracle/alter_13_2_x_to_14_0_0.sql         |   1 +
 .../database/oracle/setupDatabase.sql         |   1 +
 .../postgresql/alter_13_2_x_to_14_0_0.sql     |   2 +-
 .../database/postgresql/setupDatabase.sql     |   1 +
 19 files changed, 327 insertions(+), 18 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectShareDocumentsController.java
 create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/share_documents.html

diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java
index ceab8f08f02..435521febc3 100644
--- a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java
+++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java
@@ -56,6 +56,8 @@ public interface AdobeConnectManager {
 	public AdobeConnectMeeting updateMeeting(AdobeConnectMeeting meeting, String name, String description,
 			String templateId, Date startDate, Date endDate, AdobeConnectErrors error);
 	
+	public AdobeConnectMeeting shareDocuments(AdobeConnectMeeting meeting, List<AdobeConnectSco> documents);
+	
 	public boolean deleteMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors error);
 	
 	public List<AdobeConnectSco> getTemplates();
diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java
index ed19da0d77a..c4b12626434 100644
--- a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java
+++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java
@@ -20,6 +20,7 @@
 package org.olat.modules.adobeconnect;
 
 import java.util.Date;
+import java.util.List;
 
 import org.olat.core.id.CreateInfo;
 import org.olat.core.id.ModifiedInfo;
@@ -56,6 +57,10 @@ public interface AdobeConnectMeeting extends ModifiedInfo, CreateInfo {
 	
 	public String getFolderId();
 	
+	public List<String> getSharedDocumentIds();
+	
+	public void setSharedDocumentIds(List<String> ids);
+	
 	public String getEnvName();
 	
 	public RepositoryEntry getEntry();
diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java
index 2fd3696c03b..34093e7924d 100644
--- a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java
+++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java
@@ -25,6 +25,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 import javax.ws.rs.core.UriBuilder;
 
@@ -187,6 +188,14 @@ public class AdobeConnectManagerImpl implements AdobeConnectManager, DeletableGr
 		return meeting;
 	}
 	
+	@Override
+	public AdobeConnectMeeting shareDocuments(AdobeConnectMeeting meeting, List<AdobeConnectSco> documents) {
+		meeting = adobeConnectMeetingDao.loadByKey(meeting.getKey());
+		List<String> scoIds = documents.stream().map(AdobeConnectSco::getScoId).collect(Collectors.toList());
+		meeting.setSharedDocumentIds(scoIds);
+		return adobeConnectMeetingDao.updateMeeting(meeting);
+	}
+
 	@Override
 	public List<AdobeConnectSco> getTemplates() {
 		List<AdobeConnectSco> templates = getAdapter().getTemplates();
diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java
index 29b2dae8139..2f6a12ff36e 100644
--- a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java
+++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java
@@ -19,7 +19,9 @@
  */
 package org.olat.modules.adobeconnect.model;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -34,6 +36,7 @@ import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 
 import org.olat.core.id.Persistable;
+import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupImpl;
 import org.olat.modules.adobeconnect.AdobeConnectMeeting;
@@ -78,6 +81,9 @@ public class AdobeConnectMeetingImpl implements Persistable, AdobeConnectMeeting
 	private String folderId;
 	@Column(name="a_env_name", nullable=true, insertable=true, updatable=false)
 	private String envName;
+	
+	@Column(name="a_shared_documents", nullable=true, insertable=true, updatable=true)
+	private String sharedDocuments;
 
 	@ManyToOne(targetEntity=RepositoryEntry.class, fetch=FetchType.LAZY, optional=true)
 	@JoinColumn(name="fk_entry_id", nullable=true, insertable=true, updatable=false)
@@ -161,6 +167,7 @@ public class AdobeConnectMeetingImpl implements Persistable, AdobeConnectMeeting
 		return startDate;
 	}
 
+	@Override
 	public void setStartDate(Date start) {
 		this.startDate = start;
 	}
@@ -170,6 +177,7 @@ public class AdobeConnectMeetingImpl implements Persistable, AdobeConnectMeeting
 		return endDate;
 	}
 
+	@Override
 	public void setEndDate(Date end) {
 		this.endDate = end;
 	}
@@ -183,6 +191,42 @@ public class AdobeConnectMeetingImpl implements Persistable, AdobeConnectMeeting
 		this.envName = envName;
 	}
 
+	public String getSharedDocuments() {
+		return sharedDocuments;
+	}
+
+	public void setSharedDocuments(String sharedDocuments) {
+		this.sharedDocuments = sharedDocuments;
+	}
+
+	@Override
+	public List<String> getSharedDocumentIds() {
+		List<String> ids = new ArrayList<>();
+		if(StringHelper.containsNonWhitespace(sharedDocuments)) {
+			String[] idArray = sharedDocuments.split("[,]");
+			for(String id:idArray) {
+				if(StringHelper.containsNonWhitespace(id)) {
+					ids.add(id);
+				}
+			}
+		}
+		return ids;
+	}
+
+	@Override
+	public void setSharedDocumentIds(List<String> ids) {
+		StringBuilder sb = new StringBuilder();
+		if(ids != null && !ids.isEmpty()) {
+			for(String id:ids) {
+				if(StringHelper.containsNonWhitespace(id)) {
+					if(sb.length() > 0) sb.append(",");
+					sb.append(id);
+				}
+			}
+		}
+		sharedDocuments = sb.length() == 0 ? null : sb.toString();
+	}
+
 	@Override
 	public RepositoryEntry getEntry() {
 		return entry;
diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java
index efd9d45442a..ef890ee013d 100644
--- a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java
+++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java
@@ -110,4 +110,21 @@ public class AdobeConnectSco {
 	public void setDateModified(Date dateModified) {
 		this.dateModified = dateModified;
 	}
+
+	@Override
+	public int hashCode() {
+		return scoId == null ? 23657834 : scoId.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof AdobeConnectSco) {
+			AdobeConnectSco sco = (AdobeConnectSco)obj;
+			return scoId != null && scoId.equals(sco.getScoId());
+		}
+		return false;
+	}
 }
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java
index 974bf271cb7..4241c19009d 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java
@@ -48,4 +48,21 @@ public class AdobeConnectContentRow {
 	public void setOpenLink(DownloadLink openLink) {
 		this.openLink = openLink;
 	}
-}
+
+	@Override
+	public int hashCode() {
+		return sco == null ? -21801 : sco.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof AdobeConnectContentRow) {
+			AdobeConnectContentRow row = (AdobeConnectContentRow)obj;
+			return sco != null && sco.equals(row.getSco());
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java
index f727270899f..8cc9cf3cb53 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java
@@ -52,6 +52,16 @@ implements SortableFlexiTableDataModel<AdobeConnectContentRow> {
 			super.setObjects(views);
 		}
 	}
+	
+	public Integer indexOf(String scoId) {
+		for(int i=getRowCount(); i-->0; ) {
+			AdobeConnectContentRow content = getObject(i);
+			if(scoId.equals(content.getSco().getScoId())) {
+				return Integer.valueOf(i);
+			}
+		}
+		return null;
+	}
 
 	@Override
 	public Object getValueAt(int row, int col) {
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java
index be92b17d17b..0ec074be7d8 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java
@@ -42,6 +42,7 @@ import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.media.RedirectMediaResource;
 import org.olat.core.util.Formatter;
@@ -66,7 +67,7 @@ public class AdobeConnectMeetingController extends FormBasicController {
 	private final boolean readOnly;
 	private final boolean moderator;
 	private final boolean administrator;
-	private final AdobeConnectMeeting meeting;
+	private AdobeConnectMeeting meeting;
 	
 	private boolean registered;
 	private final boolean validMeeting;
@@ -74,9 +75,13 @@ public class AdobeConnectMeetingController extends FormBasicController {
 	private int counter;
 	private Link joinButton;
 	private FormLink registerButton;
+	private FormLink sharedDocumentButton;
 	private FlexiTableElement contentTableEl;
 	private AdobeConnectContentTableModel contentModel;
 	
+	private CloseableModalController cmc;
+	private AdobeConnectShareDocumentsController shareDocumentsCtrl;
+	
 	@Autowired
 	private AdobeConnectModule adobeConnectModule;
 	@Autowired
@@ -125,10 +130,12 @@ public class AdobeConnectMeetingController extends FormBasicController {
 		}
 
 		registerButton = uifactory.addFormLink("meeting.register.button", flc, Link.BUTTON);
+		sharedDocumentButton = uifactory.addFormLink("meeting.share.documents", flc, Link.BUTTON);
+		sharedDocumentButton.setVisible(administrator || moderator);
 
 		joinButton = LinkFactory.createButtonLarge("meeting.join.button", flc.getFormItemComponent(), this);
 		joinButton.setTarget("_blank");
-		
+
 		initContent(formLayout);
 	}
 	
@@ -143,24 +150,36 @@ public class AdobeConnectMeetingController extends FormBasicController {
 		contentTableEl = uifactory.addTableElement(getWindowControl(), "meetingContents", contentModel, 24, false, getTranslator(), formLayout);
 		contentTableEl.setCustomizeColumns(false);
 		contentTableEl.setNumOfRowsEnabled(false);
-		contentTableEl.setEmtpyTableMessageKey("no.contents");
+		contentTableEl.setEmtpyTableMessageKey("no.shared.contents");
 	}
 	
 	private void loadModel() {
-		AdobeConnectErrors error = new AdobeConnectErrors();
-		List<AdobeConnectSco> scos = adobeConnectManager.getRecordings(meeting, error);
-		List<AdobeConnectContentRow> rows = new ArrayList<>(scos.size());
-		for(AdobeConnectSco sco:scos) {
-			AdobeConnectContentRow row = new AdobeConnectContentRow(sco);
-			if(registered) {
-				MediaResource resource = new AdobeConnectContentRedirectResource(getIdentity(), sco);
-				DownloadLink openLink = uifactory.addDownloadLink("open-" + (++counter), translate("content.open"), null, resource, contentTableEl);
-				row.setOpenLink(openLink);
+		List<String> sharedDocumentIds = meeting.getSharedDocumentIds();
+		
+		if(!sharedDocumentIds.isEmpty() || administrator || moderator) {
+			AdobeConnectErrors error = new AdobeConnectErrors();
+			List<AdobeConnectSco> scos = adobeConnectManager.getRecordings(meeting, error);
+			List<AdobeConnectContentRow> rows = new ArrayList<>(scos.size());
+			for(AdobeConnectSco sco:scos) {
+				if(sharedDocumentIds.contains(sco.getScoId())) {
+					AdobeConnectContentRow row = new AdobeConnectContentRow(sco);
+					if(registered) {
+						MediaResource resource = new AdobeConnectContentRedirectResource(getIdentity(), sco);
+						DownloadLink openLink = uifactory.addDownloadLink("open-" + (++counter), translate("content.open"), null, resource, contentTableEl);
+						row.setOpenLink(openLink);
+					}
+					rows.add(row);
+				}
 			}
-			rows.add(row);
+			contentModel.setObjects(rows);
+			contentTableEl.reset(true, true, true);
+			contentTableEl.setVisible(true);
+			sharedDocumentButton.setVisible(!scos.isEmpty() && (administrator || moderator));
+			flc.contextPut("notRegistered", Boolean.valueOf(!registered));
+		} else {
+			contentTableEl.setVisible(false);
+			sharedDocumentButton.setVisible(false);
 		}
-		contentModel.setObjects(rows);
-		contentTableEl.reset(true, true, true);
 	}
 	
 	private void updateButtons() {
@@ -181,6 +200,28 @@ public class AdobeConnectMeetingController extends FormBasicController {
 		}
 		super.event(ureq, source, event);
 	}
+	
+	@Override
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if(shareDocumentsCtrl == source) {
+			if(event == Event.CHANGED_EVENT) {
+				meeting = shareDocumentsCtrl.getMeeting();
+				loadModel();
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if(cmc == source) {
+			cleanUp();
+		}
+		super.event(ureq, source, event);
+	}
+	
+	private void cleanUp() {
+		removeControllerListener(shareDocumentsCtrl);
+		removeControllerListener(cmc);
+		shareDocumentsCtrl = null;
+		cmc = null;
+	}
 
 	@Override
 	protected void formOK(UserRequest ureq) {
@@ -191,6 +232,8 @@ public class AdobeConnectMeetingController extends FormBasicController {
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(registerButton == source) {
 			doRegister();
+		} else if(sharedDocumentButton == source) {
+			doShareDocuments(ureq);
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
@@ -219,6 +262,16 @@ public class AdobeConnectMeetingController extends FormBasicController {
 		}
 	}
 	
+	private void doShareDocuments(UserRequest ureq) {
+		shareDocumentsCtrl = new AdobeConnectShareDocumentsController(ureq, getWindowControl(), meeting);
+		listenTo(shareDocumentsCtrl);
+		
+		String title = translate("meeting.share.documents.of", new String[] { StringHelper.escapeHtml(meeting.getName() )});
+		cmc = new CloseableModalController(getWindowControl(), "close", shareDocumentsCtrl.getInitialComponent(), true, title);
+		listenTo(cmc);
+		cmc.activate();
+	}
+	
 	private AdobeConnectMeetingPermission getPermission() {
 		AdobeConnectMeetingPermission permission;
 		if(administrator || moderator) {
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectShareDocumentsController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectShareDocumentsController.java
new file mode 100644
index 00000000000..04ec13d54ac
--- /dev/null
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectShareDocumentsController.java
@@ -0,0 +1,123 @@
+package org.olat.modules.adobeconnect.ui;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DateTimeFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.modules.adobeconnect.AdobeConnectManager;
+import org.olat.modules.adobeconnect.AdobeConnectMeeting;
+import org.olat.modules.adobeconnect.model.AdobeConnectErrors;
+import org.olat.modules.adobeconnect.model.AdobeConnectSco;
+import org.olat.modules.adobeconnect.ui.AdobeConnectContentTableModel.ACContentsCols;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 17 juin 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AdobeConnectShareDocumentsController extends FormBasicController {
+	
+	private FlexiTableElement contentTableEl;
+	private AdobeConnectContentTableModel contentModel;
+	
+	private AdobeConnectMeeting meeting;
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private AdobeConnectManager adobeConnectManager;
+	
+	public AdobeConnectShareDocumentsController(UserRequest ureq, WindowControl wControl, AdobeConnectMeeting meeting) {
+		super(ureq, wControl, "share_documents");
+		this.meeting = meeting;
+		
+		initForm(ureq);
+		loadModel();
+	}
+	
+	public AdobeConnectMeeting getMeeting() {
+		return meeting;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACContentsCols.icon, new AdobeConnectIconRenderer()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACContentsCols.name));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACContentsCols.dateBegin, new DateTimeFlexiCellRenderer(getLocale())));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACContentsCols.resource));
+
+		contentModel = new AdobeConnectContentTableModel(columnsModel, getLocale());
+		contentTableEl = uifactory.addTableElement(getWindowControl(), "meetingContents", contentModel, 24, false, getTranslator(), formLayout);
+		contentTableEl.setCustomizeColumns(false);
+		contentTableEl.setMultiSelect(true);
+		contentTableEl.setEmtpyTableMessageKey("no.contents");
+		
+		uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("save", formLayout);
+	}
+	
+	private void loadModel() {
+		AdobeConnectErrors error = new AdobeConnectErrors();
+		List<AdobeConnectSco> scos = adobeConnectManager.getRecordings(meeting, error);
+		List<AdobeConnectContentRow> rows = new ArrayList<>(scos.size());
+		
+		for(AdobeConnectSco sco:scos) {
+			rows.add(new AdobeConnectContentRow(sco));
+		}
+		contentModel.setObjects(rows);
+		contentTableEl.reset(true, true, true);
+		contentTableEl.setSelectAllEnable(true);
+
+		List<String> sharedDocumentIds = meeting.getSharedDocumentIds();
+		if(!sharedDocumentIds.isEmpty()) {
+			Set<Integer> selectedRows = new HashSet<>();
+			for(String scoId:sharedDocumentIds ) {
+				Integer index = contentModel.indexOf(scoId);
+				if(index != null) {
+					selectedRows.add(index);
+				}
+			}
+			contentTableEl.setMultiSelectedIndex(selectedRows);
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		Set<Integer> selectedRows = contentTableEl.getMultiSelectedIndex();
+		List<AdobeConnectSco> sharedScos = new ArrayList<>(selectedRows.size());
+		for(Integer selectedRow:selectedRows) {
+			AdobeConnectContentRow row = contentModel.getObject(selectedRow.intValue());
+			sharedScos.add(row.getSco());
+		}
+
+		meeting = adobeConnectManager.shareDocuments(meeting, sharedScos);
+		dbInstance.commit();
+		fireEvent(ureq, Event.CHANGED_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html
index 23db3cd6acd..b582aed5942 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html
@@ -26,7 +26,17 @@
 	$r.render("meeting.join.button")
 #end
 </div>
+#if($r.visible("meeting.share.documents") || $r.visible("meetingContents"))
 <fieldset>
 	<legend>$r.translate("meetings.content")</legend>
+	#if($r.visible("meeting.share.documents"))
+	<div class="o_button_group o_button_group_right">
+		$r.render("meeting.share.documents")
+	</div>
+	#end
+	#if($r.isTrue($notRegistered))
+		<div class="o_warning">$r.translate("warning.not.registered.shared.documents")</div>
+	#end
 	$r.render("meetingContents")
-</fieldset>
\ No newline at end of file
+</fieldset>
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/share_documents.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/share_documents.html
new file mode 100644
index 00000000000..26537678146
--- /dev/null
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/share_documents.html
@@ -0,0 +1,5 @@
+$r.render("meetingContents")
+<div class="o_button_group">
+	$r.render("cancel")
+	$r.render("save")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties
index bdd72ffcf6b..c9ab35e31be 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties
@@ -39,6 +39,8 @@ meeting.permanent=Typ
 meeting.permanent.on=Dauernd
 meeting.register.button=Anmelden
 meeting.resource=Resource
+meeting.share.documents=Dokumenten verteilen
+meeting.share.documents.of=Dokumenten von "{0}" verteilen
 meeting.start=Beginndatum
 meeting.start.button=Meeting starten
 meeting.successfully.registered=Erfolgreich angemeldet.
@@ -50,6 +52,7 @@ meetings.title=Schulungen
 meetings.upcoming=Zuk\u00FCnftige Meetings
 no.contents=Dieser Meeting enth\u00E4lt kein Inhalt
 no.meeting.configured=Es gibt kein Meeting geplant.
+no.shared.contents=Dieser Meeting verteilt kein Inhalt.
 no.template=Keine Vorlage
 no.upcoming.meetings=Sie haben kein zuk\u00FCnftige Meeting.
 option.adminlogin=Benutzername
@@ -58,3 +61,4 @@ option.baseurl=URL Adobe Connect Server
 option.baseurl.example=https\://meet73287594.adobeconnect.com/api/xml
 vc.access.open=Moderator muss im Raum online sein, um Zutritt f\u00FCr Teilnehmer zu best\u00E4tigen
 vc.access.start=Nur Moderatoren d\u00FCrfen diesen Raum er\u00F6ffnen
+warning.not.registered.shared.documents=Nur die Personen die sich an den Meeting angemeldet haben d\u00FCrfen die Dokumenten ansehen.
diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties
index 861270e1b14..39346f24213 100644
--- a/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties
@@ -40,6 +40,8 @@ meeting.permanent=Typ
 meeting.permanent.on=Dauernd
 meeting.register.button=Register
 meeting.resource=Resource
+meeting.share.documents=Share documents
+meeting.share.documents.of=Share documents of "{0}"
 meeting.start=Start date
 meeting.start.button=Start the meeting
 meeting.successfully.registered=Successfully registered.
@@ -51,6 +53,7 @@ meetings.title=Trainings
 meetings.upcoming=Upcoming meetings
 no.contents=This meeting doesn't have any content
 no.meeting.configured=There isn't any planned meeting.
+no.shared.contents=This meeting doesn't have any shared content yet.
 no.template=No template
 no.upcoming.meetings=You don't have any upcoming meeting.
 option.adminlogin=Username
@@ -59,3 +62,5 @@ option.baseurl=URL Adobe Connect Server
 option.baseurl.example=https\://meet73287594.adobeconnect.com/api/xml
 vc.access.open=Moderator must be in classroom to grant access to users
 vc.access.start=Only moderators are allowed to open this classroom
+warning.not.registered.shared.documents=Only the persons which attended the meeting are allowed to open the shared documents.
+
diff --git a/src/main/resources/database/mysql/alter_13_2_x_to_14_0_0.sql b/src/main/resources/database/mysql/alter_13_2_x_to_14_0_0.sql
index 9d382e17bf0..5e2c65c71d8 100644
--- a/src/main/resources/database/mysql/alter_13_2_x_to_14_0_0.sql
+++ b/src/main/resources/database/mysql/alter_13_2_x_to_14_0_0.sql
@@ -144,6 +144,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date datetime default null,
    a_end_date datetime default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id bigint default null,
    a_sub_ident varchar(64) default null,
    fk_group_id bigint default null,
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index b7def7d09f7..2724ce92ba9 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1167,6 +1167,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date datetime default null,
    a_end_date datetime default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id bigint default null,
    a_sub_ident varchar(64) default null,
    fk_group_id bigint default null,
diff --git a/src/main/resources/database/oracle/alter_13_2_x_to_14_0_0.sql b/src/main/resources/database/oracle/alter_13_2_x_to_14_0_0.sql
index d6b7bb4950c..2456a1562d4 100644
--- a/src/main/resources/database/oracle/alter_13_2_x_to_14_0_0.sql
+++ b/src/main/resources/database/oracle/alter_13_2_x_to_14_0_0.sql
@@ -143,6 +143,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date timestamp default null,
    a_end_date timestamp default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id number(20) default null,
    a_sub_ident varchar(64) default null,
    fk_group_id number(20) default null,
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 6fc2bdf4125..8d57a386cf4 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1232,6 +1232,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date timestamp default null,
    a_end_date timestamp default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id number(20) default null,
    a_sub_ident varchar(64) default null,
    fk_group_id number(20) default null,
diff --git a/src/main/resources/database/postgresql/alter_13_2_x_to_14_0_0.sql b/src/main/resources/database/postgresql/alter_13_2_x_to_14_0_0.sql
index c28ab813971..902706624e4 100644
--- a/src/main/resources/database/postgresql/alter_13_2_x_to_14_0_0.sql
+++ b/src/main/resources/database/postgresql/alter_13_2_x_to_14_0_0.sql
@@ -142,6 +142,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date timestamp default null,
    a_end_date timestamp default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id int8 default null,
    a_sub_ident varchar(64) default null,
    fk_group_id int8 default null,
@@ -186,4 +187,3 @@ alter table o_as_mode_course add constraint as_mode_to_lblock_idx foreign key (f
 create index idx_as_mode_to_lblock_idx on o_as_mode_course (fk_lecture_block);
 
 
-
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 203f06b2250..4a192014bbb 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1192,6 +1192,7 @@ create table o_aconnect_meeting (
    a_description varchar(2000) default null,
    a_start_date timestamp default null,
    a_end_date timestamp default null,
+   a_shared_documents varchar(2000) default null,
    fk_entry_id int8 default null,
    a_sub_ident varchar(64) default null,
    fk_group_id int8 default null,
-- 
GitLab