From f926106af364d90c0bcfa0d5ef71235cd49e5fd7 Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Fri, 4 Dec 2020 10:44:58 +0100
Subject: [PATCH] OO-5128: Deletion of Opencast events from presentation
 service

---
 .../olat/modules/opencast/OpencastModule.java | 13 ++++
 .../manager/client/OpencastRestClient.java    | 60 +++++++++++++++++++
 .../opencast/manager/client/SearchResult.java | 45 ++++++++++++++
 .../manager/client/SearchResults.java         | 43 +++++++++++++
 .../opencast/ui/OpencastAdminController.java  | 11 ++++
 .../ui/_i18n/LocalStrings_de.properties       |  4 +-
 .../ui/_i18n/LocalStrings_en.properties       |  4 +-
 .../ui/_i18n/LocalStrings_fr.properties       |  1 -
 .../ui/_i18n/LocalStrings_it.properties       |  1 -
 .../ui/_i18n/LocalStrings_pt_BR.properties    |  1 -
 .../resources/serviceconfig/olat.properties   |  3 +
 .../client/OpencastRestClientTest.java        | 23 ++++++-
 12 files changed, 203 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/opencast/manager/client/SearchResult.java
 create mode 100644 src/main/java/org/olat/modules/opencast/manager/client/SearchResults.java

diff --git a/src/main/java/org/olat/modules/opencast/OpencastModule.java b/src/main/java/org/olat/modules/opencast/OpencastModule.java
index ddf3350efb1..a990dec6cca 100644
--- a/src/main/java/org/olat/modules/opencast/OpencastModule.java
+++ b/src/main/java/org/olat/modules/opencast/OpencastModule.java
@@ -46,6 +46,7 @@ public class OpencastModule extends AbstractSpringModule implements ConfigOnOff
 
 	private static final String ENABLED = "opencast.enabled";
 	private static final String API_URL = "api.url";
+	private static final String API_PRESENTATION_URL = "api.presentation.url";
 	private static final String API_USERNAME = "api.username";
 	private static final String API_PASSOWRD = "api.password";
 	private static final String LTI_URL = "lti.url";
@@ -64,6 +65,8 @@ public class OpencastModule extends AbstractSpringModule implements ConfigOnOff
 	private boolean enabled;
 	@Value("${opencast.api.url}")
 	private String apiUrl;
+	@Value("${opencast.api.presentation.url}")
+	private String apiPresentationUrl;
 	@Value("${opencast.api.username}")
 	private String apiUsername;
 	@Value("${opencast.api.password}")
@@ -106,6 +109,7 @@ public class OpencastModule extends AbstractSpringModule implements ConfigOnOff
 		}
 		
 		apiUrl = getStringPropertyValue(API_URL, apiUrl);
+		apiPresentationUrl = getStringPropertyValue(API_PRESENTATION_URL, apiPresentationUrl);
 		apiUsername = getStringPropertyValue(API_USERNAME, apiUsername);
 		apiPassword = getStringPropertyValue(API_PASSOWRD, apiPassword);
 		refreshApiAuthorization();
@@ -158,6 +162,15 @@ public class OpencastModule extends AbstractSpringModule implements ConfigOnOff
 		setStringProperty(API_URL, apiUrl, true);
 	}
 
+	public String getApiPresentationUrl() {
+		return apiPresentationUrl;
+	}
+
+	public void setApiPresentationUrl(String apiPresentationUrl) {
+		this.apiPresentationUrl = apiPresentationUrl;
+		setStringProperty(API_PRESENTATION_URL, apiPresentationUrl, true);
+	}
+
 	public String getApiUrl() {
 		return apiUrl;
 	}
diff --git a/src/main/java/org/olat/modules/opencast/manager/client/OpencastRestClient.java b/src/main/java/org/olat/modules/opencast/manager/client/OpencastRestClient.java
index c0921524c91..2dace7682ae 100644
--- a/src/main/java/org/olat/modules/opencast/manager/client/OpencastRestClient.java
+++ b/src/main/java/org/olat/modules/opencast/manager/client/OpencastRestClient.java
@@ -142,6 +142,19 @@ public class OpencastRestClient {
 	}
 
 	public boolean deleteEvent(String identifier) {
+		boolean deleted = true;
+		Event event = getEvent(identifier);
+		if (event != null) {
+			deleted &= deleteEventFromAdmin(identifier);
+			
+		}
+		if (isEpisodeExisting(identifier)) {
+			deleted &= deleteEpisode(identifier);
+		}
+		return deleted;
+	}
+
+	private boolean deleteEventFromAdmin(String identifier) {
 		URI uri = URI.create(opencastModule.getApiUrl() + "/events/" + identifier);
 		HttpDelete request = new HttpDelete(uri);
 		decorateRequest(request);
@@ -213,6 +226,53 @@ public class OpencastRestClient {
 		return NO_SERIES;
 	}
 	
+	public boolean isEpisodeExisting(String identifier) {
+		URI uri;
+		try {
+			uri = new URIBuilder(opencastModule.getApiPresentationUrl() + "/episode.json")
+				.addParameter("id", identifier)
+				.build();
+		} catch (Exception e) {
+			log.error("Cannot get Opencast episode.", e);
+			return false;
+		}
+		
+		HttpGet request = new HttpGet(uri);
+		decorateRequest(request);
+		
+		try(CloseableHttpClient client = HttpClientBuilder.create().build();
+				CloseableHttpResponse response = client.execute(request)) {
+			int statusCode = response.getStatusLine().getStatusCode();
+			log.debug("Status code of: {} {}", uri, statusCode);
+			if (statusCode == HttpStatus.SC_OK) {
+				String json = EntityUtils.toString(response.getEntity(), "UTF-8");
+				SearchResult result = objectMapper.readValue(json, SearchResult.class);
+				return result.getSearchResults().getTotal() > 0;
+			}
+		} catch(Exception e) {
+			log.error("Cannot send: {}", uri, e);
+		}
+		return false;
+	}
+
+	private boolean deleteEpisode(String identifier) {
+		URI uri = URI.create(opencastModule.getApiPresentationUrl() + "/" + identifier);
+		HttpDelete request = new HttpDelete(uri);
+		decorateRequest(request);
+		
+		try(CloseableHttpClient client = HttpClientBuilder.create().build();
+				CloseableHttpResponse response = client.execute(request)) {
+			int statusCode = response.getStatusLine().getStatusCode();
+			log.debug("Status code of: {} {}", uri, statusCode);
+			if (statusCode == HttpStatus.SC_NO_CONTENT || statusCode == HttpStatus.SC_OK) {
+				return true;
+			}
+		} catch(Exception e) {
+			log.error("Cannot send: {}", uri, e);
+		}
+		return false;
+	}
+	
 	private void decorateRequest(HttpGet request, AuthDelegate authDelegate) {
 		decorateRequest(request);
 		if (AuthDelegate.Type.User == authDelegate.getType()) {
diff --git a/src/main/java/org/olat/modules/opencast/manager/client/SearchResult.java b/src/main/java/org/olat/modules/opencast/manager/client/SearchResult.java
new file mode 100644
index 00000000000..ae0b9afc313
--- /dev/null
+++ b/src/main/java/org/olat/modules/opencast/manager/client/SearchResult.java
@@ -0,0 +1,45 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.opencast.manager.client;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * 
+ * Initial date: 4 Dec 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class SearchResult {
+	
+	@JsonProperty("search-results")
+	private SearchResults searchResults;
+
+	public SearchResults getSearchResults() {
+		return searchResults;
+	}
+
+	public void setSearchResults(SearchResults searchResults) {
+		this.searchResults = searchResults;
+	}
+	
+}
diff --git a/src/main/java/org/olat/modules/opencast/manager/client/SearchResults.java b/src/main/java/org/olat/modules/opencast/manager/client/SearchResults.java
new file mode 100644
index 00000000000..19ed85e5973
--- /dev/null
+++ b/src/main/java/org/olat/modules/opencast/manager/client/SearchResults.java
@@ -0,0 +1,43 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.opencast.manager.client;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+/**
+ * 
+ * Initial date: 4 Dec 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class SearchResults {
+	
+	private int total;
+
+	public int getTotal() {
+		return total;
+	}
+
+	public void setTotal(int total) {
+		this.total = total;
+	}
+	
+}
diff --git a/src/main/java/org/olat/modules/opencast/ui/OpencastAdminController.java b/src/main/java/org/olat/modules/opencast/ui/OpencastAdminController.java
index c5397301575..4b999ec140b 100644
--- a/src/main/java/org/olat/modules/opencast/ui/OpencastAdminController.java
+++ b/src/main/java/org/olat/modules/opencast/ui/OpencastAdminController.java
@@ -59,6 +59,7 @@ public class OpencastAdminController extends FormBasicController {
 	
 	private MultipleSelectionElement enabledEl;
 	private TextElement apiUrlEl;
+	private TextElement apiUrlPresentationEl;
 	private TextElement apiUsernameEl;
 	private TextElement apiPasswordEl;
 	private TextElement ltiUrlEl;
@@ -103,6 +104,11 @@ public class OpencastAdminController extends FormBasicController {
 		apiUrlEl.setExampleKey("admin.api.url.example", null);
 		apiUrlEl.setMandatory(true);
 		
+		String apiPresentationUrl = opencastModule.getApiPresentationUrl();
+		apiUrlPresentationEl = uifactory.addTextElement("admin.api.presentation.url", "admin.api.presentation.url", 128, apiPresentationUrl, formLayout);
+		apiUrlPresentationEl.setExampleKey("admin.api.presentation.url.example", null);
+		apiUrlPresentationEl.setMandatory(true);
+		
 		String apiUsername = opencastModule.getApiUsername();
 		apiUsernameEl = uifactory.addTextElement("admin.api.username", 128, apiUsername, formLayout);
 		apiUsernameEl.setMandatory(true);
@@ -218,6 +224,7 @@ public class OpencastAdminController extends FormBasicController {
 		//validate only if the module is enabled
 		if(enabledEl.isAtLeastSelected(1)) {
 			allOk &= validateIsMandatory(apiUrlEl);
+			allOk &= validateIsMandatory(apiUrlPresentationEl);
 			allOk &= validateIsMandatory(apiUsernameEl);
 			allOk &= validateIsMandatory(apiPasswordEl);
 			allOk &= validateIsMandatory(ltiUrlEl);
@@ -251,6 +258,10 @@ public class OpencastAdminController extends FormBasicController {
 		apiUrl = apiUrl.endsWith("/")? apiUrl.substring(0, apiUrl.length() - 1): apiUrl;
 		opencastModule.setApiUrl(apiUrl);
 		
+		String apiPresentationUrl = apiUrlPresentationEl.getValue();
+		apiPresentationUrl = apiPresentationUrl.endsWith("/")? apiPresentationUrl.substring(0, apiPresentationUrl.length() - 1): apiPresentationUrl;
+		opencastModule.setApiPresentationUrl(apiPresentationUrl);
+		
 		String apiUsername = apiUsernameEl.getValue();
 		String apiPassword = apiPasswordEl.getValue();
 		opencastModule.setApiCredentials(apiUsername, apiPassword);
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_de.properties
index 2c79d29591a..1a5f2e4f792 100644
--- a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_de.properties
@@ -1,5 +1,7 @@
 admin.api.password=API Passwort
-admin.api.url=API URL
+admin.api.presentation.url=API URL (presentation)
+admin.api.presentation.url.example=https://presentation.opencast.example.com/search
+admin.api.url=API URL (admin)
 admin.api.url.example=https://admin.opencast.example.com/api
 admin.api.username=API Benutzername
 admin.auth.delegate.roles=Autorisierungsrollen
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_en.properties
index adce0b66cd3..25bd1442525 100644
--- a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_en.properties
@@ -1,5 +1,7 @@
 admin.api.password=API Password
-admin.api.url=API URL
+admin.api.presentation.url=API URL (presentation)
+admin.api.presentation.url.example=https://presentation.opencast.example.com/search
+admin.api.url=API URL (admin)
 admin.api.url.example=https://admin.opencast.example.com/api
 admin.api.username=API Username
 admin.auth.delegate.roles=Authorization roles
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_fr.properties
index 2c2d8e67efc..e41313e0750 100644
--- a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_fr.properties
@@ -1,6 +1,5 @@
 #Fri Aug 14 07:01:32 CEST 2020
 admin.api.password=Mot de passe API
-admin.api.url=URL de l'API (LTI)
 admin.api.url.example=https\://admin.opencast.example.com/api
 admin.api.username=Nom d'utilisateur de l'API
 admin.auth.delegate.roles=R\u00F4les des autorisations
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_it.properties
index 09bd2e7dedf..31245032c9d 100644
--- a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_it.properties
@@ -1,6 +1,5 @@
 #Sun Aug 30 15:40:09 CEST 2020
 admin.api.password=API Password
-admin.api.url=API URL
 admin.api.url.example=https\://admin.opencast.example.com/api
 admin.api.username=Nome utente API
 admin.auth.delegate.roles=Ruoli delle autorizzazioni
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties
index 046b47ec6f5..cda4a1dfd44 100644
--- a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,6 +1,5 @@
 #Fri Sep 25 19:49:48 CEST 2020
 admin.api.password=Senha API
-admin.api.url=URL API
 admin.api.url.example=https\://admin.opencast.example.com/api
 admin.api.username=Usu\u00E1rio da API
 admin.auth.delegate.roles=Fun\u00E7\u00F5es de autoriza\u00E7\u00E3o
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 20fa458bac9..1a7abeff51e 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -1780,7 +1780,10 @@ youtube.api.key=
 ###############################################################################
 opencast.enabled=false
 # API
+# REST endpoint of the admin service 
 opencast.api.url=https://admin.opencast.example.com/api
+# REST endpoint of the presentation service 
+opencast.api.presentation.url=https://presentation.opencast.example.com/search
 # Username and password of the technical opencast user
 opencast.api.username=
 opencast.api.password=
diff --git a/src/test/java/org/olat/modules/opencast/manager/client/OpencastRestClientTest.java b/src/test/java/org/olat/modules/opencast/manager/client/OpencastRestClientTest.java
index 39b0aedb2b9..2dabf488128 100644
--- a/src/test/java/org/olat/modules/opencast/manager/client/OpencastRestClientTest.java
+++ b/src/test/java/org/olat/modules/opencast/manager/client/OpencastRestClientTest.java
@@ -48,7 +48,8 @@ public class OpencastRestClientTest extends OlatTestCase {
 	
 	@Before
 	public void setUp() {
-		opencastModule.setApiUrl("http://localhost:8480");
+		opencastModule.setApiUrl("http://localhost:8480/api");
+		opencastModule.setApiPresentationUrl("http://localhost:8480/search");
 		opencastModule.setApiCredentials("admin", "opencast");
 	}
 
@@ -99,4 +100,24 @@ public class OpencastRestClientTest extends OlatTestCase {
 		softly.assertAll();
 	}
 	
+	@Test
+	public void shouldDeleteEvent() throws InterruptedException {
+		String identifier = "41a88d0d-a9f4-4928-81cf-7a23fef2f992";
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(sut.getEvent(identifier)).as("Event exists in admin").isNotNull();
+		softly.assertThat(sut.isEpisodeExisting(identifier)).as("Episode exists in presentation").isTrue();
+		
+		softly.assertThat(sut.deleteEvent(identifier)).as("deleted").isTrue();
+		
+		Thread.sleep(5000);
+		softly.assertThat(sut.getEvent(identifier)).as("Event does not exist in admin anymore").isNull();
+		softly.assertThat(sut.isEpisodeExisting(identifier)).as("Episode does not exist in presentation anymore").isFalse();
+		
+		softly.assertThat(sut.deleteEvent(identifier)).as("2. deleted").isTrue(); // because nothing to delete
+		
+		softly.assertAll();
+	}
+
+	
 }
-- 
GitLab