diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonOpenCastRecordingsHandler.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonOpenCastRecordingsHandler.java index 7ce253716a50d5eba37279749b76f0df0124e112..dcd246878247b03c8b4c09e3c4a1532fb0b68e9b 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonOpenCastRecordingsHandler.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonOpenCastRecordingsHandler.java @@ -105,7 +105,7 @@ public class BigBlueButtonOpenCastRecordingsHandler implements BigBlueButtonReco return Collections.emptyList(); } - List<OpencastEvent> events = opencastService.getEvents(meeting.getMeetingId()); + List<OpencastEvent> events = opencastService.getEvents(meeting.getMeetingId(), true); List<BigBlueButtonRecording> recordings = new ArrayList<>(events.size()); for (OpencastEvent event : events) { String recordId = event.getIdentifier(); diff --git a/src/main/java/org/olat/modules/opencast/OpencastModule.java b/src/main/java/org/olat/modules/opencast/OpencastModule.java index ddf3350efb1f101055425645b3a359f0a585cf3a..a990dec6cca6f4d9a4dfc8a719210d60afd371c0 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/OpencastService.java b/src/main/java/org/olat/modules/opencast/OpencastService.java index b4e5c14c58a896c9830a7e2c5a00fe2348106bfa..9915777f85e8a9eae914dd71b3167f75e20587cf 100644 --- a/src/main/java/org/olat/modules/opencast/OpencastService.java +++ b/src/main/java/org/olat/modules/opencast/OpencastService.java @@ -59,9 +59,10 @@ public interface OpencastService { * Get the events with the metadata in the bibliographic data * * @param metadata + * @param publishedOnly only get events which are published on the presentation service * @return */ - List<OpencastEvent> getEvents(String metadata); + List<OpencastEvent> getEvents(String metadata, boolean publishedOnly); /** * Delete all events with the identifier. diff --git a/src/main/java/org/olat/modules/opencast/manager/OpencastServiceImpl.java b/src/main/java/org/olat/modules/opencast/manager/OpencastServiceImpl.java index 97a73122ec532055e6e350a603e52450f84041b2..d9083ccb879935d6b07dee3257fc001d267f58d1 100644 --- a/src/main/java/org/olat/modules/opencast/manager/OpencastServiceImpl.java +++ b/src/main/java/org/olat/modules/opencast/manager/OpencastServiceImpl.java @@ -93,11 +93,17 @@ public class OpencastServiceImpl implements OpencastService { } @Override - public List<OpencastEvent> getEvents(String metadata) { + public List<OpencastEvent> getEvents(String metadata, boolean publishedOnly) { GetEventsParams params = GetEventsParams.builder() .addFilter(Filter.textFilter, metadata) .build(); - return getEvents(params); + List<OpencastEvent> events = getEvents(params); + if (publishedOnly) { + events = events.stream() + .filter(event -> opencastRestClient.isEpisodeExisting(event.getIdentifier())) + .collect(Collectors.toList()); + } + return events; } private List<OpencastEvent> getEvents(GetEventsParams params) { 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 c0921524c919076cbf396ac40a1df28f27d7a9a0..2dace7682ae6327a32c2e990b60de6d7c0840440 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 0000000000000000000000000000000000000000..ae0b9afc3139ada4b0bcb7a3a3a93909165a9274 --- /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 0000000000000000000000000000000000000000..19ed85e597398efd53e983ecebbf46065152204e --- /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 c539730157509dd97345f76b20f1ac050cabe628..4b999ec140bd26178a7ee95720ba985e21d24ec5 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 2c79d29591a8c0df2def18e1207abcbd52b46ca0..1a5f2e4f79282808ba44864c22463bf69694715c 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 adce0b66cd37ffb65889fedf488c0c95cad3fd3f..25bd1442525ffcac5df0499e76d34cd7410275a8 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 600ee15851d2ede3cce264eaef1d7acba1800932..43e1fcccd0c0f0621873823ce91435e2e41972b3 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 Nov 20 07:19:48 CET 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 09bd2e7dedf20a1d8bf0a2c042bde873789c0839..31245032c9dda2843fc427ad1a6d7c1ef0848945 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 046b47ec6f507af124a5e0280e47d39d46fc5765..cda4a1dfd441a62ddf7266bef15e0c034c0ecc9a 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 dfbb1363a344ddfd379f9223d55aa76b1f3d65c2..fd9e2712d37a0a6dafcde571ca8668d61ebbbaeb 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -1817,7 +1817,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 39b0aedb2b90821cb9678258976c261bd28e9232..2dabf488128d1a86660b8c4f200abd860e652eec 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(); + } + + }