From 4c9ab3e7f1dcf646439edc7bc53d6a9f5e38974d Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Tue, 23 Apr 2019 16:20:22 +0200 Subject: [PATCH] OO-3887: new Adobe Connect course element (DFN impl. partial) --- src/main/java/de/bps/_spring/bpsContext.xml | 4 - .../de/bps/course/nodes/VCCourseNode.java | 208 ----- .../nodes/vc/DefaultVCConfiguration.java | 96 -- .../nodes/vc/VCDatesTableDataModel.java | 77 -- .../bps/course/nodes/vc/VCEditController.java | 267 ------ .../de/bps/course/nodes/vc/VCEditForm.java | 302 ------ .../java/de/bps/course/nodes/vc/VCModul.java | 83 -- .../bps/course/nodes/vc/VCRunController.java | 130 --- .../bps/course/nodes/vc/VCSelectionForm.java | 95 -- .../de/bps/course/nodes/vc/_content/edit.html | 13 - .../course/nodes/vc/_content/editForm.html | 53 -- .../course/nodes/vc/_content/noprovider.html | 3 - .../de/bps/course/nodes/vc/_content/run.html | 22 - .../nodes/vc/_i18n/LocalStrings_de.properties | 46 - .../nodes/vc/_i18n/LocalStrings_en.properties | 46 - .../nodes/vc/_i18n/LocalStrings_fr.properties | 48 - .../nodes/vc/_i18n/LocalStrings_it.properties | 43 - .../nodes/vc/_i18n/LocalStrings_pl.properties | 35 - .../vc/_i18n/LocalStrings_pt_BR.properties | 43 - .../nodes/vc/_spring/buildingblockContext.xml | 18 - .../bps/course/nodes/vc/_spring/vcContext.xml | 85 -- .../course/nodes/vc/provider/VCProvider.java | 199 ---- .../nodes/vc/provider/VCProviderFactory.java | 91 -- .../provider/adobe/AdobeConfigController.java | 78 -- .../adobe/AdobeConnectCleanupJob.java | 179 ---- .../adobe/AdobeConnectConfiguration.java | 64 -- .../provider/adobe/AdobeConnectProvider.java | 799 ---------------- .../adobe/AdobeDisplayController.java | 232 ----- .../vc/provider/adobe/AdobeEditForm.java | 99 -- .../adobe/AdobeEditTableDataModel.java | 77 -- .../vc/provider/adobe/_content/edit.html | 5 - .../nodes/vc/provider/adobe/_content/run.html | 28 - .../adobe/_i18n/LocalStrings_de.properties | 27 - .../adobe/_i18n/LocalStrings_en.properties | 29 - .../adobe/_i18n/LocalStrings_fr.properties | 29 - .../adobe/_i18n/LocalStrings_it.properties | 25 - .../adobe/_i18n/LocalStrings_pl.properties | 19 - .../adobe/_i18n/LocalStrings_pt_BR.properties | 25 - .../provider/adobe/_spring/adobeContext.xml | 17 - .../nodes/vc/provider/wimba/StatusCode.java | 74 -- .../wimba/WimbaClassroomProvider.java | 856 ------------------ .../provider/wimba/WimbaConfigController.java | 120 --- .../wimba/WimbaDisplayController.java | 402 -------- .../vc/provider/wimba/WimbaEditForm.java | 85 -- .../vc/provider/wimba/WimbaResponse.java | 99 -- .../vc/provider/wimba/_content/edit.html | 6 - .../nodes/vc/provider/wimba/_content/run.html | 58 -- .../wimba/_i18n/LocalStrings_de.properties | 49 - .../wimba/_i18n/LocalStrings_en.properties | 54 -- .../wimba/_i18n/LocalStrings_fr.properties | 54 -- .../wimba/_i18n/LocalStrings_it.properties | 49 - .../wimba/_i18n/LocalStrings_pl.properties | 20 - .../wimba/_i18n/LocalStrings_pt_BR.properties | 49 - .../provider/wimba/_spring/wimbaContext.xml | 32 - .../collaboration/CollaborationTools.java | 12 + .../CollaborationToolsFactory.java | 5 + .../_i18n/LocalStrings_de.properties | 1 + .../_i18n/LocalStrings_en.properties | 1 + .../_i18n/LocalStrings_fr.properties | 1 + .../scheduler/_spring/schedulerContext.xml | 1 - .../table/DateTimeFlexiCellRenderer.java | 53 ++ .../core/gui/media/RedirectMediaResource.java | 15 +- .../activity/OlatResourceableType.java | 3 +- src/main/java/org/olat/core/util/Encoder.java | 71 +- .../java/org/olat/core/util/ObjectCloner.java | 33 +- .../org/olat/course/CourseXStreamAliases.java | 10 + .../org/olat/course/_spring/courseContext.xml | 1 + .../course/nodes/AdobeConnectCourseNode.java | 180 ++++ .../AdobeConnectCourseNodeConfiguration.java} | 47 +- .../AdobeConnectEditController.java | 126 +++ .../AdobeConnectEditFormController.java | 92 ++ .../AdobeConnectPeekViewController.java} | 41 +- .../nodes/adobeconnect/_content/edit.html | 1 + .../_i18n/LocalStrings_de.properties | 10 + .../_i18n/LocalStrings_en.properties | 9 + .../_spring/buildingblockContext.xml | 21 + ...dobeConnectCompatibilityConfiguration.java | 100 ++ .../MeetingCompatibilityDate.java} | 54 +- ...aClassroomCompatibilityConfiguration.java} | 78 +- .../OpenMeetingsEditController.java | 2 +- .../nodes/st/PeekViewWrapperController.java | 2 +- .../run/BusinessGroupMainRunController.java | 99 +- .../ui/run/_i18n/LocalStrings_de.properties | 2 + .../ui/run/_i18n/LocalStrings_en.properties | 2 + .../olat/modules/_spring/modulesContext.xml | 20 + .../adobeconnect/AdobeConnectManager.java | 103 +++ .../adobeconnect/AdobeConnectMeeting.java | 65 ++ .../AdobeConnectMeetingPermission.java | 45 + .../AdobeConnectMettingSecurityCallback.java | 34 + .../adobeconnect/AdobeConnectModule.java | 253 ++++++ .../adobeconnect/AdobeConnectUser.java | 36 + .../manager/AbstractAdobeConnectProvider.java | 700 ++++++++++++++ .../manager/AdobeConnect9Provider.java | 137 +++ .../manager/AdobeConnectDOMHelper.java | 139 +++ .../manager/AdobeConnectManagerImpl.java | 382 ++++++++ .../manager/AdobeConnectMeetingDAO.java | 153 ++++ .../adobeconnect/manager/AdobeConnectSPI.java | 88 ++ .../manager/AdobeConnectUserDAO.java | 71 ++ .../adobeconnect/manager/DFNprovider.java | 165 ++++ .../manager/NoAdapterProvider.java | 146 +++ .../adobeconnect/model/AdobeConnectError.java | 59 ++ .../model/AdobeConnectErrorCodes.java | 43 + .../model/AdobeConnectErrors.java} | 48 +- .../model/AdobeConnectMeetingImpl.java | 223 +++++ .../model/AdobeConnectPermission.java | 57 ++ .../model/AdobeConnectPrincipal.java | 61 ++ .../adobeconnect/model/AdobeConnectSco.java | 113 +++ .../model/AdobeConnectUserImpl.java | 137 +++ .../adobeconnect/model/BreezeSession.java | 71 ++ .../ui/AdobeConnectAdminController.java | 104 +++ .../AdobeConnectAdminMeetingsController.java | 171 ++++ .../AdobeConnectConfigurationController.java | 297 ++++++ .../AdobeConnectContentRedirectResource.java | 103 +++ .../ui/AdobeConnectContentRow.java | 51 ++ .../ui/AdobeConnectContentTableModel.java | 108 +++ .../AdobeConnectEditMeetingsController.java | 228 +++++ .../ui/AdobeConnectErrorEvent.java | 47 + .../ui/AdobeConnectErrorHelper.java | 45 + .../ui/AdobeConnectIconRenderer.java | 85 ++ .../ui/AdobeConnectMeetingController.java | 222 +++++ ...obeConnectMeetingDefaultConfiguration.java | 21 + .../ui/AdobeConnectMeetingTableModel.java | 117 +++ .../ui/AdobeConnectMeetingsController.java | 167 ++++ .../ui/AdobeConnectRunController.java | 167 ++++ .../ui/EditAdobeConnectMeetingController.java | 228 +++++ .../ui/SelectAdobeConnectMeetingEvent.java | 48 + .../adobeconnect/ui/_content/adminconfig.html | 6 + .../ui/_content/adobeconnect_admin.html | 7 + .../adobeconnect/ui/_content/meeting.html | 28 + .../adobeconnect/ui/_content/meetings.html | 6 + .../ui/_content/meetings_admin.html | 6 + .../modules/adobeconnect/ui/_content/run.html | 8 + .../adobeconnect/ui/_content/run_admin.html | 11 + .../ui/_i18n/LocalStrings_de.properties | 59 ++ .../ui/_i18n/LocalStrings_en.properties | 60 ++ .../ui/_i18n/LocalStrings_fr.properties | 7 + .../ui/GoToMeetingsController.java | 2 +- .../manager/OpenMeetingsLanguages.java | 3 +- .../manager/OpenMeetingsManagerImpl.java | 12 +- .../OpenMeetingsConfigurationController.java | 6 +- .../ui/OpenMeetingsRunController.java | 13 +- .../openmeetings/ui/_content/adminconfig.html | 7 +- src/main/resources/META-INF/persistence.xml | 4 +- .../database/mysql/alter_13_2_x_to_13_3_0.sql | 35 + .../database/mysql/setupDatabase.sql | 34 + .../oracle/alter_13_2_x_to_13_3_0.sql | 34 + .../database/oracle/setupDatabase.sql | 34 + .../postgresql/alter_13_2_x_to_13_3_0.sql | 32 + .../database/postgresql/setupDatabase.sql | 37 +- .../resources/serviceconfig/olat.properties | 34 +- .../java/org/olat/core/util/EncoderTest.java | 30 + .../manager/AdobeConnectMeetingDAOTest.java | 149 +++ .../manager/AdobeConnectProviderTest.java | 47 + .../manager/AdobeConnectUserDAOTest.java | 98 ++ .../java/org/olat/test/AllTestsJunit4.java | 3 + 155 files changed, 7209 insertions(+), 5980 deletions(-) delete mode 100644 src/main/java/de/bps/course/nodes/VCCourseNode.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/DefaultVCConfiguration.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCDatesTableDataModel.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCEditController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCEditForm.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCModul.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCRunController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/VCSelectionForm.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/_content/edit.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/_content/editForm.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/_content/noprovider.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/_content/run.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_de.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_en.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_fr.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_it.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pl.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pt_BR.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/_spring/buildingblockContext.xml delete mode 100644 src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/VCProvider.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/VCProviderFactory.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConfigController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectCleanupJob.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectConfiguration.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectProvider.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeDisplayController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditForm.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditTableDataModel.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/edit.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/run.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_de.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_en.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_fr.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_it.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pl.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pt_BR.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/adobe/_spring/adobeContext.xml delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/StatusCode.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomProvider.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaConfigController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaDisplayController.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaEditForm.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaResponse.java delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/edit.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/run.html delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_de.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_en.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_fr.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_it.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pl.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pt_BR.properties delete mode 100644 src/main/java/de/bps/course/nodes/vc/provider/wimba/_spring/wimbaContext.xml create mode 100644 src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DateTimeFlexiCellRenderer.java create mode 100644 src/main/java/org/olat/course/nodes/AdobeConnectCourseNode.java rename src/main/java/{de/bps/course/nodes/vc/VCCourseNodeConfiguration.java => org/olat/course/nodes/adobeconnect/AdobeConnectCourseNodeConfiguration.java} (63%) create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditController.java create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditFormController.java rename src/main/java/{de/bps/course/nodes/vc/NoProviderController.java => org/olat/course/nodes/adobeconnect/AdobeConnectPeekViewController.java} (51%) create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/_content/edit.html create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_de.properties create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_en.properties create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/_spring/buildingblockContext.xml create mode 100644 src/main/java/org/olat/course/nodes/adobeconnect/compatibility/AdobeConnectCompatibilityConfiguration.java rename src/main/java/{de/bps/course/nodes/vc/MeetingDate.java => org/olat/course/nodes/adobeconnect/compatibility/MeetingCompatibilityDate.java} (56%) rename src/main/java/{de/bps/course/nodes/vc/provider/wimba/WimbaClassroomConfiguration.java => org/olat/course/nodes/adobeconnect/compatibility/WimbaClassroomCompatibilityConfiguration.java} (76%) create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeetingPermission.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectMettingSecurityCallback.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectModule.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/AdobeConnectUser.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AbstractAdobeConnectProvider.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnect9Provider.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectDOMHelper.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAO.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectSPI.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAO.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/DFNprovider.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/manager/NoAdapterProvider.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectError.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrorCodes.java rename src/main/java/{de/bps/course/nodes/vc/VCConfiguration.java => org/olat/modules/adobeconnect/model/AdobeConnectErrors.java} (51%) create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPermission.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPrincipal.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectUserImpl.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/model/BreezeSession.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminMeetingsController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectConfigurationController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRedirectResource.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectEditMeetingsController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorEvent.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorHelper.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectIconRenderer.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingTableModel.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingsController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectRunController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/EditAdobeConnectMeetingController.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/SelectAdobeConnectMeetingEvent.java create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/adminconfig.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/adobeconnect_admin.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings_admin.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/run.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_content/run_admin.html create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties create mode 100644 src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_fr.properties create mode 100644 src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAOTest.java create mode 100644 src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectProviderTest.java create mode 100644 src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAOTest.java diff --git a/src/main/java/de/bps/_spring/bpsContext.xml b/src/main/java/de/bps/_spring/bpsContext.xml index aaebf954991..64fc9e1c493 100644 --- a/src/main/java/de/bps/_spring/bpsContext.xml +++ b/src/main/java/de/bps/_spring/bpsContext.xml @@ -11,10 +11,6 @@ <import resource="classpath:/de/bps/course/nodes/cl/_spring/buildingblockContext.xml"/> <import resource="classpath:/de/bps/course/nodes/den/_spring/buildingblockContext.xml"/> <import resource="classpath:/de/bps/course/nodes/ll/_spring/buildingblockContext.xml"/> - <import resource="classpath:/de/bps/course/nodes/vc/_spring/buildingblockContext.xml"/> - <import resource="classpath:/de/bps/course/nodes/vc/_spring/vcContext.xml"/> - <import resource="classpath:/de/bps/course/nodes/vc/provider/adobe/_spring/adobeContext.xml"/> - <import resource="classpath:/de/bps/course/nodes/vc/provider/wimba/_spring/wimbaContext.xml"/> <import resource="classpath:/de/bps/olat/user/_spring/changeEmailContext.xml"/> </beans> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/VCCourseNode.java b/src/main/java/de/bps/course/nodes/VCCourseNode.java deleted file mode 100644 index 5c2e0966deb..00000000000 --- a/src/main/java/de/bps/course/nodes/VCCourseNode.java +++ /dev/null @@ -1,208 +0,0 @@ -// <OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes; - -import java.util.List; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.stack.BreadcrumbPanel; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.generic.tabbable.TabbableController; -import org.olat.core.gui.control.generic.tabbable.TabbableDefaultController; -import org.olat.core.util.Util; -import org.olat.core.util.ValidationStatus; -import org.olat.course.ICourse; -import org.olat.course.condition.ConditionEditController; -import org.olat.course.editor.CourseEditorEnv; -import org.olat.course.editor.NodeEditController; -import org.olat.course.editor.StatusDescription; -import org.olat.course.nodes.AbstractAccessableCourseNode; -import org.olat.course.nodes.CourseNode; -import org.olat.course.nodes.StatusDescriptionHelper; -import org.olat.course.nodes.TitledWrapperHelper; -import org.olat.course.run.navigation.NodeRunConstructionResult; -import org.olat.course.run.userview.NodeEvaluation; -import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.repository.RepositoryEntry; - -import de.bps.course.nodes.vc.NoProviderController; -import de.bps.course.nodes.vc.VCConfiguration; -import de.bps.course.nodes.vc.VCEditController; -import de.bps.course.nodes.vc.VCRunController; -import de.bps.course.nodes.vc.provider.VCProvider; -import de.bps.course.nodes.vc.provider.VCProviderFactory; - -/** - * Description:<br> - * date list course node. - * - * <P> - * Initial Date: 19.07.2010 <br> - * - * @author Jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber - */ -public class VCCourseNode extends AbstractAccessableCourseNode { - - private static final String TYPE = "vc"; - - // configuration - public static final String CONF_VC_CONFIGURATION = "vc_configuration"; - public static final String CONF_PROVIDER_ID = "vc_provider_id"; - - public VCCourseNode() { - super(TYPE); - } - - /** - * To support different virtual classroom implementations it's necessary to - * check whether the persisted configuration suits to the actual virtual - * classroom implementation or not. If not a new one will be created and - * persisted. - * - * @param provider - * @return the persisted configuration or a fresh one - */ - private VCConfiguration handleConfig(final VCProvider provider) { - getModuleConfiguration().setStringValue(CONF_PROVIDER_ID, provider.getProviderId()); - VCConfiguration config = (VCConfiguration) getModuleConfiguration().get(CONF_VC_CONFIGURATION); - if (config == null || config.getProviderId() == null || !config.getProviderId().equals(provider.getProviderId())) { - config = provider.createNewConfiguration(); - } - getModuleConfiguration().set(CONF_VC_CONFIGURATION, config); - return config; - } - - @Override - public void updateModuleConfigDefaults(boolean isNewNode) { - // no update to default config necessary - } - - @Override - public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, - UserCourseEnvironment userCourseEnv) { - updateModuleConfigDefaults(false); - CourseNode chosenNode = course.getEditorTreeModel().getCourseNode(userCourseEnv.getCourseEditorEnv().getCurrentCourseNodeId()); - // load and check configuration - String providerId = getModuleConfiguration().getStringValue(CONF_PROVIDER_ID); - VCProvider provider = providerId == null ? VCProviderFactory.createDefaultProvider() : VCProviderFactory.createProvider(providerId); - - TabbableDefaultController childTabCntrllr; - if(provider != null) { - VCConfiguration config = handleConfig(provider); - // create room if configured to do it immediately - if(config.isCreateMeetingImmediately()) { - Long key = course.getResourceableId(); - // here, the config is empty in any case, thus there are no start and end dates - provider.createClassroom(key + "_" + this.getIdent(), this.getShortName(), this.getLongTitle(), null, null, config); - } - // create edit controller - childTabCntrllr = new VCEditController(ureq, wControl, this, course, userCourseEnv, provider, config); - } else { - //empty panel - childTabCntrllr = new NoProviderController(ureq, wControl); - } - - NodeEditController nodeEditCtr = new NodeEditController(ureq, wControl, course.getEditorTreeModel(), course, chosenNode, - userCourseEnv, childTabCntrllr); - nodeEditCtr.addControllerListener(childTabCntrllr); - return nodeEditCtr; - } - - @Override - public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl, - UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) { - updateModuleConfigDefaults(false); - // check if user is moderator of the virtual classroom - boolean moderator = userCourseEnv.isAdmin(); - - // load configuration - final String providerId = getModuleConfiguration().getStringValue(CONF_PROVIDER_ID); - VCProvider provider = providerId == null ? VCProviderFactory.createDefaultProvider() : VCProviderFactory.createProvider(providerId); - VCConfiguration config = handleConfig(provider); - // create run controller - Long key = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); - Controller runCtr = new VCRunController(ureq, wControl, key + "_" + getIdent(), getShortName(), getLongTitle(), config, provider, - moderator, userCourseEnv.isCourseReadOnly()); - Controller controller = TitledWrapperHelper.getWrapper(ureq, wControl, runCtr, this, "o_vc_icon"); - return new NodeRunConstructionResult(controller); - } - - @Override - public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, - NodeEvaluation ne) { - return null; - } - - @Override - public StatusDescription[] isConfigValid(CourseEditorEnv cev) { - String translatorStr = Util.getPackageName(ConditionEditController.class); - List<StatusDescription> statusDescs = isConfigValidWithTranslator(cev, translatorStr, getConditionExpressions()); - return StatusDescriptionHelper.sort(statusDescs); - } - - @Override - public RepositoryEntry getReferencedRepositoryEntry() { - return null; - } - - @Override - public StatusDescription isConfigValid() { - if (oneClickStatusCache != null) { return oneClickStatusCache[0]; } - StatusDescription status = StatusDescription.NOERROR; - - // load configuration - final String providerId = getModuleConfiguration().getStringValue(CONF_PROVIDER_ID); - VCProvider provider = providerId == null ? VCProviderFactory.createDefaultProvider() : VCProviderFactory.createProvider(providerId); - boolean invalid = provider == null || !handleConfig(provider).isConfigValid(); - if (invalid) { - String[] params = new String[] { this.getShortTitle() }; - String shortKey = "error.config.short"; - String longKey = "error.config.long"; - String translationPackage = VCEditController.class.getPackage().getName(); - status = new StatusDescription(ValidationStatus.ERROR, shortKey, longKey, params, translationPackage); - status.setDescriptionForUnit(getIdent()); - status.setActivateableViewIdentifier(VCEditController.PANE_TAB_VCCONFIG); - } - - return status; - } - - @Override - public boolean needsReferenceToARepositoryEntry() { - return false; - } - - @Override - public void cleanupOnDelete(ICourse course) { - super.cleanupOnDelete(course); - - // load configuration - final String providerId = getModuleConfiguration().getStringValue(CONF_PROVIDER_ID); - VCProvider provider = providerId == null ? VCProviderFactory.createDefaultProvider() : VCProviderFactory.createProvider(providerId); - VCConfiguration config = handleConfig(provider); - // remove meeting - provider.removeClassroom(course.getResourceableId() + "_" + this.getIdent(), config); - } - -} -// </OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/DefaultVCConfiguration.java b/src/main/java/de/bps/course/nodes/vc/DefaultVCConfiguration.java deleted file mode 100644 index 22af303284c..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/DefaultVCConfiguration.java +++ /dev/null @@ -1,96 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import java.io.Serializable; -import java.util.List; - - -/** - * - * Description:<br> - * Standard configuration object, each provider implementation must override this class - * and extend it with it's specific configuration values. - * - * <P> - * Initial Date: 18.01.2011 <br> - * @author skoeber - */ -public abstract class DefaultVCConfiguration implements VCConfiguration, Serializable { - - public static String DEFAULT_TEMPLATE = "default"; - - private String providerId; - private String templateKey; - private List<MeetingDate> meetingDatas; - private boolean useMeetingDates; - private boolean createMeetingImmediately; - - @Override - public String getProviderId() { - return providerId; - } - - public void setProviderId(String providerId) { - this.providerId = providerId; - } - - @Override - public String getTemplateKey() { - return templateKey; - } - - public void setTemplateKey(String templateKey) { - this.templateKey = templateKey; - } - - @Override - public boolean isUseMeetingDates() { - return useMeetingDates; - } - - public void setUseMeetingDates(boolean useMeetingDates) { - this.useMeetingDates = useMeetingDates; - } - - @Override - public List<MeetingDate> getMeetingDates() { - return meetingDatas; - } - - public void setMeetingDatas(List<MeetingDate> meetingDatas) { - this.meetingDatas = meetingDatas; - } - - public void setCreateMeetingImmediately(boolean createMeetingImmediately) { - this.createMeetingImmediately = createMeetingImmediately; - } - - @Override - public boolean isCreateMeetingImmediately() { - return createMeetingImmediately; - } - - @Override - public abstract boolean isConfigValid(); - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/VCDatesTableDataModel.java b/src/main/java/de/bps/course/nodes/vc/VCDatesTableDataModel.java deleted file mode 100644 index 03f8812154c..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCDatesTableDataModel.java +++ /dev/null @@ -1,77 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import java.util.List; - -import org.olat.core.gui.components.table.DefaultTableDataModel; - - -/** - * - * Description:<br> - * Table model for run view of vc course node. Summarizes all planned dates for meetings. - * - * <P> - * Initial Date: 19.01.2011 <br> - * @author skoeber - */ -public class VCDatesTableDataModel extends DefaultTableDataModel<MeetingDate> { - - //title, description, begin, end - private static final int COLUMN_COUNT = 4; - - public VCDatesTableDataModel(List<MeetingDate> objects) { - super(objects); - } - - @Override - public int getColumnCount() { - return COLUMN_COUNT; - } - - @Override - public Object getValueAt(int row, int col) { - final MeetingDate model = objects.get(row); - - switch (col) { - case 0: - return model.getTitle(); - case 1: - return model.getDescription(); - case 2: - return model.getBegin(); - case 3: - return model.getEnd(); - default: - return "error"; - } - } - - public MeetingDate getEntryAt(int row) { - return objects.get(row); - } - - public void setEntries(List<MeetingDate> newEntries) { - this.objects = newEntries; - } -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/VCEditController.java b/src/main/java/de/bps/course/nodes/vc/VCEditController.java deleted file mode 100644 index 7ba8164f8e7..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCEditController.java +++ /dev/null @@ -1,267 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import java.util.Date; -import java.util.List; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.tabbedpane.TabbedPane; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.ControllerEventListener; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.generic.modal.DialogBoxController; -import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; -import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController; -import org.olat.course.ICourse; -import org.olat.course.assessment.AssessmentHelper; -import org.olat.course.condition.Condition; -import org.olat.course.condition.ConditionEditController; -import org.olat.course.editor.NodeEditController; -import org.olat.course.run.userview.UserCourseEnvironment; -import org.olat.modules.ModuleConfiguration; - -import de.bps.course.nodes.VCCourseNode; -import de.bps.course.nodes.vc.provider.VCProvider; -import de.bps.course.nodes.vc.provider.VCProviderFactory; - -/** - * Description:<br> - * Edit controller for dates list course nodes - Virtual Classroom dates . - * - * <P> - * Initial Date: 30.08.2010 <br> - * - * @author Jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber - */ -public class VCEditController extends ActivateableTabbableDefaultController implements ControllerEventListener { - - private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility"; - public static final String PANE_TAB_VCCONFIG = "pane.tab.vcconfig"; - final static String[] paneKeys = { PANE_TAB_VCCONFIG, PANE_TAB_ACCESSIBILITY }; - - // GUI - private VelocityContainer editVc; - private ConditionEditController accessibilityCondContr; - private TabbedPane tabPane; - private Controller configCtr; - private VCSelectionForm selForm; - private VCEditForm editForm; - private DialogBoxController yesNoUpdate; - private DialogBoxController yesNoDelete; - - // runtime data - private VCCourseNode courseNode; - private VCConfiguration config; - private VCProvider provider; - private String roomId; - - public VCEditController(UserRequest ureq, WindowControl wControl, VCCourseNode courseNode, - ICourse course, UserCourseEnvironment userCourseEnv, VCProvider provider, VCConfiguration config) { - super(ureq, wControl); - this.courseNode = courseNode; - this.config = config; - this.provider = provider; - - editVc = this.createVelocityContainer("edit"); - - Condition accessCondition = courseNode.getPreConditionAccess(); - accessibilityCondContr = new ConditionEditController(ureq, wControl, userCourseEnv, - accessCondition, AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), courseNode)); - listenTo(accessibilityCondContr); - - // show selection form when there is more than one registered virtual classroom provider - List<VCProvider> registeredProviders = VCProviderFactory.getProviders(); - if(registeredProviders.size() > 1) { - selForm = new VCSelectionForm(ureq, wControl, provider.getProviderId()); - listenTo(selForm); - editVc.put("VCSelectionForm", selForm.getInitialComponent()); - } - - editForm = new VCEditForm(ureq, wControl, provider.getTemplates(), (DefaultVCConfiguration) config); - listenTo(editForm); - editVc.put("editForm", editForm.getInitialComponent()); - - roomId = course.getResourceableId() + "_" + courseNode.getIdent(); - - configCtr = provider.createConfigController(ureq, wControl, roomId, config); - listenTo(configCtr); - editVc.put("configCtr", configCtr.getInitialComponent()); - } - - @Override - public String[] getPaneKeys() { - return paneKeys; - } - - @Override - public TabbedPane getTabbedPane() { - return tabPane; - } - - @Override - protected void doDispose() { - if(configCtr != null) { - removeAsListenerAndDispose(configCtr); - configCtr = null; - } - if(editForm != null) { - removeAsListenerAndDispose(editForm); - editForm = null; - } - if(selForm != null) { - removeAsListenerAndDispose(selForm); - selForm = null; - } - if(yesNoDelete != null) { - removeAsListenerAndDispose(yesNoDelete); - yesNoDelete = null; - } - if(yesNoUpdate != null) { - removeAsListenerAndDispose(yesNoUpdate); - yesNoUpdate = null; - } - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - // nothing to do - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if (source == accessibilityCondContr) { - if (event == Event.CHANGED_EVENT) { - Condition cond = accessibilityCondContr.getCondition(); - courseNode.setPreConditionAccess(cond); - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } - } else if (source == configCtr | source == editForm) { - courseNode.getModuleConfiguration().set(VCCourseNode.CONF_VC_CONFIGURATION, config); - courseNode.getModuleConfiguration().setStringValue(VCCourseNode.CONF_PROVIDER_ID, config.getProviderId()); - /* - if(provider.existsClassroom(roomId, config)) { - removeAsListenerAndDispose(yesNoUpdate); - yesNoUpdate = DialogBoxUIFactory.createYesNoDialog(ureq, getWindowControl(), translate("sync.meeting.title"), translate("sync.meeting.text")); - listenTo(yesNoUpdate); - yesNoUpdate.activate(); - } - */ - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } else if (source == selForm) { - /* - * If classroom already exists and the user changes the provider, - * the existing room has to be deleted for cleanup purposes. Ask - * the user if this is intended. - */ - if(provider.existsClassroom(roomId, config)) { - removeAsListenerAndDispose(yesNoDelete); - yesNoDelete = DialogBoxUIFactory.createYesNoDialog(ureq, getWindowControl(), translate("delete.meeting.title"), translate("delete.meeting.text")); - listenTo(yesNoDelete); - yesNoDelete.activate(); - } else { - reset(ureq); - } - } else if (source == yesNoDelete) { - if(DialogBoxUIFactory.isYesEvent(event)) { - provider.removeClassroom(roomId, config); - reset(ureq); - } - } else if(source == yesNoUpdate) { - if(DialogBoxUIFactory.isYesEvent(event)) { - Date allBegin = null, allEnd = null; - if(config.getMeetingDates() != null) { - for(MeetingDate date : config.getMeetingDates()) { - Date begin = date.getBegin(); - Date end = date.getEnd(); - allBegin = allBegin == null ? begin : begin.before(allBegin) ? begin : allBegin; - allEnd = allEnd == null ? end : end.after(allEnd) ? end : allEnd; - } - } - boolean success = provider.updateClassroom(roomId, courseNode.getShortTitle(), courseNode.getLongTitle(), allBegin, allEnd, config); - if(success) { - getWindowControl().setInfo(translate("success.update.room")); - } else { - getWindowControl().setError(translate("error.update.room")); - } - } - } else if(event == NodeEditController.NODECONFIG_CHANGED_EVENT) { - // something has changed, maybe the title or description, thus ask to update - if(provider.existsClassroom(roomId, config)) { - removeAsListenerAndDispose(yesNoUpdate); - yesNoUpdate = DialogBoxUIFactory.createYesNoDialog(ureq, getWindowControl(), translate("sync.meeting.title"), translate("sync.meeting.text")); - listenTo(yesNoUpdate); - yesNoUpdate.activate(); - } - } - } - - private void reset(UserRequest ureq) { - removeAsListenerAndDispose(editForm); - removeAsListenerAndDispose(configCtr); - // prepare new edit view - String providerId = selForm.getSelectedProvider(); - provider = VCProviderFactory.createProvider(providerId); - config = provider.createNewConfiguration(); - // create room if configured to do it immediately - if(config.isCreateMeetingImmediately()) { - // here, the config is empty in any case, thus there are no start and end dates - provider.createClassroom(roomId, courseNode.getShortName(), courseNode.getLongTitle(), null, null, config); - } - editForm = new VCEditForm(ureq, getWindowControl(), provider.getTemplates(), (DefaultVCConfiguration) config); - listenTo(editForm); - editVc.put("editForm", editForm.getInitialComponent()); - configCtr = provider.createConfigController(ureq, getWindowControl(), roomId, config); - listenTo(configCtr); - editVc.put("configCtr", configCtr.getInitialComponent()); - editVc.setDirty(true); - // save the minimal config - courseNode.getModuleConfiguration().set(VCCourseNode.CONF_VC_CONFIGURATION, config); - courseNode.getModuleConfiguration().setStringValue(VCCourseNode.CONF_PROVIDER_ID, config.getProviderId()); - - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } - - public void addTabs(TabbedPane tabbedPane) { - tabPane = tabbedPane; - tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), - accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate("condition.accessibility.title"))); - tabbedPane.addTab(translate(PANE_TAB_VCCONFIG), editVc); - - } - - public static boolean isConfigValid(ModuleConfiguration moduleConfig) { - List<MeetingDate> dateList = (List<MeetingDate>) moduleConfig.get(VCCourseNode.CONF_VC_CONFIGURATION); - if (dateList != null) { - for (MeetingDate date : dateList) { - if (date.getTitle().isEmpty() || date.getDescription().isEmpty()) { return false; } - - } - return true; - } - return false; - } -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/VCEditForm.java b/src/main/java/de/bps/course/nodes/vc/VCEditForm.java deleted file mode 100644 index 696b1ade1b2..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCEditForm.java +++ /dev/null @@ -1,302 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TimeZone; - -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.DateChooser; -import org.olat.core.gui.components.form.flexible.elements.FormLink; -import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; -import org.olat.core.gui.components.form.flexible.elements.SingleSelection; -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.form.flexible.impl.elements.FormLinkImpl; -import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; -import org.olat.core.gui.components.link.Link; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.course.editor.NodeEditController; - - -/** - * - * Description:<br> - * Form for standard options of the virtual classroom course node. - * - * <P> - * Initial Date: 18.01.2011 <br> - * @author skoeber - */ -public class VCEditForm extends FormBasicController { - - // GUI - private FormLayoutContainer editVC; - private FormSubmit submit; - private List<TextElement> vcTitleInputList; - private List<TextElement> vcDescriptionInputList; - private List<DateChooser> vcCalenderbeginInputList; - private List<TextElement> vcDurationInputList; - private List<FormLink> vcDelButtonList; - private List<FormLink> vcAddButtonList; - private SingleSelection vcTemplate; - private MultipleSelectionElement multiSelectOptions; - private static String OPTION_DATES = "vc.access.dates"; - - // data - private DefaultVCConfiguration config; - private Map<String,String> templates = new HashMap<String, String>(); - private List<MeetingDate> dateList = new ArrayList<MeetingDate>(); - - private int counter = 0; - - public VCEditForm(UserRequest ureq, WindowControl wControl, Map<String, String> templates, DefaultVCConfiguration config) { - super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL); - this.config = config; - this.templates.putAll(templates); - - // read existing dates from config - if(config.getMeetingDates() != null) dateList.addAll(config.getMeetingDates()); - - this.vcTitleInputList = new ArrayList<TextElement>(dateList.size()); - this.vcDescriptionInputList = new ArrayList<TextElement>(dateList.size()); - this.vcCalenderbeginInputList = new ArrayList<DateChooser>(dateList.size()); - this.vcDurationInputList = new ArrayList<TextElement>(dateList.size()); - this.vcAddButtonList = new ArrayList<FormLink>(dateList.size()); - this.vcDelButtonList = new ArrayList<FormLink>(dateList.size()); - - initForm(this.flc, this, ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - editVC = FormLayoutContainer.createCustomFormLayout("titleLayout", getTranslator(), velocity_root + "/editForm.html"); - formLayout.add(editVC); - - // template chooser - String[] keys = new String[templates.size() + 1]; - keys[0] = DefaultVCConfiguration.DEFAULT_TEMPLATE; - String[] values = new String[templates.size() + 1]; - values[0] = ""; - int index = 1; - for(String key:templates.keySet()) { - keys[index] = key; - values[index] = templates.get(key); - index++; - } - boolean hasTemplates = templates.size() > 0; - if(hasTemplates) { - vcTemplate = uifactory.addDropdownSingleselect("vc.template.choose", "vc.template.choose.label", editVC, keys, values, null); - String templateKey = config.getTemplateKey(); - vcTemplate.select(templateKey == null ? DefaultVCConfiguration.DEFAULT_TEMPLATE : templateKey, true); - } - editVC.contextPut("hasTemplates", hasTemplates); - - // meeting options - boolean useDates = !dateList.isEmpty() | config.isUseMeetingDates(); - String[] accessKeys = new String[] {OPTION_DATES}; - String[] accessVals = new String[] {translate(OPTION_DATES)}; - multiSelectOptions = uifactory.addCheckboxesVertical("vc.options", "vc.options.label", editVC, accessKeys, accessVals, 1); - multiSelectOptions.select(OPTION_DATES, useDates); - multiSelectOptions.addActionListener(FormEvent.ONCHANGE); - - // create gui elements for all meetings - editVC.contextPut("useDates", useDates); - if(useDates) addDates(); - - editVC.contextPut("dateList", dateList); - editVC.contextPut("vcTitleInputList", vcTitleInputList); - editVC.contextPut("vcDescriptionInputList", vcDescriptionInputList); - editVC.contextPut("vcCalenderbeginInputList", vcCalenderbeginInputList); - editVC.contextPut("vcDurationInputList", vcDurationInputList); - editVC.contextPut("vcAddButtonList", vcAddButtonList); - editVC.contextPut("vcDelButtonList", vcDelButtonList); - - submit = new FormSubmit("subm", "submit"); - - formLayout.add(submit); - } - - private void addDates() { - if (dateList.isEmpty()) { - MeetingDate meetingData = new MeetingDate(); - meetingData.setBegin(new Date()); - meetingData.setEnd(new Date(meetingData.getBegin().getTime() + 1000*60*60)); - dateList.add(meetingData); - } - for (int i = 0; i < dateList.size(); i++) { - MeetingDate date = dateList.get(i); - addRow(i, date); - } - } - - private void removeDates() { - for (int i = 0; i < dateList.size(); i++) { - removeRow(i); - } - } - - @Override - protected void doDispose() { - // nothing to dispose - } - - @Override - protected void formOK(UserRequest ureq) { - // read data from form elements - for (int i = 0; i < dateList.size(); i++) { - MeetingDate date = dateList.get(i); - String dateValue = vcTitleInputList.get(i).getValue(); - date.setTitle(dateValue); - - StringTokenizer strTok = new StringTokenizer(vcDurationInputList.get(i).getValue(), ":", false); - long dur = 1000 * 60 * 60 * Long.parseLong(strTok.nextToken()) + 1000 * 60 * Long.parseLong(strTok.nextToken()); - - date.setBegin(vcCalenderbeginInputList.get(i).getDate()); - date.setEnd(new Date(date.getBegin().getTime() + dur)); - date.setDescription(vcDescriptionInputList.get(i).getValue()); - } - boolean useDates = multiSelectOptions.getSelectedKeys().contains(OPTION_DATES); - config.setUseMeetingDates(useDates); - if(useDates) config.setMeetingDatas(dateList); - if(!templates.isEmpty() && vcTemplate.isOneSelected()) config.setTemplateKey(vcTemplate.getSelectedKey()); - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } - - @Override - protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if (source.getComponent() instanceof Link) { - if (vcAddButtonList.contains(source)) { - Long row = new Long(vcAddButtonList.indexOf(source)); - int index = row.intValue() + 1; - MeetingDate meetingData = new MeetingDate(); - meetingData.setBegin(new Date()); - meetingData.setEnd(new Date(meetingData.getBegin().getTime() + 1000*60*60)); - dateList.add(index, meetingData); - addRow(index, meetingData); - } else if (vcDelButtonList.contains(source)) { - // special case: only one line existent - if (dateList.size() == 1) { - // clear this line - vcTitleInputList.get(0).setValue(""); - vcDescriptionInputList.get(0).setValue(""); - vcCalenderbeginInputList.get(0).setDate(new Date()); - vcDurationInputList.get(0).setValue("01:00"); - } else { - int row = vcDelButtonList.indexOf(source); - removeRow(row); - } - } - } else if(source == multiSelectOptions) { - boolean useDates = multiSelectOptions.getSelectedKeys().contains(OPTION_DATES); - if(useDates) addDates(); - else removeDates(); - editVC.contextRemove("useDates"); - editVC.contextPut("useDates", useDates); - editVC.setDirty(true); - } - super.formInnerEvent(ureq, source, event); - } - - private void addRow(int index, final MeetingDate date) { - // title - TextElement vcTitle = uifactory.addTextElement("title" + counter, null, -1, date.getTitle(), editVC); - vcTitle.setDisplaySize(30); - vcTitle.setMandatory(true); - vcTitle.setNotEmptyCheck("vc.table.title.empty"); - vcTitleInputList.add(index, vcTitle); - - // description - TextElement vcDescription = uifactory.addTextElement("description" + counter, null, -1, date.getDescription(), editVC); - vcDescription.setDisplaySize(20); - vcDescription.setNotEmptyCheck("vc.table.description.empty"); - vcDescription.setMandatory(true); - vcDescriptionInputList.add(index, vcDescription); - - // begin - DateChooser vcScheduleDate = uifactory.addDateChooser("begin" + counter, "vc.table.begin", null, editVC); - vcScheduleDate.setNotEmptyCheck("vc.table.begin.empty"); - vcScheduleDate.setValidDateCheck("vc.table.begin.error"); - vcScheduleDate.setMandatory(true); - vcScheduleDate.setDisplaySize(20); - vcScheduleDate.setDateChooserTimeEnabled(true); - vcScheduleDate.setDate(date.getBegin()); - vcCalenderbeginInputList.add(index, vcScheduleDate); - - // add date duration - SimpleDateFormat sdDuration = new SimpleDateFormat("HH:mm"); - TimeZone tz = TimeZone.getTimeZone("Etc/GMT+0"); - sdDuration.setTimeZone(tz); - - TextElement vcDuration = uifactory.addTextElement("duration" + counter, "vc.table.duration", 5, String.valueOf(0), editVC); - vcDuration.setDisplaySize(5); - vcDuration.setValue(sdDuration.format(new Date(date.getEnd().getTime() - date.getBegin().getTime()))); - vcDuration.setRegexMatchCheck("\\d{1,2}:\\d\\d", "form.error.format"); - vcDuration.setExampleKey("vc.table.duration.example", null); - vcDuration.setNotEmptyCheck("vc.table.duration.empty"); - vcDuration.setErrorKey("vc.table.duration.error", null); - vcDuration.setMandatory(true); - vcDuration.showExample(true); - vcDuration.showError(false); - this.vcDurationInputList.add(index, vcDuration); - - // add row button - FormLink addButton = new FormLinkImpl("add" + counter, "add" + counter, "vc.table.add", Link.BUTTON_SMALL); - editVC.add(addButton); - vcAddButtonList.add(index, addButton); - - // remove row button - FormLink delButton = new FormLinkImpl("delete" + counter, "delete" + counter, "vc.table.delete", Link.BUTTON_SMALL); - editVC.add(delButton); - vcDelButtonList.add(index, delButton); - - // increase the counter to enable unique component names - counter++; - } - - private void removeRow(int row) { - // remove date from model list - if(dateList.get(row) != null) dateList.remove(row); - - editVC.remove(vcTitleInputList.remove(row)); - editVC.remove(vcDescriptionInputList.remove(row)); - editVC.remove(vcDurationInputList.remove(row)); - editVC.remove(vcCalenderbeginInputList.remove(row)); - editVC.remove(vcAddButtonList.remove(row)); - editVC.remove(vcDelButtonList.remove(row)); - - // decrease the counter for unique component names - counter--; - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/VCModul.java b/src/main/java/de/bps/course/nodes/vc/VCModul.java deleted file mode 100644 index db542c4e87b..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCModul.java +++ /dev/null @@ -1,83 +0,0 @@ -// <OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; - -/** - * Description:<br> - * Virtual classroom configuration, setup by spring - * - * <P> - * Initial Date: 28.08.2010 <br> - * - * @author Jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber - */ -public class VCModul { - - static final OLog log = Tracing.createLoggerFor(VCModul.class); - - private String baseUrl, adminLogin, adminPassword, connectID, version; - - public String getBaseUrl() { - return baseUrl; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public String getAdminLogin() { - return adminLogin; - } - - public void setAdminLogin(String adminLogin) { - this.adminLogin = adminLogin; - } - - public String getAdminPassword() { - return adminPassword; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - public String getConnectID() { - return connectID; - } - - public void setConnectID(String connectID) { - this.connectID = connectID; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - -} -// </OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/VCRunController.java b/src/main/java/de/bps/course/nodes/vc/VCRunController.java deleted file mode 100644 index 68d4c410e23..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCRunController.java +++ /dev/null @@ -1,130 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.table.DefaultColumnDescriptor; -import org.olat.core.gui.components.table.TableController; -import org.olat.core.gui.components.table.TableGuiConfiguration; -import org.olat.core.gui.components.velocity.VelocityContainer; -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 de.bps.course.nodes.vc.provider.VCProvider; - -/** - * - * Description:<br> - * Run view for virtual classroom course node - * - * <P> - * Initial Date: 18.01.2011 <br> - * @author skoeber - */ -public class VCRunController extends BasicController { - - //objects for run view - private VelocityContainer runVC; - private Controller displayCtr; - private TableController tableCtr; - - // data - private VCConfiguration config; - private VCDatesTableDataModel tableData; - private List<MeetingDate> dateList = new ArrayList<MeetingDate>(); - private MeetingDate meeting; - - public VCRunController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, VCConfiguration config, VCProvider provider, - boolean isModerator, boolean readOnly) { - super(ureq, wControl); - this.config = config; - - if(this.config.getMeetingDates() != null) dateList.addAll(this.config.getMeetingDates()); - - // select actual meeting - if(config.isUseMeetingDates()) { - Date now = new Date((new Date()).getTime() + 15*60*1000); // allow to start meetings about 15 minutes before begin - for(MeetingDate date : dateList) { - Date begin = date.getBegin(); - Date end = date.getEnd(); - if(now.after(begin) & now.before(end)) { - meeting = date; - } - } - } - - tableData = new VCDatesTableDataModel(dateList); - - TableGuiConfiguration tableConfig = new TableGuiConfiguration(); - tableConfig.setTableEmptyMessage("<b>"+translate("vc.table.empty")+"</b>"); - tableConfig.setSortingEnabled(true); - tableCtr = new TableController(tableConfig, ureq, wControl, getTranslator()); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("vc.table.title", 0, null, ureq.getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("vc.table.description", 1, null, ureq.getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("vc.table.begin", 2, null, ureq.getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("vc.table.end", 3, null, ureq.getLocale())); - tableCtr.setTableDataModel(tableData); - tableCtr.setSortColumn(2, true);// timeframe - listenTo(tableCtr); - - runVC = createVelocityContainer("run"); - runVC.put("datesTable", tableCtr.getInitialComponent()); - - runVC.contextPut("isModerator", isModerator); - boolean isUseDates = config.isUseMeetingDates(); - runVC.contextPut("useDates", isUseDates); - boolean isMeeting = !isUseDates | meeting != null; - runVC.contextPut("isMeeting", isMeeting); - boolean show = isModerator | (isUseDates & isMeeting) | !isUseDates; - runVC.contextPut("show", show); - - displayCtr = provider.createDisplayController(ureq, wControl, roomId, name, description, isModerator, readOnly, config); - runVC.put("displayCtr", displayCtr.getInitialComponent()); - - putInitialPanel(runVC); - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - // nothing to do - } - - @Override - protected void doDispose() { - if(tableCtr != null) { - removeAsListenerAndDispose(tableCtr); - tableCtr = null; - } - if(displayCtr != null) { - removeAsListenerAndDispose(displayCtr); - displayCtr = null; - } - } - -} -//</OLATCE-103> diff --git a/src/main/java/de/bps/course/nodes/vc/VCSelectionForm.java b/src/main/java/de/bps/course/nodes/vc/VCSelectionForm.java deleted file mode 100644 index 5a499d00064..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/VCSelectionForm.java +++ /dev/null @@ -1,95 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc; - -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.SingleSelection; -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.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; - -import de.bps.course.nodes.vc.provider.VCProvider; -import de.bps.course.nodes.vc.provider.VCProviderFactory; - -/** - * - * Description:<br> - * Support selection of a virtual classroom, if there are multiple ones registered. - * - * <P> - * Initial Date: 07.01.2011 <br> - * @author skoeber - */ -public class VCSelectionForm extends FormBasicController { - - private SingleSelection selVC; - private String selectedProvider; - - public VCSelectionForm(UserRequest ureq, WindowControl wControl, String selectedProvider) { - super(ureq, wControl); - this.selectedProvider = selectedProvider; - initForm(flc, this, ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - int num = VCProviderFactory.getProviders().size(); - String[] keys = new String[num]; - String[] vals = new String[num]; - int i = 0; - for(VCProvider provider : VCProviderFactory.getProviders()) { - keys[i] = provider.getProviderId(); - vals[i] = provider.getDisplayName(); - i++; - } - - selVC = uifactory.addDropdownSingleselect("config.select.vc", flc, keys, vals, null); - selVC.select(selectedProvider, true); - selVC.addActionListener(FormEvent.ONCHANGE); - } - - @Override - protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if(source == selVC) { - fireEvent(ureq, Event.CHANGED_EVENT); - } - } - - public String getSelectedProvider() { - return selVC.getSelectedKey(); - } - - @Override - protected void formOK(UserRequest ureq) { - // nothing to do - } - - @Override - protected void doDispose() { - // nothing to dispose - } - -} -//<OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_content/edit.html b/src/main/java/de/bps/course/nodes/vc/_content/edit.html deleted file mode 100644 index 3c4c97c5dad..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_content/edit.html +++ /dev/null @@ -1,13 +0,0 @@ -<!-- <OLATCE-103> --> -<fieldset> - <legend>$r.translate("config.header")</legend> - #if($r.available("VCSelectionForm")) - $r.render("VCSelectionForm") - #end - $r.render("editForm") -</fieldset> -<fieldset> - <legend>$r.translate("config.header.extended")</legend> - $r.render("configCtr") -</fieldset> -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_content/editForm.html b/src/main/java/de/bps/course/nodes/vc/_content/editForm.html deleted file mode 100644 index 79c6d1ac17f..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_content/editForm.html +++ /dev/null @@ -1,53 +0,0 @@ -<!-- <OLATCE-103> --> -#if($hasTemplates) - <strong>$r.translate("vc.template.choose.intro")</strong> - $r.render("vc.template.choose") -#else - <p>$r.translate("vc.template.empty")</p> -#end -<br/> -<strong>$r.translate("vc.options.intro")</strong> -$r.render("vc.options") -<br/> -#if($useDates) - <strong>$r.translate("vc.meetings.intro")</strong> - <table> - <tr> - <td>$r.translate("vc.table.title")</td> - <td>$r.translate("vc.table.description")</td> - <td>$r.translate("vc.table.begin")</td> - <td colspan="3">$r.translate("vc.table.duration")</td> - </tr> - - #foreach($date in $dateList) - #set( $iter = $foreach.count - 1) - #set( $title = $vcTitleInputList.get($iter).getName() ) - #set( $titleErr = $title + "_ERROR" ) - #set( $descr = $vcDescriptionInputList.get($iter).getName() ) - #set( $descrErr = $descr + "_ERROR" ) - #set( $begin = $vcCalenderbeginInputList.get($iter).getName() ) - #set( $beginErr = $begin + "_ERROR" ) - #set( $duration = $vcDurationInputList.get($iter).getName() ) - #set( $durationErr = $duration + "_ERROR" ) - <tr> - <td>#if($f.hasError($title)) <span class="o_icon o_icon_error form-control-feedback"> </span> $r.render($titleErr)#end</td> - <td>#if($f.hasError($descr)) <span class="o_icon o_icon_error form-control-feedback"> </span> $r.render($descrErr)#end</td> - <td>#if($f.hasError($begin)) <span class="o_icon o_icon_error form-control-feedback"> </span> $r.render($beginErr)#end</td> - <td>#if($f.hasError($duration)) <span class="o_icon o_icon_error form-control-feedback"> </span> $r.render($durationErr)#end</td> - <td></td> - <td></td> - </tr> - <tr> - <td>$r.render($title)</td> - <td>$r.render($descr)</td> - <td>$r.render($begin)</td> - <td>$r.render($duration)</td> - <td style="white-space: nowrap;"> - $r.render($vcAddButtonList.get($iter).getName()) - $r.render($vcDelButtonList.get($iter).getName()) - </td> - </tr> - #end - </table> -#end -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_content/noprovider.html b/src/main/java/de/bps/course/nodes/vc/_content/noprovider.html deleted file mode 100644 index dfb2c364afb..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_content/noprovider.html +++ /dev/null @@ -1,3 +0,0 @@ -<div class="o_warning"> - $r.translate("error.config.noprovider") -</div> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_content/run.html b/src/main/java/de/bps/course/nodes/vc/_content/run.html deleted file mode 100644 index 2cb55c0f24f..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_content/run.html +++ /dev/null @@ -1,22 +0,0 @@ -<!-- <OLATCE-103> --> -#if($useDates) - <p>$r.translate("vc.table.intro")</p> - $r.render("datesTable") - <br/> -#end - -#if($isModerator) - #if(!$isMeeting) - <p>$r.translate("no.meeting.moderator")</p> - #end -#else - #if(!$show) - <p>$r.translate("no.meeting.learner")</p> - #end -#end - -#if($show) - $r.render("displayCtr") -#end - -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_de.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_de.properties deleted file mode 100644 index 774a2436d32..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_de.properties +++ /dev/null @@ -1,46 +0,0 @@ -pane.tab.accessibility=Zugang -pane.tab.vcconfig=Konfiguration -condition.accessibility.title=Zugang -title_vc=Virtuelles Klassenzimmer -config.header=Konfiguration des virtuellen Klassenzimmers -config.header.extended=Erweiterte Konfiguration -config.select.vc=System f\u00fcr virtuellen Klassenraum -error.config.short=Konfiguration von "{0}" fehlerhaft -error.config.long=Die Konfiguration des Kursbausteins "{0}" ist fehlerhaft oder unvollst\u00e4ndig. -error.config.noprovider=Es gibt kein Provider f\u00fcr virtuellen Klassenzimmer in diesem OpenOLAT eingestellt. Bitte fragen Sie ihr Administrator! -error.update.room=Das virtuelle Klassenzimmer konnte nicht mit den aktuellen Einstellungen synchronisiert werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. - -delete.meeting.title=Virtuelles Klassenzimmers l\u00f6schen -delete.meeting.text=Sie haben ein anderes System f\u00fcr das virtuelle Klassenzimmer ausgew\u00e4hlt. Das bestehende Virtuelle Klassenzimmer wird bei dieser \u00c4nderung gel\u00f6scht. Wollen Sie das System wirklich wechseln? - -no.meeting.learner=Derzeit findet kein Meeting statt, dem Sie beitreten k\u00f6nnten. -no.meeting.moderator=Derzeit findet kein Meeting statt. Teilnehmer k\u00f6nnen das virtuelle Klassenzimmer 15 Minuten vor einem geplanten Meeting betreten. - -sync.meeting.title=Virtuelles Klassenzimmer synchronisieren -sync.meeting.text=Sie haben die Einstellungen f\u00fcr diese virtuelle Klassenzimmer ge\u00e4ndert, nachdem dieses er\u00f6ffnet wurde. Die \u00c4nderungen werden erst wirksam, wenn Sie das virtuelle Klassenzimmer mit den neuen Einstellungen synchronisieren. Die Einstellungen k\u00f6nnen auch jederzeit direkt im Kurs synchronisiert werden. M\u00f6chten Sie die Einstellungen jetzt synchronisieren? -success.update.room=Das virtuelle Klassenzimmer wurde erfolgreich synchronisiert. Bitte vergessen Sie nicht, die \u00c4nderungen zu publizieren. - -vc.access.dates=Virtuelles Klassenzimmer soll nur zu bestimmten Terminen betreten werden k\u00f6nnen -vc.meetings.intro=Termine f\u00fcr Meetings -vc.table.add=+ -vc.table.begin=Start -vc.table.begin.empty=Datumsangabe fehlt -vc.table.begin.error=Fehlerhafte Eingabe -vc.table.description=Beschreibung -vc.table.description.empty=Beschreibung fehlt -vc.table.delete=- -vc.table.duration=Dauer -vc.table.duration.empty=Dauer fehlt -vc.table.duration.error=Falsches Format -vc.table.duration.example=hh\:mm -vc.table.empty=Derzeit sind keine Meetings geplant. -vc.table.end=Ende -vc.table.intro=Hier finden Sie eine Liste aller geplanten Meetings: -vc.table.title=Titel -vc.table.title.empty=Titel fehlt -vc.template.choose.intro=Vorlage f\u00fcr virtuelles Klassenzimmer -vc.template.choose.label=Vorlage -vc.template.empty=Es stehen keine Templates zur Verf\u00fcgung -vc.options=Zutrittsberechtigung -vc.options.intro=Zutrittsberechtigung -vc.options.label=Zutrittsberechtigung \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_en.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_en.properties deleted file mode 100644 index d85bc7a3a88..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_en.properties +++ /dev/null @@ -1,46 +0,0 @@ -pane.tab.accessibility=Access -pane.tab.vcconfig=Configuration -condition.accessibility.title=Access -title_vc=Virtual classroom -config.header=Configuration of the virtual classroom -config.header.extended=Extended configuration -config.select.vc=System for virtual classroom -error.config.short=Configuration of "{0}" contains errors -error.config.long=The configuration of the course node "{0}" contains errors or is incomplete. -error.config.noprovider=There isn't any virtual classroom provider configured for this OpenOLAT, please ask for administrator. -error.update.room=Sorry! An error occured while synchronizing the virtual class room with the actual configuration. Please, inform your tutor or system administrator. - -delete.meeting.title=Delete virtual classroom -delete.meeting.text=You have changed the system for your virtual classroom. The existing classroom will thus be deleted. Do you really want to delete the classroom? - -no.meeting.learner=Currently, there are no meetings planned. -no.meeting.moderator=Currently, there are no meetings planned. Participants may enter the virtual classroom 15 minutes prior to meeting start. - -sync.meeting.title=Synchronize virtual classroom -sync.meeting.text=You have changed the configuration of the virtual classroom after it had been started. The changes will be taken into account only after having synchronized the virtual class room with the new configuration. You can synchronize the configuration at any time directly from the course run. Do you want to synchronize now? -success.update.room=The virtual classroom has been synchronized successfully. Do not forget to publish the current changes. - -vc.access.dates=Virtual classroom shall only be available at defined dates -vc.meetings.intro=Planned dates for meetings -vc.table.add=+ -vc.table.begin=Begin -vc.table.begin.empty=Missing date -vc.table.begin.error=Wrong format -vc.table.description=Description -vc.table.description.empty=Missing description -vc.table.delete=- -vc.table.duration=Duration -vc.table.duration.empty=Missing duration -vc.table.duration.error=Wrong format -vc.table.duration.example=hh\:mm -vc.table.empty=There are no meetings planned, yet. -vc.table.end=End -vc.table.intro=List of currently planned meetings: -vc.table.title=Title -vc.table.title.empty=Missing title -vc.template.choose.intro=Template for virtual classroom -vc.template.choose.label=Template -vc.template.empty=No templates available -vc.options=Access authorisation -vc.options.intro=Access authorisation -vc.options.label=Access authorisation diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_fr.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_fr.properties deleted file mode 100644 index 51a8e12f8e0..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_fr.properties +++ /dev/null @@ -1,48 +0,0 @@ -#Sun Oct 27 17:50:36 CET 2013 - - - - - -condition.accessibility.title=Acc\u00E8s -config.header=Configuration de la classe virtuelle -config.header.extended=Configuration \u00E9tendue -config.select.vc=Syst\u00E8me des classes virtuelles -delete.meeting.text=Vous avez choisi un autre syst\u00E8me de classe virtuelle. Les classes virtuelles existantes seront supprim\u00E9e. Voulez-vous vraiment changer de type de syst\u00E8me? -delete.meeting.title=Supprimer la classe virtuelle -error.config.long=La configuration de l'\u00E9l\u00E9ment de cours "{0}" est corrompu ou incompl\u00E8te. -error.config.noprovider=Il n'y a pas de fournisseur de classe virtuelle dans cet OpenOLAT. S'il vous pla\u00EEt demander \u00E0 votre administrateur\! -error.config.short=Configuration de "{0}" est incorrecte. -error.update.room=La classe virtuelle ne peut pas \u00EAtre synchronis\u00E9 avec les param\u00E8tres actuels. Veuillez contactez votre coach ou votre administrateur syst\u00E8me. -no.meeting.learner=Il n'y a pour l'instant aucune r\u00E9union auquel vous pouvez participer. -no.meeting.moderator=Il n'y a pas de r\u00E9union pr\u00E9vue pour l'instant. Les participants pourront entrer dans la classe virtuelle 15 minutes avant la r\u00E9union pr\u00E9vue. -pane.tab.accessibility=Acc\u00E8s -pane.tab.vcconfig=Configuration -success.update.room=La classe virtuelle a \u00E9t\u00E9 synchronis\u00E9 avec succ\u00E8s. N'oubliez pas de publier vos modifications. -sync.meeting.text=Vous avez modifi\u00E9 les param\u00E8tres de cette classe virtuelle apr\u00E8s son ouverture. Les modifications ne prendront effet que lorsque vous aurez synchronis\u00E9 cette classe virtuelle avec ses nouveaux param\u00E8tres. Les param\u00E8tres peuvent \u00E9galement \u00EAtre synchronis\u00E9s \u00E0 tout moment depuis le cours. Ne souhaitez-vous pas synchroniser les param\u00E8tres d\u00E8s maintenant? -sync.meeting.title=Synchroniser la classe virtuelle -title_vc=Classes virtuelles -vc.access.dates=Il n'est possible d'entrer dans la classe virtuelle qu'\u00E0 certaines dates. -vc.meetings.intro=Rendez-vous pour les r\u00E9unions -vc.options=Autorisation d'acc\u00E8s -vc.options.intro=Autorisation d'acc\u00E8s -vc.options.label=Autorisation d'acc\u00E8s -vc.table.add=+ -vc.table.begin=D\u00E9marrer -vc.table.begin.empty=La date manque -vc.table.begin.error=Donn\u00E9e incorrecte -vc.table.delete=- -vc.table.description=Description -vc.table.description.empty=La description manque -vc.table.duration=Dur\u00E9e -vc.table.duration.empty=La dur\u00E9e manque -vc.table.duration.error=Format incorrect -vc.table.duration.example=hh\:mm -vc.table.empty=Aucun rendez-vous n'est pr\u00E9vu pour l'instant. -vc.table.end=Fin -vc.table.intro=Ici vous trouverez la liste de tous les rendez-vous pr\u00E9vus\: -vc.table.title=Titre -vc.table.title.empty=Le titre manque -vc.template.choose.intro=Mod\u00E8le de classes virtuelles -vc.template.choose.label=Mod\u00E8le -vc.template.empty=Il n'y a aucun mod\u00E8le \u00E0 disposition diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_it.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_it.properties deleted file mode 100644 index dc8bd513feb..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_it.properties +++ /dev/null @@ -1,43 +0,0 @@ -#Mon Sep 12 15:10:53 CEST 2016 -condition.accessibility.title=Accesso -config.header=Configurazione della classe virtuale -config.header.extended=Configurazione estesa -config.select.vc=Sistema per aula virtuale -delete.meeting.text=Hai modificato il sistema per la tua aula virtuale. L'aula esistente sar\u00E0 eliminata. Vuoi veramente cambiare il tipo di sistema ed eliminare l'aula? -delete.meeting.title=Eliminare aula virtuale -error.config.long=La configurazione dell'elemento di corso "{0}" contiene errori o \u00E8 incompleta. -error.config.noprovider=Non esiste alcun provider di aule virtuali configurato per questo OpenOLAT, contattare l'amministratore. -error.config.short=La configurazione di "{0}" contiene errori -error.update.room=Si \u00E8 verificato un errore durante la sincronizzazione delle aule virtuali con la configurazione attuale. Informare il tutore o l'amministratore di sistema. -no.meeting.learner=Al momento non esiste alcuna riunione pianificata. -no.meeting.moderator=Non ci sono riunioni previste al momento. I partecipanti possono accedere all'aula virtuale da 15 minuti prima dell'avvio della riunione. -pane.tab.accessibility=Accesso -pane.tab.vcconfig=Configurazione -success.update.room=L'aula virtuale \u00E8 stata sincronizzata con successo. Non dimenticare di pubblicare i cambiamenti. -sync.meeting.text=Hai modificato la configurazione dell'aula virtuale dopo il suo avvio. I cambiamenti saranno presi in considerazione solo dopo la sincronizzazione dell'aula virtuale con la nuova configurazione. Puoi sincronizzare la configurazione in ogni momento direttamente in esecuzione del corso. Vuoi sincronizzare ora? -sync.meeting.title=Sincronizzare l'aula virtuale -title_vc=Aula virtuale -vc.access.dates=L'aula virtuale dovrebbe essere acceduta solo in date definite -vc.meetings.intro=Date pianificate per le riunioni -vc.options=Autorizzazioni di accesso -vc.options.intro=Autorizzazioni di accesso -vc.options.label=Autorizzazioni di accesso -vc.table.add=+ -vc.table.begin=Inizio -vc.table.begin.empty=Data mancante -vc.table.begin.error=Formato errato -vc.table.delete=- -vc.table.description=Descrizione -vc.table.description.empty=Descrizione mancante -vc.table.duration=Durata -vc.table.duration.empty=Durata mancante -vc.table.duration.error=Formato errato -vc.table.duration.example=hh\:mm -vc.table.empty=Non ci sono incontri pianificati al momento. -vc.table.end=Fine -vc.table.intro=Lista degli incontri pianificati\: -vc.table.title=Titolo -vc.table.title.empty=Titolo mancante -vc.template.choose.intro=Modello per l'aula virtuale -vc.template.choose.label=Modello -vc.template.empty=Nessun modello disponibile diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pl.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pl.properties deleted file mode 100644 index 2b1ef8a4419..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pl.properties +++ /dev/null @@ -1,35 +0,0 @@ -#Sun Dec 23 12:39:38 CET 2012 - - -condition.accessibility.title=Dost\u0119p -config.header=Konfiguracja wirtualnej klasy -config.header.extended=Zaawansowana konfiguracja -delete.meeting.title=Usu\u0144 wirtualn\u0105 klas\u0119 -error.config.short=Konfiguracja "{0}" zawiera b\u0142\u0119dy -no.meeting.learner=W tym momencie nie ma \u017Cadnych zaplanowanych spotka\u0144. -no.meeting.moderator=W tym momencie nie ma \u017Cadnych zaplanowanych spotka\u0144. Uczestnicy mog\u0105 wej\u015B\u0107 do wirtualnej klasy 15 minut przed rozpocz\u0119ciem spotkania. -pane.tab.accessibility=Dost\u0119p -pane.tab.vcconfig=Konfiguracja -sync.meeting.title=Synchronizuj wirtualn\u0105 klas\u0119 -title_vc=Wirtualna klasa -vc.meetings.intro=Zaplanowane daty spotka\u0144 -vc.options=Autoryzacja dost\u0119pu -vc.table.add=+ -vc.table.begin=Rozpocznij -vc.table.begin.empty=Brakuj\u0105ca data -vc.table.begin.error=Nieprawid\u0142owy format -vc.table.delete=- -vc.table.description=Opis -vc.table.description.empty=Brakuj\u0105cy opis -vc.table.duration=Czas trwania -vc.table.duration.empty=Brakuj\u0105cy czas trwania -vc.table.duration.error=Nieprawid\u0142owy format -vc.table.duration.example=hh\:mm -vc.table.empty=Nie zaplanowano jeszcze \u017Cadnych spotka\u0144. -vc.table.end=Zako\u0144cz -vc.table.intro=Lista aktualnie zaplanowanych spotka\u0144. -vc.table.title=Tytu\u0142 -vc.table.title.empty=Brakuj\u0105cy tytu\u0142 -vc.template.choose.intro=Szablon wirtualnej klasy -vc.template.choose.label=Szablon -vc.template.empty=Brak dost\u0119pnych szablon\u00F3w diff --git a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pt_BR.properties b/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pt_BR.properties deleted file mode 100644 index fcc7b773beb..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_i18n/LocalStrings_pt_BR.properties +++ /dev/null @@ -1,43 +0,0 @@ -#Mon Jan 16 22:03:40 CET 2017 -condition.accessibility.title=Acesso -config.header=Configura\u00E7\u00E3o de sala de aula virtual -config.header.extended=Configura\u00E7\u00E3o extendida -config.select.vc=Sistema para sala de aula virtual -delete.meeting.text=Voc\u00EA mudou o sistema para sua sala de aula virtual. A sala de aula existente ser\u00E1 assim exclu\u00EDda. Voc\u00EA realmente quer apagar a sala de aula? -delete.meeting.title=Excluir sala de aula virtual -error.config.long=A configura\u00E7\u00E3o do m\u00F3dulo do curso "{0}" cont\u00E9m erros ou est\u00E1 incompleta. -error.config.noprovider=N\u00E3o h\u00E1 qualquer provedor de sala de aula virtual configurado para este OpenOLAT, por favor, pergunte para o administrador. -error.config.short=A configura\u00E7\u00E3o de "{0}" cont\u00E9m erros -error.update.room=Desculpe\! Ocorreu um erro ao sincronizar a sala de aula virtual com a configura\u00E7\u00E3o real. Por favor, informe o seu tutor ou administrador do sistema. -no.meeting.learner=Atualmente, n\u00E3o h\u00E1 reuni\u00F5es planejadas. -no.meeting.moderator=Atualmente, n\u00E3o h\u00E1 reuni\u00F5es planejadas. Os participantes podem entrar na sala de aula virtual 15 minutos antes do in\u00EDcio da reuni\u00E3o. -pane.tab.accessibility=Acesso -pane.tab.vcconfig=Configura\u00E7\u00E3o -success.update.room=A sala de aula virtual foi sincronizada com sucesso. N\u00E3o se esque\u00E7a de publicar as altera\u00E7\u00F5es atuais. -sync.meeting.text=Voc\u00EA mudou a configura\u00E7\u00E3o da sala de aula virtual depois de ter sido iniciada. As altera\u00E7\u00F5es ser\u00E3o levadas em conta somente depois de ter sincronizado a sala de aula virtual com a nova configura\u00E7\u00E3o. Voc\u00EA pode sincronizar a configura\u00E7\u00E3o a qualquer momento diretamente da execu\u00E7\u00E3o do curso. Deseja sincronizar agora? -sync.meeting.title=Sincronizar sala de aula virtual -title_vc=Sala de aula virtual -vc.access.dates=A sala de aula virtual s\u00F3 estar\u00E1 dispon\u00EDvel em datas definidas -vc.meetings.intro=Datas previstas para as reuni\u00F5es -vc.options=Autoriza\u00E7\u00E3o de acesso -vc.options.intro=Autoriza\u00E7\u00E3o de acesso -vc.options.label=Autoriza\u00E7\u00E3o de acesso -vc.table.add=+ -vc.table.begin=Iniciar -vc.table.begin.empty=Data em falta -vc.table.begin.error=Formato errado -vc.table.delete=- -vc.table.description=Descri\u00E7\u00E3o -vc.table.description.empty=Descri\u00E7\u00E3o faltando -vc.table.duration=Dura\u00E7\u00E3o -vc.table.duration.empty=Dura\u00E7\u00E3o em falta -vc.table.duration.error=Formato errado -vc.table.duration.example=hh\:mm -vc.table.empty=Ainda n\u00E3o h\u00E1 reuni\u00F5es planejadas. -vc.table.end=Fim -vc.table.intro=Lista de reuni\u00F5es planeadas atualmente\: -vc.table.title=T\u00EDtulo -vc.table.title.empty=T\u00EDtulo faltando -vc.template.choose.intro=Modelo para sala de aula virtual -vc.template.choose.label=Modelo -vc.template.empty=Nenhum modelo dispon\u00EDvel diff --git a/src/main/java/de/bps/course/nodes/vc/_spring/buildingblockContext.xml b/src/main/java/de/bps/course/nodes/vc/_spring/buildingblockContext.xml deleted file mode 100644 index 88bcd11c82a..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_spring/buildingblockContext.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - - <bean id="vc" class="de.bps.course.nodes.vc.VCCourseNodeConfiguration" scope="prototype"> - <property name="enabled" value="${course.node.vc.enabled}" /> - <property name="order" value="300" /> - <property name="alternativeCourseNodes"> - <list> - <value>openmeetings</value> - </list> - </property> - </bean> - -</beans> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml b/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml deleted file mode 100644 index 35e4bd045d5..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - -<!-- ####################################### --> -<!-- # VIRTUAL CLASSROOM SERVICE PROVIDERS # --> -<!-- ####################################### --> - - <!-- Activation of the providers --> - <bean id="vcProviderFactory" class="de.bps.course.nodes.vc.provider.VCProviderFactory" scope="singleton"> - <property name="registeredProviders"> - <list value-type="de.bps.course.nodes.vc.provider.VCProvider"> - <ref bean="adobeProvider" /> - <ref bean="wimbaProvider" /> - </list> - </property> - </bean> - - <!-- Definition of the providers --> - <bean id="wimbaProvider" class="de.bps.course.nodes.vc.provider.wimba.WimbaClassroomProvider"> - <property name="enabled" value="${vc.wimba.enabled}" /> - <property name="providerId" value="wimba" /> - <property name="displayName" value="Wimba Classroom" /> - <property name="protocol" value="${vc.wimba.protocol}" /> - <property name="port" value="${vc.wimba.port}" /> - <property name="baseUrl" value="${vc.wimba.baseurl}" /> - <property name="adminLogin" value="${vc.wimba.adminlogin}" /> - <property name="adminPassword" value="${vc.wimba.adminpassword}" /> - <!-- Options --> - <property name="defaultConfig"> - <ref bean="wimbaDefaultConfig" /> - </property> - </bean> - - <bean id="adobeProvider" class="de.bps.course.nodes.vc.provider.adobe.AdobeConnectProvider"> - <property name="enabled" value="${vc.adobe.enabled}" /> - <property name="providerId" value="adobe" /> - <property name="displayName" value="Adobe Connect" /> - <property name="protocol" value="${vc.adobe.protocol}" /> - <property name="port" value="${vc.adobe.port}" /> - <property name="baseUrl" value="${vc.adobe.baseurl}" /> - <property name="adminLogin" value="${vc.adobe.adminlogin}" /> - <property name="adminPassword" value="${vc.adobe.adminpassword}" /> - <property name="accountId" value="${vc.adobe.accountid}" /> - <property name="templates"><!-- optional --> - <map key-type="java.lang.String" value-type="java.lang.String"> - <entry value="${vc.template.name.0}" key="${vc.template.key.0}" /> - <entry value="${vc.template.name.1}" key="${vc.template.key.1}" /> - <entry value="${vc.template.name.2}" key="${vc.template.key.2}" /> - </map> - </property> - <property name="showOptions" value="${vc.adobe.showoptions}" /> - <!-- type of user accounts, allowed values are: guest, user --> - <property name="userType" value="${vc.adobe.usertype}" /> - <!-- Options --> - <property name="defaultConfig"> - <ref bean="adobeDefaultConfig" /> - </property> - </bean> - -<!-- ################################## --> -<!-- # VIRTUAL CLASSROOM SERVICE JOBS # --> -<!-- ################################## --> - <bean id="adobeCleanupJob" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> - <property name="jobDetail"> - <bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> - <property name="jobClass" value="de.bps.course.nodes.vc.provider.adobe.AdobeConnectCleanupJob" /> - <property name="jobDataAsMap"> - <map> - <entry key="providerId" value="adobe" /> - <entry key="daysToKeep" value="${vc.adobe.daysToKeep}" /> - <entry key="cleanupMeetings" value="${vc.adobe.cleanupMeetings}" /> - <entry key="cleanupModerators" value="${vc.adobe.cleanupModerators}" /> - </map> - </property> - </bean> - </property> - <property name="cronExpression" value="0 0 2 * * ?"/><!-- 2am, daily --> - <property name="startDelay" value="45000" /> - </bean> - -</beans> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/VCProvider.java b/src/main/java/de/bps/course/nodes/vc/provider/VCProvider.java deleted file mode 100644 index 539adfc54df..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/VCProvider.java +++ /dev/null @@ -1,199 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider; - -import java.net.URL; -import java.util.Date; -import java.util.Map; - -import org.olat.core.configuration.ConfigOnOff; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.id.Identity; - -import de.bps.course.nodes.vc.VCConfiguration; - -/** - * - * Description:<br> - * Interface defines the API a virtual classroom provider has to provide. It is designed - * to have an own instance for every single user. - * - * <P> - * Initial Date: 09.12.2010 <br> - * @author skoeber - */ -public interface VCProvider extends ConfigOnOff { - - /** - * @return new independent instance of the provider - */ - public VCProvider newInstance(); - - /** - * @return provider id as defined in the configuration - */ - public String getProviderId(); - - /** - * @return display name of the provider - */ - public String getDisplayName(); - - /** - * @return mapping of key and displayname for available templates or empty map, but never <code>null</code> - */ - public Map<String, String> getTemplates(); - - /** - * @return <code>true</code> if virtual classroom is available at present, <code>false</code> otherwise - */ - public boolean isProviderAvailable(); - - /** - * Create a new virtual classroom to be used e.g. in a course node - * @param roomId (maybe prefixed automatically) - * @param name (optional name for meeting) - * @param description (optional description for meeting) - * @param begin (usage dependent on target platform, can be NULL) - * @param end (usage dependent on target platform, can be NULL) - * @param templateId - * @return success - */ - public boolean createClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config); - - /** - * Update an existing virtual classroom - * @param roomId of the existing classroom - * @param name the new name - * @param description the new description - * @param begin the new begin - * @param end the new end - * @param config the new configuration - * @return success - */ - public boolean updateClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config); - - /** - * Delete an existing virtual classroom - * @param roomId - * @param config - * @return success - */ - public boolean removeClassroom(String roomId, VCConfiguration config); - - /** - * Create user specific access url for the virtual classroom. Maybe the user - * must authenticated before. - * @param roomId - * @param identity - * @param config - * @return url - */ - public URL createClassroomUrl(String roomId, Identity identity, VCConfiguration config); - - /** - * Create guest access url for the virtual classroom. Dependent on the - * implementation the url can be user specific (e.g. to pre-set the username) - * @param roomId - * @param identity - * @param config - * @return url - */ - public URL createClassroomGuestUrl(String roomId, Identity identity, VCConfiguration config); - - /** - * Check whether the virtual classroom exists or not. - * @param roomId - * @param config - * @return <code>true</code> if the classroom exists, <code>false</code> otherwise - */ - public boolean existsClassroom(String roomId, VCConfiguration config); - - /** - * Login the user. Dependent on the implemenation the password can be <code>null</code>. - * If this is the case, the implementation can try to login automatically generated - * users with a default password or a password that's build up by a rule. - * @param identity - * @param password - * @return success - */ - public boolean login(Identity identity, String password); - - /** - * Create a new user. The user has moderator rights. If the user already exists, - * nothing is to do. - * @param identity - * @param roomId - * @return success - */ - public boolean createModerator(Identity identity, String roomId); - - /** - * Create a new user. The user has no specific rights. If the user already exists, - * nothing is to do. - * @param identity - * @param roomId - * @return success - */ - public boolean createUser(Identity identity, String roomId); - - /** - * Create a new guest. Dependent on the implementation the user must not be persistent. - * @param identity - * @param roomId - * @return success - */ - public boolean createGuest(Identity identity, String roomId); - - /** - * Create controller for using the virtual classroom. - * @param ureq - * @param wControl - * @param roomId - * @param name - * @param description - * @param isModerator - * @param config - * @return the controller to be embedded - */ - public Controller createDisplayController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, - boolean isModerator, boolean readOnly, VCConfiguration config); - - /** - * Create controller for creation and configuration of the virtual classroom. - * @param ureq - * @param wControl - * @param roomId - * @param config - * @return the controller to be embedded - */ - public Controller createConfigController(UserRequest ureq, WindowControl wControl, String roomId, VCConfiguration config); - - /** - * Create a new default configuration. This configuration must reflect all - * necessary settings to ensure that the virtual classroom will work. - * @return new configuration - */ - public VCConfiguration createNewConfiguration(); -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/VCProviderFactory.java b/src/main/java/de/bps/course/nodes/vc/provider/VCProviderFactory.java deleted file mode 100644 index 4af90452dac..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/VCProviderFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - * Description:<br> - * Factory to create an instance of a registered virtual classroom provider. Note that - * the providers are designed to be used as own instances for every single user. - * - * <P> - * Initial Date: 09.12.2010 <br> - * @author skoeber - */ -public class VCProviderFactory { - - public static String VC_PROVIDER = "vcProvider"; - - private final static Map<String, VCProvider> _registeredProviders = new HashMap<String, VCProvider>(); - - public static VCProvider createProvider(String providerId) { - return _registeredProviders.get(providerId).newInstance(); - } - - public static VCProvider createDefaultProvider() { - if(_registeredProviders == null || _registeredProviders.isEmpty()) { - return null; - } - List<VCProvider> providers = getProviders(); - if(!providers.isEmpty()) { - return createProvider(providers.get(0).getProviderId()); - } - return null; - } - - public static boolean existsProvider(String providerId) { - return _registeredProviders.containsKey(providerId); - } - - public static void registerProvider(VCProvider provider) { - _registeredProviders.put(provider.getProviderId(), provider); - } - - public void setRegisteredProviders(List<VCProvider> providers) { - for(VCProvider provider : providers) { - registerProvider(provider); - } - } - - public static List<VCProvider> getProviders() { - List<VCProvider> providers = new ArrayList<VCProvider>(); - for(VCProvider provider:_registeredProviders.values()) { - if(provider.isEnabled()) { - providers.add(provider); - } - } - return providers; - } - - /** used by spring */ - public List<VCProvider> getRegisteredProviders() { - List<VCProvider> providers = new ArrayList<VCProvider>(); - providers.addAll(_registeredProviders.values()); - return providers; - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConfigController.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConfigController.java deleted file mode 100644 index ce5e355346c..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConfigController.java +++ /dev/null @@ -1,78 +0,0 @@ -// <OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.velocity.VelocityContainer; -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; - -/** - * - * Description:<br> - * Config controller for Adobe Connect implementation - * - * <P> - * Initial Date: 05.01.2011 <br> - * @author skoeber - */ -public class AdobeConfigController extends BasicController { - - private VelocityContainer editVC; - private AdobeEditForm editForm; - - protected AdobeConfigController(UserRequest ureq, WindowControl wControl, String roomId, AdobeConnectProvider adobe, AdobeConnectConfiguration config) { - super(ureq, wControl); - - this.editForm = new AdobeEditForm(ureq, wControl, adobe.isShowOptions(), config); - listenTo(editForm); - - editVC = createVelocityContainer("edit"); - editVC.put("editForm", editForm.getInitialComponent()); - - putInitialPanel(editVC); - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - // nothing to do - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if(source == editForm) { - fireEvent(ureq, event); - } - } - - @Override - protected void doDispose() { - if (editForm != null) { - removeAsListenerAndDispose(editForm); - editForm = null; - } - } - -} -// </OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectCleanupJob.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectCleanupJob.java deleted file mode 100644 index 180def2bf6d..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectCleanupJob.java +++ /dev/null @@ -1,179 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import java.util.Date; -import java.util.List; - -import org.olat.core.commons.services.scheduler.JobWithDB; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.olat.course.CourseFactory; -import org.olat.course.ICourse; -import org.olat.course.nodes.CourseNode; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; - -import de.bps.course.nodes.VCCourseNode; -import de.bps.course.nodes.vc.MeetingDate; -import de.bps.course.nodes.vc.provider.VCProvider; -import de.bps.course.nodes.vc.provider.VCProviderFactory; - -/** - * - * Description:<br> - * Cleanup unused Adobe Connect ressources:<br/> - * - unused meetings<br/> - * - temporary guest users - * - * <P> - * Initial Date: 04.01.2011 <br> - * @author skoeber - */ -public class AdobeConnectCleanupJob extends JobWithDB { - - private OLog logger = Tracing.createLoggerFor(AdobeConnectCleanupJob.class); - - private String providerId; - private boolean cleanupMeetings, cleanupModerators; - private int daysToKeep; - - - @Override - public void executeWithDB(JobExecutionContext arg0) throws JobExecutionException { - if(!VCProviderFactory.existsProvider(providerId)) { - return;//same as dummy job - } - - VCProvider provider = VCProviderFactory.createProvider(providerId); - if(!provider.isEnabled()) { - return; - } - if(!(provider instanceof AdobeConnectProvider)) { - logger.error("Invalid configuration: defined a virtual classroom cleanup job and provider implementation doesn't fit"); - return; - } - AdobeConnectProvider adobe = (AdobeConnectProvider)provider; - if(!adobe.isProviderAvailable()) { - logger.debug("Tried to cleanup Adobe Connect meetings but it's actually not available"); - return; - } - - /* - * the concrete jobs - */ - // cleanup unused meetings - if(cleanupMeetings) { - logger.info("Start cleaning unused Adobe Connect meetings"); - cleanupMeetings(adobe, daysToKeep); - } - // cleanup unused moderator guest accounts - if(cleanupModerators) { - logger.info("Start cleaning unused Adobe Connect moderator guest accounts"); - cleanupModerators(adobe); - } - } - - /** - * @param adobe - */ - protected void cleanupMeetings(AdobeConnectProvider adobe, int daysToKeep) { - boolean success = false; - - Date lowerLimit = new Date((new Date()).getTime() - (daysToKeep * 24*60*60*1000)); - - // search all virtual classrooms with the used prefix - List<String> roomIds = adobe.findClassrooms(AdobeConnectProvider.PREFIX); - for(String roomId : roomIds) { - // format is olat-courseId-nodeId, e.g. olat-82823405537032-82823405537043 - // load course and node - String courseId = roomId.split("-")[1]; - String nodeId = roomId.split("-")[2]; - ICourse course = CourseFactory.loadCourse(Long.parseLong(courseId)); - CourseNode vcNode = course.getRunStructure().getNode(nodeId); - if(!(vcNode instanceof VCCourseNode)) { - logger.warn("Tried to cleanup Adobe Connect meeting for a non Adobe Connect course node: " + roomId); - continue; - } - AdobeConnectConfiguration config = (AdobeConnectConfiguration) vcNode.getModuleConfiguration().get(VCCourseNode.CONF_VC_CONFIGURATION); - if(config == null) { - // invalid configuration, do nothing and continue - continue; - } - - boolean keep = false; - for(MeetingDate date : config.getMeetingDates()) { - if(keep) continue; - Date end = date.getEnd(); - keep = lowerLimit.before(end); - } - - // no planned date in the future, we can delete - // build the correct roomId - String toDelete = courseId + "-" + nodeId; - if(!keep) success = adobe.removeClassroom(toDelete, config); - - if(!success) { - logger.warn("Error when cleaning up Adobe Connect meeting \"" + roomId + "\""); - continue; - } - } - } - - protected void cleanupModerators(AdobeConnectProvider adobe) { -// boolean success = false; -// TODO implement - } - - public String getProviderId() { - return providerId; - } - - public void setProviderId(String providerId) { - this.providerId = providerId; - } - - public int getDaysToKeep() { - return daysToKeep; - } - - public void setDaysToKeep(int daysToKeep) { - this.daysToKeep = daysToKeep; - } - - public void setCleanupMeetings(boolean cleanupMeetings) { - this.cleanupMeetings = cleanupMeetings; - } - - public boolean isCleanupMeetings() { - return cleanupMeetings; - } - - public void setCleanupModerators(boolean cleanupModerators) { - this.cleanupModerators = cleanupModerators; - } - - public boolean isCleanupModerators() { - return cleanupModerators; - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectConfiguration.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectConfiguration.java deleted file mode 100644 index f21c9618903..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectConfiguration.java +++ /dev/null @@ -1,64 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import java.io.Serializable; - -import de.bps.course.nodes.vc.DefaultVCConfiguration; - -/** - * - * Description:<br> - * Configuration object for Adobe Connect - * - * <P> - * Initial Date: 20.12.2010 <br> - * @author skoeber - */ -public class AdobeConnectConfiguration extends DefaultVCConfiguration implements Serializable { - - private boolean guestAccessAllowed; - private boolean guestStartMeetingAllowed; - - public boolean isGuestAccessAllowed() { - return guestAccessAllowed; - } - public void setGuestAccessAllowed(boolean guestAccessAllowed) { - this.guestAccessAllowed = guestAccessAllowed; - } - public boolean isGuestStartMeetingAllowed() { - return guestStartMeetingAllowed; - } - public void setGuestStartMeetingAllowed(boolean guestStartMeetingAllowed) { - this.guestStartMeetingAllowed = guestStartMeetingAllowed; - } - - @Override - public boolean isConfigValid() { - boolean valid = true; - if(isUseMeetingDates()) { - valid = getMeetingDates() != null && !getMeetingDates().isEmpty(); - } - return valid; - } - -} -//</OLATCE-103> diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectProvider.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectProvider.java deleted file mode 100644 index 5caebf316ea..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeConnectProvider.java +++ /dev/null @@ -1,799 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.UriBuilder; -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.apache.commons.lang.NotImplementedException; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.helpers.Settings; -import org.olat.core.id.Identity; -import org.olat.core.id.UserConstants; -import org.olat.core.logging.AssertException; -import org.olat.core.logging.LogDelegator; -import org.olat.core.util.Encoder; -import org.olat.core.util.StringHelper; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import de.bps.course.nodes.vc.VCConfiguration; -import de.bps.course.nodes.vc.provider.VCProvider; - -/** - * - * Description:<br> - * Virtual classroom provider for Adobe Connect. - * - * <P> - * Initial Date: 09.12.2010 <br> - * @author skoeber - */ -public class AdobeConnectProvider extends LogDelegator implements VCProvider { - - private static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; - private static final String COOKIE = "BREEZESESSION="; - protected static final String PREFIX = "olat-"; - private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm"; - - protected static String DEFAULT_TEMPLATE = "default"; - - // configuration - private static AdobeConnectConfiguration defaultConfig; - private boolean enabled; - private String providerId; - private String displayName; - private String protocol; - private int port; - private String baseUrl; - private String adminLogin; - private String adminPassword; - private String accountId; - private Map<String, String> templates; - private boolean guestAccessAllowedDefault; - private boolean guestStartMeetingAllowedDefault; - private boolean useMeetingDatesDefault; - private boolean showOptions; - private String userType; - - // runtime data - private String cookie; - - /** - * Constructor for internal use to create new instance - * @param providerId - * @param protocol - * @param port - * @param baseUrl - * @param adminLogin - * @param adminPassword - */ - private AdobeConnectProvider(String providerId, String displayName, String protocol, int port, String baseUrl, String adminLogin, String adminPassword, - String accountId, Map<String, String> templates, boolean guestAccessAllowedDefault, boolean guestStartMeetingAllowedDefault, - boolean showOptions, String userType) { - setProviderId(providerId); - setDisplayName(displayName); - setProtocol(protocol); - setPort(port); - setBaseUrl(baseUrl); - setAdminLogin(adminLogin); - setAdminPassword(adminPassword); - setAccountId(accountId); - setTemplates(templates); - setGuestAccessAllowedDefault(guestAccessAllowedDefault); - setGuestStartMeetingAllowedDefault(guestStartMeetingAllowedDefault); - setShowOptions(showOptions); - setUserType(userType); - } - - /** - * Public constructor, mostly used by spring<br/> - * <b>Important</b> when using: set configuration manually! - */ - public AdobeConnectProvider() { - // - } - - @Override - public boolean createClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config) { - if(existsClassroom(roomId, config)) return true; - - if(!loginAdmin()) { - logError("Cannot login to Adobe Connect. Please check module configuration and Adobe Connect connectivity.", null); - return false; - } - - // begin and end can be NULL, see interface description - if(begin == null) begin = new Date(); - if(end == null) end = new Date(begin.getTime() + 365*24*60*60*1000); // preset one year - - // formatter for begin and end - SimpleDateFormat sd = new SimpleDateFormat(DATE_FORMAT); - - // find my-meetings - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "sco-shortcuts"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - String folderScoId = null; - // use my-meetings folder - String result = evaluate(responseDoc, "//sco[@type=\"my-meetings\"]"); - if(result != null && !result.isEmpty()) { - folderScoId = evaluate(responseDoc, "//sco[@type=\"my-meetings\"]/attribute::sco-id"); - } - // my-meetings folder not found, fallback to meetings - if(folderScoId == null) { - result = evaluate(responseDoc, "//sco[@type=\"meetings\"]"); - if(result != null && !result.isEmpty()) { - folderScoId = evaluate(responseDoc, "//sco[@type=\"meetings\"]/attribute::sco-id"); - } - } - // meetings folder not found, error case - if(folderScoId == null) return false; - // folder found where to insert the new meeting - // create new meeting - parameters = new HashMap<String, String>(); - parameters.put("action", "sco-update"); - parameters.put("type", "meeting"); - parameters.put("name", PREFIX + roomId); - parameters.put("folder-id", folderScoId); - parameters.put("date-begin", sd.format(begin)); - parameters.put("date-end", sd.format(end)); - parameters.put("url-path", PREFIX + roomId); - String templateId = ((AdobeConnectConfiguration)config).getTemplateKey(); - if(templateId != null && !templateId.equals(DEFAULT_TEMPLATE)) - parameters.put("source-sco-id", templateId); - responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - // adjust permissions - String meetingScoId = evaluate(responseDoc, "//sco/attribute::sco-id"); - parameters.clear(); - parameters.put("action", "permissions-update"); - parameters.put("acl-id", meetingScoId); - parameters.put("principal-id", "public-access"); - if(((AdobeConnectConfiguration)config).isGuestAccessAllowed()) - parameters.put("permission-id", "view-hidden"); - else - parameters.put("permission-id", "remove"); - responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - logout(); - return true; - } - - @Override - public boolean updateClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config) { - if(!existsClassroom(roomId, config)) return false; - if(!loginAdmin()) throw new AssertException("Cannot login to Adobe Connect. Please check module configuration and that Adobe Connect is available."); - - String scoId = getScoIdFor(roomId); - if(scoId == null) return false; - - // formatter for begin and end - SimpleDateFormat sd = new SimpleDateFormat(DATE_FORMAT); - - Map<String, String> parameters = new HashMap<String, String>(); - // update meeting configuration - parameters.put("action", "sco-update"); - parameters.put("sco-id", scoId); - if(begin != null) - parameters.put("date-begin", sd.format(begin)); - if(end != null) - parameters.put("date-end", sd.format(end)); - String templateId = ((AdobeConnectConfiguration)config).getTemplateKey(); - if(templateId != null && !templateId.equals(DEFAULT_TEMPLATE)) - parameters.put("source-sco-id", templateId); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - // adjust permissions - parameters.clear(); - parameters.put("action", "permissions-update"); - parameters.put("acl-id", scoId); - parameters.put("principal-id", "public-access"); - if(((AdobeConnectConfiguration)config).isGuestAccessAllowed()) - parameters.put("permission-id", "view-hidden"); - else - parameters.put("permission-id", "remove"); - responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - logout(); - return true; - } - - @Override - public boolean removeClassroom(String roomId, VCConfiguration config) { - if(!existsClassroom(roomId, config)) return true; - if(!loginAdmin()) throw new AssertException("Cannot login to Adobe Connect. Please check module configuration and that Adobe Connect is available."); - - String scoId = getScoIdFor(roomId); - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "sco-delete"); - parameters.put("sco-id", scoId); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - logout(); - return true; - } - - private String getScoIdFor(String roomId) { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "sco-search-by-field"); - parameters.put("query", PREFIX + roomId); - parameters.put("filter-type", "meeting"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return null; - - Object result = evaluate(responseDoc, "//sco/url-path[text()='/" + PREFIX + roomId + "/']", XPathConstants.NODESET); - if(result == null) return null; - NodeList nodes = (NodeList) result; - if(nodes.getLength() == 1) { - String scoId = evaluate(responseDoc, "//sco[1]/attribute::sco-id"); - return scoId; - } - else if(nodes.getLength() > 1) - throw new AssertException("More than one Adobe Connect room found for one course node!"); - else - return null; - } - - @Override - public URL createClassroomUrl(String roomId, Identity identity, VCConfiguration config) { - URL url = null; - URI uri = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port) - .path(PREFIX + roomId).queryParam("session", cookie).build(); - try { - url = uri.toURL(); - } catch (MalformedURLException e) { - logWarn("Cannot create access URL to Adobe Connect meeting for id \"" + PREFIX + roomId + "\" and user \"" + identity.getKey() + "\"", e); - } - return url; - } - - @Override - public URL createClassroomGuestUrl(String roomId, Identity identity, VCConfiguration config) { - URL url = null; - URI uri = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port) - .path(PREFIX + roomId).queryParam("guestName", identity.getName()).build(); - try { - url = uri.toURL(); - } catch (MalformedURLException e) { - logWarn("Cannot create access URL to Adobe Connect meeting for id \"" + PREFIX + roomId + "\" and user \"" + identity.getKey() + "\"", e); - } - return url; - } - - @Override - public boolean existsClassroom(String roomId, VCConfiguration config) { - if(!loginAdmin()) return false; - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "sco-search-by-field"); - parameters.put("query", PREFIX + roomId); - parameters.put("filter-type", "meeting"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) return false; - - Object result = evaluate(responseDoc, "//sco/url-path[text()='/" + PREFIX + roomId + "/']", XPathConstants.NODESET); - logout(); - if(result == null) return false; - NodeList nodes = (NodeList) result; - if(nodes.getLength() == 1) - return true; - else if(nodes.getLength() > 1) - throw new AssertException("More than one Adobe Connect room found for one course node!"); - else - return false; - } - - protected List<String> findClassrooms(String name) { - List<String> results = new ArrayList<String>(); - if(!loginAdmin()) return results; - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "sco-search-by-field"); - parameters.put("field", "name"); - parameters.put("query", name); - parameters.put("filter-type", "meeting"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - if(!evaluateOk(responseDoc)) { - logError("Invalid response when searching for classrooms with the name \"" + name + "\"", null); - return results; - } - - Object result = evaluate(responseDoc, "descendant-or-self::sco-search-by-field-info/child::sco/child::name", XPathConstants.NODESET); - logout(); - if(result == null) if(isLogDebugEnabled()) logDebug("Search for Adobe Connect classrooms with name \"" + name + "\" with no results"); - NodeList nodes = (NodeList) result; - for(int i=0; i<nodes.getLength(); i++) { - Node node = nodes.item(i); - String roomId = node.getFirstChild().getNodeValue(); - results.add(roomId); - } - - return results; - } - - @Override - public boolean createModerator(Identity identity, String roomId) { - if(!loginAdmin()) return false; - Map<String, String> parameters = new HashMap<>(); - // create user - parameters.put("action", "principal-update"); - parameters.put("first-name", identity.getUser().getProperty(UserConstants.FIRSTNAME, null)); - parameters.put("last-name", identity.getUser().getProperty(UserConstants.LASTNAME, null)); - parameters.put("login", PREFIX + identity.getName()); - parameters.put("password", Encoder.md5hash(identity.getName() + "@" + Settings.getApplicationName())); - parameters.put("type", userType); - parameters.put("has-children", "false"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - - if(!evaluateOk(responseDoc)) { - boolean exists = false; - String error = evaluate(responseDoc, "/results/status[1]/attribute::code"); - if(error.equals("invalid")) { - error = evaluate(responseDoc, "/results[1]/status[1]/invalid/attribute::subcode"); - exists = error.equals("duplicate"); - } - if(!exists) return false; - } - - // search the user - String principalId = getPrincipalIdFor(identity); - if(principalId == null) return false; // error case - - // create permissions for the meeting - String scoId = getScoIdFor(roomId); - if(scoId == null) return false; - parameters.clear(); - parameters.put("action", "permissions-update"); - parameters.put("acl-id", scoId); - parameters.put("principal-id", principalId); - parameters.put("permission-id", "host"); - String response = sendRequest(parameters); - responseDoc = getResponseDocument(response); - logout(); - - return evaluateOk(responseDoc); - } - - @Override - public boolean createUser(Identity identity, String roomId) { - throw new NotImplementedException("method createUser not yet implemented"); - } - - @Override - public boolean createGuest(Identity identity, String roomId) { - throw new NotImplementedException("method createGuest not yet implemented"); - } - - @Override - public String getProviderId() { - return providerId; - } - - @Override - public String getDisplayName() { - return displayName; - } - - @Override - public VCProvider newInstance() { - AdobeConnectProvider newInstance = new AdobeConnectProvider(providerId, displayName, protocol, port, baseUrl, adminLogin, adminPassword, accountId, templates, - guestAccessAllowedDefault, guestStartMeetingAllowedDefault, showOptions, userType); - return newInstance; - } - - @Override - public Controller createDisplayController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, - boolean isModerator, boolean readOnly, VCConfiguration config) { - AdobeDisplayController displayCtr = new AdobeDisplayController(ureq, wControl, roomId, name, description, isModerator, readOnly, (AdobeConnectConfiguration) config, this); - return displayCtr; - } - - @Override - public Controller createConfigController(UserRequest ureq, WindowControl wControl, String roomId, VCConfiguration config) { - AdobeConfigController configCtr = new AdobeConfigController(ureq, wControl, roomId, this, (AdobeConnectConfiguration) config); - return configCtr; - } - - @Override - public boolean login(Identity identity, String password) { - if(cookie == null) createCookie(); - Map<String,String> parameters = new HashMap<>(); - parameters.put("action", "login"); - if(accountId != null) parameters.put("account-id", accountId); - parameters.put("login", PREFIX + identity.getName()); - parameters.put("password", Encoder.md5hash(identity.getName() + "@" + Settings.getApplicationName())); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - - return evaluateOk(responseDoc); - } - - private boolean loginAdmin() { - if(cookie == null) createCookie(); - Map<String,String> parameters = new HashMap<>(); - parameters.put("action", "login"); - if(accountId != null) parameters.put("account-id", accountId); - parameters.put("login", adminLogin); - parameters.put("password", adminPassword); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - boolean success = evaluateOk(responseDoc); - if(!success) { - logWarn("Admin login to Adobe Connect failed", null); - } - return success; - } - - private boolean logout() { - if(cookie == null) return true; - Map<String,String> parameters = new HashMap<String, String>(); - parameters.put("action", "logout"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - cookie = null; - - return evaluateOk(responseDoc); - } - - private boolean createCookie() { - Map<String, String> parameters = new HashMap<>(); - parameters.put("action", "common-info"); - String response = sendRequest(parameters); - - Document responseDoc = getResponseDocument(response); - boolean success = evaluateOk(responseDoc); - if (success) { - // get cookie - String result = evaluate(responseDoc, "/results/common[1]/cookie[1]/text()"); - cookie = result; - } - return success; - } - - private String getPrincipalIdFor(Identity identity) { - Map<String, String> parameters = new HashMap<>(); - parameters.put("action", "principal-list"); - parameters.put("filter-type", userType); - parameters.put("filter-type", "user"); - parameters.put("filter-login", PREFIX + identity.getName()); - String response = sendRequest(parameters); - - Document responseDoc = getResponseDocument(response); - boolean success = evaluateOk(responseDoc); - if(!success) return null; - // get principalId - NodeList nodes = (NodeList) evaluate(responseDoc, "//principal", XPathConstants.NODESET); - if(nodes == null) return null; // error case - if(nodes.getLength() == 1) { - String principalId = evaluate(responseDoc, "//principal[1]/attribute::principal-id"); - return principalId; - } else if(nodes.getLength() > 1) { - throw new AssertException("Multiple Adobe Connect users with the same login name found: " + identity.getName()); - } else return null; - } - - private Document getResponseDocument(String response) { - DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); - domFactory.setNamespaceAware(true); // never forget this! - DocumentBuilder builder; - Document doc = null; - try { - builder = domFactory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(response)); - doc = builder.parse(is); - } catch (ParserConfigurationException e) { - if(isLogDebugEnabled()) logDebug("Error while creating DOM parser."); - } catch (SAXException e) { - if(isLogDebugEnabled()) logDebug("Error while parsing result XML document."); - } catch (IOException e) { - if(isLogDebugEnabled()) logDebug("Error while reading response."); - } - return doc; - } - - private boolean evaluateOk(Document responseDoc) { - String result = evaluate(responseDoc, "/results/status[1]/attribute::code"); - if(result == null || result.isEmpty()) - return false; - return result.equals("ok"); - } - - private String evaluate(Document responseDoc, String expression) { - Object result = evaluate(responseDoc, expression, XPathConstants.STRING); - if(result == null || !(result instanceof String)) - return new String(); - return (String)result; - } - - private Object evaluate(Document responseDoc, String expression, QName type) { - if(responseDoc == null) return null; - XPathFactory factory = XPathFactory.newInstance(); - XPath xpath = factory.newXPath(); - XPathExpression expr; - Object result; - try { - expr = xpath.compile(expression); - result = expr.evaluate(responseDoc, type); - } catch (XPathExpressionException e) { - result = null; - } - - return result; - } - - private String sendRequest(Map<String, String> parameters) { - URL url = createRequestUrl(parameters); - URLConnection urlConn; - - try { - urlConn = url.openConnection(); - // setup url connection - urlConn.setDoOutput(true); - urlConn.setUseCaches(false); - // add content type - urlConn.setRequestProperty("Content-Type", CONTENT_TYPE); - // add cookie information - if(cookie != null) urlConn.setRequestProperty("Cookie", COOKIE + cookie); - - // send request - urlConn.connect(); - - // read response - BufferedReader input = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); - StringBuilder response= new StringBuilder(); - String line; - while( (line = input.readLine()) != null ) response.append(line); - input.close(); - - if(isLogDebugEnabled()) { - logDebug("Requested URL: " + url); - logDebug("Response: " + response); - } - - return response.toString(); - } catch (IOException e) { - logError("Sending request to Adobe Connect failed. Request: " + url.toString(), e); - return ""; - } - } - - private URL createRequestUrl(Map<String, String> parameters) { - UriBuilder ubu = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port).path("api").path("xml"); - - for(String key : parameters.keySet()) { - ubu.queryParam(key, parameters.get(key)); - } - - URL url = null; - try { - url = ubu.build().toURL(); - } catch (Exception e) { - logWarn("Error while creating URL for Adobe Connect request.", e); - // try to build the URL in a naiv way below - } - if(url == null) { - // error case, try the naiv way - try { - StringBuilder sb = new StringBuilder(protocol + "://" + baseUrl + ":" + port + "/api/xml"); - if(!parameters.isEmpty()) sb.append("?"); - for(String key : parameters.keySet()) { - sb.append(key + "=" + parameters.get(key) + "&"); - } - sb.replace(sb.length(), sb.length(), ""); - url = new URL(sb.toString()); - } catch (MalformedURLException e) { - logError("Error while creating URL for Adobe Connect request. Please check the configuration!", e); - } - } - - return url; - } - - @Override - public boolean isProviderAvailable() { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("action", "common-info"); - Document responseDoc = getResponseDocument(sendRequest(parameters)); - - return evaluateOk(responseDoc); - } - - @Override - public VCConfiguration createNewConfiguration() { - AdobeConnectConfiguration config = new AdobeConnectConfiguration(); - config.setProviderId(providerId); - config.setGuestAccessAllowed(defaultConfig.isGuestAccessAllowed()); - config.setGuestStartMeetingAllowed(defaultConfig.isGuestStartMeetingAllowed()); - config.setUseMeetingDates(defaultConfig.isUseMeetingDates()); - return config; - } - - @Override - public Map<String, String> getTemplates() { - if(templates == null) templates = Collections.emptyMap(); - return templates; - } - - //////////////////////////// - // setters used by spring // - //////////////////////////// - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void setProviderId(String providerId) { - this.providerId = providerId; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public void setPort(int port) { - this.port = port; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public void setAdminLogin(String adminLogin) { - this.adminLogin = adminLogin; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - public void setAccountId(String accountId) { - if(StringHelper.containsNonWhitespace(accountId)) { - this.accountId = accountId; - } else { - this.accountId = null; - } - } - - public void setTemplates(Map<String,String> templates) { - this.templates = templates; - - List<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>(templates.entrySet()); - for(Map.Entry<String, String> entry:entries) { - if(!StringHelper.containsNonWhitespace(entry.getKey()) || !StringHelper.containsNonWhitespace(entry.getValue())) { - templates.remove(entry.getKey()); - } - } - } - - public void setGuestAccessAllowedDefault(boolean guestAccessAllowedDefault) { - this.guestAccessAllowedDefault = guestAccessAllowedDefault; - } - - public void setGuestStartMeetingAllowedDefault(boolean guestStartMeetingAllowedDefault) { - this.guestStartMeetingAllowedDefault = guestStartMeetingAllowedDefault; - } - - public void setUseMeetingDatesDefault(boolean useMeetingDatesDefault) { - this.useMeetingDatesDefault = useMeetingDatesDefault; - } - - public void setShowOptions(boolean showOptions) { - this.showOptions = showOptions; - } - - public void setUserType(String userType) { - this.userType = userType; - } - - public void setDefaultConfig(AdobeConnectConfiguration config) { - defaultConfig = config; - defaultConfig.setProviderId(providerId); - } - - ///////////////////////////// - // getters used internally // - ///////////////////////////// - @Override - public boolean isEnabled() { - return enabled; - } - - protected String getProtocol() { - return protocol; - } - - protected int getPort() { - return port; - } - - protected String getBaseUrl() { - return baseUrl; - } - - protected String getAdminLogin() { - return adminLogin; - } - - protected String getAdminPassword() { - return adminPassword; - } - - protected String getAccountId() { - return accountId; - } - - protected boolean isGuestAccessAllowedDefault() { - return guestAccessAllowedDefault; - } - - protected boolean isGuestStartMeetingAllowedDefault() { - return guestStartMeetingAllowedDefault; - } - - protected boolean isUseMeetingDatesDefault() { - return useMeetingDatesDefault; - } - - protected boolean isShowOptions() { - return showOptions; - } - - protected String getUserType() { - return userType; - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeDisplayController.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeDisplayController.java deleted file mode 100644 index d82ca347780..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeDisplayController.java +++ /dev/null @@ -1,232 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Date; -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; -import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.velocity.VelocityContainer; -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.media.RedirectMediaResource; - -import de.bps.course.nodes.vc.MeetingDate; -import de.bps.course.nodes.vc.provider.VCProvider; - -/** - * - * Description:<br> - * Display controller for Adobe Connect implementation, mostly used as - * run controller in the course node. - * - * <P> - * Initial Date: 16.12.2010 <br> - * @author skoeber - */ -public class AdobeDisplayController extends BasicController { - - private static String COMMAND_START_MEETING = "cmd.start.meeting"; - private static String COMMAND_START_JOIN_MEETING = "cmd.start.join.meeting"; - private static String COMMAND_JOIN_MODERATOR = "cmd.join.moderator"; - private static String COMMAND_JOIN_LEARNER = "cmd.join.learner"; - private static String COMMAND_REMOVE_MEETING = "cmd.remove.meeting"; - private static String COMMAND_SYNC_MEETING = "cmd.sync.meeting"; - - // objects for run view - private VelocityContainer runVC; - private String roomId; - private Link startModerator, startJoinLearner, joinModerator, joinLearner; - private Link removeMeeting, updateMeeting; - - // data - private List<MeetingDate> dateList = new ArrayList<MeetingDate>(); - private AdobeConnectConfiguration config; - private MeetingDate meeting; - private Date allBegin, allEnd; - - private VCProvider adobe; - - public AdobeDisplayController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, - boolean isModerator, boolean readOnly, AdobeConnectConfiguration config, VCProvider provider) { - super(ureq, wControl); - this.roomId = roomId; - this.adobe = provider; - this.config = config; - - // The dates Table to the Course odes - if(config.getMeetingDates() != null) dateList.addAll(config.getMeetingDates()); - - // select actual meeting - if(config.isUseMeetingDates()) { - Date now = new Date((new Date()).getTime() + 15*60*1000); // allow to start meetings about 15 minutes before begin - for(MeetingDate date : dateList) { - Date begin = date.getBegin(); - Date end = date.getEnd(); - if(now.after(begin) & now.before(end)) { - meeting = date; - } - allBegin = allBegin == null ? begin : begin.before(allBegin) ? begin : allBegin; - allEnd = allEnd == null ? end : end.after(allEnd) ? end : allEnd; - } - } else { - allBegin = new Date(); - allEnd = new Date(allBegin.getTime() + 365*24*60*60*1000); // preset one year - meeting = new MeetingDate(); - meeting.setBegin(allBegin); - meeting.setEnd(allEnd); - meeting.setTitle(name); - meeting.setDescription(description); - } - - runVC = createVelocityContainer("run"); - - startModerator = LinkFactory.createButton(COMMAND_START_MEETING, runVC, this); - startModerator.setVisible(!readOnly); - startJoinLearner = LinkFactory.createButton(COMMAND_START_JOIN_MEETING, runVC, this); - startJoinLearner.setVisible(!readOnly); - joinLearner = LinkFactory.createButton(COMMAND_JOIN_LEARNER, runVC, this); - joinLearner.setVisible(!readOnly); - joinModerator = LinkFactory.createButton(COMMAND_JOIN_MODERATOR, runVC, this); - joinModerator.setVisible(!readOnly); - removeMeeting = LinkFactory.createButton(COMMAND_REMOVE_MEETING, runVC, this); - removeMeeting.setVisible(!readOnly); - updateMeeting = LinkFactory.createButton(COMMAND_SYNC_MEETING, runVC, this); - updateMeeting.setVisible(!readOnly); - // set target to be able to open new browser window on event - startJoinLearner.setTarget("_blank"); - joinLearner.setTarget("_blank"); - joinModerator.setTarget("_blank"); - // render the right button - boolean isUseDates = config.isUseMeetingDates(); - boolean isMeeting = !isUseDates | meeting != null; - boolean exists = adobe.existsClassroom(roomId, config); - boolean guestCanStart = config.isGuestStartMeetingAllowed(); - runVC.contextPut("isModerator", isModerator); - runVC.contextPut("exists", exists); - runVC.contextPut("guestCanStart", guestCanStart); - runVC.contextPut("useDates", isUseDates); - joinLearner.setEnabled(isMeeting & exists); - - putInitialPanel(runVC); - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - if(source == startModerator) { - /* - * create new meeting room and prepare to join it - */ - boolean success = adobe.createClassroom(roomId, null, null, allBegin, allEnd, config); - if(success) { - runVC.contextPut("exists", true); - runVC.setDirty(true); - } else { - getWindowControl().setError(translate("error.create.room")); - } - } else if(source == startJoinLearner) { - /* - * create new meeting room and join immediately as guest - */ - boolean success = adobe.createClassroom(roomId, null, null, allBegin, allEnd, config); - if(success) { - runVC.contextPut("exists", true); - runVC.setDirty(true); - // join meeting as guest - URL url = adobe.createClassroomGuestUrl(roomId, ureq.getIdentity(), config); - RedirectMediaResource rmr = new RedirectMediaResource(url.toString()); - ureq.getDispatchResult().setResultingMediaResource(rmr); - return; - } else { - getWindowControl().setError(translate("error.create.room")); - } - } else if(source == joinLearner) { - /* - * easiest case: simply generate link to join meeting as guest - */ - URL url = adobe.createClassroomGuestUrl(roomId, ureq.getIdentity(), config); - RedirectMediaResource rmr = new RedirectMediaResource(url.toString()); - ureq.getDispatchResult().setResultingMediaResource(rmr); - return; - } else if(source == joinModerator) { - /* - * join meeting as moderator, first prepare user to have appropriate rights - */ - boolean success = adobe.existsClassroom(roomId, config); - // update rights for user to moderate meeting - if(success) { - success = adobe.createModerator(ureq.getIdentity(), roomId); - } else { - // room not found, should not appear - getWindowControl().setError(translate("error.no.room")); - return; - } - // login the user as moderator - if(success) { - success = adobe.login(ureq.getIdentity(), null); - } else { - // could not create moderator or update the rights - getWindowControl().setError(translate("error.update.rights")); - return; - } - // redirect to the meeting - if(success) { - URL url = adobe.createClassroomUrl(roomId, ureq.getIdentity(), config); - RedirectMediaResource rmr = new RedirectMediaResource(url.toString()); - ureq.getDispatchResult().setResultingMediaResource(rmr); - } else { - // login failed - getWindowControl().setError(translate("error.no.login")); - return; - } - return; - } else if(source == removeMeeting) { - boolean success = adobe.removeClassroom(roomId, config); - if(success) { - runVC.contextPut("exists", false); - runVC.setDirty(true); - } else { - // removing failed - getWindowControl().setError(translate("error.remove.room")); - } - } else if(source == updateMeeting) { - boolean success = adobe.updateClassroom(roomId, null, null, allBegin, allEnd, config); - if(success) { - getWindowControl().setInfo(translate("success.update.room")); - } else { - // update failed - getWindowControl().setError(translate("error.update.room")); - } - } - } - - @Override - protected void doDispose() { - // nothing to dispose - } -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditForm.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditForm.java deleted file mode 100644 index 1698f3f45b3..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditForm.java +++ /dev/null @@ -1,99 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; -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.elements.FormSubmit; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.course.editor.NodeEditController; - -/** - * Description:<br> - * Edit form for Adobe Connect specific options. - * - * <P> - * Initial Date: 30.08.2010 <br> - * - * @author jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber - */ -public class AdobeEditForm extends FormBasicController { - - // GUI - private FormSubmit submit; - private MultipleSelectionElement multiSelectOptions; - private static String OPTION_START_MEETING = "vc.access.start"; - private static String OPTION_OPEN_MEETING = "vc.access.open"; - private boolean showOptions; - - // data - private AdobeConnectConfiguration config; - - public AdobeEditForm(UserRequest ureq, WindowControl wControl, boolean showOptions, AdobeConnectConfiguration config) { - super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL); - this.config = config; - this.showOptions = showOptions; - - initForm(this.flc, this, ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - - // meeting options - String[] accessKeys = new String[] {OPTION_OPEN_MEETING, OPTION_START_MEETING}; - String[] accessVals = new String[] {translate(OPTION_OPEN_MEETING), translate(OPTION_START_MEETING)}; - multiSelectOptions = uifactory.addCheckboxesVertical("vc.access", "vc.access.label", formLayout, accessKeys, accessVals, 1); - multiSelectOptions.select(OPTION_START_MEETING, !config.isGuestStartMeetingAllowed()); - multiSelectOptions.select(OPTION_OPEN_MEETING, !config.isGuestAccessAllowed()); - multiSelectOptions.setVisible(showOptions); - multiSelectOptions.addActionListener(FormEvent.ONCHANGE); - multiSelectOptions.showLabel(false); - - submit = new FormSubmit("subm", "submit"); - formLayout.add(submit); - } - - @Override - protected void doDispose() { - // nothing to dispose - } - - @Override - protected void formOK(UserRequest ureq) { - // read data from form elements - if(showOptions) { - config.setGuestAccessAllowed(!multiSelectOptions.getSelectedKeys().contains(OPTION_OPEN_MEETING)); - config.setGuestStartMeetingAllowed(!multiSelectOptions.getSelectedKeys().contains(OPTION_START_MEETING)); - } - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } - - protected AdobeConnectConfiguration getConfig() { - return config; - } -} -//</OLATCE-103> diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditTableDataModel.java b/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditTableDataModel.java deleted file mode 100644 index 35fc10e5250..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/AdobeEditTableDataModel.java +++ /dev/null @@ -1,77 +0,0 @@ -// <OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.adobe; - -import java.text.SimpleDateFormat; -import java.util.List; - -import org.olat.core.gui.components.table.DefaultTableDataModel; - -import de.bps.course.nodes.vc.MeetingDate; - -/** - * Description:<br> - * Data model for editing dates lists - Virtual Classroom dates. - * - * <P> - * Initial Date: 14.07.2010 <br> - * - * @author Jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber - */ -public class AdobeEditTableDataModel extends DefaultTableDataModel<MeetingDate> { - - private static int COLUMN_COUNT = 4; - - public AdobeEditTableDataModel(final List<MeetingDate> objects) { - super(objects); - } - - /** - * {@inheritDoc} - */ - @Override - public int getColumnCount() { - return COLUMN_COUNT; - } - - /** - * {@inheritDoc} - */ - @Override - public Object getValueAt(int row, int col) { - final MeetingDate model = objects.get(row); - switch (col) { - case 0: - return model.getTitle(); - case 1: - return model.getDescription(); - case 2: - return model.getBegin(); - case 3: - SimpleDateFormat sd = new SimpleDateFormat("dd.MM.yyyy HH:mm"); - return sd.format(model.getEnd()); - default: - return "error"; - } - } -} -// </OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/edit.html b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/edit.html deleted file mode 100644 index 35873e555e7..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/edit.html +++ /dev/null @@ -1,5 +0,0 @@ -<!-- <OLATCE-103> --> - - -$r.render("editForm") -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/run.html b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/run.html deleted file mode 100644 index 0dbcf41bc93..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_content/run.html +++ /dev/null @@ -1,28 +0,0 @@ -<!-- <OLATCE-103> --> -#if($isModerator) - #if($exists) - <p>$r.translate("cmd.join.moderator.intro")</p> - $r.render("cmd.join.moderator") - <div class="o_info"> - <p><strong>$r.translate("title.options")</strong></p> - $r.render("cmd.remove.meeting") - $r.render("cmd.sync.meeting") - </div> - #else - <p>$r.translate("cmd.start.meeting.intro")</p> - $r.render("cmd.start.meeting") - #end -#else - #if($exists) - <p>$r.translate("cmd.join.learner.intro")</p> - $r.render("cmd.join.learner") - #else - #if($guestCanStart) - <p>$r.translate("cmd.join.learner.intro")</p> - $r.render("cmd.start.join.meeting") - #else - <p>$r.translate("cmd.join.learner.wait")</p> - #end - #end -#end -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_de.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_de.properties deleted file mode 100644 index d8083f4017c..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_de.properties +++ /dev/null @@ -1,27 +0,0 @@ -vc.access.label=Zutrittsberechtigung -vc.access.start=Nur Moderatoren d\u00fcrfen diesen Raum er\u00f6ffnen -vc.access.open=Moderator muss im Raum online sein, um Zutritt f\u00fcr Teilnehmer zu best\u00e4tigen -vc.access.dates=Virtuelles Klassenzimmer soll nur zu bestimmten Terminen betreten werden k\u00f6nnen - -cmd.start.meeting=Virtuelles Klassenzimmer er\u00f6ffnen -cmd.start.meeting.intro=Das virtuelle Klassenzimmer wurde noch nicht er\u00f6ffnet. Teilnehmer k\u00f6nnen den Raum f\u00fcr ein geplantes Meeting ggf. nicht betreten. -cmd.start.join.meeting=Virtuelles Klassenzimmer betreten -cmd.join.moderator=Virtuelles Klassenzimmer moderieren -cmd.join.moderator.intro=Das virtuelle Klassenzimmer wurde er\u00f6ffnet. Sie k\u00f6nnen den Raum nun betreten und moderieren. Teilnehmer k\u00f6nnen das virtuelle Klassenzimmer ohne Zustimmung eines Moderators ggf. nicht betreten. -cmd.join.learner=Virtuelles Klassenzimmer betreten -cmd.join.learner.intro=Das virtuelle Klassenzimmer kann betreten werden. -cmd.join.learner.wait=Das virtuelle Klassenzimmer wurde noch nicht er\u00f6ffnet. -cmd.remove.meeting=Meeting schlie\u00dfen -cmd.sync.meeting=Meeting synchronisieren -title.options=Weiterf\u00fchrende Informationen und Optionen f\u00fcr Autoren - -error.no.room=Das virtuelle Klassenzimmer konnte nicht geladen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.no.login=Die Anmeldung war nicht erfolgreich. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.create.room=Das virtuelle Klassenzimmer konnte nicht erzeugt werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.remove.room=Das virtuelle Klassenzimmer konnte nicht entfernt werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.update.room=Das virtuelle Klassenzimmer konnte nicht mit den aktuellen Einstellungen synchronisiert werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.update.rights=Ihnen konnten nicht die notwendigen Rechte f\u00fcr diesen Raum zugewiesen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. - -sync.meeting.title=Virtuelles Klassenzimmer synchronisieren -sync.meeting.text=Sie haben die Einstellungen f\u00fcr diese virtuelle Klassenzimmer ge\u00e4ndert, nachdem dieses er\u00f6ffnet wurde. Die \u00c4nderungen werden erst wirksam, wenn Sie das virtuelle Klassenzimmer mit den neuen Einstellungen synchronisieren. Die Einstellungen k\u00f6nnen auch jederzeit direkt im Kurs synchronisiert werden. M\u00f6chten Sie die Einstellungen jetzt synchronisieren? -success.update.room=Das virtuelle Klassenzimmer wurde erfolgreich mit den aktuellen Einstellungen synchronisiert. \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_en.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_en.properties deleted file mode 100644 index f871faea0a0..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_en.properties +++ /dev/null @@ -1,29 +0,0 @@ -#Tue Jan 15 14:20:25 CET 2013 - - - - -cmd.join.learner=Enter virtual classroom -cmd.join.learner.intro=You can join the virtual classroom. -cmd.join.learner.wait=The virtual classroom has not been opened, yet. -cmd.join.moderator=Moderate virtual classroom -cmd.join.moderator.intro=The virtual classroom has been opened. You may now enter the classroom and moderate the meeting. Participants are not able to join the meeting until the moderator grant them access. -cmd.remove.meeting=Close meeting -cmd.start.join.meeting=Enter virtual classroom -cmd.start.meeting=Open virtual classroom -cmd.start.meeting.intro=The virtual classroom has not been opened, yet. Participants are not able to enter the classroom for a meeting. -cmd.sync.meeting=Synchronize meeting -error.create.room=Sorry\! An error occured while creating the virtual classroom. Please inform your tutor or system administrator. -error.no.login=Login was not successfull. Please, contact your tutor or system administrator for any further information. -error.no.room=Sorry\! An error occured while loading the virtual classroom. Please inform your tutor or system administrator. -error.remove.room=Sorry\! An error occured while removing the virtual class room. Please inform your tutor or system administrator. -error.update.rights=Sorry\! An error occured while granting access to the virtual classroom. Please inform your tutor or system administrator. -error.update.room=Sorry\! An error occured while synchronizing the virtual class room with the actual configuration. Please inform your tutor or system administrator. -success.update.room=Successfully synchronized the virtual classroom with the current configuration. -sync.meeting.text=You have changed the configuration of the virtual classroom after it had been started. The changes will be taken into account only after having synchronized the virtual class room with the new configuration. You can synchronize the configuration at any time directly from the course run. Do you want to synchronize now? -sync.meeting.title=Synchronize virtual classroom -title.options=Additional information and options for authors -vc.access.dates=Virtual classroom shall only be available at defined dates -vc.access.label=Access authorisation -vc.access.open=Moderator must be in classroom to grant access to users -vc.access.start=Only moderators are allowed to open this virtual classroom diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_fr.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_fr.properties deleted file mode 100644 index 3260d7c1f41..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_fr.properties +++ /dev/null @@ -1,29 +0,0 @@ -#Tue Oct 23 15:26:25 CEST 2012 - - - - -cmd.join.learner=Acc\u00E9der \u00E0 la classe virtuelle -cmd.join.learner.intro=L'acc\u00E8s \u00E0 la classe virtuelle est ouvert. -cmd.join.learner.wait=La classe virtuelle n'est pas encore disponible. -cmd.join.moderator=Mod\u00E9rer la classe virtuelle -cmd.join.moderator.intro=La classe virtuelle a \u00E9t\u00E9 ouverte. Vous pouvez entrer dans la salle et la mod\u00E9rer. Les participants ne peuvent acc\u00E9der \u00E0 cette classe virtuelle sans le consentement d'un mod\u00E9rateur. -cmd.remove.meeting=Termin\u00E9 une r\u00E9union -cmd.start.join.meeting=Acc\u00E9der \u00E0 la classe virtuelle -cmd.start.meeting=Ouvrir la classe virtuelle -cmd.start.meeting.intro=La classe virtuelle n'est pas encore disponible. Les participants \u00E0 cette classe ne peuvent pas encore y acc\u00E9der. -cmd.sync.meeting=Synchroniser les r\u00E9unions -error.create.room=La classe virtuelle n'a pas pu \u00EAtre cr\u00E9\u00E9e. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -error.no.login=L'inscription n'a pas r\u00E9ussi. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.no.room=La classe virtuelle ne peut pas \u00EAtre charg\u00E9. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -error.remove.room=La salle de classe virtuelle n'a pas pu \u00EAtre supprim\u00E9e. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -error.update.rights=Les autorisations n\u00E9cessaires \u00E0 cette classe n'ont pas pu vous \u00EAtre assign\u00E9. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -error.update.room=La classe virtuelle n'a pas pu \u00EAtre synchronis\u00E9e avec les param\u00E8tres actuels. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -success.update.room=La classe virtuelle a \u00E9t\u00E9 synchronis\u00E9e avec succ\u00E8s avec les param\u00E8tres actuels. -sync.meeting.text=Vous avez modifi\u00E9 les param\u00E8tres de cette classe virtuelle apr\u00E8s son ouverture. Les modifications ne prendront effet qu'apr\u00E8s l'avoir synchronis\u00E9e avec ses nouveaux param\u00E8tres. Les param\u00E8tres peuvent \u00E9galement \u00EAtre synchronis\u00E9s \u00E0 tout moment depuis le cours. Souhaitez-vous synchroniser les nouveaux param\u00E8tres maintenant? -sync.meeting.title=Synchroniser la classe virtuelle -title.options=Plus d'informations et d'options pour les auteurs -vc.access.dates=L'acc\u00E8s \u00E0 cet classe virtuelle est limit\u00E9e \u00E0 certaines dates -vc.access.label=Autorisation d'acc\u00E8s -vc.access.open=Les mod\u00E9rateur de la classe doivent \u00EAtre connect\u00E9 pour confirmer l'acc\u00E8s des participants -vc.access.start=Seuls les mod\u00E9rateurs ont le droit d'ouvrir cette classe diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_it.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_it.properties deleted file mode 100644 index 4c57d6995c2..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -#Tue Feb 07 11:57:18 CET 2017 -cmd.join.learner=Accesso all'aula virtuale -cmd.join.learner.intro=L'accesso all'aula virtuale \u00E8 aperto -cmd.join.learner.wait=L'aula virtuale non \u00E8 ancora disponibile. -cmd.join.moderator=Moderare l'aula virtuale -cmd.join.moderator.intro=L'aula virtuale \u00E8 stata aperta. Puoi ora accedere all'aula virtuale e moderare l'incontro. I partecipanti non potranno collegarsi alla riunione fino a che il moderatore non conceda il diritto di accedere. -cmd.remove.meeting=Chiudere la riunione -cmd.start.join.meeting=Accedere all'aula virtuale -cmd.start.meeting=Aprire l'aula virtuale -cmd.start.meeting.intro=L'aula virtuale non \u00E8 ancora disponibile. I partecipanti a questa riunione non possono ancora accedere all'aula. -cmd.sync.meeting=Sincronizzare le riunioni -error.create.room=Si \u00E8 verificato un errore durante la creazione dell'aula virtuale. Informare il tutore o l'amministratore di sistema. -error.no.login=Il login non \u00E8 riuscito. Contattare il tutore o l'amministratore di sistema per ulteriori informazioni. -error.no.room=Si \u00E8 verificato un errore nel caricamento dell'aula virtuale. Informare il tutore o l'amministratore di sistema. -error.remove.room=Si \u00E8 verificato un errore nella eliminazione dell'aula virtuale. Informare il tutore o l'amministratore di sistema. -error.update.rights=Si \u00E8 verificato un errore durante l'assegnazione dei diritti di accesso all'aula virtuale. Si prega di informare il tutore/docente o l'amministratore di sistema. -error.update.room=Si \u00E8 verificato un errore durante la sincronizzazione dell'aula virtuale con le impostazioni correnti. Si prega di informare il tutore/docente o l'amministratore di sistema. -success.update.room=Sincronizzazione dell'aula virtuale con le impostazioni correnti avvenuta con successo. -sync.meeting.text=Sono state modificate le impostazioni dell'aula virtuale dopo che \u00E8 stata aperta. I cambiamenti saranno applicati sono dopo aver sincronizzato l'aula virtuale con la nuova configurazione. Si pu\u00F2 effettuare la sincronizzazione della configurazione in qualsiasi momento all'interno del corso. Si desidera effettuare la sincronizzazione adesso? -sync.meeting.title=Sincronizzare aula virtuale -title.options=Informazioni addizionali e opzioni per gli autori -vc.access.dates=L'aula virtuale deve essere disponibile solo in date definite -vc.access.label=Autorizzazioni di accesso -vc.access.open=Il moderatore deve essere presente nell'aula per permettere l'accesso agli utenti -vc.access.start=Solo i moderatori sono abilitati ad aprire l'aula virtuale diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pl.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pl.properties deleted file mode 100644 index bd69060689e..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pl.properties +++ /dev/null @@ -1,19 +0,0 @@ -#Sun Dec 23 12:49:16 CET 2012 - - - - -cmd.join.learner=Wejd\u017A do wirtualnej klasy -cmd.join.learner.intro=Mo\u017Cesz wej\u015B\u0107 do wirtualnej klasy. -cmd.join.learner.wait=Wirtualna klasa nie zosta\u0142a jeszcze otwarta. -cmd.join.moderator=Moderuj wirtualn\u0105 klas\u0119 -cmd.join.moderator.intro=Wirtualna klasa zosta\u0142a otwarta. Mo\u017Cesz teraz wej\u015B\u0107 do pokoju i moderowa\u0107 spotkanie. U\u017Cytkownicy nie b\u0119d\u0105 mogli do\u0142\u0105czy\u0107 do spotkania bez zgody moderatora. -cmd.remove.meeting=Zamknij spotkanie -cmd.start.join.meeting=Wejd\u017A do wirtualnej klasy -cmd.start.meeting=Otw\u00F3rz wirtualn\u0105 klas\u0119 -cmd.start.meeting.intro=Wirtualna klasa nie zosta\u0142a jeszcze otwarta. Uczestnicy nie mog\u0105 wej\u015B\u0107 na spotkanie. -error.create.room=Wyst\u0105pi\u0142 b\u0142\u0105d podczas pr\u00F3by utworzenia wirtualnej klas. Prosz\u0119 skontaktowa\u0107 si\u0119 z administratorem. -sync.meeting.title=Synchronizuj wirtualn\u0105 klas\u0119 -title.options=Dodatkowe informacje i opcje dla autor\u00F3w -vc.access.label=Autoryzacja dost\u0119pu -vc.access.start=Tylko moderatorzy mog\u0105 otworzy\u0107 ten pok\u00F3j. diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pt_BR.properties b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pt_BR.properties deleted file mode 100644 index 81dc031f2e6..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_i18n/LocalStrings_pt_BR.properties +++ /dev/null @@ -1,25 +0,0 @@ -#Tue Nov 22 17:51:38 CET 2016 -cmd.join.learner=Entrar sala de aula virtual -cmd.join.learner.intro=Voc\u00EA pode participar da sala de aula virtual. -cmd.join.learner.wait=A sala de aula virtual ainda n\u00E3o foi aberta. -cmd.join.moderator=Moderar sala de aula virtual -cmd.join.moderator.intro=A sala de aula virtual foi aberta. Agora voc\u00EA pode entrar na sala de aula e moderar a reuni\u00E3o. Os participantes n\u00E3o poder\u00E3o participar da reuni\u00E3o at\u00E9 que o moderador lhes conceda acesso. -cmd.remove.meeting=Fechar reuni\u00E3o -cmd.start.join.meeting=Entrar na sala de aula virtual -cmd.start.meeting=Abrir a sala de aula virtual -cmd.start.meeting.intro=A sala de aula virtual ainda n\u00E3o foi aberta. Os participantes n\u00E3o s\u00E3o capazes de entrar na sala de aula para uma reuni\u00E3o. -cmd.sync.meeting=Sincronizar reuni\u00E3o -error.create.room=Desculpe\! Ocorreu um erro ao criar a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.no.login=O login n\u00E3o foi bem-sucedido. Entre em contato com o seu tutor ou administrador do sistema para obter mais informa\u00E7\u00F5es. -error.no.room=Desculpe\! Ocorreu um erro ao carregar a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.remove.room=Desculpe\! Ocorreu um erro ao remover a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.update.rights=Desculpe\! Ocorreu um erro ao conceder acesso \u00E0 sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.update.room=Desculpe\! Ocorreu um erro ao sincronizar a sala de aula virtual com a configura\u00E7\u00E3o real. Informe o seu tutor ou administrador do sistema. -success.update.room=Sincronizou com \u00EAxito a sala de aula virtual com a configura\u00E7\u00E3o atual. -sync.meeting.text=Voc\u00EA mudou a configura\u00E7\u00E3o da sala de aula virtual depois de ter sido iniciada. As altera\u00E7\u00F5es ser\u00E3o levadas em conta somente depois de ter sincronizado a sala de aula virtual com a nova configura\u00E7\u00E3o. Voc\u00EA pode sincronizar a configura\u00E7\u00E3o a qualquer momento diretamente da execu\u00E7\u00E3o do curso. Deseja sincronizar agora? -sync.meeting.title=Sincronizar sala de aula virtual -title.options=Informa\u00E7\u00F5es adicionais e op\u00E7\u00F5es para autores -vc.access.dates=A sala de aula virtual s\u00F3 estar\u00E1 dispon\u00EDvel em datas definidas -vc.access.label=Autoriza\u00E7\u00E3o de acesso -vc.access.open=O moderador deve estar em sala de aula para conceder acesso aos usu\u00E1rios -vc.access.start=Somente os moderadores podem abrir esta sala de aula virtual diff --git a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_spring/adobeContext.xml b/src/main/java/de/bps/course/nodes/vc/provider/adobe/_spring/adobeContext.xml deleted file mode 100644 index 2412a19a721..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/adobe/_spring/adobeContext.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd"> - - <bean id="adobeDefaultConfig" class="de.bps.course.nodes.vc.provider.adobe.AdobeConnectConfiguration"> - <!-- general --> - <property name="createMeetingImmediately" value="${vc.adobe.createMeetingImmediately}" /> - <!-- Adobe Connect specific --> - <property name="guestAccessAllowed" value="${vc.adobe.guestAccessAllowed}" /> - <property name="guestStartMeetingAllowed" value="${vc.adobe.guestStartMeetingAllowed}" /> - <property name="useMeetingDates" value="${vc.adobe.useMeetingDates}" /> - </bean> - -</beans> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/StatusCode.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/StatusCode.java deleted file mode 100644 index 4e08b5fc3f3..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/StatusCode.java +++ /dev/null @@ -1,74 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -/** - * - * Description:<br> - * API return codes, see Wimba Classroom 6.0 API Guide, page 5 - * - * <P> - * Initial Date: 07.01.2011 <br> - * @author skoeber - */ -public enum StatusCode { - - /** 100 OK */ OK(100), - /** 200 Database access error (database unavailable) */ DB_ACCESS_ERROR(200), - /** 201 Permission denied */ DENIED(201), - /** 204 Not authenticated, invalid authentication */ NO_AUTH(204), - /** 300 Database constraint error */ DB_CONSTRAINT_ERROR(300), - /** 301 Target already exists */ ALREADY_EXISTS(301), - /** 302 Target not found */ NOT_FOUND(302), - /** 400 Miscellaneous */ MISC(400), - /** 401 Not implemented */ NOT_IMPLEMENTED(401), - /** 402 Malformed query */ MALFORMED_QUERY(402), - /** 404 API HTTP server error */ SERVER_ERROR(404), - /** Undefined */ UNDEFINED(666); - - private int code; - - private StatusCode(int code) { - this.code = code; - } - - public int getCode() { - return code; - } - - public static StatusCode getStatus(int code) { - switch (code) { - case 100: return OK; - case 200: return DB_ACCESS_ERROR; - case 201: return DENIED; - case 204: return NO_AUTH; - case 300: return DB_CONSTRAINT_ERROR; - case 301: return ALREADY_EXISTS; - case 302: return NOT_FOUND; - case 400: return MISC; - case 401: return NOT_IMPLEMENTED; - case 402: return MALFORMED_QUERY; - case 404: return SERVER_ERROR; - default: return UNDEFINED; - } - } -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomProvider.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomProvider.java deleted file mode 100644 index 37b082b7923..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomProvider.java +++ /dev/null @@ -1,856 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.LineNumberReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.StringReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.UriBuilder; - -import org.apache.commons.lang.NotImplementedException; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.helpers.Settings; -import org.olat.core.id.Identity; -import org.olat.core.id.UserConstants; -import org.olat.core.logging.AssertException; -import org.olat.core.logging.LogDelegator; -import org.olat.core.util.Encoder; - -import de.bps.course.nodes.vc.VCConfiguration; -import de.bps.course.nodes.vc.provider.VCProvider; - -/** - * - * Description:<br> - * Virtual classroom provider implementation for Wimba Classroom - * - * <P> - * Initial Date: 06.01.2011 <br> - * @author skoeber - */ -public class WimbaClassroomProvider extends LogDelegator implements VCProvider { - - /** Return type of responses, see Wimba Classroom 6.0 API Guide, page 5 */ - private static final String CONTENT_TYPE = "text/html"; - /** Session cookie, see Wimba Classroom 6.0 API Guide, page 6 */ - private static final String COOKIE = "AuthCookieHandler_Horizon="; - /** Session token for remote login, see Wimba Classroom 6.0 API Guide, page 56 */ - private static final String TOKEN = "authToken"; - /** Delimiter for data in record format, see Wimba Classroom 6.0 API Guide, page 5 */ - private static final String DELIM = "=END RECORD"; - protected static final String PREFIX = "olat_"; - - // targets for service URLs - protected static String TARGET_OPEN_MANAGEROOM = "cmd.open.manageroom"; - protected static String TARGET_OPEN_POLLRESULTS = "cmd.open.pollresults"; - protected static String TARGET_OPEN_TRACKING = "cmd.open.tracking"; - protected static String TARGET_OPEN_ROOMSETTINGS = "cmd.open.roomsettings"; - protected static String TARGET_OPEN_MEDIASETTINGS = "cmd.open.mediasettings"; - protected static String TARGET_OPEN_WIZARD = "cmd.open.wizard"; - - private static String ENDPOINT_WIZARD = "/wizard/wizard.html.pl?wizardconf=wizard.conf"; - - // configuration - private static WimbaClassroomConfiguration defaultConfig; - private boolean enabled; - private String providerId; - private String displayName; - private String protocol; - private int port; - private String baseUrl; - private String adminLogin; - private String adminPassword; - - // runtime data - private String cookie; - private String token; - - private WimbaClassroomProvider(String providerId, String displayName, String protocol, int port, String baseUrl, String adminLogin, String adminPassword) { - setProviderId(providerId); - setDisplayName(displayName); - setProtocol(protocol); - setPort(port); - setBaseUrl(baseUrl); - setAdminLogin(adminLogin); - setAdminPassword(adminPassword); - } - - /** - * Public constructor, mostly used by spring<br/> - * <b>Important</b> when using: set configuration manually! - */ - public WimbaClassroomProvider() { - // - } - - @Override - public VCProvider newInstance() { - return new WimbaClassroomProvider(providerId, displayName, protocol, port, baseUrl, adminLogin, adminPassword); - } - - @Override - public String getProviderId() { - return providerId; - } - - @Override - public String getDisplayName() { - return displayName; - } - - @Override - public boolean isEnabled() { - return enabled; - } - - @Override - public boolean isProviderAvailable() { - if(!loginAdmin()) return false; - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "statusServer"); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - return success; - } - - @Override - public boolean createClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config) { - if(existsClassroom(roomId, config)) return true; - boolean success = handleClassroomRequest("createClass", roomId, name, description, begin, end, config); - // set preview mode because this setting has no effect on creation - if(success) { - success = setPreviewMode(roomId, false, false); - updateRights(null, roomId, "Student", true, false); - updateGroupRights(null, roomId, "Student", "RegisteredUser", true); - } - return success; - } - - @Override - public boolean updateClassroom(String roomId, String name, String description, Date begin, Date end, VCConfiguration config) { - if(!existsClassroom(roomId, config)) { - logWarn("Tried to update Wimba Classroom meeting, that not exists!", null); - return false; - } - return handleClassroomRequest("modifyClass", roomId, name, description, begin, end, config); - } - - private boolean handleClassroomRequest(String function, String roomId, String name, String description, Date begin, Date end, VCConfiguration config) { - WimbaClassroomConfiguration wc = (WimbaClassroomConfiguration) config; - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", function); - parameters.put("target", PREFIX + roomId); - parameters.put("userlimit", "-1"); - /** name is limited to maximum of 50 characters, see Wimba Classroom 6.0 API Guide, page 15 */ - if(name != null && name.length() > 50) name = name.substring(0, 49); - parameters.put("longname", name); - /** name is limited to maximum of 50 characters, see Wimba Classroom 6.0 API Guide, page 15 */ - if(description != null && description.length() > 50) description = description.substring(0, 49); - parameters.put("can_liveshare", param(wc.isAppshareEnabled())); - parameters.put("can_archive", param(wc.isArchivingEnabled())); - parameters.put("auto_open_new__archives", param(wc.isAutoOpenNewArchives())); - parameters.put("bor_enabled", param(wc.isBreakoutRoomsEnabled())); - parameters.put("can_ppt_import", param(wc.isPowerPointImportEnabled())); - parameters.put("student_wb_enabled", param(wc.isStudentEBoardEnabled())); - parameters.put("hms_two_way_enabled", param(wc.isStudentsSpeakAllowed())); - parameters.put("media_format", "hms"); - parameters.put("media_type", wc.isStudentsVideoAllowed() ? "two-way-video" : "simulcast-only"); - parameters.put("hms_simulcast_restricted", param(!wc.isToolsToStudentsEnabled())); - parameters.put("userstatus_enabled", param(wc.isUserStatusIndicatorsEnabled())); - parameters.put("send_userstatus_updates", param(wc.isUserStatusUpdateInChatEnabled())); - parameters.put("chatenable", param(wc.isStudentsChatAllowed())); - parameters.put("privatechatenable", param(wc.isStudentsPrivateChatAllowed())); - parameters.put("archive", param(false)); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - - boolean success = evaluateOk(response); - if(!success) handleError(response.getStatus(), null); - - if(wc.isGuestAccessAllowed()) { - updateRights(null, roomId, "Student", true, false); - } else if(function.equals("modifyClass")) { - // only delete guest access if this is an already existing meeting - updateRights(null, roomId, "Student", true, true); - } - - return success; - } - - @Override - public boolean removeClassroom(String roomId, VCConfiguration config) { - if(!existsClassroom(roomId, config)) return true; - - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - // first delete recordings - Map<String, String> mapRecordings = listRecordings(roomId); - for(String key : mapRecordings.keySet()) { - removeClassroomRecording(key); - } - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "deleteClass"); - parameters.put("target", PREFIX + roomId); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - - boolean success = evaluateOk(response); - if(!success) handleError(response.getStatus(), null); - - return success; - } - - @Override - public URL createClassroomUrl(String roomId, Identity identity, VCConfiguration config) { - URL url = null; - URI uri = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port) - .path("check_wizard.pl").queryParam("channel", PREFIX + roomId).queryParam("hzA", token).build(); - try { - url = uri.toURL(); - } catch (MalformedURLException e) { - logWarn("Cannot create access URL to Wimba Classroom meeting for id \"" + PREFIX + roomId + "\" and user \"" + identity.getKey() + "\" ("+identity.getKey()+")", e); - } - - return url; - } - - @Override - public URL createClassroomGuestUrl(String roomId, Identity identity, VCConfiguration config) { - URL url = null; - URI uri = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port) - .path("launcher.cgi").queryParam("room",PREFIX + roomId).build(); - try { - url = uri.toURL(); - } catch (MalformedURLException e) { - logWarn("Cannot create guest access URL to Wimba Classroom meeting for id \"" + PREFIX + roomId, e); - } - - return url; - } - - @Override - public boolean existsClassroom(String roomId, VCConfiguration config) { - if(!loginAdmin()) return false; - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "listClass"); - parameters.put("filter00", "class_id"); - parameters.put("filter00value", PREFIX + roomId); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - - boolean success = evaluateOk(response); - if(success) success = response.hasRecords() && response.numRecords() == 1; - - return success; - } - - @Override - public boolean login(Identity identity, String password) { - if(!loginAdmin()) return false; - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "getAuthToken"); - parameters.put("target", PREFIX + identity.getKey()); - parameters.put("nickname", identity.getUser().getProperty(UserConstants.FIRSTNAME, null).replaceAll("\\W", "_")+"_"+identity.getUser().getProperty(UserConstants.LASTNAME, null).replaceAll("\\W", "_")); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - if(success & response.hasRecords()) { - String responseToken = response.findRecord(TOKEN); - if(responseToken != null) { - token = responseToken; - } else { - success = false; - } - } - - return success; - } - - private boolean loginAdmin() { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "NoOp"); - parameters.put("AuthType", "AuthCookieHandler"); - parameters.put("AuthName", "Horizon"); - parameters.put("credential_0", adminLogin); - parameters.put("credential_1", adminPassword); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - if(!success) { - logError("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity", null); - } - - return success; - } - - @Override - public boolean createModerator(Identity identity, String roomId) { - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - boolean success = false; - boolean exists = existsLogin(identity); - - // create login if necessary - if(!exists) success = createLogin(identity); - // update access rights - if(exists | success) success = updateRights(identity, roomId, "Instructor", false, false); - - return success; - } - - @Override - public boolean createUser(Identity identity, String roomId) { - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - boolean success = false; - boolean exists = existsLogin(identity); - - // create login if necessary - if(!exists) success = createLogin(identity); - // update access rights - if(exists | success) success = updateRights(identity, roomId, "Student", false, false); - - return success; - } - - /** - * - * @param identity - * @param roomId - * @param role - * @param isGuest - * @param delete - * @return - */ - private boolean updateRights(Identity identity, String roomId, String role, boolean isGuest, boolean delete) { - if (identity==null && !isGuest) return false; - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", delete ? "deleteRole" : "createRole"); - parameters.put("target", PREFIX + roomId); - parameters.put("user_id", isGuest ? "Guest" : PREFIX + identity.getKey()); - parameters.put("role_id", role); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - return success; - } - - /** - * - * @param identity - * @param roomId - * @param role - * @param group_id - * @param delete - * @return - */ - private boolean updateGroupRights(Identity identity, String roomId, String role, String group_id, boolean delete) { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", delete ? "deleteRole" : "createRole"); - parameters.put("target", PREFIX + roomId); - parameters.put("group_id", group_id); - parameters.put("role_id", role); - if (identity != null) - parameters.put("user_id", PREFIX + identity.getKey()); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - return success; - } - - private boolean createLogin(Identity identity) { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "createUser"); - parameters.put("target", PREFIX + identity.getKey()); - parameters.put("password_type", "P");// specified password, see Wimba Classroom 6.0 API Guide, page 8 - parameters.put("password", Encoder.md5hash(identity.getName() + "@" + Settings.getApplicationName())); - parameters.put("first_name", identity.getUser().getProperty(UserConstants.FIRSTNAME, null)); - parameters.put("last_name", identity.getUser().getProperty(UserConstants.LASTNAME, null)); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - return success; - } - - private boolean existsLogin(Identity identity) { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "listUser"); - parameters.put("attribute", "user_id"); - parameters.put("filter01", "user_id"); - parameters.put("filter01value", PREFIX + identity.getKey()); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - boolean exists = false; - if(success) exists = response.numRecords() == 1; - - return exists; - } - - @Override - public boolean createGuest(Identity identity, String roomId) { - throw new NotImplementedException("method createGuest not yet implemented"); - } - - @Override - public Controller createDisplayController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, - boolean isModerator, boolean readOnly, VCConfiguration config) { - WimbaDisplayController displayCtr = new WimbaDisplayController(ureq, wControl, roomId, name, description, isModerator, (WimbaClassroomConfiguration) config, this); - return displayCtr; - } - - @Override - public Controller createConfigController(UserRequest ureq, WindowControl wControl, String roomId, VCConfiguration config) { - WimbaConfigController configCtr = new WimbaConfigController(ureq, wControl, roomId, this, (WimbaClassroomConfiguration) config); - return configCtr; - } - - public boolean isPreviewMode(String roomId, boolean isRecording) { - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - boolean mode = false; - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "listClass"); - parameters.put("attribute", "preview"); - parameters.put("filter00", "class_id"); - parameters.put("filter00value", isRecording ? roomId : PREFIX + roomId); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - if(success & response.hasRecords()) { - String modeStr = response.getRecords().get(0).get("preview"); - if(modeStr == null || modeStr.equals("0")) mode = false; - else if(modeStr.equals("1")) mode = true; - } - - return mode; - } - - public boolean setPreviewMode(String roomId, boolean enabled, boolean isRecording) { - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "modifyClass"); - parameters.put("target", isRecording ? roomId : PREFIX + roomId); - parameters.put("preview", param(enabled)); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - - boolean success = evaluateOk(response); - if(!success) handleError(response.getStatus(), null); - - return success; - } - - /** - * - * @param roomId - * @return map with recordingId and name - */ - public Map<String, String> listRecordings(String roomId) { - Map<String, String> mapKeyName = new HashMap<String, String>(); - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "listClass"); - parameters.put("attribute", "longname"); - parameters.put("filter00", "archive_of"); - parameters.put("filter00value", PREFIX + roomId); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - boolean success = evaluateOk(response); - - if(success & response.hasRecords()) { - List<Map<String, String>> records = response.getRecords(); - for(Map<String, String> record : records) { - mapKeyName.put(record.get("class_id"), record.get("longname")); - } - } - - return mapKeyName; - } - - public URL createClassroomRecordingUrl(String recordingId, Identity identity) { - URL url = null; - /* Notice: This is a very special and wimba specific case, the recordingId must not prefixed! */ - URI uri = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port) - .path("check_wizard.pl").queryParam("channel", recordingId).queryParam("hzA", token).build(); - try { - url = uri.toURL(); - } catch (MalformedURLException e) { - logWarn("Cannot create access URL to Wimba Classroom meeting for id \"" + recordingId + "\" and user \"" + identity.getKey() + "\" ("+identity.getKey()+")", e); - } - - return url; - } - - public boolean removeClassroomRecording(String recordingId) { - if(!loginAdmin()) throw new AssertException("Cannot login to Wimba Classroom. Please check module configuration and Wimba Classroom connectivity"); - - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("function", "deleteClass"); - parameters.put("target", recordingId); - String raw = sendRequest(parameters); - WimbaResponse response = getResponseDocument(raw); - - boolean success = evaluateOk(response); - if(!success) handleError(response.getStatus(), null); - - return success; - } - - @Override - public VCConfiguration createNewConfiguration() { - // do a deep copy - Object deepCopy = null; - try { - ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); - ObjectOutputStream objectOutput; - objectOutput = new ObjectOutputStream(byteOutput); - objectOutput.writeObject(defaultConfig); - ByteArrayInputStream byteInput = new ByteArrayInputStream(byteOutput.toByteArray()); - ObjectInputStream objectInput = new ObjectInputStream(byteInput); - deepCopy = objectInput.readObject(); - } catch (Exception e) { - logError("Creation of default Wimba Classroom configuration failed.", e); - } - WimbaClassroomConfiguration newConfig = (WimbaClassroomConfiguration) deepCopy; - - return newConfig; - } - - /** - * Creates Wimba Classroom specific direct access URLs for several services - * @param target - * @param roomId - * @return - */ - protected String createServiceUrl(String target, String roomId) { - StringBuilder sb = new StringBuilder(); - sb.append(getProtocol()).append("://").append(getBaseUrl()).append(":").append(getPort()); - String classId = PREFIX + roomId; - String hzA = "&hzA=" + token; - if(target.equals(TARGET_OPEN_WIZARD)) { - sb.append(ENDPOINT_WIZARD); - } else if(target.equals(TARGET_OPEN_MANAGEROOM)) { - sb.append("/admin/api/class/carousels?class_id="); - sb.append(classId); - sb.append(hzA); - } else if(target.equals(TARGET_OPEN_POLLRESULTS)) { - sb.append("/admin/api/class/results?class_id="); - sb.append(classId); - sb.append(hzA); - } else if(target.equals(TARGET_OPEN_TRACKING)) { - sb.append("/admin/api/server/tracking?mode=detailed&popup=1&channel="); - sb.append(classId); - sb.append(hzA); - } else if(target.equals(TARGET_OPEN_ROOMSETTINGS)) { - sb.append("/admin/api/class/properties.pl?class_id="); - sb.append(classId); - sb.append(hzA); - } else if(target.equals(TARGET_OPEN_MEDIASETTINGS)) { - sb.append("/admin/api/class/media.pl?class_id="); - sb.append(classId); - sb.append(hzA); - } - sb.append("&no_sidebar=1"); - - return sb.toString(); - } - - ///////////////////////////// - // internal helper methods // - ///////////////////////////// - - private boolean evaluateOk(WimbaResponse response) { - return response.getStatus().equals(StatusCode.OK); - } - - private WimbaResponse getResponseDocument(String rawResponse) { - StringReader input = new StringReader(rawResponse); - LineNumberReader reader = new LineNumberReader(input); - - WimbaResponse response = new WimbaResponse(); - String line; - Map<String, String> record = new HashMap<String, String>(); - try { - // start with status code in first line - line = reader.readLine(); - response.setStatus(getStatusCode(line)); - // read the records following - while( (line=reader.readLine()) != null ) { - if(line.equals(DELIM)) { - // end of record - response.addRecord(record); - record = new HashMap<String, String>(); - } else { - // regular part of a record - String[] elem = line.split("=", 2); - record.put(elem[0], elem[1]); - } - } - } catch (IOException e) { - logError("The Wimba Classroom response could not parsed. Raw response: " + rawResponse, e); - } - - return response; - } - - /** - * @param line - */ - private int getStatusCode(String line) { - int code = StatusCode.UNDEFINED.getCode(); - if(line != null) { - String extracted = line.split(" ", 2)[0]; - if(extracted != null && !extracted.isEmpty()) { - try { - code = Integer.parseInt(extracted); - } catch(NumberFormatException e) { - // nothing to do since code is pre-set - } - } - } - return code; - } - - private String sendRequest(Map<String, String> parameters) { - URL url = createRequestUrl(parameters); - HttpURLConnection urlConn; - - try { - urlConn = (HttpURLConnection) url.openConnection(); - // setup url connection - urlConn.setDoOutput(true); - urlConn.setUseCaches(false); - urlConn.setInstanceFollowRedirects(false); - // add content type - urlConn.setRequestProperty("Content-Type", CONTENT_TYPE); - // add cookie information - if(cookie != null) urlConn.setRequestProperty("Cookie", cookie); - - // send request - urlConn.connect(); - - // detect redirect - int code = urlConn.getResponseCode(); - boolean moved = code == HttpURLConnection.HTTP_MOVED_PERM | code == HttpURLConnection.HTTP_MOVED_TEMP; - if(moved) { - String location = urlConn.getHeaderField("Location"); - List<String> headerVals = urlConn.getHeaderFields().get("Set-Cookie"); - for(String val : headerVals) { - if(val.startsWith(COOKIE)) cookie = val; - } - url = createRedirectUrl(location); - urlConn = (HttpURLConnection) url.openConnection(); - urlConn.setRequestProperty("Cookie", cookie); - } - - // read response - BufferedReader input = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); - StringBuilder response= new StringBuilder(); - String line; - while( (line = input.readLine()) != null ) response.append(line).append("\n"); - input.close(); - - if(isLogDebugEnabled()) logDebug("Response: " + response); - - return response.toString(); - } catch (IOException e) { - logError("Sending request to Wimba Classroom failed. Request: " + url.toString(), e); - return ""; - } - } - - private URL createRedirectUrl(String location) { - UriBuilder ubu = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port).path(location); - - URL url = null; - try { - url = ubu.build().toURL(); - } catch (Exception e) { - logWarn("Error while creating redirect URL for Wimba Classroom request.", e); - // try to build the URL in a naiv way below - } - if(url == null) { - // error case, try the naiv way - try { - String urlString = new String(protocol + "://" + baseUrl + ":" + port + location); - url = new URL(urlString); - } catch (MalformedURLException e) { - logError("Error while creating URL for Wimba Classroom request. Please check the configuration!", e); - } - } - - if(isLogDebugEnabled()) logDebug("Redirect: " + url); - - return url; - } - - private URL createRequestUrl(Map<String, String> parameters) { - UriBuilder ubu = UriBuilder.fromUri(protocol + "://" + baseUrl).port(port).path("admin").path("api").path("api.pl"); - - for(String key : parameters.keySet()) { - ubu.queryParam(key, parameters.get(key)); - } - - URL url = null; - try { - url = ubu.build().toURL(); - } catch (Exception e) { - logWarn("Error while creating URL for Wimba Classroom request.", e); - // try to build the URL in a naiv way below - } - if(url == null) { - // error case, try the naiv way - try { - StringBuilder sb = new StringBuilder(protocol + "://" + baseUrl + ":" + port + "/admin/api/api.pl"); - if(!parameters.isEmpty()) sb.append("?"); - for(String key : parameters.keySet()) { - sb.append(key + "=" + parameters.get(key) + "&"); - } - sb.replace(sb.length(), sb.length(), ""); - url = new URL(sb.toString()); - } catch (MalformedURLException e) { - logError("Error while creating URL for Wimba Classroom request. Please check the configuration!", e); - } - } - - if(isLogDebugEnabled()) logDebug("Request: " + url); - - return url; - } - - private void handleError(StatusCode status, Throwable cause) { - logError("Request to Wimba Classroom returned error: " + status.getCode() + " (" + status.name() + ")", cause); - } - - private String param(boolean bool) { - return bool ? "1" : "0"; - } - - @Override - public Map<String, String> getTemplates() { - // no support for templating meetings - return Collections.emptyMap(); - } - - //////////////////////////// - // setters used by spring // - //////////////////////////// - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void setProviderId(String providerId) { - this.providerId = providerId; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public void setPort(int port) { - this.port = port; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public void setAdminLogin(String adminLogin) { - this.adminLogin = adminLogin; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - public void setDefaultConfig(WimbaClassroomConfiguration config) { - defaultConfig = config; - defaultConfig.setProviderId(providerId); - } - - ///////////////////////////// - // getters used internally // - ///////////////////////////// - - protected String getProtocol() { - return protocol; - } - - protected int getPort() { - return port; - } - - protected String getBaseUrl() { - return baseUrl; - } - - protected String getAdminLogin() { - return adminLogin; - } - - protected String getAdminPassword() { - return adminPassword; - } - - public WimbaClassroomConfiguration getDefaultConfig() { - return defaultConfig; - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaConfigController.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaConfigController.java deleted file mode 100644 index 11cf80a473a..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaConfigController.java +++ /dev/null @@ -1,120 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -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.velocity.VelocityContainer; -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.gui.media.RedirectMediaResource; - -/** - * - * Description:<br> - * Config controller to adjust settings of Wimba Classroom, e.g. for usage in course editor - * - * <P> - * Initial Date: 06.01.2011 <br> - * @author skoeber - */ -public class WimbaConfigController extends BasicController { - - private static String COMMAND_OPEN_ROOMSETTINGS = WimbaClassroomProvider.TARGET_OPEN_ROOMSETTINGS; - private static String COMMAND_OPEN_MEDIASETTINGS = WimbaClassroomProvider.TARGET_OPEN_MEDIASETTINGS; - - // GUI - private VelocityContainer editVC; - private WimbaEditForm editForm; - private Link openRoomSettings, openMediaSettings; - - private WimbaClassroomProvider wimba; - private WimbaClassroomConfiguration config; - private String roomId; - - protected WimbaConfigController(UserRequest ureq, WindowControl wControl, String roomId, WimbaClassroomProvider wimba, WimbaClassroomConfiguration config) { - super(ureq, wControl); - this.wimba = wimba; - this.config = config; - this.roomId = roomId; - - editVC = createVelocityContainer("edit"); - editForm = new WimbaEditForm(ureq, wControl, config); - listenTo(editForm); - editVC.put("editForm", editForm.getInitialComponent()); - - openRoomSettings = LinkFactory.createButton(COMMAND_OPEN_ROOMSETTINGS, editVC, this); - openMediaSettings = LinkFactory.createButton(COMMAND_OPEN_MEDIASETTINGS, editVC, this); - openRoomSettings.setTarget("_blank"); - openMediaSettings.setTarget("_blank"); - - putInitialPanel(editVC); - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if(source == editForm) { - fireEvent(ureq, event); - } - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - if(source == openRoomSettings | source == openMediaSettings) { - boolean exists = wimba.existsClassroom(roomId, config); - if(exists) { - openWimbaUrl(ureq, ((Link)source).getCommand()); - } else { - // normally this case should not occure, but be failsafe and show msg - getWindowControl().setError("error.no.room"); - } - return; - } - } - - private void openWimbaUrl(UserRequest ureq, String target) { - boolean success = wimba.createModerator(ureq.getIdentity(), roomId); - if(success) { - wimba.login(ureq.getIdentity(), null); - String url = wimba.createServiceUrl(target, roomId); - RedirectMediaResource rmr = new RedirectMediaResource(url); - ureq.getDispatchResult().setResultingMediaResource(rmr); - } else { - // could not create moderator or update the rights - getWindowControl().setError(translate("error.update.rights")); - return; - } - } - - @Override - protected void doDispose() { - if(editForm != null) { - removeAsListenerAndDispose(editForm); - editForm = null; - } - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaDisplayController.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaDisplayController.java deleted file mode 100644 index ce302b3a990..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaDisplayController.java +++ /dev/null @@ -1,402 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -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.table.DefaultColumnDescriptor; -import org.olat.core.gui.components.table.StaticColumnDescriptor; -import org.olat.core.gui.components.table.TableController; -import org.olat.core.gui.components.table.TableDataModel; -import org.olat.core.gui.components.table.TableEvent; -import org.olat.core.gui.components.table.TableGuiConfiguration; -import org.olat.core.gui.components.velocity.VelocityContainer; -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.gui.media.RedirectMediaResource; -import org.olat.core.gui.translator.Translator; - -/** - * - * Description:<br> - * Display controller for Wimba Classroom usage at run-time - * - * <P> - * Initial Date: 06.01.2011 <br> - * @author skoeber - */ -public class WimbaDisplayController extends BasicController { - - private static String COMMAND_JOIN_MODERATOR = "cmd.join.moderator"; - private static String COMMAND_JOIN_LEARNER = "cmd.join.learner"; - private static String COMMAND_JOIN_GUEST = "cmd.join.guest"; - private static String COMMAND_START_MEETING = "cmd.start.meeting"; - private static String COMMAND_CLOSE_MEETING = "cmd.close.meeting"; - private static String COMMAND_UNCLOSE_MEETING = "cmd.unclose.meeting"; - private static String COMMAND_UPDATE_MEETING = "cmd.update.meeting"; - private static String COMMAND_OPEN_MANAGEROOM = WimbaClassroomProvider.TARGET_OPEN_MANAGEROOM; - private static String COMMAND_OPEN_POLLRESULTS = WimbaClassroomProvider.TARGET_OPEN_POLLRESULTS; - private static String COMMAND_OPEN_TRACKING = WimbaClassroomProvider.TARGET_OPEN_TRACKING; - private static String COMMAND_OPEN_WIZARD = WimbaClassroomProvider.TARGET_OPEN_WIZARD; - private static String COMMAND_OPEN_RECORDING = "cmd.open.recording"; - private static String COMMAND_TOGGLESTATUS_RECORDING = "cmd.togglestatus.recording"; - private static String COMMAND_DELETE_RECORDING = "cmd.delete.recording"; - - // GUI - private VelocityContainer runVC; - private Link joinModerator, joinLearner, joinGuest; - private Link startMeeting, closeMeeting, uncloseMeeting, updateMeeting; - private Link openWizard, openManageRoom, openPollResults, openTracking; - private TableController recTable; - - //data - private WimbaClassroomConfiguration config; - private String name, description; - private String roomId; - private RecordingsTableModel recTableModel; - - private WimbaClassroomProvider wimba; - - protected WimbaDisplayController(UserRequest ureq, WindowControl wControl, String roomId, String name, String description, boolean isModerator, - WimbaClassroomConfiguration config, WimbaClassroomProvider provider) { - super(ureq, wControl); - this.wimba = provider; - this.config = config; - this.roomId = roomId; - this.name = name; - this.description = description; - - runVC = createVelocityContainer("run"); - - boolean exists = wimba.existsClassroom(roomId, config); - boolean closed = exists ? wimba.isPreviewMode(roomId, false) : false; - boolean isGuest = ureq.getUserSession().getRoles().isGuestOnly(); - boolean showGuestLink = config.isGuestAccessAllowed(); - - if(isModerator) { - wimba.createModerator(ureq.getIdentity(), roomId); - } else if(!isGuest) { - wimba.createUser(ureq.getIdentity(), roomId); - } - - String guestLink = wimba.createClassroomGuestUrl(roomId, ureq.getIdentity(), config).toString(); - - joinModerator = LinkFactory.createButton(COMMAND_JOIN_MODERATOR, runVC, this); - joinLearner = LinkFactory.createButton(COMMAND_JOIN_LEARNER, runVC, this); - joinGuest = LinkFactory.createButton(COMMAND_JOIN_GUEST, runVC, this); - startMeeting = LinkFactory.createButton(COMMAND_START_MEETING, runVC, this); - closeMeeting = LinkFactory.createButton(COMMAND_CLOSE_MEETING, runVC, this); - uncloseMeeting = LinkFactory.createButton(COMMAND_UNCLOSE_MEETING, runVC, this); - updateMeeting = LinkFactory.createButton(COMMAND_UPDATE_MEETING, runVC, this); - // set target to be able to open new browser window on event - joinGuest.setTarget("_blank"); - joinLearner.setTarget("_blank"); - joinModerator.setTarget("_blank"); - - joinLearner.setEnabled(!closed); - joinGuest.setEnabled(!closed); - - runVC.contextPut("exists", exists); - runVC.contextPut("closed", closed); - runVC.contextPut("isGuest", isGuest); - runVC.contextPut("isModerator", isModerator); - runVC.contextPut("showGuestLink", showGuestLink); - runVC.contextPut("guestLink", guestLink); - - // convenience links - openWizard = LinkFactory.createButton(COMMAND_OPEN_WIZARD, runVC, this); - openWizard.setTarget("_blank"); - - // moderator links - if(isModerator) { - openManageRoom = LinkFactory.createButton(COMMAND_OPEN_MANAGEROOM, runVC, this); - openPollResults = LinkFactory.createButton(COMMAND_OPEN_POLLRESULTS, runVC, this); - openTracking = LinkFactory.createButton(COMMAND_OPEN_TRACKING, runVC, this); - openManageRoom.setTarget("_blank"); - openPollResults.setTarget("_blank"); - openTracking.setTarget("_blank"); - } - - // show recordings - TableGuiConfiguration tableConfig = new TableGuiConfiguration(); - tableConfig.setDisplayRowCount(true); - tableConfig.setPageingEnabled(true); - tableConfig.setTableEmptyMessage(translate("table.recordings.empty")); - recTable = new TableController(tableConfig, ureq, wControl, getTranslator()); - DefaultColumnDescriptor recCol = new DefaultColumnDescriptor("table.recordings.name", 1, COMMAND_OPEN_RECORDING, getLocale()); - recCol.setIsPopUpWindowAction(true, null); - recTable.addColumnDescriptor(recCol); - if(isModerator) { - recTable.addColumnDescriptor(new DefaultColumnDescriptor("table.recordings.status", 2, COMMAND_TOGGLESTATUS_RECORDING, getLocale())); - recTable.addColumnDescriptor(new StaticColumnDescriptor(COMMAND_DELETE_RECORDING, "table.recordings.action", translate("table.recordings.delete"))); - } - Map<String, String> recordings = wimba.listRecordings(roomId); - List<String> keys = new ArrayList<String>(recordings.keySet()); - Collections.sort(keys); - List<Object[]> recordingData = new ArrayList<Object[]>(); - for(String key : keys) { - String title = recordings.get(key); - boolean preview = wimba.isPreviewMode(key, true); - /* - * for moderators: add all recordings and show actions - * for users: add only recordings that are not in preview mode - */ - if(!preview | isModerator) recordingData.add(new Object[] {key, title, preview}); - } - recTableModel = new RecordingsTableModel(recordingData, getTranslator()); - recTable.setTableDataModel(recTableModel); - listenTo(recTable); - runVC.put("recordingsTable", recTable.getInitialComponent()); - - putInitialPanel(runVC); - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - if(source == startMeeting) { - boolean success = wimba.createClassroom(roomId, name, description, null, null, config); - if(success) { - runVC.contextPut("exists", true); - runVC.setDirty(true); - } else { - getWindowControl().setError(translate("error.create.room")); - } - } else if(source == joinModerator) { - boolean success = wimba.existsClassroom(roomId, config); - // update rights for user to moderate meeting - if(success) { - success = wimba.createModerator(ureq.getIdentity(), roomId); - } else { - // room not found, should not appear - getWindowControl().setError(translate("error.no.room")); - return; - } - // login the user as moderator - if(success) { - success = wimba.login(ureq.getIdentity(), null); - } else { - // could not create moderator or update the rights - getWindowControl().setError(translate("error.update.rights")); - return; - } - // redirect to the meeting - if(success) { - joinMeeting(ureq, false); - } else { - // login failed - getWindowControl().setError(translate("error.no.login")); - return; - } - return; - } else if(source == joinLearner) { - joinMeeting(ureq, false); - return; - } else if(source == joinGuest) { - joinMeeting(ureq, true); - return; - } else if(source == closeMeeting) { - boolean success = wimba.setPreviewMode(roomId, true, false); - if(success) { - runVC.contextPut("closed", true); - runVC.setDirty(true); - } else { - // closing failed - getWindowControl().setError(translate("error.remove.room")); - } - } else if(source == uncloseMeeting) { - boolean success = wimba.setPreviewMode(roomId, false, false); - if(success) { - runVC.contextPut("closed", false); - runVC.setDirty(true); - } else { - // reopen failed - getWindowControl().setError(translate("error.update.room")); - } - } else if(source == updateMeeting) { - boolean success = wimba.updateClassroom(roomId, name, description, null, null, config); - if(success) { - getWindowControl().setInfo(translate("success.update.room")); - } else { - // update failed - getWindowControl().setError(translate("error.update.room")); - } - } else if(source == openWizard | source == openManageRoom | source == openPollResults | source == openTracking) { - openWimbaUrl(ureq, ((Link)source).getCommand()); - return; - } - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if(source == recTable) { - if(event instanceof TableEvent) { - TableEvent tEvent = (TableEvent)event; - String action = tEvent.getActionId(); - int row = tEvent.getRowId(); - String key = (String) recTable.getTableDataModel().getValueAt(row, 0); - if(action.equals(COMMAND_OPEN_RECORDING)) { - wimba.login(ureq.getIdentity(), null); - URL url = wimba.createClassroomRecordingUrl(key, ureq.getIdentity()); - RedirectMediaResource rmr = new RedirectMediaResource(url.toString()); - ureq.getDispatchResult().setResultingMediaResource(rmr); - return; - } else if(action.equals(COMMAND_TOGGLESTATUS_RECORDING)) { - Object[] entry = (Object[]) recTable.getTableDataModel().getObject(row); - Boolean preview = (Boolean) entry[2]; - if(wimba.setPreviewMode(key, !preview, true)) { - String text = preview ? "table.recordings.unclose.success" : "table.recordings.close.success"; - getWindowControl().setInfo(translate(text)); - recTableModel.toggleStatus(row); - recTable.modelChanged(); - runVC.setDirty(true); - } else { - String text = preview ? "table.recordings.unclose.error" : "table.recordings.close.error"; - getWindowControl().setError(translate(text)); - } - } else if(action.equals(COMMAND_DELETE_RECORDING)) { - if(wimba.removeClassroomRecording(key)) { - getWindowControl().setInfo(translate("table.recordings.delete.success")); - recTableModel.removeRecording(row); - recTable.modelChanged(); - runVC.setDirty(true); - } else { - getWindowControl().setError(translate("table.recordings.delete.error")); - } - } - } - } - } - - private void openWimbaUrl(UserRequest ureq, String target) { - boolean success = false; - if (target.equals(COMMAND_OPEN_WIZARD)) { - String url = wimba.createServiceUrl(target, null); - RedirectMediaResource rmr = new RedirectMediaResource(url); - ureq.getDispatchResult().setResultingMediaResource(rmr); - } - else { - success = wimba.createModerator(ureq.getIdentity(), roomId); - if(success) { - wimba.login(ureq.getIdentity(), null); - String url = wimba.createServiceUrl(target, roomId); - RedirectMediaResource rmr = new RedirectMediaResource(url); - ureq.getDispatchResult().setResultingMediaResource(rmr); - } else { - // could not create moderator or update the rights - getWindowControl().setError(translate("error.update.rights")); - return; - } - } - } - - private void joinMeeting(UserRequest ureq, boolean guest) { - URL url; - if(guest) { - url = wimba.createClassroomGuestUrl(roomId, ureq.getIdentity(), config); - } else { - boolean success = wimba.login(ureq.getIdentity(), null); - // no success, maybe the user account doesn't exist, create it and try the login again - if(!success) wimba.createUser(ureq.getIdentity(), roomId); - wimba.login(ureq.getIdentity(), null); - url = wimba.createClassroomUrl(roomId, ureq.getIdentity(), config); - } - RedirectMediaResource rmr = new RedirectMediaResource(url.toString()); - ureq.getDispatchResult().setResultingMediaResource(rmr); - } - - @Override - protected void doDispose() { - // nothing to dispose - } - -} - -class RecordingsTableModel implements TableDataModel<Object[]> { - - private List<Object[]> recordings = new ArrayList<Object[]>(); - private Translator translator; - - public RecordingsTableModel(List<Object[]> recordings, Translator translator) { - this.recordings.addAll(recordings); - this.translator = translator; - } - - @Override - public int getColumnCount() { - return 2; - } - - @Override - public int getRowCount() { - return recordings.size(); - } - - @Override - public Object getValueAt(int row, int col) { - Object[] recording = this.recordings.get(row); - switch(col) { - case 0: return recording[col];//key - case 1: return recording[col];//title - case 2: //action string depending on status - Boolean preview = (Boolean) recording[col]; - return preview - ? translator.translate("table.recordings.unclose") - : translator.translate("table.recordings.close"); - default: return recording[col]; - } - } - - @Override - public Object[] getObject(int row) { - return recordings.get(row); - } - - @Override - public void setObjects(List<Object[]> objects) { - this.recordings = objects; - } - - @Override - public Object createCopyWithEmptyList() { - // not used - return ""; - } - - public void removeRecording(int row) { - this.recordings.remove(row); - } - - public void toggleStatus(int row) { - Boolean status = (Boolean) this.recordings.get(row)[2]; - this.recordings.get(row)[2] = !status; - } -} -//</OLATCE-103> diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaEditForm.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaEditForm.java deleted file mode 100644 index 31c89f17738..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaEditForm.java +++ /dev/null @@ -1,85 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; -import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.WindowControl; -import org.olat.course.editor.NodeEditController; - -/** - * - * Description:<br> - * Edit form for date list and Wimba Classroom specific configuration - * - * <P> - * Initial Date: 12.01.2011 <br> - * @author skoeber - */ -public class WimbaEditForm extends FormBasicController { - - // GUI - private FormSubmit submit; - private MultipleSelectionElement multiSelectOptions; - private static String OPTION_GUEST_ACCESS = "vc.guest.access"; - - // data - private WimbaClassroomConfiguration config; - - public WimbaEditForm(UserRequest ureq, WindowControl wControl, WimbaClassroomConfiguration config) { - super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL); - this.config = config; - - initForm(this.flc, this, ureq); - } - - @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - - // options - String[] optionKeys = new String[] {OPTION_GUEST_ACCESS}; - String[] optionVals = new String[] {translate(OPTION_GUEST_ACCESS)}; - multiSelectOptions = uifactory.addCheckboxesVertical("vc.options", "vc.options.label", formLayout, optionKeys, optionVals, 1); - multiSelectOptions.select(OPTION_GUEST_ACCESS, config.isGuestAccessAllowed()); - multiSelectOptions.showLabel(false); - - submit = new FormSubmit("subm", "submit"); - - formLayout.add(submit); - } - - @Override - protected void formOK(UserRequest ureq) { - config.setGuestAccessAllowed(multiSelectOptions.getSelectedKeys().contains(OPTION_GUEST_ACCESS)); - fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); - } - - @Override - protected void doDispose() { - // nothing to dispose - } - -} -//<OLATCE-103> diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaResponse.java b/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaResponse.java deleted file mode 100644 index 5b8da75fa89..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaResponse.java +++ /dev/null @@ -1,99 +0,0 @@ -//<OLATCE-103> -/** - * <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> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de - * <p> - */ -package de.bps.course.nodes.vc.provider.wimba; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * - * Description:<br> - * Response object for API calls to Wimba Classroom - * - * <P> - * Initial Date: 07.01.2011 <br> - * @author skoeber - */ -public class WimbaResponse { - - private StatusCode status = StatusCode.UNDEFINED; - private List<Map<String, String>> records = new ArrayList<Map<String,String>>(); - - /* - * several constructors for efficiency - */ - - public WimbaResponse() { - // - } - - public WimbaResponse(StatusCode status) { - setStatus(status); - } - - public WimbaResponse(int code) { - setStatus(code); - } - - protected StatusCode getStatus() { - return status; - } - - protected void setStatus(StatusCode status) { - this.status = status; - } - - protected void setStatus(int code) { - this.status = StatusCode.getStatus(code); - } - - protected void addRecord(Map<String, String> record) { - records.add(record); - } - - protected List<Map<String, String>> getRecords() { - return records; - } - - /** - * Will return the first value found, but there may be more than this one - * @param key - * @return value found or <code>null</code> - */ - protected String findRecord(String key) { - String value = null; - for(Map<String, String> record : records) { - value = record.get(key); - } - return value; - } - - protected boolean hasRecords() { - return !records.isEmpty(); - } - - protected int numRecords() { - return records.size(); - } - -} -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/edit.html b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/edit.html deleted file mode 100644 index c3fdd8e9e4a..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/edit.html +++ /dev/null @@ -1,6 +0,0 @@ -<!-- <OLATCE-103> --> -$r.render("cmd.open.roomsettings") -<!-- $r.render("cmd.open.mediasettings") --> - -$r.render("editForm") -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/run.html b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/run.html deleted file mode 100644 index ba58c1040ad..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_content/run.html +++ /dev/null @@ -1,58 +0,0 @@ -<!-- <OLATCE-103> --> -#if($exists) - #if($closed) - <p class="o_warning">$r.translate("meeting.status")</p> - #end - - #if($isModerator) - #if(!$closed) - <p>$r.translate("cmd.join.moderator.intro")</p> - #end - <p> - $r.render("cmd.join.moderator") - </p> - $r.render("recordingsTable") - <div class="o_info"> - <p><strong>$r.translate("title.options")</strong></p> - #if($showGuestLink) - <p>$r.translate("description.guestlink") - <pre>$guestLink</pre></p> - <br/> - #end - #if($closed) - ##<p class="o_warning">$r.translate("meeting.status")</p> - $r.render("cmd.unclose.meeting") - #else - $r.render("cmd.close.meeting") - #end - ##$r.render("cmd.update.meeting") - $r.render("cmd.open.manageroom") - $r.render("cmd.open.pollresults") - ##$r.render("cmd.open.tracking") - </div> - #else - #if($isGuest && $showGuestLink) - $r.render("cmd.join.guest") - #else - #if(!$closed) - <p>$r.translate("cmd.join.learner.intro")</p> - #end - $r.render("cmd.join.learner") - <p> - $r.render("recordingsTable") - </p> - #end - #end -#else - #if($isModerator) - <p>$r.translate("cmd.start.meeting.intro")</p> - $r.render("cmd.start.meeting") - #else - <p>$r.translate("cmd.join.learner.wait")</p> - #end -#end -<div class="o_info"> -<p>$r.translate("cmd.open.wizard.intro")</p> -$r.render("cmd.open.wizard") -</div> -<!-- </OLATCE-103> --> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_de.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_de.properties deleted file mode 100644 index c3739c34fa4..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_de.properties +++ /dev/null @@ -1,49 +0,0 @@ -#Fri Sep 30 15:07:00 CEST 2016 -cmd.close.meeting=Virtuelles Klassenzimmer schlie\u00DFen -cmd.delete.recording=Aufzeichnung l\u00F6schen -cmd.join.guest=Meeting als Gast betreten -cmd.join.learner=Klassenzimmer betreten -cmd.join.learner.intro=Das virtuelle Klassenzimmer kann betreten werden. -cmd.join.learner.wait=Das virtuelle Klassenzimmer wurde noch nicht er\u00F6ffnet. -cmd.join.moderator=Meeting moderieren -cmd.join.moderator.intro=Das virtuelle Klassenzimmer ist ge\u00F6ffnet. Sie k\u00F6nnen das Meeting moderieren. Teilnehmer k\u00F6nnen dem Meeting ohne Zustimmung eines Moderators ggf. nicht beitreten. -cmd.open.manageroom=Rauminhalte verwalten -cmd.open.mediasettings=Medienkonfiguration -cmd.open.pollresults=Umfrageergebnisse einsehen -cmd.open.recording=Aufzeichnung starten -cmd.open.roomsettings=Raumkonfiguration -cmd.open.tracking=Tracking -cmd.open.wizard=Setup-Wizard starten -cmd.open.wizard.intro=Benutzen Sie den Setup Wizard um sicherzustellen, dass ihr Computer f\u00FCr die Benutzung von Wimba Classroom vorbereitet ist. -cmd.start.meeting=Meeting starten -cmd.start.meeting.intro=Das virtuelle Klassenzimmer wurde noch nicht ge\u00F6ffnet. Teilnehmer k\u00F6nnen einem geplanten Meeting je nach Konfiguration ggf. noch nicht beitreten. -cmd.unclose.meeting=Virtuelles Klassenzimmer \u00F6ffnen -cmd.update.meeting=Konfiguration synchronisieren -description.guestlink=Der Gastzugang f\u00FCr dieses Meeting ist erlaubt. Folgender Link erm\u00F6glicht den direkten Zugang zum virtuellen Klassenzimmer als Gast\: -error.close.room=Das virtuelle Klassenzimmer konnte nicht geschlossen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.create.room=Das virtuelle Klassenzimmer konnte nicht erzeugt werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.no.login=Die Anmeldung war nicht erfolgreich. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.no.room=Das virtuelle Klassenzimmer konnte nicht geladen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.remove.room=Das virtuelle Klassenzimmer konnte nicht entfernt werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.update.rights=Ihnen konnten nicht die notwendigen Rechte f\u00FCr dieses Meeting zugewiesen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -error.update.room=Das virtuelle Klassenzimmer konnte nicht mit den aktuellen Einstellungen synchronisiert werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -meeting.status=Das Meeting ist geschlossen und kann momentan nicht von Studenten betreten werden. -success.update.room=Das virtuelle Klassenzimmer wurde erfolgreich mit den aktuellen Einstellungen synchronisiert. -sync.meeting.text=Sie haben die Einstellungen f\u00FCr diese virtuelle Klassenzimmer ge\u00E4ndert, nachdem dieses er\u00F6ffnet wurde. Die \u00C4nderungen werden erst wirksam, wenn Sie das virtuelle Klassenzimmer mit den neuen Einstellungen synchronisieren. Die Einstellungen k\u00F6nnen auch jederzeit direkt im Kurs synchronisiert werden. M\u00F6chten Sie die Einstellungen jetzt synchronisieren? -sync.meeting.title=Virtuelles Klassenzimmer synchronisieren -table.recordings.action=Aktion -table.recordings.close=Aufzeichnung schlie\u00DFen -table.recordings.close.error=Die Aufzeichnung konnte nicht geschlossen werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -table.recordings.close.success=Aufzeichnung erfolgreich geschlossen -table.recordings.delete=Aufzeichnung entfernen -table.recordings.delete.error=Die Aufzeichnung konnte nicht entfernt werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -table.recordings.delete.success=Aufzeichnung erfolgreich entfernt -table.recordings.empty=Es sind keine Aufzeichnungen f\u00FCr dieses virtuelle Klassenzimmer verf\u00FCgbar. -table.recordings.name=Aufzeichnungen -table.recordings.status=Status \u00E4ndern -table.recordings.unclose=Aufzeichnung \u00F6ffnen -table.recordings.unclose.error=Die Aufzeichnung konnte nicht ge\u00F6ffnet werden. Bitte wenden Sie sich an Ihren Betreuer oder Ihre Systemadministratoren. -table.recordings.unclose.success=Aufzeichnung erfolgreich ge\u00F6ffnet -title.options=Erweiterte Optionen f\u00FCr Kursautoren -vc.guest.access=Gastzugang erlauben -vc.options.label=Optionen diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_en.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_en.properties deleted file mode 100644 index 93c37e504a9..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_en.properties +++ /dev/null @@ -1,54 +0,0 @@ -#Tue Jan 15 14:20:36 CET 2013 - - - - - -cmd.close.meeting=Close virtual classroom -cmd.delete.recording=Delete recording -cmd.join.guest=Enter virtual classroom as guest -cmd.join.learner=Enter virtual classroom -cmd.join.learner.intro=You can join the virtual classroom. -cmd.join.learner.wait=The virtual classroom has not been opened, yet. Please contact your tutor for any further information. -cmd.join.moderator=Moderate virtual classroom -cmd.join.moderator.intro=The virtual classroom has been opened. You may now enter the classroom and moderate the meeting. Participants might not be able to join the meeting until they are granted access by a moderator. -cmd.open.manageroom=Manage room content -cmd.open.mediasettings=Media settings -cmd.open.pollresults=View survey results -cmd.open.recording=Start recording -cmd.open.roomsettings=Room settings -cmd.open.tracking=Tracking -cmd.open.wizard=Start setup wizard -cmd.open.wizard.intro=Run the setup wizard to make sure that your computer is able to use the Wimba Classroom. -cmd.start.meeting=Open virtual classroom -cmd.start.meeting.intro=The virtual classroom has not been opened, yet. Participants might not be able to enter the classroom for a meeting. -cmd.unclose.meeting=Reopen virtual classroom -cmd.update.meeting=Synchronize configuration -description.guestlink=Guest access for this meeting is allowed. The following link gives a direct access to the virtual classroom as a guest\: -error.close.room=The virtual class room could not be closed. Please contact your coach or the system administrator. -error.create.room=Sorry\! An error occured while creating the virtual classroom. Please inform your tutor or system administrator. -error.no.login=Login was not successfull. Please, contact your tutor or system administrator for any further questions. -error.no.room=Sorry\! An error occured while loading the virtual classroom. Please inform your tutor or system administrator. -error.remove.room=Sorry\! An error occured while removing the virtual class room. Please inform your tutor or system administrator. -error.update.rights=Sorry\! An error occured while granting access to the virtual classroom. Please inform your tutor or system administrator. -error.update.room=Sorry\! An error occured while synchronizing the virtual class room with the actual configuration. Please inform your tutor or system administrator. -meeting.status=This virtual classroom ist currently closed. Students cannot access this room. -success.update.room=The virtual classroom has been synchronized successfully with its new configuration. -sync.meeting.text=You have changed the configuration of the virtual classroom after it had been started. The changes will be taken into account only after having synchronized the virtual class room with the new configuration. You can synchronize the configuration at any time directly from the course run. Do you want to synchronize now? -sync.meeting.title=Synchronize virtual classroom -table.recordings.action=Action -table.recordings.close=Close recording -table.recordings.close.error=Sorry\! An error occured while removing the recording. Please inform your support or system administrator. -table.recordings.close.success=Closed recording successfully -table.recordings.delete=Remove recording -table.recordings.delete.error=Sorry\! An error occured while removing the recording. Please inform your support or system administrator. -table.recordings.delete.success=Recording removed successfully -table.recordings.empty=There are no recordings available for this virtual classroom. -table.recordings.name=Recordings -table.recordings.status=Change status -table.recordings.unclose=Open recording -table.recordings.unclose.error=Sorry\! An error occured while opening the recording. Please inform your support or system administrator. -table.recordings.unclose.success=Recording opened successfully -title.options=Additional information and options for authors -vc.guest.access=Allow access as guest (anonymously) -vc.options.label=Options diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_fr.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_fr.properties deleted file mode 100644 index 33b8eab2ac6..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_fr.properties +++ /dev/null @@ -1,54 +0,0 @@ -#Tue Oct 23 15:55:09 CEST 2012 - - - - - -cmd.close.meeting=Ferme la classe virtuelle -cmd.delete.recording=Supprimer l'enregistrement -cmd.join.guest=Participer \u00E0 la r\u00E9union en tant qu'invit\u00E9 -cmd.join.learner=Entrez dans la salle de classe -cmd.join.learner.intro=La classe virtuelle est accessible. -cmd.join.learner.wait=La classe virtuelle n'a pas encore \u00E9t\u00E9 ouverte. -cmd.join.moderator=Mod\u00E9rer la r\u00E9union -cmd.join.moderator.intro=La classe virtuelle est ouverte. Vous pouvez mod\u00E9rer la r\u00E9union. Les participants peuvent se joindre \u00E0 la r\u00E9union sans l'approbation d'un mod\u00E9rateur mais celiu-ci pourra s'y opposer. -cmd.open.manageroom=G\u00E9rer le contenu de la classe -cmd.open.mediasettings=Configuration m\u00E9dia -cmd.open.pollresults=Voir les r\u00E9sultats du sondage -cmd.open.recording=D\u00E9marrer l'enregistrement -cmd.open.roomsettings=Configuration de la classe -cmd.open.tracking=Tracking -cmd.open.wizard=D\u00E9marrer l'assistant de configuration -cmd.open.wizard.intro=Utilisez l'assistant de configuration pour vous assurer que votre ordinateur est pr\u00EAt \u00E0 utiliser une classe Wimba. -cmd.start.meeting=D\u00E9marrer la r\u00E9union -cmd.start.meeting.intro=La salle de classe virtuelle n'a pas \u00E9t\u00E9 ouverte. Les participants de la r\u00E9union ne peuvent pas y adh\u00E9rer \u00E0 cause de sa configuration. -cmd.unclose.meeting=Ouvrir la classe virtuelle -cmd.update.meeting=Synchroniser la configuration -description.guestlink=L'acc\u00E8s invit\u00E9 est autoris\u00E9 pour cette r\u00E9union. Le lien suivant fournit un acc\u00E8s direct \u00E0 la classe virtuelle en tant qu'invit\u00E9\: -error.close.room=La classe virtuelle n'a pas pu \u00EAtre ferm\u00E9e. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.create.room=La classe virtuelle n'a pas pu \u00EAtre cr\u00E9\u00E9. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.no.login=L'inscription n'a pas r\u00E9ussi. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.no.room=La classe virtuelle n'a pas pu \u00EAtre charg\u00E9e. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.remove.room=La classe virtuelle n'a pas pu \u00EAtre supprim\u00E9e. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.update.rights=Vous n'avez pas pu recevoir les autorisations n\u00E9cessaires pour cette r\u00E9union. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -error.update.room=La classe virtuelle n'a pas pu \u00EAtre synchronis\u00E9e avec ses param\u00E8tres actuels. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -meeting.status=La r\u00E9union est termin\u00E9e pour l'instant et les participants ne peuvent y acc\u00E9der. -success.update.room=La classe virtuelle a \u00E9t\u00E9 synchronis\u00E9e avec ses param\u00E8tres actuels. -sync.meeting.text=Vous avez modifi\u00E9 les param\u00E8tres de cette classe virtuelle apr\u00E8s son ouverture. Les modifications ne prendront effet qu'apr\u00E8s avoir synchronis\u00E9 la classe virtuelle avec ses nouveaux param\u00E8tres. Les param\u00E8tres peuvent \u00E9galement \u00EAtre synchronis\u00E9s \u00E0 tout moment depuis le cours. Souhaitez-vous synchroniser les nouveaux param\u00E8tres maintenant? -sync.meeting.title=Synchroniser la classe virtuelle -table.recordings.action=Action -table.recordings.close=Fermer l'enregistrement -table.recordings.close.error=L'enregistrement n'a pas pu \u00EAtre ferm\u00E9. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -table.recordings.close.success=Enregistrement ferm\u00E9 avec succ\u00E8s -table.recordings.delete=Supprimer l'enregistrement -table.recordings.delete.error=L'enregistrement n'a pas pu \u00EAtre supprim\u00E9. Veuillez contacter votre superviseur ou votre administrateur syst\u00E8me. -table.recordings.delete.success=Enregistrement supprim\u00E9 avec succ\u00E8s -table.recordings.empty=Il n'y a aucun enregistrement disponible pour cette classe. -table.recordings.name=Enregistrements -table.recordings.status=Changer le status -table.recordings.unclose=Ouvrir l'enregistrement -table.recordings.unclose.error=L'enregistrement n'a pas \u00EAtre ouvert. Veuillez contactez votre superviseur ou votre administrateur syst\u00E8me. -table.recordings.unclose.success=Enregistrement ouvert avec succ\u00E8s -title.options=Options suppl\u00E9mentaires pour les auteurs -vc.guest.access=Permettre l'acc\u00E8s invit\u00E9 -vc.options.label=Options diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_it.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_it.properties deleted file mode 100644 index 1181ffeac9f..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_it.properties +++ /dev/null @@ -1,49 +0,0 @@ -#Tue Feb 07 12:16:36 CET 2017 -cmd.close.meeting=Chiudere l'aula virtuale -cmd.delete.recording=Eliminare la registrazione -cmd.join.guest=Accedere all'aula virtuale come ospite -cmd.join.learner=Accedere all'aula virtuale -cmd.join.learner.intro=Puoi accedere all'aula virtuale. -cmd.join.learner.wait=L'aula virtuale non \u00E8 stata ancora aperta. Si prega di contattare il tutore/docente per qualsiasi informazione. -cmd.join.moderator=Moderare l'aula virtuale -cmd.join.moderator.intro=L'aula virtuale \u00E8 stata aperta. \u00C8 ora possibile accedere nell'aula virtuale e moderare l'incontro. I partecipanti potrebbero non avere diritto di accesso all'aula prima di essere autorizzati da un moderatore. -cmd.open.manageroom=Gestire contenuto della stanza -cmd.open.mediasettings=Impostazioni media -cmd.open.pollresults=Vedere risultati del sondaggio -cmd.open.recording=Inizio registrazione -cmd.open.roomsettings=Impostazioni stanza -cmd.open.tracking=Tracciamento -cmd.open.wizard=Inizio procedura guidata di impostazione -cmd.open.wizard.intro=Avviare la procedura guidata per l'impostazione, per assicurarsi che il computer sia pronto per l'uso di una aula virtuale Wimba. -cmd.start.meeting=Aprire aula virtuale -cmd.start.meeting.intro=L'aula virtuale non \u00E8 stata ancora aperta. I partecipanti non sono ancora abilitati ad accedere all'aula per l'incontro. -cmd.unclose.meeting=Riaprire aula virtuale -cmd.update.meeting=Sincronizzare configurazione -description.guestlink=L'accesso ospite per questo incontro \u00E8 attivo. Il seguente collegamento permette l'accesso diretto all'aula virtuale come ospite\: -error.close.room=L'aula virtuale non pu\u00F2 essere chiusa. Si prega di contattare il tutore/docente o l'amministratore di sistema. -error.create.room=Si \u00E8 verificato un errore durante la creazione dell'aula virtuale. Si prega di informare il tutore/docente o l'amministratore di sistema. -error.no.login=Il login non ha avuto successo. Si prega di contattare il tutore/docente o l'amministratore di sistema per ulteriori informazioni. -error.no.room=Si \u00E8 verificato un errore durante il caricamento dell'aula virtuale. Si prega di informare il tuo tutore/docente o l'amministratore di sistema. -error.remove.room=Si \u00E8 verificato un errore durante la rimozione dell'aula virtuale. Si prega di informare il tutore/docente o l'amministratore di sistema. -error.update.rights=Si \u00E8 verificato un errore durante l'assegnazione dei diritti di accesso all'aula virtuale. SI prega di informare il tutore/docente o l'amministratore di sistema. -error.update.room=Si \u00E8 verificato un errore durante la sincronizzazione dell'aula virtuale con la configurazione corrente. Si prega di informare il tutore/docente o l'amministratore di sistema. -meeting.status=Questa aula virtuale \u00E8 attualmente chiusa. Gli studenti non possono accedere a questa aula. -success.update.room=L'aula virtuale \u00E8 stata sincronizzata con successo con la nuova configurazione. -sync.meeting.text=Sono state modificate le impostazioni dell'aula virtuale dopo che \u00E8 stata aperta. Le modifiche avranno effetto solo dopo la sincronizzazione dell'aula virtuale con la nuova configurazione. \u00C8 possibile sincronizzare la configurazione in qualsiasi momento all'interno del corso. Si desidera effettuare la sincronizzazione adesso? -sync.meeting.title=Sincronizzare l'aula virtuale -table.recordings.action=Azione -table.recordings.close=Chiudere la registrazione -table.recordings.close.error=Si \u00E8 verificato un errore durante la chiusura della registrazione. Si prega di informare il tutore/docente o l'amministratore di sistema. -table.recordings.close.success=La registrazione \u00E8 stata chiusa con successo -table.recordings.delete=Rimuovere la registrazione -table.recordings.delete.error=Si \u00E8 verificato un errore durante la rimozione della registrazione. Si prega di informare il tutore/docente o l'amministratore di sistema. -table.recordings.delete.success=La registrazione \u00E8 stata rimossa con successo -table.recordings.empty=Non ci sono registrazioni disponibili per questa aula virtuale. -table.recordings.name=Registrazioni -table.recordings.status=Cambiare lo stato -table.recordings.unclose=Aprire la registrazione -table.recordings.unclose.error=Si \u00E8 verificato un errore durante l'apertura della registrazione. Si prega di informare il tutore/docente o l'amministratore di sistema. -table.recordings.unclose.success=Registrazione aperta con successo -title.options=Informazioni aggiuntive e opzioni per gli autori -vc.guest.access=Consentire l'accesso ospite (anonimo) -vc.options.label=Opzioni diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pl.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pl.properties deleted file mode 100644 index a910161268c..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pl.properties +++ /dev/null @@ -1,20 +0,0 @@ -#Sun Dec 23 12:54:36 CET 2012 - - -cmd.close.meeting=Zamknij wirtualn\u0105 klas\u0119 -cmd.join.guest=Wejd\u017A jako go\u015B\u0107 -cmd.join.learner=Wejd\u017A do wirtualnej klasy -cmd.join.learner.intro=Mo\u017Cesz wej\u015B\u0107 do wirtualnej klasy. -cmd.join.moderator=Moderuj wirtualn\u0105 klas\u0119 -cmd.open.pollresults=Zobacz wyniki ankiety -cmd.open.roomsettings=Ustawienia pokoju -cmd.start.meeting=Rozpocznij spotkanie -cmd.start.meeting.intro=Wirtualna klasa nie zosta\u0142a jeszcze otwarta. Uczestnicy nie mog\u0105 wej\u015B\u0107 na spotkanie. -cmd.update.meeting=Synchronizuj konfiguracj\u0119 -meeting.status=Wirtualna klasa jest obecnie zamkni\u0119ta. Studenci nie mog\u0105 wej\u015B\u0107 do pokoju. -sync.meeting.title=Synchronizuj wirtualn\u0105 klas\u0119 -table.recordings.action=Akcja -table.recordings.status=Zmie\u0144 status -title.options=Dodatkowe informacje i opcje dla autor\u00F3w -vc.guest.access=Zezw\u00F3l na dost\u0119p jako go\u015B\u0107 -vc.options.label=Opcje diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pt_BR.properties b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pt_BR.properties deleted file mode 100644 index 2b0ad0b3d08..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_i18n/LocalStrings_pt_BR.properties +++ /dev/null @@ -1,49 +0,0 @@ -#Tue Nov 22 18:16:36 CET 2016 -cmd.close.meeting=Fechar sala de aula virtual -cmd.delete.recording=Excluir grava\u00E7\u00E3o -cmd.join.guest=Entre na sala de aula virtual como convidado -cmd.join.learner=Entrar na sala virtual -cmd.join.learner.intro=Voc\u00EA pode participar da sala de aula virtual. -cmd.join.learner.wait=A sala de aula virtual ainda n\u00E3o foi aberta. Entre em contato com o seu tutor para obter mais informa\u00E7\u00F5es. -cmd.join.moderator=Moderar sala de aula virtual -cmd.join.moderator.intro=A sala de aula virtual foi aberta. Agora voc\u00EA pode entrar na sala de aula e moderar a reuni\u00E3o. Os participantes podem n\u00E3o ser capazes de entrar na reuni\u00E3o at\u00E9 que lhes seja concedido o acesso por um moderador. -cmd.open.manageroom=Gerenciar conte\u00FAdo da sala -cmd.open.mediasettings=Configura\u00E7\u00F5es de m\u00EDdia -cmd.open.pollresults=Ver resultados da pesquisa -cmd.open.recording=Iniciar grava\u00E7\u00E3o -cmd.open.roomsettings=Defini\u00E7\u00F5es da sala -cmd.open.tracking=Tracking -cmd.open.wizard=Iniciar o assistente de configura\u00E7\u00E3o -cmd.open.wizard.intro=Execute o assistente de configura\u00E7\u00E3o para se certificar de que seu computador \u00E9 capaz de usar o Wimba Classroom. -cmd.start.meeting=Abrir sala de aula virtual -cmd.start.meeting.intro=A sala de aula virtual ainda n\u00E3o foi aberta. Os participantes podem n\u00E3o ser capazes de entrar na sala de aula para uma reuni\u00E3o. -cmd.unclose.meeting=Reabrir a sala de aula virtual -cmd.update.meeting=Sincronizar a configura\u00E7\u00E3o -description.guestlink=O acesso de convidado para esta reuni\u00E3o \u00E9 permitido. O link a seguir d\u00E1 acesso direto \u00E0 sala de aula virtual como convidado\: -error.close.room=A sala de aula virtual n\u00E3o p\u00F4de ser fechada. Entre em contato com o treinador ou com o administrador do sistema. -error.create.room=Desculpe\! Ocorreu um erro ao criar a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.no.login=O login n\u00E3o foi bem-sucedido. Entre em contato com o seu tutor ou administrador do sistema para qualquer d\u00FAvida. -error.no.room=Desculpe\! Ocorreu um erro ao carregar a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.remove.room=Desculpe\! Ocorreu um erro ao remover a sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.update.rights=Desculpe\! Ocorreu um erro ao conceder acesso \u00E0 sala de aula virtual. Informe o seu tutor ou administrador do sistema. -error.update.room=Desculpe\! Ocorreu um erro ao sincronizar a sala de aula virtual com a configura\u00E7\u00E3o real. Informe o seu tutor ou administrador do sistema. -meeting.status=Esta sala de aula virtual est\u00E1 fechada atualmente. Os alunos n\u00E3o podem acessar esta sala. -success.update.room=A sala de aula virtual foi sincronizada com sucesso com sua nova configura\u00E7\u00E3o. -sync.meeting.text=Voc\u00EA mudou a configura\u00E7\u00E3o da sala de aula virtual depois de ter sido iniciada. As altera\u00E7\u00F5es ser\u00E3o levadas em conta somente depois de ter sincronizado a sala de aula virtual com a nova configura\u00E7\u00E3o. Voc\u00EA pode sincronizar a configura\u00E7\u00E3o a qualquer momento diretamente da execu\u00E7\u00E3o do curso. Deseja sincronizar agora? -sync.meeting.title=Sincronizar sala de aula virtual -table.recordings.action=A\u00E7\u00E3o -table.recordings.close=Encerrar grava\u00E7\u00E3o -table.recordings.close.error=Desculpe\! Ocorreu um erro ao remover a grava\u00E7\u00E3o. Informe o seu suporte ou administrador do sistema. -table.recordings.close.success=Grava\u00E7\u00E3o encerrada com \u00EAxito -table.recordings.delete=Remover grava\u00E7\u00E3o -table.recordings.delete.error=Desculpe\! Ocorreu um erro ao remover a grava\u00E7\u00E3o. Informe o seu suporte ou administrador do sistema. -table.recordings.delete.success=A grava\u00E7\u00E3o foi removida com \u00EAxito -table.recordings.empty=N\u00E3o existem grava\u00E7\u00F5es dispon\u00EDveis para esta sala de aula virtual. -table.recordings.name=Grava\u00E7\u00F5es -table.recordings.status=Mudar status -table.recordings.unclose=Abrir grava\u00E7\u00E3o -table.recordings.unclose.error=Desculpe\! Ocorreu um erro ao abrir a grava\u00E7\u00E3o. Informe o seu suporte ou administrador do sistema. -table.recordings.unclose.success=Grava\u00E7\u00E3o aberta com \u00EAxito -title.options=Informa\u00E7\u00F5es adicionais e op\u00E7\u00F5es para autores -vc.guest.access=Permitir acesso como convidado (anonimamente) -vc.options.label=Op\u00E7\u00F5es diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_spring/wimbaContext.xml b/src/main/java/de/bps/course/nodes/vc/provider/wimba/_spring/wimbaContext.xml deleted file mode 100644 index 621c9d4878a..00000000000 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/_spring/wimbaContext.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - - <bean id="wimbaDefaultConfig" class="de.bps.course.nodes.vc.provider.wimba.WimbaClassroomConfiguration"> - <!-- general --> - <property name="createMeetingImmediately" value="true" /> - <!-- Wimba specific --> - <property name="toolsToStudentsEnabled" value="true" /> - <property name="studentsSpeakAllowed" value="true" /> - <property name="studentsVideoAllowed" value="true" /> - <property name="userStatusIndicatorsEnabled" value="true" /> - <property name="userStatusUpdateInChatEnabled" value="true" /> - <property name="studentEBoardEnabled" value="true" /> - <property name="breakoutRoomsEnabled" value="true" /> - <property name="archivingEnabled" value="true" /> - <property name="autoOpenNewArchives" value="false" /> - <property name="appshareEnabled" value="true" /> - <property name="powerPointImportEnabled" value="true" /> - <property name="guestAccessAllowed" value="false" /> - <property name="regUsersAccessAllowed" value="false" /> - <property name="studentsChatAllowed" value="true" /> - <property name="studentsPrivateChatAllowed" value="true" /> - </bean> - -</beans> \ No newline at end of file diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java index 40a3b9e6f06..b4fb74cc7c5 100644 --- a/src/main/java/org/olat/collaboration/CollaborationTools.java +++ b/src/main/java/org/olat/collaboration/CollaborationTools.java @@ -85,6 +85,8 @@ import org.olat.group.BusinessGroupService; import org.olat.group.ui.run.InfoGroupRunController; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.instantMessaging.ui.ChatToolController; +import org.olat.modules.adobeconnect.ui.AdobeConnectMeetingDefaultConfiguration; +import org.olat.modules.adobeconnect.ui.AdobeConnectRunController; import org.olat.modules.co.ContactFormController; import org.olat.modules.fo.Forum; import org.olat.modules.fo.ForumCallback; @@ -155,6 +157,7 @@ public class CollaborationTools implements Serializable { public static final String KEY_FORUM = "forumKey"; public static final String KEY_PORTFOLIO = "portfolioMapKey"; public static final String KEY_OPENMEETINGS = "openMeetingsKey"; + public static final String KEY_ACONNECTMEETINGS = "adobeConnectKey"; /** * <code>PROP_CAT_BG_COLLABTOOLS</code> identifies properties concerning @@ -199,6 +202,10 @@ public class CollaborationTools implements Serializable { * constant used to identify the open meetings for a group */ public static final String TOOL_OPENMEETINGS = "hasOpenMeetings"; + /** + * constant used to identify the open meetings for a group + */ + public static final String TOOL_ADOBECONNECT = "hasAdobeConnect"; /** * Only owners have write access to the calendar. @@ -610,6 +617,11 @@ public class CollaborationTools implements Serializable { public Controller createOpenMeetingsController(final UserRequest ureq, WindowControl wControl, final BusinessGroup group, boolean admin) { return new OpenMeetingsRunController(ureq, wControl, group, null, null, admin, admin, false); } + + public Controller createAdobeConnectController(final UserRequest ureq, WindowControl wControl, final BusinessGroup group, boolean admin) { + AdobeConnectMeetingDefaultConfiguration configuration = new AdobeConnectMeetingDefaultConfiguration(true); + return new AdobeConnectRunController(ureq, wControl, null, null, group, configuration, admin, admin, false); + } /** * @param toolToChange diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java b/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java index 34123c6fb34..c25972f6eed 100644 --- a/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java +++ b/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java @@ -38,6 +38,7 @@ import org.olat.core.util.cache.CacheWrapper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.group.BusinessGroup; import org.olat.instantMessaging.InstantMessagingModule; +import org.olat.modules.adobeconnect.AdobeConnectModule; import org.olat.modules.openmeetings.OpenMeetingsModule; import org.olat.modules.portfolio.PortfolioV2Module; import org.olat.modules.wiki.WikiModule; @@ -106,6 +107,10 @@ public class CollaborationToolsFactory { if(openMeetingsModule.isEnabled()) { toolArr.add(CollaborationTools.TOOL_OPENMEETINGS); } + AdobeConnectModule adobeConnectModule = CoreSpringFactory.getImpl(AdobeConnectModule.class); + if(adobeConnectModule.isEnabled()) { + toolArr.add(CollaborationTools.TOOL_ADOBECONNECT); + } TOOLS = ArrayHelper.toArray(toolArr); } diff --git a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties index 2e7258ff010..d77c2b36623 100644 --- a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties @@ -3,6 +3,7 @@ calendar.access=Kalender Schreibberechtigung calendar.access.all=Alle Mitglieder calendar.access.owners=Besitzer bzw. Betreuer calendar.access.title=Kalender Schreibberechtigung konfigurieren +collabtools.named.hasAdobeConnect=Adobe Connect collabtools.named.hasCalendar=Kalender collabtools.named.hasChat=Chat collabtools.named.hasContactForm=E-Mail diff --git a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties index ac79946b3f9..f20d59f6f3d 100644 --- a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties @@ -3,6 +3,7 @@ calendar.access=Calendar write permission calendar.access.all=All members calendar.access.owners=Coaches calendar.access.title=Configure calendar write permission +collabtools.named.hasAdobeConnect=Adobe Connect collabtools.named.hasCalendar=Calendar collabtools.named.hasChat=Chat collabtools.named.hasContactForm=E-mail diff --git a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_fr.properties index 1f3995af6d5..d33a220566d 100644 --- a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_fr.properties @@ -3,6 +3,7 @@ calendar.access=Droit d'\u00E9criture calendrier calendar.access.all=Tous les membres calendar.access.owners=Propri\u00E9taire resp. tuteur calendar.access.title=Configurer droit d'\u00E9criture calendrier +collabtools.named.hasAdobeConnect=Adobe Connect collabtools.named.hasCalendar=Calendrier collabtools.named.hasChat=Chat collabtools.named.hasContactForm=E-mail diff --git a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml index 602bd9c0e59..f27e65ef671 100644 --- a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml +++ b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml @@ -35,7 +35,6 @@ How to add a new job: <list> <!-- Include every bean here that should be scheduled --> <ref bean="sendNotificationsEmailTrigger" /> - <ref bean="adobeCleanupJob"/> <ref bean="updateStatisticsTrigger"/> <ref bean="searchIndexingTrigger"/> <ref bean="invitationCleanupTrigger" /> diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DateTimeFlexiCellRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DateTimeFlexiCellRenderer.java new file mode 100644 index 00000000000..c4fcb9d304a --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DateTimeFlexiCellRenderer.java @@ -0,0 +1,53 @@ +/** + * <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.core.gui.components.form.flexible.impl.elements.table; + +import java.util.Date; +import java.util.Locale; + +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.Formatter; + +/** + * Render a date object as date and time. + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DateTimeFlexiCellRenderer implements FlexiCellRenderer { + + private final Formatter format; + + public DateTimeFlexiCellRenderer(Locale locale) { + format = Formatter.getInstance(locale); + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, + int row, FlexiTableComponent source, URLBuilder ubu, Translator translator) { + if(cellValue instanceof Date) { + target.append(format.formatDateAndTime((Date)cellValue)); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/media/RedirectMediaResource.java b/src/main/java/org/olat/core/gui/media/RedirectMediaResource.java index bc3a5e0dcf4..0ad50bac923 100644 --- a/src/main/java/org/olat/core/gui/media/RedirectMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/RedirectMediaResource.java @@ -41,7 +41,7 @@ public class RedirectMediaResource implements MediaResource { private static final OLog log = Tracing.createLoggerFor(RedirectMediaResource.class); - private String redirectURL; + private final String redirectURL; /** * @param redirectURL @@ -84,22 +84,13 @@ public class RedirectMediaResource implements MediaResource { public void prepare(HttpServletResponse hres) { try { hres.sendRedirect(redirectURL); - } catch (IOException e) { - // if redirect failed, we do nothing; the browser may have stopped the - // tcp/ip or whatever - log.error("redirect failed: url=" + redirectURL, e); - } catch (IllegalStateException ise){ - // redirect failed, to find out more about the strange null null exception - // FIXME:pb:a decide if this catch has to be removed again, after finding problem. + } catch (IOException | IllegalStateException ise){ log.error("redirect failed: url=" + redirectURL, ise); - //introduced only more debug information but behavior is still the same - throw(ise); } } @Override public void release() { - // nothing to do + // nothing to do } - } \ No newline at end of file diff --git a/src/main/java/org/olat/core/logging/activity/OlatResourceableType.java b/src/main/java/org/olat/core/logging/activity/OlatResourceableType.java index d82265b7a5d..44ca3130ca6 100644 --- a/src/main/java/org/olat/core/logging/activity/OlatResourceableType.java +++ b/src/main/java/org/olat/core/logging/activity/OlatResourceableType.java @@ -90,8 +90,9 @@ public enum OlatResourceableType implements ILoggingResourceableType { assignment, media, - /** represents openmeetings **/ + /** represents virtual class room **/ openmeetings, + adobeconnect, /** business path component **/ businessPath, diff --git a/src/main/java/org/olat/core/util/Encoder.java b/src/main/java/org/olat/core/util/Encoder.java index 1856b19dd17..86632495d1f 100644 --- a/src/main/java/org/olat/core/util/Encoder.java +++ b/src/main/java/org/olat/core/util/Encoder.java @@ -34,6 +34,8 @@ import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; @@ -84,7 +86,12 @@ public class Encoder { /** * SHA-256 with one iteration no salted */ - sha256Exam("SHA-256", 1, false, null); + sha256Exam("SHA-256", 1, false, null), + /** + * AES + */ + aes("AES", 2000, true, null); + private final boolean salted; private final int iterations; @@ -172,9 +179,18 @@ public class Encoder { return digest(s, salt, algorithm); case pbkdf2: return secretKey(s, salt, algorithm); + case aes: + return encodeAes(s, "rk6R9pQy7dg3usJk", salt, algorithm.getIterations()); default: return md5(s, salt, algorithm.getCharset()); } } + + public static String decrypt(String s, String salt, Algorithm algorithm) { + switch(algorithm) { + case aes: return decodeAes(s, "rk6R9pQy7dg3usJk", salt, algorithm.getIterations()); + default: return null; + } + } protected static String md5(String s, String salt, Charset charset) { try { @@ -241,4 +257,57 @@ public class Encoder { public static String byteToBase64(byte[] data){ return StringHelper.encodeBase64(data); } + + public static String encodeAes(String password, String secretKey, String salt, int iteration) { + try { + Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING"); + cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey, salt, iteration)); + byte[] encrypted = cipher.doFinal(password.getBytes("UTF-8")); + return asHexString(encrypted); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + public static String decodeAes(String password, String secretKey, String salt, int iteration) { + try { + Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING"); + cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey, salt, iteration)); + byte[] encrypted = cipher.doFinal(toByteArray(password)); + return new String(encrypted); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + private static SecretKey generateKey(String passphrase, String salt, int iteration) throws Exception { + PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(), salt.getBytes(), iteration, 128); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC"); + return keyFactory.generateSecret(keySpec); + } + + private static final String asHexString(byte buf[]) { + StringBuilder strbuf = new StringBuilder(buf.length * 2); + int i; + for (i = 0; i < buf.length; i++) { + if (((int) buf[i] & 0xff) < 0x10) { + strbuf.append("0"); + } + strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); + } + return strbuf.toString(); + } + + private static final byte[] toByteArray(String hexString) { + int arrLength = hexString.length() >> 1; + byte buf[] = new byte[arrLength]; + for (int ii = 0; ii < arrLength; ii++) { + int index = ii << 1; + String l_digit = hexString.substring(index, index + 2); + buf[ii] = (byte) Integer.parseInt(l_digit, 16); + } + return buf; + } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/ObjectCloner.java b/src/main/java/org/olat/core/util/ObjectCloner.java index 4d2e1c8caed..6d6b0641066 100644 --- a/src/main/java/org/olat/core/util/ObjectCloner.java +++ b/src/main/java/org/olat/core/util/ObjectCloner.java @@ -48,7 +48,7 @@ public class ObjectCloner { * @return copied object * @throws RuntimeException */ - static public Object deepCopy(Object oldObj) throws RuntimeException { + public static Object deepCopy(Object oldObj) throws RuntimeException { ObjectOutputStream oos = null; ObjectInputStream ois = null; try { @@ -62,6 +62,7 @@ public class ObjectCloner { // return the new object return ois.readObject(); } catch (Exception e) { + e.printStackTrace(); throw new RuntimeException("Exception in ObjectCloner = ", e); } finally { try { @@ -72,34 +73,4 @@ public class ObjectCloner { } } } - - /** - * Determines the size of an object in bytes when it is serialized. - * <br> - * This should not be used for anything other than optimization - * testing since it can be memory and processor intensive. - * <br> - * @author http://churchillobjects.com/c/13029.html - */ - public static int getObjectSize(Object object){ - if(object==null){ - return -1; - } - try{ - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(object); - byte[] bytes = baos.toByteArray(); - oos.close(); - baos.close(); - return bytes.length; - } - catch(Exception e){ - e.printStackTrace(); - } - return -1; - } - - - } \ No newline at end of file diff --git a/src/main/java/org/olat/course/CourseXStreamAliases.java b/src/main/java/org/olat/course/CourseXStreamAliases.java index 0c01683cbdf..1d5fc03d61c 100644 --- a/src/main/java/org/olat/course/CourseXStreamAliases.java +++ b/src/main/java/org/olat/course/CourseXStreamAliases.java @@ -36,6 +36,7 @@ import org.olat.course.condition.operators.IsNotInAttributeOperator; import org.olat.course.condition.operators.LowerThanEqualsOperator; import org.olat.course.condition.operators.LowerThanOperator; import org.olat.course.config.CourseConfig; +import org.olat.course.nodes.AdobeConnectCourseNode; import org.olat.course.nodes.AssessableCourseNode; import org.olat.course.nodes.BCCourseNode; import org.olat.course.nodes.BasicLTICourseNode; @@ -63,6 +64,9 @@ import org.olat.course.nodes.TACourseNode; import org.olat.course.nodes.TUCourseNode; import org.olat.course.nodes.ViteroCourseNode; import org.olat.course.nodes.WikiCourseNode; +import org.olat.course.nodes.adobeconnect.compatibility.AdobeConnectCompatibilityConfiguration; +import org.olat.course.nodes.adobeconnect.compatibility.MeetingCompatibilityDate; +import org.olat.course.nodes.adobeconnect.compatibility.WimbaClassroomCompatibilityConfiguration; import org.olat.course.tree.CourseEditorTreeModel; import org.olat.course.tree.CourseEditorTreeNode; import org.olat.modules.edubase.model.BookSectionImpl; @@ -135,6 +139,12 @@ public class CourseXStreamAliases { readXstream.alias("ExtendedCondition", ExtendedCondition.class); readXstream.alias("Condition", Condition.class); + // vc node to new adobe connect cours element + readXstream.alias("de.bps.course.nodes.VCCourseNode", AdobeConnectCourseNode.class); + readXstream.alias("de.bps.course.nodes.vc.MeetingDate", MeetingCompatibilityDate.class); + readXstream.alias("de.bps.course.nodes.vc.provider.adobe.AdobeConnectConfiguration", AdobeConnectCompatibilityConfiguration.class); + readXstream.alias("de.bps.course.nodes.vc.provider.wimba.WimbaClassroomConfiguration", WimbaClassroomCompatibilityConfiguration.class); + // conditions can hold operators and they get serialized as well. So we need all of the as aliases readXstream.alias("IsInAttributeOperator", IsInAttributeOperator.class); readXstream.alias("EqualsOperator", EqualsOperator.class); diff --git a/src/main/java/org/olat/course/_spring/courseContext.xml b/src/main/java/org/olat/course/_spring/courseContext.xml index 407dc3371c3..f5788faac81 100644 --- a/src/main/java/org/olat/course/_spring/courseContext.xml +++ b/src/main/java/org/olat/course/_spring/courseContext.xml @@ -21,6 +21,7 @@ <import resource="classpath:/org/olat/course/nodes/info/_spring/infoMessageContext.xml"/> <import resource="classpath:/org/olat/course/nodes/gotomeeting/_spring/buildingblockContext.xml"/> <import resource="classpath:/org/olat/course/nodes/openmeetings/_spring/buildingblockContext.xml"/> + <import resource="classpath:/org/olat/course/nodes/adobeconnect/_spring/buildingblockContext.xml"/> <import resource="classpath:/org/olat/course/nodes/portfolio/_spring/portfolioBBContext.xml"/> <import resource="classpath:/org/olat/course/nodes/vitero/_spring/buildingblockContext.xml"/> <import resource="classpath:/org/olat/course/statistic/_spring/statisticContext.xml"/> diff --git a/src/main/java/org/olat/course/nodes/AdobeConnectCourseNode.java b/src/main/java/org/olat/course/nodes/AdobeConnectCourseNode.java new file mode 100644 index 00000000000..7fa2213ca8b --- /dev/null +++ b/src/main/java/org/olat/course/nodes/AdobeConnectCourseNode.java @@ -0,0 +1,180 @@ +/** + * <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.course.nodes; + +import java.util.List; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.stack.BreadcrumbPanel; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.messages.MessageUIFactory; +import org.olat.core.gui.control.generic.tabbable.TabbableController; +import org.olat.core.gui.translator.Translator; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.Util; +import org.olat.course.ICourse; +import org.olat.course.condition.ConditionEditController; +import org.olat.course.editor.CourseEditorEnv; +import org.olat.course.editor.NodeEditController; +import org.olat.course.editor.StatusDescription; +import org.olat.course.groupsandrights.CourseGroupManager; +import org.olat.course.nodes.adobeconnect.AdobeConnectCourseNodeConfiguration; +import org.olat.course.nodes.adobeconnect.AdobeConnectEditController; +import org.olat.course.nodes.adobeconnect.compatibility.AdobeConnectCompatibilityConfiguration; +import org.olat.course.run.navigation.NodeRunConstructionResult; +import org.olat.course.run.userview.NodeEvaluation; +import org.olat.course.run.userview.UserCourseEnvironment; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.ui.AdobeConnectMeetingDefaultConfiguration; +import org.olat.modules.adobeconnect.ui.AdobeConnectRunController; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 28 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectCourseNode extends AbstractAccessableCourseNode { + + private static final long serialVersionUID = 7965344505304490859L; + private static final OLog log = Tracing.createLoggerFor(AdobeConnectCourseNode.class); + private static final String TYPE = "adobeconnect"; + + // configuration + public static final String CONF_VC_CONFIGURATION = "vc_configuration"; + + private transient CourseGroupManager groupMgr; + + public AdobeConnectCourseNode() { + super(TYPE); + } + + @Override + public void updateModuleConfigDefaults(boolean isNewNode) { + ModuleConfiguration config = getModuleConfiguration(); + if(config.getConfigurationVersion() < 2) { + Object oldConfiguration = config.get(CONF_VC_CONFIGURATION); + if(oldConfiguration instanceof AdobeConnectCompatibilityConfiguration) { + AdobeConnectCompatibilityConfiguration oldConfig = (AdobeConnectCompatibilityConfiguration)oldConfiguration; + config.setBooleanEntry(AdobeConnectEditController.GUEST_ACCESS_ALLOWED, oldConfig.isGuestAccessAllowed()); + config.setBooleanEntry(AdobeConnectEditController.MODERATOR_START_MEETING, !oldConfig.isGuestStartMeetingAllowed()); + } + } + config.setConfigurationVersion(2); + } + + @Override + protected String getDefaultTitleOption() { + // default is to only display content because the room has its own room title + return CourseNode.DISPLAY_OPTS_CONTENT; + } + + @Override + public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, + ICourse course, UserCourseEnvironment userCourseEnv) { + updateModuleConfigDefaults(false); + + CourseNode chosenNode = course.getEditorTreeModel().getCourseNode(userCourseEnv.getCourseEditorEnv().getCurrentCourseNodeId()); + // create edit controller + AdobeConnectEditController childTabCtrl = new AdobeConnectEditController(ureq, wControl, this, course, userCourseEnv); + + NodeEditController nodeEditCtr = new NodeEditController(ureq, wControl, course.getEditorTreeModel(), course, chosenNode, + userCourseEnv, childTabCtrl); + nodeEditCtr.addControllerListener(childTabCtrl); + return nodeEditCtr; + } + + @Override + public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl, + UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) { + updateModuleConfigDefaults(false); + + String providerId = getModuleConfiguration().getStringValue("vc_provider_id"); + + Controller controller; + if("wimba".equals(providerId)) { + Translator trans = Util.createPackageTranslator(AdobeConnectCourseNodeConfiguration.class, ureq.getLocale()); + String title = trans.translate("wimba.not.supported.title"); + String message = trans.translate("wimba.not.supported.message"); + controller = MessageUIFactory.createInfoMessage(ureq, wControl, title, message); + } else { + // check if user is moderator of the virtual classroom + boolean admin = userCourseEnv.isAdmin(); + boolean moderator = admin || userCourseEnv.isCoach(); + // create run controller + RepositoryEntry entry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + boolean allowGuestAccess = getModuleConfiguration().getBooleanSafe(AdobeConnectEditController.GUEST_ACCESS_ALLOWED, false); + AdobeConnectMeetingDefaultConfiguration configuration = new AdobeConnectMeetingDefaultConfiguration(allowGuestAccess); + controller = new AdobeConnectRunController(ureq, wControl, entry, getIdent(), null, configuration, + admin, moderator, userCourseEnv.isCourseReadOnly()); + } + Controller ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, controller, this, "o_vc_icon"); + return new NodeRunConstructionResult(ctrl); + } + + @Override + public StatusDescription isConfigValid() { + if (oneClickStatusCache != null) { return oneClickStatusCache[0]; } + + StatusDescription sd = StatusDescription.NOERROR; + if(groupMgr != null) { + // + } + return sd; + } + + @Override + public StatusDescription[] isConfigValid(CourseEditorEnv cev) { + String translatorStr = Util.getPackageName(ConditionEditController.class); + if (groupMgr == null) { + groupMgr = cev.getCourseGroupManager(); + } + List<StatusDescription> statusDescs = isConfigValidWithTranslator(cev, translatorStr, getConditionExpressions()); + return StatusDescriptionHelper.sort(statusDescs); + } + + @Override + public RepositoryEntry getReferencedRepositoryEntry() { + return null; + } + + @Override + public boolean needsReferenceToARepositoryEntry() { + return false; + } + + @Override + public void cleanupOnDelete(ICourse course) { + super.cleanupOnDelete(course); + // remove meeting + try { + AdobeConnectManager provider = CoreSpringFactory.getImpl(AdobeConnectManager.class); + RepositoryEntry courseRe = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + provider.delete(courseRe, getIdent()); + } catch(Exception e) { + log.error("A room could not be deleted for course node: " + getIdent() + " of course:" + course, e); + } + } +} diff --git a/src/main/java/de/bps/course/nodes/vc/VCCourseNodeConfiguration.java b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectCourseNodeConfiguration.java similarity index 63% rename from src/main/java/de/bps/course/nodes/vc/VCCourseNodeConfiguration.java rename to src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectCourseNodeConfiguration.java index cc4c9b908f0..58f18f18c20 100644 --- a/src/main/java/de/bps/course/nodes/vc/VCCourseNodeConfiguration.java +++ b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectCourseNodeConfiguration.java @@ -1,4 +1,3 @@ -//<OLATCE-103> /** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> @@ -15,37 +14,49 @@ * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de + * 12.10.2011 by frentix GmbH, http://www.frentix.com * <p> */ -package de.bps.course.nodes.vc; +package org.olat.course.nodes.adobeconnect; import java.util.Locale; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.course.nodes.AbstractCourseNodeConfiguration; +import org.olat.course.nodes.AdobeConnectCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeConfiguration; import org.olat.course.nodes.CourseNodeGroup; - -import de.bps.course.nodes.VCCourseNode; +import org.olat.modules.adobeconnect.AdobeConnectModule; /** + * * Description:<br> - * Configuration for date lists - Virtual Classroom dates. - * + * Configuration for the Adobe Connect course element with aliasing + * for the deleted one with alias "vc". + * * <P> - * Initial Date: 04.07.2010 <br> + * Initial Date: 6 oct. 2011 <br> * - * @author Jens Lindner(jlindne4@hs-mittweida.de) - * @author skoeber + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class VCCourseNodeConfiguration extends AbstractCourseNodeConfiguration { +public class AdobeConnectCourseNodeConfiguration extends AbstractCourseNodeConfiguration { + + private final String alias; + + public AdobeConnectCourseNodeConfiguration() { + this("adobeconnect"); + } + + public AdobeConnectCourseNodeConfiguration(String alias) { + this.alias = alias; + } @Override public String getAlias() { - return "vc"; + return alias; } @Override @@ -60,14 +71,18 @@ public class VCCourseNodeConfiguration extends AbstractCourseNodeConfiguration { @Override public CourseNode getInstance() { - return new VCCourseNode(); + return new AdobeConnectCourseNode(); } - @Override public String getLinkText(Locale locale) { Translator fallback = Util.createPackageTranslator(CourseNodeConfiguration.class, locale); Translator translator = Util.createPackageTranslator(this.getClass(), locale, fallback); return translator.translate("title_vc"); } -} -//</OLATCE-103> \ No newline at end of file + + @Override + public boolean isEnabled() { + AdobeConnectModule module = CoreSpringFactory.getImpl(AdobeConnectModule.class); + return module.isEnabled(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditController.java b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditController.java new file mode 100644 index 00000000000..121cc0dbc1d --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditController.java @@ -0,0 +1,126 @@ +/** + * <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.course.nodes.adobeconnect; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.tabbedpane.TabbedPane; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.ControllerEventListener; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController; +import org.olat.course.ICourse; +import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.condition.Condition; +import org.olat.course.condition.ConditionEditController; +import org.olat.course.editor.NodeEditController; +import org.olat.course.nodes.AdobeConnectCourseNode; +import org.olat.course.run.userview.UserCourseEnvironment; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectEditController extends ActivateableTabbableDefaultController implements ControllerEventListener { + + public static final String GUEST_ACCESS_ALLOWED = "guestAccessAllowed"; + public static final String MODERATOR_START_MEETING = "moderatorStartMeeting"; + + private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility"; + public static final String PANE_TAB_VCCONFIG = "pane.tab.vcconfig"; + private static final String[] paneKeys = { PANE_TAB_VCCONFIG, PANE_TAB_ACCESSIBILITY }; + + private TabbedPane tabPane; + private final VelocityContainer editVc; + + private AdobeConnectEditFormController editForm; + private ConditionEditController accessibilityCondContr; + + private final AdobeConnectCourseNode courseNode; + + public AdobeConnectEditController(UserRequest ureq, WindowControl wControl, AdobeConnectCourseNode courseNode, + ICourse course, UserCourseEnvironment userCourseEnv) { + super(ureq, wControl); + this.courseNode = courseNode; + editVc = createVelocityContainer("edit"); + + String providerId = courseNode.getModuleConfiguration().getStringValue("vc_provider_id"); + if("wimba".equals(providerId)) { + showWarning("wimba.not.supported.message"); + } + + Condition accessCondition = courseNode.getPreConditionAccess(); + accessibilityCondContr = new ConditionEditController(ureq, wControl, userCourseEnv, + accessCondition, AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), courseNode)); + listenTo(accessibilityCondContr); + + editForm = new AdobeConnectEditFormController(ureq, getWindowControl(), courseNode); + listenTo(editForm); + editVc.put("configuration", editForm.getInitialComponent()); + } + + @Override + public String[] getPaneKeys() { + return paneKeys; + } + + @Override + public TabbedPane getTabbedPane() { + return tabPane; + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == accessibilityCondContr) { + if (event == Event.CHANGED_EVENT) { + Condition cond = accessibilityCondContr.getCondition(); + courseNode.setPreConditionAccess(cond); + fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); + } + } else if (source == editForm) { // config form action + if (event == NodeEditController.NODECONFIG_CHANGED_EVENT) { + fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); + } + } + } + + @Override + public void addTabs(TabbedPane tabbedPane) { + tabPane = tabbedPane; + tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), + accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate("condition.accessibility.title"))); + tabbedPane.addTab(translate(PANE_TAB_VCCONFIG), editVc); + } + +} diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditFormController.java b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditFormController.java new file mode 100644 index 00000000000..f5b491e9b17 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectEditFormController.java @@ -0,0 +1,92 @@ +/** + * <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.course.nodes.adobeconnect; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.Util; +import org.olat.course.editor.NodeEditController; +import org.olat.course.nodes.AdobeConnectCourseNode; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.adobeconnect.ui.AdobeConnectRunController; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectEditFormController extends FormBasicController { + + private static final String[] onKeys = new String[] { "on" }; + + private MultipleSelectionElement guestAllowedEl; + //private MultipleSelectionElement guestAllowedStartEl; + + private ModuleConfiguration config; + + public AdobeConnectEditFormController(UserRequest ureq, WindowControl wControl, + AdobeConnectCourseNode courseNode) { + super(ureq, wControl, Util.createPackageTranslator(AdobeConnectRunController.class, ureq.getLocale())); + config = courseNode.getModuleConfiguration(); + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + setFormTitle("pane.tab.vcconfig"); + setFormContextHelp("Communication and Collaboration#_openmeeting"); + + String[] guestValues = new String[] { translate("vc.access.open") }; + guestAllowedEl = uifactory.addCheckboxesHorizontal("guest.allowed", formLayout, onKeys, guestValues); + if(!config.getBooleanSafe(AdobeConnectEditController.GUEST_ACCESS_ALLOWED, false)) { + guestAllowedEl.select(onKeys[0], true); + } + /* + String[] guestStartValues = new String[] { translate("vc.access.start") }; + guestAllowedStartEl = uifactory.addCheckboxesHorizontal("moderator.start.meeting", formLayout, onKeys, guestStartValues); + if(config.getBooleanSafe(AdobeConnectEditController.MODERATOR_START_MEETING, true)) { + guestAllowedStartEl.select(onKeys[0], true); + } + */ + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("save", buttonsCont); + + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + config.setBooleanEntry(AdobeConnectEditController.GUEST_ACCESS_ALLOWED, !guestAllowedEl.isSelected(0)); + //config.setBooleanEntry(AdobeConnectEditController.MODERATOR_START_MEETING, guestAllowedStartEl.isSelected(0)); + fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); + } +} diff --git a/src/main/java/de/bps/course/nodes/vc/NoProviderController.java b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectPeekViewController.java similarity index 51% rename from src/main/java/de/bps/course/nodes/vc/NoProviderController.java rename to src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectPeekViewController.java index 4f0a56610ef..a4940da9dc2 100644 --- a/src/main/java/de/bps/course/nodes/vc/NoProviderController.java +++ b/src/main/java/org/olat/course/nodes/adobeconnect/AdobeConnectPeekViewController.java @@ -17,46 +17,37 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package de.bps.course.nodes.vc; +package org.olat.course.nodes.adobeconnect; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.tabbedpane.TabbedPane; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.Event; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.generic.tabbable.TabbableDefaultController; -/** - * - * this is a dummy controller to show only a tab with an error message. - * - * Initial date: 29.05.2013<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class NoProviderController extends TabbableDefaultController { - - private final VelocityContainer noProviderVc; - - public NoProviderController(UserRequest ureq, WindowControl wControl) { +public class AdobeConnectPeekViewController extends FormBasicController { + + public AdobeConnectPeekViewController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - noProviderVc = createVelocityContainer("noprovider"); + + initForm(ureq); } @Override - public void addTabs(TabbedPane tabbedPane) { - tabbedPane.addTab(translate(VCEditController.PANE_TAB_VCCONFIG), noProviderVc); + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { // } @Override - protected void event(UserRequest ureq, Component source, Event event) { + protected void doDispose() { // } + @Override - protected void doDispose() { + protected void formOK(UserRequest ureq) { // } -} \ No newline at end of file + + +} diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/_content/edit.html b/src/main/java/org/olat/course/nodes/adobeconnect/_content/edit.html new file mode 100644 index 00000000000..f29500cf361 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/_content/edit.html @@ -0,0 +1 @@ +$r.render("configuration") diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_de.properties new file mode 100644 index 00000000000..03e966b331c --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_de.properties @@ -0,0 +1,10 @@ +title_vc=Adobe Connect +pane.tab.accessibility=Zugang +pane.tab.vcconfig=Konfiguration +condition.accessibility.title=Zugang +guest.allowed=Zutritt +moderator.start.meeting=Raum \u00F6ffnen +wimba.not.supported.title=Wimba Classroom +wimba.not.supported.message=Wimba Classroom ist nicht unterscht\u00FCtzt. +vc.access.start=Nur Moderatoren d\u00fcrfen diesen Raum er\u00F6ffnen +vc.access.open=Moderator muss im Raum online sein, um Zutritt f\u00FCr Teilnehmer zu best\u00e4tigen diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_en.properties new file mode 100644 index 00000000000..24a18c5fe79 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/_i18n/LocalStrings_en.properties @@ -0,0 +1,9 @@ +#Tue Dec 18 17:54:01 CET 2012 +condition.accessibility.title=Access +title_vc=Adobe Connect +pane.tab.accessibility=Access +pane.tab.vcconfig=Room +guest.allowed=Access +moderator.start.meeting=Room opening +wimba.not.supported.title=Wimba Classroom +wimba.not.supported.message=Wimba Classroom is not supported. diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/_spring/buildingblockContext.xml b/src/main/java/org/olat/course/nodes/adobeconnect/_spring/buildingblockContext.xml new file mode 100644 index 00000000000..98b9c92a919 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/_spring/buildingblockContext.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context.xsd"> + + <bean id="adobeconnect" class="org.olat.course.nodes.adobeconnect.AdobeConnectCourseNodeConfiguration" scope="prototype"> + <property name="order" value="303" /> + </bean> + + <bean id="vc" class="org.olat.course.nodes.adobeconnect.AdobeConnectCourseNodeConfiguration" scope="prototype"> + <constructor-arg index="0" value="vc" /> + <property name="deprecated" value="true" /> + <property name="order" value="30000" /> + </bean> + +</beans> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/AdobeConnectCompatibilityConfiguration.java b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/AdobeConnectCompatibilityConfiguration.java new file mode 100644 index 00000000000..c61345764ef --- /dev/null +++ b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/AdobeConnectCompatibilityConfiguration.java @@ -0,0 +1,100 @@ +/** + * <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.course.nodes.adobeconnect.compatibility; + +import java.io.Serializable; +import java.util.List; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectCompatibilityConfiguration implements Serializable { + + private static final long serialVersionUID = -90842707525111572L; + + private String providerId; + private boolean guestAccessAllowed; + private boolean guestStartMeetingAllowed; + + private String templateKey; + private boolean useMeetingDates; + private boolean createMeetingImmediately; + + private List<MeetingCompatibilityDate> meetingDatas; + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public boolean isGuestAccessAllowed() { + return guestAccessAllowed; + } + + public void setGuestAccessAllowed(boolean guestAccessAllowed) { + this.guestAccessAllowed = guestAccessAllowed; + } + + public boolean isGuestStartMeetingAllowed() { + return guestStartMeetingAllowed; + } + + public void setGuestStartMeetingAllowed(boolean guestStartMeetingAllowed) { + this.guestStartMeetingAllowed = guestStartMeetingAllowed; + } + + public String getTemplateKey() { + return templateKey; + } + + public void setTemplateKey(String templateKey) { + this.templateKey = templateKey; + } + + public boolean isUseMeetingDates() { + return useMeetingDates; + } + + public void setUseMeetingDates(boolean useMeetingDates) { + this.useMeetingDates = useMeetingDates; + } + + public boolean isCreateMeetingImmediately() { + return createMeetingImmediately; + } + + public void setCreateMeetingImmediately(boolean createMeetingImmediately) { + this.createMeetingImmediately = createMeetingImmediately; + } + + public List<MeetingCompatibilityDate> getMeetingDatas() { + return meetingDatas; + } + + public void setMeetingDatas(List<MeetingCompatibilityDate> meetingDatas) { + this.meetingDatas = meetingDatas; + } +} diff --git a/src/main/java/de/bps/course/nodes/vc/MeetingDate.java b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/MeetingCompatibilityDate.java similarity index 56% rename from src/main/java/de/bps/course/nodes/vc/MeetingDate.java rename to src/main/java/org/olat/course/nodes/adobeconnect/compatibility/MeetingCompatibilityDate.java index bce81b10fbd..18519d7aafa 100644 --- a/src/main/java/de/bps/course/nodes/vc/MeetingDate.java +++ b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/MeetingCompatibilityDate.java @@ -1,4 +1,3 @@ -//<OLATCE-103> /** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> @@ -15,62 +14,51 @@ * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de + * frentix GmbH, http://www.frentix.com * <p> */ -package de.bps.course.nodes.vc; +package org.olat.course.nodes.adobeconnect.compatibility; import java.io.Serializable; import java.util.Date; /** - * Description:<br> - * Virtual Classroom appointment model to be used in course module configuration. - * Initial Date: 30.08.2010 <br> * - * @author Jens Lindner (jlindne4@hs-mittweida.de) - * @author skoeber + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * */ -public class MeetingDate implements Serializable { +public class MeetingCompatibilityDate implements Serializable { + + private static final long serialVersionUID = -3849348910151430025L; private String title; private String description; private Date start; private Date end; - public MeetingDate() { - // nothing to do - } - - public MeetingDate(final String title, final String description, Date start, Date end) { - this.title = title; - this.description = description; - this.start= start; - this.end = end; - } - - public final String getTitle() { + public String getTitle() { return title; } - - public final void setTitle(final String title) { + + public void setTitle(String title) { this.title = title; } - - public final String getDescription() { + + public String getDescription() { return description; } - - public final void setDescription(final String description) { + + public void setDescription(String description) { this.description = description; } - public Date getBegin() { + public Date getStart() { return start; } - - public void setBegin(Date start) { - this.start = start; + + public void setStart(Date start) { + this.start = start; } public Date getEnd() { @@ -80,5 +68,7 @@ public class MeetingDate implements Serializable { public void setEnd(Date end) { this.end = end; } + + + } -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomConfiguration.java b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/WimbaClassroomCompatibilityConfiguration.java similarity index 76% rename from src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomConfiguration.java rename to src/main/java/org/olat/course/nodes/adobeconnect/compatibility/WimbaClassroomCompatibilityConfiguration.java index 8113572e29f..d7fdd32c61b 100644 --- a/src/main/java/de/bps/course/nodes/vc/provider/wimba/WimbaClassroomConfiguration.java +++ b/src/main/java/org/olat/course/nodes/adobeconnect/compatibility/WimbaClassroomCompatibilityConfiguration.java @@ -18,11 +18,10 @@ * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ -package de.bps.course.nodes.vc.provider.wimba; +package org.olat.course.nodes.adobeconnect.compatibility; import java.io.Serializable; - -import de.bps.course.nodes.vc.DefaultVCConfiguration; +import java.util.List; /** * @@ -33,7 +32,9 @@ import de.bps.course.nodes.vc.DefaultVCConfiguration; * Initial Date: 06.01.2011 <br> * @author skoeber */ -public class WimbaClassroomConfiguration extends DefaultVCConfiguration implements Serializable { +public class WimbaClassroomCompatibilityConfiguration implements Serializable { + + private static final long serialVersionUID = -5335478926224404373L; /** presentation tools are available only to instructors or to both students and instructors */ private boolean toolsToStudentsEnabled; @@ -66,11 +67,17 @@ public class WimbaClassroomConfiguration extends DefaultVCConfiguration implemen /** enable registered users access */ private boolean regUsersAccessAllowed; + private String providerId; + private String templateKey; + private List<MeetingCompatibilityDate> meetingDatas; + private boolean useMeetingDates; + private boolean createMeetingImmediately; + /* be compatible with old configuration versions */ @SuppressWarnings("unused") private transient boolean chatEnabled; @SuppressWarnings("unused") private transient boolean privateChatEnabled; - public boolean isToolsToStudentsEnabled() { + public boolean isToolsToStudentsEnabled() { return toolsToStudentsEnabled; } @@ -190,11 +197,64 @@ public class WimbaClassroomConfiguration extends DefaultVCConfiguration implemen return studentsPrivateChatAllowed; } - @Override + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public String getTemplateKey() { + return templateKey; + } + + public void setTemplateKey(String templateKey) { + this.templateKey = templateKey; + } + + public List<MeetingCompatibilityDate> getMeetingDatas() { + return meetingDatas; + } + + public void setMeetingDatas(List<MeetingCompatibilityDate> meetingDatas) { + this.meetingDatas = meetingDatas; + } + + public boolean isUseMeetingDates() { + return useMeetingDates; + } + + public void setUseMeetingDates(boolean useMeetingDates) { + this.useMeetingDates = useMeetingDates; + } + + public boolean isCreateMeetingImmediately() { + return createMeetingImmediately; + } + + public void setCreateMeetingImmediately(boolean createMeetingImmediately) { + this.createMeetingImmediately = createMeetingImmediately; + } + + public boolean isChatEnabled() { + return chatEnabled; + } + + public void setChatEnabled(boolean chatEnabled) { + this.chatEnabled = chatEnabled; + } + + public boolean isPrivateChatEnabled() { + return privateChatEnabled; + } + + public void setPrivateChatEnabled(boolean privateChatEnabled) { + this.privateChatEnabled = privateChatEnabled; + } + public boolean isConfigValid() { - // TODO implement logic return true; } -} -//</OLATCE-103> \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java index 69261120d34..828a45780a6 100644 --- a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java +++ b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java @@ -50,7 +50,7 @@ public class OpenMeetingsEditController extends ActivateableTabbableDefaultContr private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility"; public static final String PANE_TAB_VCCONFIG = "pane.tab.vcconfig"; - final static String[] paneKeys = { PANE_TAB_VCCONFIG, PANE_TAB_ACCESSIBILITY }; + private static final String[] paneKeys = { PANE_TAB_VCCONFIG, PANE_TAB_ACCESSIBILITY }; public static final String CONFIG_ROOM_NAME = "roomName"; public static final String CONFIG_ROOM_SIZE = "roomSize"; diff --git a/src/main/java/org/olat/course/nodes/st/PeekViewWrapperController.java b/src/main/java/org/olat/course/nodes/st/PeekViewWrapperController.java index 66fd5856a6d..a3b8384f344 100644 --- a/src/main/java/org/olat/course/nodes/st/PeekViewWrapperController.java +++ b/src/main/java/org/olat/course/nodes/st/PeekViewWrapperController.java @@ -70,7 +70,7 @@ public class PeekViewWrapperController extends BasicController { peekViewWrapperVC.setDomReplacementWrapperRequired(false); // we provide our own DOM replacement ID // Add course node to get title etc peekViewWrapperVC.contextPut("coursenode", courseNode); - peekViewWrapperVC.contextPut("accessible", new Boolean(accessible)); + peekViewWrapperVC.contextPut("accessible", Boolean.valueOf(accessible)); // Add link to jump to course node nodeLink = LinkFactory.createLink("nodeLink", peekViewWrapperVC, this); nodeLink.setCustomDisplayText(StringHelper.escapeHtml(courseNode.getShortTitle())); diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java index 6efcc10d560..70a21c8cbda 100644 --- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java +++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java @@ -90,6 +90,7 @@ import org.olat.group.ui.edit.BusinessGroupModifiedEvent; import org.olat.instantMessaging.CloseInstantMessagingEvent; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.instantMessaging.InstantMessagingService; +import org.olat.modules.adobeconnect.AdobeConnectModule; import org.olat.modules.co.ContactFormController; import org.olat.modules.openmeetings.OpenMeetingsModule; import org.olat.modules.portfolio.PortfolioV2Module; @@ -138,37 +139,40 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im public static final OLATResourceable ORES_TOOLPORTFOLIO = OresHelper.createOLATResourceableType("toolportfolio"); public static final OLATResourceable ORES_TOOLBOOKING = OresHelper.createOLATResourceableType("toolbooking"); public static final OLATResourceable ORES_TOOLOPENMEETINGS = OresHelper.createOLATResourceableType("toolopenmeetings"); + public static final OLATResourceable ORES_TOOLADOBECONNECT = OresHelper.createOLATResourceableType("tooladobeconnect"); public static final OLATResourceable ORES_TOOLWIKI = OresHelper.createOLATResourceableType(WikiManager.WIKI_RESOURCE_FOLDER_NAME); - // activity identifyers are used as menu user objects and for the user + // activity identifiers are used as menu user objects and for the user // activity events // change value with care, used in logfiles etc!! - /** activity identitfyer: user selected overview in menu * */ + /** activity identifier: user selected overview in menu * */ public static final String ACTIVITY_MENUSELECT_OVERVIEW = "MENU_OVERVIEW"; - /** activity identitfyer: user selected information in menu * */ + /** activity identifier: user selected information in menu * */ public static final String ACTIVITY_MENUSELECT_INFORMATION = "MENU_INFORMATION"; - /** activity identitfyer: user selected memberlist in menu * */ + /** activity identifier: user selected memberlist in menu * */ public static final String ACTIVITY_MENUSELECT_MEMBERSLIST = "MENU_MEMBERLIST"; - /** activity identitfyer: user selected contactform in menu * */ + /** activity identifier: user selected contactform in menu * */ public static final String ACTIVITY_MENUSELECT_CONTACTFORM = "MENU_CONTACTFORM"; - /** activity identitfyer: user selected forum in menu * */ + /** activity identifier: user selected forum in menu * */ public static final String ACTIVITY_MENUSELECT_FORUM = "MENU_FORUM"; - /** activity identitfyer: user selected folder in menu * */ + /** activity identifier: user selected folder in menu * */ public static final String ACTIVITY_MENUSELECT_FOLDER = "MENU_FOLDER"; - /** activity identitfyer: user selected chat in menu * */ + /** activity identifier: user selected chat in menu * */ public static final String ACTIVITY_MENUSELECT_CHAT = "MENU_CHAT"; - /** activity identitfyer: user selected calendar in menu * */ + /** activity identifier: user selected calendar in menu * */ public static final String ACTIVITY_MENUSELECT_CALENDAR = "MENU_CALENDAR"; - /** activity identitfyer: user selected administration in menu * */ + /** activity identifier: user selected administration in menu * */ public static final String ACTIVITY_MENUSELECT_ADMINISTRATION = "MENU_ADMINISTRATION"; - /** activity identitfyer: user selected show resources in menu * */ + /** activity identifier: user selected show resources in menu * */ public static final String ACTIVITY_MENUSELECT_SHOW_RESOURCES = "MENU_SHOW_RESOURCES"; public static final String ACTIVITY_MENUSELECT_WIKI = "MENU_SHOW_WIKI"; - /* activity identitfyer: user selected show portoflio in menu */ + /* activity identifier: user selected show portoflio in menu */ public static final String ACTIVITY_MENUSELECT_PORTFOLIO = "MENU_SHOW_PORTFOLIO"; - /* activity identifyer: user selected show OPENMEETINGS in menu */ + /* activity identifier: user selected show OPENMEETINGS in menu */ public static final String ACTIVITY_MENUSELECT_OPENMEETINGS = "MENU_SHOW_OPENMEETINGS"; - /* activity identitfyer: user selected show access control in menu */ + /* activity identifier: user selected show OPENMEETINGS in menu */ + public static final String ACTIVITY_MENUSELECT_ADOBECONNECT = "MENU_SHOW_ADOBECONNECT"; + /* activity identifier: user selected show access control in menu */ /* access control of resources */ public static final String ACTIVITY_MENUSELECT_AC = "MENU_SHOW_AC"; @@ -206,7 +210,13 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im // not null indicates tool is enabled private final String nodeIdPrefix; - private GenericTreeNode nodeFolder, nodeForum, nodeWiki, nodeCal, nodePortfolio, nodeOpenMeetings; + private GenericTreeNode nodeFolder; + private GenericTreeNode nodeForum; + private GenericTreeNode nodeWiki; + private GenericTreeNode nodeCal; + private GenericTreeNode nodePortfolio; + private GenericTreeNode nodeOpenMeetings; + private GenericTreeNode nodeAdobeConnect; private GenericTreeNode nodeContact, nodeGroupOwners, nodeResources, nodeInformation, nodeAdmin; private boolean groupRunDisabled; private OLATResourceable assessmentEventOres; @@ -227,7 +237,11 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im @Autowired private PortfolioV2Module portfolioV2Module; @Autowired - private BusinessGroupService businessGroupService; + private OpenMeetingsModule openMeetingsModule; + @Autowired + private AdobeConnectModule adobeConnectModule; + @Autowired + private BusinessGroupService businessGroupService; /** * Do not use this constructor! Use the BGControllerFactory instead! @@ -356,7 +370,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im AccessResult acResult = acService.isAccessible(businessGroup, getIdentity(), false); if(acResult.isAccessible()) { needActivation = false; - } else if (businessGroup != null && acResult.getAvailableMethods().size() > 0) { + } else if (businessGroup != null && !acResult.getAvailableMethods().isEmpty()) { accessController = new AccessListController(ureq, getWindowControl(), acResult.getAvailableMethods()); listenTo(accessController); mainPanel.setContent(accessController.getInitialComponent()); @@ -412,10 +426,6 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im main.contextPut("hasOwners", 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) { // events from menutree @@ -443,10 +453,6 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im } } - /** - * @see org.olat.core.gui.control.DefaultController#event(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 == bgEditCntrllr) { @@ -526,7 +532,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im } /** - * generates the email adress list. + * Generates the email address list. * * @param ureq * @return a contact form controller for this group @@ -675,7 +681,9 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im doPortfolio(ureq); } else if (ACTIVITY_MENUSELECT_OPENMEETINGS.equals(cmd)) { doOpenMeetings(ureq); - } else if (ACTIVITY_MENUSELECT_AC.equals(cmd)) { + } else if (ACTIVITY_MENUSELECT_ADOBECONNECT.equals(cmd)) { + doAdobeConnect(ureq); + } else if (ACTIVITY_MENUSELECT_AC.equals(cmd)) { doAccessControlHistory(ureq); } @@ -815,6 +823,20 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im listenTo(collabToolCtr); mainPanel.setContent(collabToolCtr.getInitialComponent()); } + + private void doAdobeConnect(UserRequest ureq) { + addLoggingResourceable(LoggingResourceable.wrap(ORES_TOOLADOBECONNECT, OlatResourceableType.adobeconnect)); + + ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(ORES_TOOLADOBECONNECT); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, getWindowControl()); + ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapPortfolioOres(ce.getOLATResourceable())); + addToHistory(ureq, bwControl); + + CollaborationTools collabTools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroup); + collabToolCtr = collabTools.createAdobeConnectController(ureq, bwControl, businessGroup, isAdmin); + listenTo(collabToolCtr); + mainPanel.setContent(collabToolCtr.getInitialComponent()); + } private Activateable2 doAdministration(UserRequest ureq) { removeAsListenerAndDispose(bgEditCntrllr); @@ -967,6 +989,16 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im listenTo(mc); // cleanup on dispose mainPanel.setContent(mc.getInitialComponent()); } + } else if (OresHelper.equals(ores, ORES_TOOLADOBECONNECT)) { + if (nodeAdobeConnect != null) { + doAdobeConnect(ureq); + bgTree.setSelectedNode(nodeAdobeConnect); + } else if(mainPanel != null) { // not enabled + String text = translate("warn.portfolionotavailable"); + Controller mc = MessageUIFactory.createInfoMessage(ureq, getWindowControl(), null, text); + listenTo(mc); // cleanup on dispose + mainPanel.setContent(mc.getInitialComponent()); + } } else if (OresHelper.equals(ores, ORES_TOOLADMIN)) { if (nodeAdmin != null) { doAdministration(ureq).activate(ureq, entries, ce.getTransientState()); @@ -1202,8 +1234,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im root.addChild(gtnChild); nodePortfolio = gtnChild; } - - OpenMeetingsModule openMeetingsModule = CoreSpringFactory.getImpl(OpenMeetingsModule.class); + if (openMeetingsModule.isEnabled() && collabTools.isToolEnabled(CollaborationTools.TOOL_OPENMEETINGS)) { gtnChild = new GenericTreeNode(nodeIdPrefix.concat("meetings")); gtnChild.setTitle(translate("menutree.openmeetings")); @@ -1213,6 +1244,16 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im root.addChild(gtnChild); nodeOpenMeetings = gtnChild; } + + if(adobeConnectModule.isEnabled() && collabTools.isToolEnabled(CollaborationTools.TOOL_ADOBECONNECT)) { + gtnChild = new GenericTreeNode(nodeIdPrefix.concat("adobeconnect")); + gtnChild.setTitle(translate("menutree.adobeconnect")); + gtnChild.setUserObject(ACTIVITY_MENUSELECT_ADOBECONNECT); + gtnChild.setAltText(translate("menutree.adobeconnect.alt")); + gtnChild.setIconCssClass("o_vc_icon"); + root.addChild(gtnChild); + nodeAdobeConnect = gtnChild; + } if (isAdmin) { gtnChild = new GenericTreeNode(nodeIdPrefix.concat("admin")); diff --git a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_de.properties index d0d5dc3ae9f..e47614ca0f6 100644 --- a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_de.properties @@ -17,6 +17,8 @@ mail.body.more=Weitere Mitteilungen members.noParticipants.message=Dieser Gruppe sind keine Teilnehmer zugeordnet. menutree.administration=Administration menutree.administration.alt=Administration +menutree.adobeconnect=Adobe Connect +menutree.adobeconnect.alt=Adobe Connect web conferencing menutree.calendar=Kalender menutree.calendar.alt=Kalender menutree.chat=Chat diff --git a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_en.properties index 93a6288cb1c..98f9998d92e 100644 --- a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_en.properties @@ -19,6 +19,8 @@ menutree.ac=Bookings menutree.ac.alt=Bookings menutree.administration=Administration menutree.administration.alt=Administration +menutree.adobeconnect=Adobe Connect +menutree.adobeconnect.alt=Adobe Connect web conferencing menutree.calendar=Calendar menutree.calendar.alt=Calendar menutree.chat=Chat diff --git a/src/main/java/org/olat/modules/_spring/modulesContext.xml b/src/main/java/org/olat/modules/_spring/modulesContext.xml index 52bf9496038..b21c3eecc93 100644 --- a/src/main/java/org/olat/modules/_spring/modulesContext.xml +++ b/src/main/java/org/olat/modules/_spring/modulesContext.xml @@ -175,6 +175,26 @@ </property> </bean> + <!-- Adobe Connect admin. panel --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> + <property name="order" value="7211" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.modules.adobeconnect.ui.AdobeConnectAdminController"/> + </bean> + </property> + <property name="navigationKey" value="adobeconnect" /> + <property name="parentTreeNodeIdentifier" value="externalToolsParent" /> + <property name="i18nActionKey" value="admin.menu.title"/> + <property name="i18nDescriptionKey" value="admin.menu.title.alt"/> + <property name="translationPackage" value="org.olat.modules.adobeconnect.ui"/> + <property name="extensionPoints"> + <list> + <value>org.olat.admin.SystemAdminMainController</value> + </list> + </property> + </bean> + <!-- OpenMeetings admin. panel --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="7210" /> diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java new file mode 100644 index 00000000000..ceab8f08f02 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectManager.java @@ -0,0 +1,103 @@ +/** + * <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.adobeconnect; + +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.olat.core.id.Identity; +import org.olat.group.BusinessGroup; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface AdobeConnectManager { + + public boolean checkConnection(String url, String login, String password, AdobeConnectErrors error); + + public void createMeeting(String name, String description, String templateId, + Date start, Date end, Locale locale, boolean allAccess, + RepositoryEntry entry, String subIdent, BusinessGroup businessGroup, + Identity actingIdentity, AdobeConnectErrors error); + + /** + * + * @param meeting The meeting to update + * @param name The name to update or null + * @param description The description to update or null + * @param startDate The date to update or null + * @param endDate The end date to update or null + * @param error + */ + public AdobeConnectMeeting updateMeeting(AdobeConnectMeeting meeting, String name, String description, + String templateId, Date startDate, Date endDate, AdobeConnectErrors error); + + public boolean deleteMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors error); + + public List<AdobeConnectSco> getTemplates(); + + public List<AdobeConnectSco> getRecordings(AdobeConnectMeeting meeting, AdobeConnectErrors error); + + /** + * + * @param entry The repository entry + * @param subIdent The course element identifier + * @param businessGroup The business group + * @return The list of meetings of the course element or the group + */ + public List<AdobeConnectMeeting> getMeetings(RepositoryEntry entry, String subIdent, BusinessGroup businessGroup); + + public List<AdobeConnectMeeting> getAllMeetings(); + + /** + * Check if the user is already registered. + * + * @param meeting + * @param identity + * @param error + * @return + */ + public boolean isRegistered(AdobeConnectMeeting meeting, Identity identity, + AdobeConnectMeetingPermission permission, AdobeConnectErrors error); + + /** + * + * @param meeting + * @param identity + * @param error + * @return + */ + public boolean registerFor(AdobeConnectMeeting meeting, Identity identity, + AdobeConnectMeetingPermission permission, AdobeConnectErrors error); + + public String join(AdobeConnectMeeting meeting, Identity identity, AdobeConnectErrors error); + + public String linkTo(AdobeConnectSco content, Identity identity, AdobeConnectErrors error); + + public void delete(RepositoryEntry entry, String subIdent); + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java new file mode 100644 index 00000000000..f902e33996a --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeeting.java @@ -0,0 +1,65 @@ +/** + * <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.adobeconnect; + +import java.util.Date; + +import org.olat.core.id.CreateInfo; +import org.olat.core.id.ModifiedInfo; +import org.olat.group.BusinessGroup; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface AdobeConnectMeeting extends ModifiedInfo, CreateInfo { + + public Long getKey(); + + public String getName(); + + public void setName(String name); + + public String getDescription(); + + public void setDescription(String description); + + public Date getStartDate(); + + public void setStartDate(Date date); + + public Date getEndDate(); + + public void setEndDate(Date date); + + public String getScoId(); + + public String getEnvName(); + + public RepositoryEntry getEntry(); + + public String getSubIdent(); + + public BusinessGroup getBusinessGroup(); + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeetingPermission.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeetingPermission.java new file mode 100644 index 00000000000..df3456005d5 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMeetingPermission.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.adobeconnect; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum AdobeConnectMeetingPermission { + + host("host"), + miniHost("mini-host"), + view("view"), + remove("remove"); + + private final String permission; + + private AdobeConnectMeetingPermission(String permission) { + this.permission = permission; + } + + public String permission() { + return permission; + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMettingSecurityCallback.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMettingSecurityCallback.java new file mode 100644 index 00000000000..1d1a9e50eed --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectMettingSecurityCallback.java @@ -0,0 +1,34 @@ +/** + * <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.adobeconnect; + +/** + * + * Initial date: 6 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface AdobeConnectMettingSecurityCallback { + + public boolean isAccessAllowed(); + + public boolean isAllowedToStart(); + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectModule.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectModule.java new file mode 100644 index 00000000000..38cda7fdeab --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectModule.java @@ -0,0 +1,253 @@ +/** + * <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.adobeconnect; + +import java.net.URI; + +import javax.ws.rs.core.UriBuilder; + +import org.olat.core.configuration.AbstractSpringModule; +import org.olat.core.configuration.ConfigOnOff; +import org.olat.core.util.StringHelper; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 28 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AdobeConnectModule extends AbstractSpringModule implements ConfigOnOff { + + private static final String ENABLED = "vc.adobe.enabled"; + private static final String PROTOCOL = "vc.adobe.protocol"; + private static final String PORT = "vc.adobe.port"; + private static final String USERTYPE = "vc.adobe.usertype"; + private static final String BASEURL = "vc.adobe.baseurl"; + private static final String CONTEXTPATH = "vc.adobe.contextpath"; + private static final String ADMIN_LOGIN = "vc.adobe.adminlogin"; + private static final String ADMIN_CRED = "vc.adobe.adminpassword"; + private static final String ACCOUNTID = "vc.adobe.accountid"; + private static final String PROVIDERID = "vc.adobe.providerid"; + + @Value("${vc.adobe.enabled}") + private boolean enabled; + @Value("${vc.adobe.protocol:https}") + private String protocol; + @Value("${vc.adobe.port:443}") + private int port; + @Value("${vc.adobe.usertype:user}") + private String userType; + + @Value("${vc.adobe.baseurl}") + private String baseUrl; + @Value("${vc.adobe.context:/api/xml}") + private String contextPath; + + @Value("${vc.adobe.adminlogin}") + private String adminLogin; + @Value("${vc.adobe.adminpassword}") + private String adminPassword; + @Value("${vc.adobe.accountid:#{null}}") + private String accountId; + @Value("${vc.adobe.provider:connect9}") + private String providerId; + + @Autowired + public AdobeConnectModule(CoordinatorManager coordinatorManager) { + super(coordinatorManager); + } + + @Override + public void init() { + String enabledObj = getStringPropertyValue(ENABLED, true); + if(StringHelper.containsNonWhitespace(enabledObj)) { + enabled = "true".equals(enabledObj); + } + + protocol = getStringPropertyValue(PROTOCOL, protocol); + String portObj = getStringPropertyValue(PORT, true); + if(StringHelper.containsNonWhitespace(portObj)) { + port = Integer.parseInt(portObj); + } + userType = getStringPropertyValue(USERTYPE, userType); + adminLogin = getStringPropertyValue(ADMIN_LOGIN, adminLogin); + adminPassword = getStringPropertyValue(ADMIN_CRED, adminPassword); + baseUrl = getStringPropertyValue(BASEURL, baseUrl); + contextPath = getStringPropertyValue(CONTEXTPATH, contextPath); + accountId = getStringPropertyValue(ACCOUNTID, accountId); + providerId = getStringPropertyValue(PROVIDERID, providerId); + } + + @Override + protected void initFromChangedProperties() { + init(); + } + + @Override + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + setBooleanProperty(ENABLED, enabled, true); + } + + public URI getAdobeConnectURI() { + if(StringHelper.containsNonWhitespace(baseUrl)) { + UriBuilder builder = getAdobeConnectUriBuilder(); + return builder.build(); + } + return null; + } + + public UriBuilder getAdobeConnectUriBuilder() { + String acProtocol = getProtocol(); + UriBuilder builder = UriBuilder.fromUri(acProtocol + "://" + getBaseUrl()); + int acPort = getPort(); + if(acPort > 0 + && !(acPort == 443 && "https".equals(acProtocol)) + && !(acPort == 80 && "http".equals(acProtocol))) { + builder = builder.port(getPort()); + } + if(StringHelper.containsNonWhitespace(getContextPath())) { + builder = builder.path(getContextPath()); + } + return builder; + } + + public UriBuilder getAdobeConnectHostUriBuilder() { + String acProtocol = getProtocol(); + UriBuilder builder = UriBuilder.fromUri(acProtocol + "://" + getBaseUrl()); + int acPort = getPort(); + if(acPort > 0 + && !(acPort == 443 && "https".equals(acProtocol)) + && !(acPort == 80 && "http".equals(acProtocol))) { + builder = builder.port(getPort()); + } + return builder; + } + + public void setAdobeConnectURI(URI uri) { + if(uri == null) { + setBaseUrl(null); + setContextPath(null); + setProtocol(null); + } else { + String host = uri.getHost(); + setBaseUrl(host); + int omPort = uri.getPort(); + setPort(omPort); + String path = uri.getPath(); + if(StringHelper.containsNonWhitespace(path) && path.startsWith("/")) { + path = path.substring(1, path.length()); + } + setContextPath(path); + String scheme = uri.getScheme(); + setProtocol(scheme); + } + } + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + setStringProperty(PROVIDERID, providerId, true); + } + + public String getAdminLogin() { + return adminLogin; + } + + public void setAdminLogin(String adminLogin) { + this.adminLogin = adminLogin; + setStringProperty(ADMIN_LOGIN, adminLogin, true); + } + + public String getAdminPassword() { + return adminPassword; + } + + public void setAdminPassword(String adminPassword) { + this.adminPassword = adminPassword; + setSecretStringProperty(ADMIN_CRED, adminPassword, true); + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + setStringProperty(PROTOCOL, protocol, true); + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + setStringProperty(BASEURL, baseUrl, true); + } + + public String getContextPath() { + return contextPath; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + setStringProperty(CONTEXTPATH, contextPath, true); + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + setStringProperty(PORT, String.valueOf(port), true); + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + setStringProperty(USERTYPE, userType, true); + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + setStringProperty(ACCOUNTID, accountId, true); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/AdobeConnectUser.java b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectUser.java new file mode 100644 index 00000000000..6a6304340b3 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/AdobeConnectUser.java @@ -0,0 +1,36 @@ +/** + * <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.adobeconnect; + +import org.olat.core.id.Identity; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface AdobeConnectUser { + + public String getPrincipalId(); + + public Identity getIdentity(); + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AbstractAdobeConnectProvider.java b/src/main/java/org/olat/modules/adobeconnect/manager/AbstractAdobeConnectProvider.java new file mode 100644 index 00000000000..f5983a0c2ed --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AbstractAdobeConnectProvider.java @@ -0,0 +1,700 @@ +/** + * <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.adobeconnect.manager; + +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.apache.http.util.EntityUtils; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.i18n.I18nModule; +import org.olat.course.ICourse; +import org.olat.course.nodes.AdobeConnectCourseNode; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.AdobeConnectModule; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPermission; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; +import org.olat.modules.adobeconnect.model.BreezeSession; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public abstract class AbstractAdobeConnectProvider implements AdobeConnectSPI { + + private static final OLog log = Tracing.createLoggerFor(AbstractAdobeConnectProvider.class); + + private static final String PREFIX = "olat-"; + public static final String COOKIE = "BREEZESESSION="; + private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm"; + private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT); + private static final String DATE_ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + private static final SimpleDateFormat DATE_ISO_FORMATTER = new SimpleDateFormat(DATE_ISO_FORMAT); + + private static final String SHARED_TEMPLATES_FOLDER = "shared-meeting-templates"; + private static final String MY_TEMPLATES_FOLDER = "my-meeting-templates"; + + private String adminFolderScoId; + private BreezeSession currentSession; + + @Autowired + protected AdobeConnectModule adobeConnectModule; + + /** + * https://example.com/api/xml?action=sco-update + * &type=meeting + * &name=August%20All%20Hands%20Meeting + * &description=For all company employees + * &folder-id=2006258750 to create a sco OR &sco-id=23678 to update an sco + * &date-begin=2006-08-01T09:00 + * &date-end=2006-08-01T17:00 + * &url-path=august + * &lang=en + * &source-sco-id=2006349744 + * @return + */ + @Override + public AdobeConnectSco createScoMeeting(String name, String description, String folderScoId, + String templateId, Date startDate, Date endDate, Locale locale, AdobeConnectErrors error) { + if(folderScoId == null) { + folderScoId = adminFolderScoId(error); + } + String lang = getLanguage(locale); + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-update") + .queryParam("type", "meeting") + .queryParam("name", name) + .queryParam("folder-id", folderScoId) + .queryParam("lang", lang); + if(StringHelper.containsNonWhitespace(description)) { + builder.queryParam("description", description); + } + if(StringHelper.containsNonWhitespace(templateId)) { + builder.queryParam("source-sco-id", templateId); + } + if(startDate != null) { + builder + .queryParam("date-begin", formatDate(startDate)) + .queryParam("date-end", formatDate(endDate)); + } + + URI createUri = builder.build(); + List<AdobeConnectSco> createdScos = sendScoRequest(createUri, error); + return createdScos == null || createdScos.isEmpty() ? null : createdScos.get(0); + } + + private String getLanguage(Locale locale) { + if(locale != null && isCompatibleLanguage(locale.getLanguage())) { + return locale.getLanguage(); + } + Locale defLocale = I18nModule.getDefaultLocale(); + if(isCompatibleLanguage(defLocale.getLanguage())) { + return defLocale.getLanguage(); + } + return "en"; + } + + private boolean isCompatibleLanguage(String language) { + return "fr".equals(language) || "en".equals(language) || "de".equals(language) + || "ja".equals(language) ||"ko".equals(language); + } + + @Override + public AdobeConnectSco createFolder(String name, AdobeConnectErrors errors) { + String folderScoId = adminFolderScoId(errors); + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-update") + .queryParam("type", "folder") + .queryParam("name", name) + .queryParam("folder-id", folderScoId); + URI createUri = builder.build(); + List<AdobeConnectSco> createdScos = sendScoRequest(createUri, errors); + return createdScos == null || createdScos.isEmpty() ? null : createdScos.get(0); + } + + @Override + public List<AdobeConnectSco> getFolderByName(String name, AdobeConnectErrors errors) { + String folderScoId = adminFolderScoId(errors); + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-contents") + .queryParam("sco-id", folderScoId) + .queryParam("filter-type", "folder") + .queryParam("filter-name", name); + URI createUri = builder.build(); + return sendScoRequest(createUri, errors); + } + + @Override + public boolean updateScoMeeting(String scoId, String name, String description, String templateId, + Date startDate, Date endDate, AdobeConnectErrors errors) { + String folderScoId = adminFolderScoId(errors); + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-update") + .queryParam("type", "meeting") + .queryParam("name", name) + .queryParam("sco-id", scoId) + .queryParam("folder-id", folderScoId); + if(StringHelper.containsNonWhitespace(description)) { + builder.queryParam("description", description); + } + if(StringHelper.containsNonWhitespace(templateId)) { + builder.queryParam("source-sco-id", templateId); + } + if(startDate != null) { + builder + .queryParam("date-begin", formatDate(startDate)) + .queryParam("date-end", formatDate(endDate)); + } + + boolean ok = false; + HttpGet get = createAdminMethod(builder, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 || statusCode == 201) { + ok = AdobeConnectDOMHelper.isStatusOk(response.getEntity()); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return ok; + } + + @Override + public List<AdobeConnectSco> getTemplates() { + AdobeConnectErrors error = new AdobeConnectErrors(); + List<AdobeConnectSco> shortCuts = getShortCuts(error); + + List<AdobeConnectSco> templates = new ArrayList<>(); + if(shortCuts != null) { + for(AdobeConnectSco shortCut:shortCuts) { + if(SHARED_TEMPLATES_FOLDER.equals(shortCut.getType()) + || MY_TEMPLATES_FOLDER.equals(shortCut.getType())) { + List<AdobeConnectSco> scos = getScoContents(shortCut.getScoId(), error); + if(scos != null && !scos.isEmpty()) { + templates.addAll(scos); + } + } + } + } + + return templates; + } + + @Override + public List<AdobeConnectSco> getRecordings(AdobeConnectMeeting meeting, AdobeConnectErrors error) { + return getScoContents(meeting.getScoId(), error); + } + + protected List<AdobeConnectSco> getScoContents(String scoId, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-contents") + .queryParam("sco-id", scoId); + URI createUri = builder.build(); + return sendScoRequest(createUri, error); + } + + @Override + public AdobeConnectSco getScoMeeting(String scoId, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-info") + .queryParam("sco-id", scoId); + URI createUri = builder.build(); + List<AdobeConnectSco> createdScos = sendScoRequest(createUri, error); + return createdScos == null || createdScos.isEmpty() ? null : createdScos.get(0); + } + + @Override + public boolean deleteScoMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors error) { + if(!StringHelper.containsNonWhitespace(meeting.getScoId())) { + return true;// nothing to do + } + + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-delete") + .queryParam("sco-id", "adahgf" /* meeting.getScoId() */); + + boolean ok = false; + HttpGet get = createAdminMethod(builder, error); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode >= 200 && statusCode < 400) { + ok = AdobeConnectDOMHelper.isStatusOk(response.getEntity()); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return ok; + } + + /** + * https://example.com/api/xml?action=permissions-update&acl-id=2007018414 + * &principal-id=public-access&permission-id=view-hidden + */ + @Override + public boolean setPermissions(String scoId, boolean allAccess, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "permissions-update") + .queryParam("principal-id", "public-access") + .queryParam("acl-id", scoId); + if(allAccess) { + builder.queryParam("permission-id", "view-hidden"); + } else { + builder.queryParam("permission-id", "remove"); + } + + boolean ok = false; + HttpGet get = createAdminMethod(builder, error); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode >= 200 && statusCode < 400) { + ok = true; + } + EntityUtils.consume(response.getEntity()); + } catch(Exception e) { + log.error("", e); + } + return ok; + } + + /** + * https://example.com/api/xml?action=permissions-update + * &principal-id=2006258745 + * &acl-id=2007018414 (the sco-id) + * &permission-id=host + * @param scoId + * @param error + */ + @Override + public boolean setMember(String scoId, String principalId, String permission, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "permissions-update") + .queryParam("principal-id", principalId) + .queryParam("acl-id", scoId) + .queryParam("permission-id", permission); + + boolean ok = false; + HttpGet get = createAdminMethod(builder, error); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode >= 200 && statusCode < 400) { + ok = true; + } + EntityUtils.consume(response.getEntity()); + } catch(Exception e) { + log.error("", e); + } + return ok; + } + + /** + * https://server/lmsapi/xml?action=permissions-info + * &acl-id=integer + * &principal-id=integer + * &filter-permission-id=value + * &session=SessionCookie + */ + @Override + public boolean isMember(String scoId, String principalId, String permission, AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "permissions-info") + .queryParam("principal-id", principalId) + .queryParam("acl-id", scoId) + .queryParam("filter-permission-id", permission); + + boolean ok = false; + HttpGet get = createAdminMethod(builder, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode >= 200 && statusCode < 400) { + List<AdobeConnectPermission> permissions = parsePermissions(response.getEntity(), errors); + ok = permissions != null && !permissions.isEmpty(); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return ok; + } + + protected static final String formatDate(Date date) { + synchronized(DATE_FORMATTER) { + return DATE_FORMATTER.format(date); + } + } + + protected static final Date parseIsoDate(String val) { + if(!StringHelper.containsNonWhitespace(val)) return null; + + try { + synchronized(DATE_ISO_FORMATTER) { + return DATE_ISO_FORMATTER.parse(val); + } + } catch (ParseException e) { + log.error("", e); + return null; + } + } + + protected String adminFolderScoId(AdobeConnectErrors error) { + if(adminFolderScoId != null) { + return adminFolderScoId; + } + + String meetingsScoId = null; + String myMeetingsScoId = null; + List<AdobeConnectSco> shortCuts = getShortCuts(error); + if(shortCuts != null) { + for(AdobeConnectSco shortCut:shortCuts) { + if("meetings".equals(shortCut.getType())) { + meetingsScoId = shortCut.getScoId(); + } else if("my-meetings".equals(shortCut.getType())) { + myMeetingsScoId = shortCut.getScoId(); + } + } + } + adminFolderScoId = myMeetingsScoId == null ? meetingsScoId : myMeetingsScoId; + return adminFolderScoId; + } + + protected List<AdobeConnectSco> getShortCuts(AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "sco-shortcuts"); + + List<AdobeConnectSco> shortCuts = null; + HttpGet get = createAdminMethod(builder, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + shortCuts = parseScos(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return shortCuts; + } + + /** + * https://server/lmsapi/xml?action=common-info + * + * @return + */ + @Override + public AdobeConnectPrincipal adminCommonInfo(AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "common-info"); + + AdobeConnectPrincipal user = null; + HttpGet get = createAdminMethod(builder, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + user = parseCommonInfo(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return user; + } + + protected List<AdobeConnectSco> parseScos(HttpEntity entity, AdobeConnectErrors errors) { + List<AdobeConnectSco> scos = new ArrayList<>(); + try { + Document doc = AdobeConnectDOMHelper.getDocumentFromEntity(entity); + if(AdobeConnectDOMHelper.isStatusOk(doc)) { + NodeList nodes = doc.getElementsByTagName("sco"); + int numOfNodes = nodes.getLength(); + for(int i=0; i<numOfNodes; i++) { + Element sco = (Element)nodes.item(i); + + AdobeConnectSco connectSco = new AdobeConnectSco(); + connectSco.setScoId(sco.getAttribute("sco-id")); + connectSco.setType(sco.getAttribute("type")); + connectSco.setIcon(sco.getAttribute("icon")); + String urlPath = getFirstElementValue(sco, "url-path"); + connectSco.setUrlPath(urlPath); + String name = getFirstElementValue(sco, "name"); + connectSco.setName(name); + connectSco.setDateBegin(parseIsoDate(getFirstElementValue(sco, "date-begin"))); + connectSco.setDateEnd(parseIsoDate(getFirstElementValue(sco, "date-end"))); + connectSco.setDateCreated(parseIsoDate(getFirstElementValue(sco, "date-created"))); + connectSco.setDateModified(parseIsoDate(getFirstElementValue(sco, "date-modified"))); + + scos.add(connectSco); + } + AdobeConnectDOMHelper.print(doc); + } else { + AdobeConnectDOMHelper.print(doc); + AdobeConnectDOMHelper.error(doc, errors); + } + } catch(Exception e) { + log.error("", e); + } + return scos; + } + + private String getFirstElementValue(Element parent, String tagName) { + Element element = getFirstElement(parent, tagName); + return (element == null) ? "" : getCharacterDataFromElement(element); + } + + private Element getFirstElement(Element parent, String tagName) { + NodeList nodes = parent.getElementsByTagName(tagName); + return (nodes != null && nodes.getLength() > 0) ? (Element) (nodes.item(0)) : null; + } + + private String getCharacterDataFromElement(Element e) { + StringBuilder sb = new StringBuilder(); + for(Node child = e.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child instanceof CharacterData) { + CharacterData cd = (CharacterData)child; + sb.append(cd.getData()); + } + } + return sb.toString(); + } + + /** + * https://server/lmsapi/xml?action=login + * &login=email + * &password=string + * &session=SessionCookie + */ + protected BreezeSession getAdminSession(AdobeConnectErrors errors) { + if(currentSession != null && currentSession.isValid()) { + return currentSession; + } + + UriBuilder builderc = adobeConnectModule.getAdobeConnectUriBuilder(); + URI uric = builderc + .queryParam("action", "common-info") + .build(); + + BreezeSession session = null; + HttpGet getInfo = new HttpGet(uric); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(getInfo)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + Header header = response.getFirstHeader("Set-Cookie"); + session = BreezeSession.valueOf(header); + } + EntityUtils.consume(response.getEntity()); + } catch(Exception e) { + log.error("", e); + } + + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + URI uri = builder + .queryParam("action", "login") + .queryParam("login", adobeConnectModule.getAdminLogin()) + .queryParam("password", adobeConnectModule.getAdminPassword()) + .queryParam("session", session.getSession()) + .build(); + + HttpGet getLogin = new HttpGet(uri); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(getLogin)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 && AdobeConnectDOMHelper.isStatusOk(response.getEntity())) { + Header header = response.getFirstHeader("Set-Cookie"); + session = BreezeSession.valueOf(header); + currentSession = session; + } + EntityUtils.consumeQuietly(response.getEntity()); + } catch(Exception e) { + log.error("", e); + } + return session; + } + + protected List<AdobeConnectSco> sendScoRequest(URI uri, AdobeConnectErrors errors) { + List<AdobeConnectSco> scos = null; + HttpGet get = createAdminMethod(uri, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 || statusCode == 201) { + scos = parseScos(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return scos; + } + + protected List<AdobeConnectPrincipal> sendPrincipalRequest(URI uri, AdobeConnectErrors errors) { + List<AdobeConnectPrincipal> users = null; + HttpGet get = createAdminMethod(uri, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 || statusCode == 201) { + users = parsePrincipals(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return users; + } + + protected List<AdobeConnectPrincipal> parsePrincipals(HttpEntity entity, AdobeConnectErrors errors) { + List<AdobeConnectPrincipal> users = new ArrayList<>(); + try { + Document doc = AdobeConnectDOMHelper.getDocumentFromEntity(entity); + if(AdobeConnectDOMHelper.isStatusOk(doc)) { + NodeList userList = doc.getElementsByTagName("principal"); + int numOfElements = userList.getLength(); + for(int i=0; i<numOfElements; i++) { + Element userEl = (Element)userList.item(i); + AdobeConnectPrincipal user = new AdobeConnectPrincipal(); + user.setPrincipalId(userEl.getAttribute("principal-id")); + users.add(user); + } + } else { + AdobeConnectDOMHelper.error(doc, errors); + } + } catch (Exception e) { + log.error("", e); + } + return users; + } + + protected AdobeConnectPrincipal parseCommonInfo(HttpEntity entity, AdobeConnectErrors errors) { + AdobeConnectPrincipal user = null; + try { + Document doc = AdobeConnectDOMHelper.getDocumentFromEntity(entity); + if(AdobeConnectDOMHelper.isStatusOk(doc)) { + NodeList userList = doc.getElementsByTagName("user"); + if(userList.getLength() == 1) { + Element userEl = (Element)userList.item(0); + user = new AdobeConnectPrincipal(); + user.setPrincipalId(userEl.getAttribute("user-id")); + } + } else { + AdobeConnectDOMHelper.error(doc, errors); + } + } catch (Exception e) { + log.error("", e); + } + return user; + } + + protected List<AdobeConnectPermission> parsePermissions(HttpEntity entity, AdobeConnectErrors errors) { + List<AdobeConnectPermission> permissions = new ArrayList<>(); + try { + Document doc = AdobeConnectDOMHelper.getDocumentFromEntity(entity); + if(AdobeConnectDOMHelper.isStatusOk(doc)) { + NodeList permissionList = doc.getElementsByTagName("permission"); + int numOfElements = permissionList.getLength(); + for(int i=0; i<numOfElements; i++) { + Element permissionEl = (Element)permissionList.item(i); + AdobeConnectPermission permission = new AdobeConnectPermission(); + permission.setAclId(permissionEl.getAttribute("acl-id")); + permission.setPrincipalId(permissionEl.getAttribute("principal-id")); + permission.setPermissionId(permissionEl.getAttribute("permission-id")); + permissions.add(permission); + } + } else { + AdobeConnectDOMHelper.error(doc, errors); + } + } catch (Exception e) { + log.error("", e); + } + return permissions; + } + + protected HttpGet createAdminMethod(UriBuilder builder, AdobeConnectErrors errors) { + return createAdminMethod(builder.build(), errors); + } + + protected HttpGet createAdminMethod(URI uri, AdobeConnectErrors errors) { + BreezeSession session = getAdminSession(errors); + HttpGet get = new HttpGet(uri); + get.setHeader(new BasicHeader("Cookie", COOKIE + session.getSession())); + return get; + } + + public String getIdentifier(ICourse course, AdobeConnectCourseNode node) { + return PREFIX + course.getResourceableId() + "_" + node.getIdent(); + } + + public String getIdentifier(RepositoryEntry entry, String subIdent) { + return PREFIX + entry.getOlatResource().getResourceableId() + "_" + subIdent; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnect9Provider.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnect9Provider.java new file mode 100644 index 00000000000..09eee9a6d34 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnect9Provider.java @@ -0,0 +1,137 @@ +/** + * <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.adobeconnect.manager; + +import java.net.URI; +import java.util.List; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.Header; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.olat.basesecurity.Authentication; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.Encoder; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.BreezeSession; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AdobeConnect9Provider extends AbstractAdobeConnectProvider { + + private static final OLog log = Tracing.createLoggerFor(AdobeConnect9Provider.class); + + @Override + public String getId() { + return "connect9"; + } + + @Override + public String getName() { + return "Adobe Connect Cloud"; + } + + @Override + public AdobeConnectPrincipal getPrincipalByLogin(String login, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "principal-list") + .queryParam("filter-login", login) + ; + URI principalUri = builder.build(); + List<AdobeConnectPrincipal> users = sendPrincipalRequest(principalUri, error); + return users != null && !users.isEmpty() ? users.get(0) : null; + } + + /** + * https://example.com/api/xml?action=principal-update + * &first-name=jazz + * &last-name=doe + * &login=jazz99@doe.com + * &password=hello + * &type=user + * &send-email=true + * &has-children=0 + * &email=jazz99@doe.com + */ + @Override + public AdobeConnectPrincipal createPrincipal(Identity identity, String login, String password, AdobeConnectErrors error) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "principal-update") + .queryParam("first-name", identity.getUser().getFirstName()) + .queryParam("last-name", identity.getUser().getLastName()) + .queryParam("email", identity.getUser().getEmail()) + .queryParam("login", login) + .queryParam("ext-login", login) + .queryParam("password", password) + .queryParam("type", "user") + .queryParam("send-email", "false") + .queryParam("has-children", "0") + ; + URI principalUri = builder.build(); + List<AdobeConnectPrincipal> users = sendPrincipalRequest(principalUri, error); + return users != null && !users.isEmpty() ? users.get(0) : null; + } + + @Override + public BreezeSession commonInfo(Authentication authentication, AdobeConnectErrors error) { + if(authentication == null) { + return null; + } + + String login = Encoder.decrypt(authentication.getCredential(), authentication.getSalt(), Encoder.Algorithm.aes); + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "login") + .queryParam("login", authentication.getAuthusername()) + .queryParam("password", login); + + URI uri = builder.build(); + BreezeSession session = null; + HttpGet getInfo = new HttpGet(uri); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(getInfo)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 && AdobeConnectDOMHelper.isStatusOk(response.getEntity())) { + Header header = response.getFirstHeader("Set-Cookie"); + session = BreezeSession.valueOf(header); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return session; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectDOMHelper.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectDOMHelper.java new file mode 100644 index 00000000000..76d8f94706d --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectDOMHelper.java @@ -0,0 +1,139 @@ +/** + * <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.adobeconnect.manager; + +import java.io.InputStream; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.http.HttpEntity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.modules.adobeconnect.model.AdobeConnectError; +import org.olat.modules.adobeconnect.model.AdobeConnectErrorCodes; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectDOMHelper { + + private static final OLog log = Tracing.createLoggerFor(AdobeConnectDOMHelper.class); + + protected static boolean isStatusOk(HttpEntity entity) { + try { + Document doc = getDocumentFromEntity(entity); + return AdobeConnectDOMHelper.isStatusOk(doc); + } catch (Exception e) { + log.error("", e); + return false; + } + } + + protected static Document getDocumentFromEntity(HttpEntity entity) throws Exception { + try(InputStream in=entity.getContent()) { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + return dBuilder.parse(in); + } catch(Exception e) { + throw e; + } + } + + protected static final boolean isStatusOk(Document doc) { + NodeList permissionList = doc.getElementsByTagName("status"); + if(permissionList != null && permissionList.getLength() == 1) { + Element status = (Element)permissionList.item(0); + return "ok".equalsIgnoreCase(status.getAttribute("code")); + } + return true; + } + + protected static final void error(Document doc, AdobeConnectErrors errors) { + NodeList permissionList = doc.getElementsByTagName("status"); + if(permissionList != null && permissionList.getLength() == 1) { + Element status = (Element)permissionList.item(0); + String code = status.getAttribute("code"); + String subcode = status.getAttribute("subcode"); + + AdobeConnectError error = new AdobeConnectError(); + error.setCode(AdobeConnectErrorCodes.unkown); + + if("invalid".equals(code)) { + String field = null; + NodeList invalidList = doc.getElementsByTagName("invalid"); + if(invalidList != null && invalidList.getLength() == 1) { + Element invalid = (Element)invalidList.item(0); + subcode = invalid.getAttribute("subcode"); + field = invalid.getAttribute("field"); + } + + if("duplicate".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.duplicateField); + } else if("format".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.formatError); + } else if("illegal-operation".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.illegalOperation); + } else if("missing".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.missingParameter); + } else if("no-such-item".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.noSuchItem); + } else if("range".equals(subcode)) { + error.setCode(AdobeConnectErrorCodes.rangeError); + } + + if(field != null) { + error.setArguments(new String[] { field }); + } + + } else if("no-access".equals(code)) { + error.setCode(AdobeConnectErrorCodes.noAccessDenied); + } + errors.append(error); + } + } + + protected static void print(Document document) { + if(log.isDebug()) { + try(StringWriter writer = new StringWriter()) { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Source source = new DOMSource(document); + transformer.transform(source, new StreamResult(writer)); + writer.flush(); + log.info(writer.toString()); + } catch (Exception e) { + log.error("", e); + } + } + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java new file mode 100644 index 00000000000..30e79e47a7f --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectManagerImpl.java @@ -0,0 +1,382 @@ +/** + * <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.adobeconnect.manager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.Header; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.apache.http.util.EntityUtils; +import org.olat.basesecurity.Authentication; +import org.olat.basesecurity.BaseSecurity; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.Encoder; +import org.olat.core.util.StringHelper; +import org.olat.core.util.WebappHelper; +import org.olat.group.BusinessGroup; +import org.olat.group.DeletableGroupData; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.AdobeConnectMeetingPermission; +import org.olat.modules.adobeconnect.AdobeConnectModule; +import org.olat.modules.adobeconnect.AdobeConnectUser; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; +import org.olat.modules.adobeconnect.model.BreezeSession; +import org.olat.repository.RepositoryEntry; +import org.olat.user.UserDataDeletable; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AdobeConnectManagerImpl implements AdobeConnectManager, DeletableGroupData, UserDataDeletable { + + private static final OLog log = Tracing.createLoggerFor(AdobeConnectManagerImpl.class); + + protected static final String ACONNECT_PROVIDER = "ACONNECT"; + + private AdobeConnectSPI adapter; + + @Autowired + private UserManager userManager; + @Autowired + private List<AdobeConnectSPI> providers; + @Autowired + private BaseSecurity securityManager; + @Autowired + private AdobeConnectUserDAO adobeConnectUserDao; + @Autowired + protected AdobeConnectModule adobeConnectModule; + @Autowired + private AdobeConnectMeetingDAO adobeConnectMeetingDao; + + private AdobeConnectSPI getAdapter() { + String providerId = adobeConnectModule.getProviderId(); + if(adapter == null || !adapter.getId().equals(providerId)) { + for(AdobeConnectSPI provider:providers) { + if(provider.getId().equals(providerId)) { + adapter = provider; + } + } + } + return adapter == null ? new NoAdapterProvider() : adapter; + } + + @Override + public void deleteUserData(Identity identity, String newDeletedUserName) { + adobeConnectUserDao.deleteAdobeConnectUser(identity); + } + + @Override + public boolean deleteGroupDataFor(BusinessGroup group) { + List<AdobeConnectMeeting> meetings = adobeConnectMeetingDao.getMeetings(group); + + AdobeConnectErrors erros = new AdobeConnectErrors(); + for(AdobeConnectMeeting meeting:meetings) { + deleteMeeting(meeting, erros); + } + return erros.hasErrors(); + } + + private String generateFolderName(RepositoryEntry entry, String subIdent, BusinessGroup businessGroup) { + StringBuilder name = new StringBuilder(); + name.append(WebappHelper.getInstanceId()); + if(entry != null) { + name.append("-").append(entry.getKey().toString()); + } + if(StringHelper.containsNonWhitespace(subIdent)) { + name.append("-").append(subIdent); + } + if(businessGroup != null) { + name.append("-").append(businessGroup.getKey()); + } + return name.toString(); + } + + @Override + public void createMeeting(String name, String description, String templateId, + Date start, Date end, Locale locale, boolean allAccess, + RepositoryEntry entry, String subIdent, BusinessGroup businessGroup, + Identity actingIdentity, AdobeConnectErrors error) { + + AdobeConnectSco folder; + String folderName = generateFolderName(entry, subIdent, businessGroup); + List<AdobeConnectSco> folderScos = getAdapter().getFolderByName(folderName, error); + if(folderScos == null || folderScos.isEmpty()) { + folder = getAdapter().createFolder(folderName, error); + } else { + folder = folderScos.get(0); + } + + AdobeConnectSco sco = getAdapter().createScoMeeting(name, description, folder.getScoId(), templateId, start, end, locale, error); + if(sco != null) { + getAdapter().setPermissions(sco.getScoId(), true, error); + AdobeConnectPrincipal admin = getAdapter().adminCommonInfo(error); + getAdapter().setMember(sco.getScoId(), admin.getPrincipalId(), AdobeConnectMeetingPermission.host.permission(), error); + + String actingUser = getOrCreateUser(actingIdentity, true, error); + if(actingUser != null) { + getAdapter().setMember(sco.getScoId(), actingUser, AdobeConnectMeetingPermission.host.permission(), error); + } + + String scoId = sco.getScoId(); + String envName = null; + adobeConnectMeetingDao.createMeeting(name, description, start, end, scoId, envName, entry, subIdent, businessGroup); + } + } + + @Override + public AdobeConnectMeeting updateMeeting(AdobeConnectMeeting meeting, String name, String description, String templateId, + Date start, Date end, AdobeConnectErrors errors) { + boolean ok = getAdapter().updateScoMeeting(meeting.getScoId(), name, description, templateId, start, end, errors); + if(ok) { + meeting.setName(name); + meeting.setDescription(description); + meeting.setStartDate(start); + meeting.setEndDate(end); + meeting = adobeConnectMeetingDao.updateMeeting(meeting); + } + return meeting; + } + + @Override + public List<AdobeConnectSco> getTemplates() { + List<AdobeConnectSco> templates = getAdapter().getTemplates(); + if(templates == null) { + templates = new ArrayList<>(); + } + return templates; + } + + @Override + public List<AdobeConnectSco> getRecordings(AdobeConnectMeeting meeting, AdobeConnectErrors error) { + List<AdobeConnectSco> recordings = getAdapter().getRecordings(meeting, error); + if(recordings == null) { + recordings = new ArrayList<>(); + } + return recordings; + } + + @Override + public boolean registerFor(AdobeConnectMeeting meeting, Identity identity, AdobeConnectMeetingPermission permission, AdobeConnectErrors error) { + boolean registered = false; + String actingUser = getOrCreateUser(identity, true, error); + if(actingUser != null) { + registered = getAdapter().setMember(meeting.getScoId(), actingUser, permission.permission(), error); + } + return registered; + } + + @Override + public boolean isRegistered(AdobeConnectMeeting meeting, Identity identity, AdobeConnectMeetingPermission permission, AdobeConnectErrors error) { + boolean registered = false; + String actingUser = getOrCreateUser(identity, false, error); + if(actingUser != null) { + registered = getAdapter().isMember(meeting.getScoId(), actingUser, permission.permission(), error); + } + return registered; + } + + @Override + public String join(AdobeConnectMeeting meeting, Identity identity, AdobeConnectErrors error) { + String actingUser = getOrCreateUser(identity, false, error); + if(actingUser != null) { + AdobeConnectSco sco = getAdapter().getScoMeeting(meeting.getScoId(), error); + String urlPath = sco.getUrlPath(); + UriBuilder builder = adobeConnectModule + .getAdobeConnectHostUriBuilder() + .path(urlPath); + + BreezeSession session = null; + Authentication authentication = securityManager.findAuthentication(identity, ACONNECT_PROVIDER); + if(authentication != null) { + session = getAdapter().commonInfo(authentication, error); + } + + if(session != null) { + builder.queryParam("session", session.getSession()); + } else { + String fullName = userManager.getUserDisplayName(identity); + builder.queryParam("guestName", fullName).build(); + } + return builder.build().toString(); + } + return null; + } + + @Override + public String linkTo(AdobeConnectSco content, Identity identity, AdobeConnectErrors error) { + String urlPath = content.getUrlPath(); + UriBuilder builder = adobeConnectModule + .getAdobeConnectHostUriBuilder() + .path(urlPath); + + BreezeSession session = null; + Authentication authentication = securityManager.findAuthentication(identity, ACONNECT_PROVIDER); + if(authentication != null) { + session = getAdapter().commonInfo(authentication, error); + } + + if(session != null) { + builder.queryParam("session", session.getSession()); + } else { + String fullName = userManager.getUserDisplayName(identity); + builder.queryParam("guestName", fullName).build(); + } + return builder.build().toString(); + } + + @Override + public void delete(RepositoryEntry entry, String subIdent) { + List<AdobeConnectMeeting> meetings = adobeConnectMeetingDao.getMeetings(entry, subIdent); + AdobeConnectErrors errors = new AdobeConnectErrors(); + for(AdobeConnectMeeting meeting:meetings) { + deleteMeeting(meeting, errors); + } + } + + @Override + public boolean deleteMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors errors) { + boolean deleted = false; + AdobeConnectErrors error = new AdobeConnectErrors(); + if(getAdapter().deleteScoMeeting(meeting, error)) { + AdobeConnectMeeting reloadedMeeting = adobeConnectMeetingDao.loadByKey(meeting.getKey()); + adobeConnectMeetingDao.deleteMeeting(reloadedMeeting); + deleted = true; + } + errors.append(error); + return deleted; + } + + @Override + public List<AdobeConnectMeeting> getMeetings(RepositoryEntry entry, String subIdent, BusinessGroup businessGroup) { + if(entry != null) { + return adobeConnectMeetingDao.getMeetings(entry, subIdent); + } else if(businessGroup != null) { + return adobeConnectMeetingDao.getMeetings(businessGroup); + } + return Collections.emptyList(); + } + + @Override + public List<AdobeConnectMeeting> getAllMeetings() { + return adobeConnectMeetingDao.getAllMeetings(); + } + + private String getOrCreateUser(Identity identity, boolean create, AdobeConnectErrors error) { + AdobeConnectUser user = adobeConnectUserDao.getUser(identity); + if(user == null && create) { + String login = identity.getUser().getEmail(); + AdobeConnectPrincipal aUser = getAdapter().getPrincipalByLogin(login, error); + + String creds = null; + if(aUser == null) { + creds = UUID.randomUUID().toString().replace("-", ""); + if(creds.length() > 32) { + creds = creds.substring(0, 32); + } + aUser = getAdapter().createPrincipal(identity, login, creds, error); + } + + if(aUser != null && StringHelper.containsNonWhitespace(aUser.getPrincipalId())) { + user = adobeConnectUserDao.createUser(aUser.getPrincipalId(), identity); + if(creds != null) { + Authentication authentication = securityManager.findAuthentication(identity, ACONNECT_PROVIDER); + if(authentication == null) { + securityManager.createAndPersistAuthentication(identity, ACONNECT_PROVIDER, login, creds, Encoder.Algorithm.aes); + } else { + securityManager.updateCredentials(authentication, creds, Encoder.Algorithm.aes); + } + } + } + } + return user == null ? null : user.getPrincipalId(); + } + + private String buildUrl(String url, String contextPath) { + StringBuilder sb = new StringBuilder(64); + sb.append(url); + if(StringHelper.containsNonWhitespace(contextPath)) { + sb.append(contextPath); + } + return sb.toString(); + } + + @Override + public boolean checkConnection(String url, String login, String password, AdobeConnectErrors error) { + boolean allOk = false; + + String common = buildUrl(url, null) + "?action=common-info"; + + BreezeSession session = null; + HttpGet commonGet = new HttpGet(common); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(commonGet)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + Header header = response.getFirstHeader("Set-Cookie"); + if(header != null) { + session = BreezeSession.valueOf(header); + } + } + EntityUtils.consume(response.getEntity()); + } catch(Exception e) { + log.error("", e); + } + + String request = buildUrl(url, null) + "?action=login&login=" + login + "&password=" + password; + HttpGet get = new HttpGet(request); + if(session != null) { + get.setHeader(new BasicHeader("Cookie", AbstractAdobeConnectProvider.COOKIE + session.getSession())); + } + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 && AdobeConnectDOMHelper.isStatusOk(response.getEntity())) { + allOk = true; + } + } catch(Exception e) { + log.error("", e); + } + + return allOk; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAO.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAO.java new file mode 100644 index 00000000000..314e8b7abb4 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAO.java @@ -0,0 +1,153 @@ +/** + * <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.adobeconnect.manager; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import javax.persistence.TypedQuery; + +import org.olat.core.commons.persistence.DB; +import org.olat.core.util.StringHelper; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupRef; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.model.AdobeConnectMeetingImpl; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRef; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AdobeConnectMeetingDAO { + + @Autowired + private DB dbInstance; + + public AdobeConnectMeeting createMeeting(String name, String description, Date start, Date end, String scoId, String envName, + RepositoryEntry entry, String subIdent, BusinessGroup businessGroup) { + AdobeConnectMeetingImpl meeting = new AdobeConnectMeetingImpl(); + meeting.setCreationDate(new Date()); + meeting.setLastModified(meeting.getCreationDate()); + meeting.setName(name); + meeting.setDescription(description); + meeting.setStartDate(cleanDate(start)); + meeting.setEndDate(cleanDate(end)); + meeting.setScoId(scoId); + meeting.setEnvName(envName); + if(entry != null) { + meeting.setEntry(entry); + meeting.setSubIdent(subIdent); + } else { + meeting.setBusinessGroup(businessGroup); + } + dbInstance.getCurrentEntityManager().persist(meeting); + return meeting; + } + + public AdobeConnectMeeting updateMeeting(AdobeConnectMeeting meeting) { + AdobeConnectMeetingImpl meet = (AdobeConnectMeetingImpl)meeting; + meet.setLastModified(new Date()); + meet.setStartDate(cleanDate(meet.getStartDate())); + meet.setEndDate(cleanDate(meet.getEndDate())); + return dbInstance.getCurrentEntityManager().merge(meet); + } + + /** + * Remove seconds and milliseconds + * @return + */ + private Date cleanDate(Date date) { + if(date == null) return null; + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + public AdobeConnectMeeting loadByKey(Long key) { + StringBuilder sb = new StringBuilder(256); + sb.append("select meeting from adobeconnectmeeting as meeting") + .append(" left join fetch meeting.entry as v") + .append(" left join fetch v.olatResource as resource") + .append(" left join fetch meeting.businessGroup as businessGroup") + .append(" where meeting.key=:key"); + + List<AdobeConnectMeeting> meetings = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdobeConnectMeeting.class) + .setParameter("key", key) + .getResultList(); + return meetings == null || meetings.isEmpty() ? null : meetings.get(0); + } + + public List<AdobeConnectMeeting> getMeetings(RepositoryEntryRef entry, String subIdent) { + StringBuilder sb = new StringBuilder(256); + sb.append("select meeting from adobeconnectmeeting as meeting") + .append(" inner join fetch meeting.entry as v") + .append(" inner join fetch v.olatResource as resource") + .append(" where v.key=:entryKey"); + if(StringHelper.containsNonWhitespace(subIdent)) { + sb.append(" and meeting.subIdent=:subIdent"); + } + + TypedQuery<AdobeConnectMeeting> query= dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdobeConnectMeeting.class) + .setParameter("entryKey", entry.getKey()); + if(StringHelper.containsNonWhitespace(subIdent)) { + query.setParameter("subIdent", subIdent); + } + return query.getResultList(); + } + + public List<AdobeConnectMeeting> getMeetings(BusinessGroupRef businessGroup) { + StringBuilder sb = new StringBuilder(256); + sb.append("select meeting from adobeconnectmeeting as meeting") + .append(" inner join fetch meeting.businessGroup as businessGroup") + .append(" where businessGroup.key=:groupKey"); + + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdobeConnectMeeting.class) + .setParameter("groupKey", businessGroup.getKey()) + .getResultList(); + } + + public List<AdobeConnectMeeting> getAllMeetings() { + StringBuilder sb = new StringBuilder(256); + sb.append("select meeting from adobeconnectmeeting as meeting") + .append(" left join fetch meeting.entry as v") + .append(" left join fetch meeting.businessGroup as businessGroup"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), AdobeConnectMeeting.class) + .getResultList(); + } + + public void deleteMeeting(AdobeConnectMeeting meeting) { + dbInstance.getCurrentEntityManager().remove(meeting); + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectSPI.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectSPI.java new file mode 100644 index 00000000000..5258fae6fa0 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectSPI.java @@ -0,0 +1,88 @@ +/** + * <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.adobeconnect.manager; + +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.olat.basesecurity.Authentication; +import org.olat.core.id.Identity; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; +import org.olat.modules.adobeconnect.model.BreezeSession; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ + +public interface AdobeConnectSPI { + + public String getId(); + + public String getName(); + + public AdobeConnectSco createScoMeeting(String name, String description, String folderScoId, + String templateId, Date startDate, Date endDate, Locale locale, AdobeConnectErrors error); + + public boolean updateScoMeeting(String scoId, String name, String description, + String templateId, Date startDate, Date endDate, AdobeConnectErrors error); + + public AdobeConnectSco getScoMeeting(String scoId, AdobeConnectErrors error); + + public boolean deleteScoMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors error); + + public AdobeConnectSco createFolder(String name, AdobeConnectErrors errors); + + /** + * Search folders under the root folder of the administration user. The + * method doesn't search the sub-tree. The name is an exact match. + * + * @param name The name of the folder + * @param errors Errors if something bad happens + * @return A list of folders + */ + public List<AdobeConnectSco> getFolderByName(String name, AdobeConnectErrors errors); + + public List<AdobeConnectSco> getTemplates(); + + public List<AdobeConnectSco> getRecordings(AdobeConnectMeeting meeting, AdobeConnectErrors error); + + public boolean setPermissions(String scoId, boolean allAccess, AdobeConnectErrors error); + + public boolean isMember(String scoId, String principalId, String permission, AdobeConnectErrors error); + + public boolean setMember(String scoId, String principalId, String permission, AdobeConnectErrors error); + + public AdobeConnectPrincipal getPrincipalByLogin(String login, AdobeConnectErrors error); + + public AdobeConnectPrincipal createPrincipal(Identity identity, String login, String password, AdobeConnectErrors error); + + public AdobeConnectPrincipal adminCommonInfo(AdobeConnectErrors error); + + public BreezeSession commonInfo(Authentication authentication, AdobeConnectErrors error); + + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAO.java b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAO.java new file mode 100644 index 00000000000..26e49e7ae6f --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAO.java @@ -0,0 +1,71 @@ +/** + * <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.adobeconnect.manager; + +import java.util.Date; +import java.util.List; + +import org.olat.basesecurity.IdentityRef; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.modules.adobeconnect.AdobeConnectUser; +import org.olat.modules.adobeconnect.model.AdobeConnectUserImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AdobeConnectUserDAO { + + @Autowired + private DB dbInstance; + + public AdobeConnectUser createUser(String principalId, Identity identity) { + AdobeConnectUserImpl user = new AdobeConnectUserImpl(); + user.setCreationDate(new Date()); + user.setLastModified(user.getCreationDate()); + user.setPrincipalId(principalId); + user.setIdentity(identity); + dbInstance.getCurrentEntityManager().persist(user); + return user; + } + + public AdobeConnectUser getUser(IdentityRef identity) { + List<AdobeConnectUser> users = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadAdobeConnectUserByIdentity", AdobeConnectUser.class) + .setParameter("identityKey", identity.getKey()) + .getResultList(); + return users == null || users.isEmpty() ? null : users.get(0); + } + + public int deleteAdobeConnectUser(IdentityRef identity) { + String q = "delete from adobeconnectuser as auser where auser.identity.key=:identityKey"; + return dbInstance.getCurrentEntityManager() + .createQuery(q) + .setParameter("identityKey", identity.getKey()) + .executeUpdate(); + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/DFNprovider.java b/src/main/java/org/olat/modules/adobeconnect/manager/DFNprovider.java new file mode 100644 index 00000000000..e37db4b44ef --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/DFNprovider.java @@ -0,0 +1,165 @@ +/** + * <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.adobeconnect.manager; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.olat.basesecurity.Authentication; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.BreezeSession; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class DFNprovider extends AbstractAdobeConnectProvider { + + private static final OLog log = Tracing.createLoggerFor(DFNprovider.class); + + @Override + public String getId() { + return "dfn"; + } + + @Override + public String getName() { + return "DFN"; + } + + @Override + public AdobeConnectPrincipal getPrincipalByLogin(String login, AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "lms-user-exists") + .queryParam("login", login); + + List<AdobeConnectPrincipal> users = null; + HttpGet get = createAdminMethod(builder, errors); + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 || statusCode == 201) { + users = parseUsers(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return users != null && !users.isEmpty() ? users.get(0) : null; + } + + @Override + public AdobeConnectPrincipal createPrincipal(Identity identity, String login, String password, AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "lms-user-create") + .queryParam("login", identity.getUser().getEmail()) + .queryParam("first-name", identity.getUser().getFirstName()) + .queryParam("last-name", identity.getUser().getLastName()); + + HttpGet get = createAdminMethod(builder, errors); + List<AdobeConnectPrincipal> users = null; + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200 || statusCode == 201) { + users = parsePrincipals(response.getEntity(), errors); + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return users != null && !users.isEmpty() ? users.get(0) : null; + } + + /** + * https://server/lmsapi/xml?action=lms-user-login + * &login=email + * &session=SessionCookie + */ + @Override + public BreezeSession commonInfo(Authentication authentication, AdobeConnectErrors errors) { + UriBuilder builder = adobeConnectModule.getAdobeConnectUriBuilder(); + builder + .queryParam("action", "lms-user-login") + .queryParam("login", authentication.getAuthusername()); + + HttpGet get = createAdminMethod(builder, errors); + BreezeSession session = null; + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + CloseableHttpResponse response = httpClient.execute(get)) { + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + session = null;//TODO adobe extract cookie + } else { + EntityUtils.consume(response.getEntity()); + } + } catch(Exception e) { + log.error("", e); + } + return session; + } + + protected List<AdobeConnectPrincipal> parseUsers(HttpEntity entity, AdobeConnectErrors errors) { + List<AdobeConnectPrincipal> users = new ArrayList<>(); + try { + Document doc = AdobeConnectDOMHelper.getDocumentFromEntity(entity); + if(AdobeConnectDOMHelper.isStatusOk(doc)) { + AdobeConnectDOMHelper.print(doc); + NodeList userList = doc.getElementsByTagName("user"); + int numOfElements = userList.getLength(); + for(int i=0; i<numOfElements; i++) { + Element userEl = (Element)userList.item(i); + AdobeConnectPrincipal user = new AdobeConnectPrincipal(); + user.setPrincipalId(userEl.getAttribute("principal-id")); + users.add(user); + } + } else { + AdobeConnectDOMHelper.print(doc); + AdobeConnectDOMHelper.error(doc, errors); + } + } catch (Exception e) { + log.error("", e); + } + return users; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/manager/NoAdapterProvider.java b/src/main/java/org/olat/modules/adobeconnect/manager/NoAdapterProvider.java new file mode 100644 index 00000000000..d77ea82a453 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/manager/NoAdapterProvider.java @@ -0,0 +1,146 @@ +/** + * <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.adobeconnect.manager; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.olat.basesecurity.Authentication; +import org.olat.core.id.Identity; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.model.AdobeConnectError; +import org.olat.modules.adobeconnect.model.AdobeConnectErrorCodes; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectPrincipal; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; +import org.olat.modules.adobeconnect.model.BreezeSession; + +/** + * This is a dummy implementation in case. + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class NoAdapterProvider implements AdobeConnectSPI { + + @Override + public String getId() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public AdobeConnectSco createScoMeeting(String name, String description, String folderScoId, String templateId, + Date startDate, Date endDate, Locale locale, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public boolean updateScoMeeting(String scoId, String name, String description, String templateId, Date startDate, + Date endDate, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return false; + } + + @Override + public AdobeConnectSco getScoMeeting(String scoId, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public boolean deleteScoMeeting(AdobeConnectMeeting meeting, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return false; + } + + @Override + public AdobeConnectSco createFolder(String name, AdobeConnectErrors errors) { + errors.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public List<AdobeConnectSco> getFolderByName(String name, AdobeConnectErrors errors) { + errors.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return new ArrayList<>(); + } + + @Override + public List<AdobeConnectSco> getTemplates() { + return new ArrayList<>(); + } + + @Override + public List<AdobeConnectSco> getRecordings(AdobeConnectMeeting meeting, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return new ArrayList<>(); + } + + @Override + public boolean setPermissions(String scoId, boolean allAccess, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return false; + } + + @Override + public boolean isMember(String scoId, String principalId, String permission, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return false; + } + + @Override + public boolean setMember(String scoId, String principalId, String permission, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return false; + } + + @Override + public AdobeConnectPrincipal getPrincipalByLogin(String login, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public AdobeConnectPrincipal createPrincipal(Identity identity, String login, String password, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public AdobeConnectPrincipal adminCommonInfo(AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } + + @Override + public BreezeSession commonInfo(Authentication authentication, AdobeConnectErrors error) { + error.append(new AdobeConnectError(AdobeConnectErrorCodes.serverNotAvailable)); + return null; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectError.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectError.java new file mode 100644 index 00000000000..3279f8d7a90 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectError.java @@ -0,0 +1,59 @@ +/** + * <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.adobeconnect.model; + +import java.io.Serializable; + +/** + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectError implements Serializable { + + private static final long serialVersionUID = 6820811247631455090L; + private AdobeConnectErrorCodes code; + private String[] arguments; + + public AdobeConnectError() { + // + } + + public AdobeConnectError(AdobeConnectErrorCodes code) { + this.code = code; + } + + public AdobeConnectErrorCodes getCode() { + return code; + } + + public void setCode(AdobeConnectErrorCodes code) { + this.code = code; + } + + public String[] getArguments() { + return arguments; + } + + public void setArguments(String[] arguments) { + this.arguments = arguments; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrorCodes.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrorCodes.java new file mode 100644 index 00000000000..c0472476227 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrorCodes.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.adobeconnect.model; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum AdobeConnectErrorCodes { + + duplicateField, + invalidField, + formatError, + illegalOperation, + missingParameter, + noSuchItem, + rangeError, + noAccessDenied, + serverNotAvailable, + + unkown + ; + +} diff --git a/src/main/java/de/bps/course/nodes/vc/VCConfiguration.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrors.java similarity index 51% rename from src/main/java/de/bps/course/nodes/vc/VCConfiguration.java rename to src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrors.java index dba386bebbb..a6e89303815 100644 --- a/src/main/java/de/bps/course/nodes/vc/VCConfiguration.java +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectErrors.java @@ -1,4 +1,3 @@ -//<OLATCE-103> /** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> @@ -15,34 +14,41 @@ * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> - * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de + * frentix GmbH, http://www.frentix.com * <p> */ -package de.bps.course.nodes.vc; +package org.olat.modules.adobeconnect.model; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; - /** * - * Description:<br> - * Each virtual classroom implementation must persist it's configuration - * by using this interface. The course node is able to differentiate for - * which implementation the stored configuration is intended (necessary to - * support multiple virtual classroom implementations in one OLAT instance). - * - * <P> - * Initial Date: 20.12.2010 <br> - * @author skoeber + * Initial date: 5 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * */ -public interface VCConfiguration extends Serializable { +public class AdobeConnectErrors implements Serializable { - public String getProviderId(); - public String getTemplateKey(); - public boolean isUseMeetingDates(); - public List<MeetingDate> getMeetingDates(); - public boolean isCreateMeetingImmediately(); - public boolean isConfigValid(); + private static final long serialVersionUID = -6676284976532851249L; + private final List<AdobeConnectError> errors = new ArrayList<>(2); + + public List<AdobeConnectError> getErrors() { + return errors; + } + + public void append(AdobeConnectErrors errors) { + if(errors.hasErrors()) { + this.errors.addAll(errors.getErrors()); + } + } + + public void append(AdobeConnectError error) { + errors.add(error); + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } } -//</OLATCE-103> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java new file mode 100644 index 00000000000..9377d6568e8 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectMeetingImpl.java @@ -0,0 +1,223 @@ +/** + * <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.adobeconnect.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.olat.core.id.Persistable; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupImpl; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="adobeconnectmeeting") +@Table(name="o_aconnect_meeting") +public class AdobeConnectMeetingImpl implements Persistable, AdobeConnectMeeting { + + private static final long serialVersionUID = -474061937981603984L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Column(name="a_name", nullable=false, insertable=true, updatable=true) + private String name; + @Column(name="a_description", nullable=true, insertable=true, updatable=true) + private String description; + @Column(name="a_start_date", nullable=true, insertable=true, updatable=true) + private Date startDate; + @Column(name="a_end_date", nullable=true, insertable=true, updatable=true) + private Date endDate; + + @Column(name="a_sco_id", nullable=true, insertable=true, updatable=false) + private String scoId; + @Column(name="a_env_name", nullable=true, insertable=true, updatable=false) + private String envName; + + @ManyToOne(targetEntity=RepositoryEntry.class, fetch=FetchType.LAZY, optional=true) + @JoinColumn(name="fk_entry_id", nullable=true, insertable=true, updatable=false) + private RepositoryEntry entry; + @Column(name="a_sub_ident", nullable=true, insertable=true, updatable=false) + private String subIdent; + + @ManyToOne(targetEntity=BusinessGroupImpl.class, fetch=FetchType.LAZY, optional=true) + @JoinColumn(name="fk_group_id", nullable=true, insertable=true, updatable=false) + private BusinessGroup businessGroup; + + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + @Override + public String getScoId() { + return scoId; + } + + public void setScoId(String scoId) { + this.scoId = scoId; + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + @Override + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date start) { + this.startDate = start; + } + + @Override + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date end) { + this.endDate = end; + } + + @Override + public String getEnvName() { + return envName; + } + + public void setEnvName(String envName) { + this.envName = envName; + } + + @Override + public RepositoryEntry getEntry() { + return entry; + } + + public void setEntry(RepositoryEntry entry) { + this.entry = entry; + } + + @Override + public String getSubIdent() { + return subIdent; + } + + public void setSubIdent(String subIdent) { + this.subIdent = subIdent; + } + + @Override + public BusinessGroup getBusinessGroup() { + return businessGroup; + } + + public void setBusinessGroup(BusinessGroup businessGroup) { + this.businessGroup = businessGroup; + } + + @Override + public int hashCode() { + return getKey() == null ? 860765 : getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof AdobeConnectMeetingImpl) { + AdobeConnectMeetingImpl meeting = (AdobeConnectMeetingImpl)obj; + return getKey() != null && getKey().equals(meeting.getKey()); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPermission.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPermission.java new file mode 100644 index 00000000000..6c262bbd0e3 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPermission.java @@ -0,0 +1,57 @@ +/** + * <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.adobeconnect.model; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectPermission { + + private String permissionId; + private String principalId; + private String aclId; + + public String getPermissionId() { + return permissionId; + } + + public void setPermissionId(String permissionId) { + this.permissionId = permissionId; + } + + public String getPrincipalId() { + return principalId; + } + + public void setPrincipalId(String principalId) { + this.principalId = principalId; + } + + public String getAclId() { + return aclId; + } + + public void setAclId(String aclId) { + this.aclId = aclId; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPrincipal.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPrincipal.java new file mode 100644 index 00000000000..9b3e16fa9fc --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectPrincipal.java @@ -0,0 +1,61 @@ +/** + * <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.adobeconnect.model; + +/** + * + * Initial date: 6 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectPrincipal { + + private String principalId; + + public String getPrincipalId() { + return principalId; + } + + public void setPrincipalId(String principalId) { + this.principalId = principalId; + } + + @Override + public int hashCode() { + return principalId == null ? 362579 : principalId.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof AdobeConnectPrincipal) { + AdobeConnectPrincipal principal = (AdobeConnectPrincipal)obj; + return principalId != null && principalId.equals(principal.principalId); + } + return false; + } + + @Override + public String toString() { + return "adobeConnectPrincipal[principalId=" + principalId + "]" + super.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java new file mode 100644 index 00000000000..efd9d45442a --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectSco.java @@ -0,0 +1,113 @@ +/** + * <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.adobeconnect.model; + +import java.util.Date; + +/** + * + * Initial date: 5 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectSco { + + private String scoId; + private String type; + private String urlPath; + private String name; + private String icon; + private Date dateCreated; + private Date dateModified; + private Date dateBegin; + private Date dateEnd; + + public String getScoId() { + return scoId; + } + + public void setScoId(String scoId) { + this.scoId = scoId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrlPath() { + return urlPath; + } + + public void setUrlPath(String urlPath) { + this.urlPath = urlPath; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public Date getDateBegin() { + return dateBegin; + } + + public void setDateBegin(Date dateBegin) { + this.dateBegin = dateBegin; + } + + public Date getDateEnd() { + return dateEnd; + } + + public void setDateEnd(Date dateEnd) { + this.dateEnd = dateEnd; + } + + public Date getDateCreated() { + return dateCreated; + } + + public void setDateCreated(Date dateCreated) { + this.dateCreated = dateCreated; + } + + public Date getDateModified() { + return dateModified; + } + + public void setDateModified(Date dateModified) { + this.dateModified = dateModified; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectUserImpl.java b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectUserImpl.java new file mode 100644 index 00000000000..52724e76e67 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/AdobeConnectUserImpl.java @@ -0,0 +1,137 @@ +/** + * <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.adobeconnect.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.olat.basesecurity.IdentityImpl; +import org.olat.core.id.Identity; +import org.olat.core.id.Persistable; +import org.olat.modules.adobeconnect.AdobeConnectUser; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="adobeconnectuser") +@Table(name="o_aconnect_user") +@NamedQuery(name="loadAdobeConnectUserByIdentity", query="select auser from adobeconnectuser as auser where auser.identity.key=:identityKey") +public class AdobeConnectUserImpl implements Persistable, AdobeConnectUser { + + private static final long serialVersionUID = -6067251741329673819L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @Column(name="a_principal_id", nullable=false, insertable=true, updatable=true) + private String principalId; + + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_identity_id", nullable=true, insertable=true, updatable=false) + private Identity identity; + + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public Date getLastModified() { + return lastModified; + } + + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + @Override + public String getPrincipalId() { + return principalId; + } + + public void setPrincipalId(String principalId) { + this.principalId = principalId; + } + + @Override + public Identity getIdentity() { + return identity; + } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + + @Override + public int hashCode() { + return getKey() == null ? -60765 : getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof AdobeConnectUserImpl) { + AdobeConnectUserImpl user = (AdobeConnectUserImpl)obj; + return getKey() != null && getKey().equals(user.getKey()); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/model/BreezeSession.java b/src/main/java/org/olat/modules/adobeconnect/model/BreezeSession.java new file mode 100644 index 00000000000..65dd160af4a --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/model/BreezeSession.java @@ -0,0 +1,71 @@ +/** + * <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.adobeconnect.model; + +import org.apache.http.Header; +import org.olat.modules.adobeconnect.manager.AbstractAdobeConnectProvider; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BreezeSession { + + private static final long EXPIRATION_NS = 5l * 60l * 1000l * 1000l * 1000l;// % Minutes in nanoseconds + + private final String cookie; + private final String session; + private final long creationTime; + + private BreezeSession(String cookie, String session) { + this.cookie = cookie; + this.session = session; + creationTime = System.nanoTime(); + } + + public String getCookie() { + return cookie; + } + + public String getSession() { + return session; + } + + public boolean isValid() { + return System.nanoTime() - creationTime < EXPIRATION_NS; + } + + /** + * BREEZESESSION=na2breezc8ewb75gvq5wdooa; HttpOnly; domain=adobeconnect.com; secure; path=/ + * @param header + * @return + */ + public static BreezeSession valueOf(Header header) { + String value = header.getValue(); + String cookie = value; + int index = cookie.indexOf(AbstractAdobeConnectProvider.COOKIE) + AbstractAdobeConnectProvider.COOKIE.length(); + int lastIndex = cookie.indexOf(';', index); + String session = cookie.substring(index, lastIndex); + return new BreezeSession(cookie, session); + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminController.java new file mode 100644 index 00000000000..78d7a5cdbcb --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminController.java @@ -0,0 +1,104 @@ +/** + * <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.adobeconnect.ui; + +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.segmentedview.SegmentViewComponent; +import org.olat.core.gui.components.segmentedview.SegmentViewEvent; +import org.olat.core.gui.components.segmentedview.SegmentViewFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; + +/** + * + * Initial date: 28 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectAdminController extends BasicController { + + private final Link meetingsLink; + private final Link configurationLink; + private final SegmentViewComponent segmentView; + private final VelocityContainer mainVC; + + private AdobeConnectConfigurationController configController; + private AdobeConnectAdminMeetingsController meetingsController; + + public AdobeConnectAdminController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + mainVC = createVelocityContainer("adobeconnect_admin"); + + segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); + configurationLink = LinkFactory.createLink("adobeconnect.account.configuration", mainVC, this); + segmentView.addSegment(configurationLink, true); + + meetingsLink = LinkFactory.createLink("meetings.title", mainVC, this); + segmentView.addSegment(meetingsLink, false); + + doOpenConfiguration(ureq); + + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(source == segmentView) { + if(event instanceof SegmentViewEvent) { + SegmentViewEvent sve = (SegmentViewEvent)event; + String segmentCName = sve.getComponentName(); + Component clickedLink = mainVC.getComponent(segmentCName); + if (clickedLink == configurationLink) { + doOpenConfiguration(ureq); + } else if (clickedLink == meetingsLink){ + doOpenMeetings(ureq); + } + } + } + } + + private void doOpenConfiguration(UserRequest ureq) { + if(configController == null) { + configController = new AdobeConnectConfigurationController(ureq, getWindowControl()); + listenTo(configController); + } + mainVC.put("segmentCmp", configController.getInitialComponent()); + } + + private void doOpenMeetings(UserRequest ureq) { + if(meetingsController == null) { + meetingsController = new AdobeConnectAdminMeetingsController(ureq, getWindowControl()); + listenTo(meetingsController); + } + mainVC.put("segmentCmp", meetingsController.getInitialComponent()); + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminMeetingsController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminMeetingsController.java new file mode 100644 index 00000000000..ad8e179cdd1 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectAdminMeetingsController.java @@ -0,0 +1,171 @@ +/** + * <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.adobeconnect.ui; + +import java.util.List; + +import org.olat.NewControllerFactory; +import org.olat.core.commons.persistence.SortKey; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions; +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.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +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.components.form.flexible.impl.elements.table.SelectionEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +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.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.util.StringHelper; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.ui.AdobeConnectMeetingTableModel.ACMeetingsCols; +import org.olat.modules.gotomeeting.ui.GoToMeetingTableModel.MeetingsCols; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 28 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectAdminMeetingsController extends FormBasicController { + + private FlexiTableElement tableEl; + private AdobeConnectMeetingTableModel tableModel; + + private DialogBoxController confirmDelete; + + @Autowired + private AdobeConnectManager adobeConnectManager; + + public AdobeConnectAdminMeetingsController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "meetings_admin"); + initForm(ureq); + updateModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.name)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.start)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.end)); + FlexiCellRenderer renderer = new StaticFlexiCellRenderer("resource", new TextFlexiCellRenderer()); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.resource.i18nHeaderKey(), ACMeetingsCols.resource.ordinal(), "resource", + true, ACMeetingsCols.resource.name(), renderer)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete")); + + tableModel = new AdobeConnectMeetingTableModel(columnsModel, getLocale()); + tableEl = uifactory.addTableElement(getWindowControl(), "meetings", tableModel, getTranslator(), formLayout); + + FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(); + sortOptions.setDefaultOrderBy(new SortKey(MeetingsCols.start.name(), false)); + tableEl.setSortSettings(sortOptions); + tableEl.setAndLoadPersistedPreferences(ureq, "adobe-connect-admin-meetings-list"); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(confirmDelete == source) { + if(DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { + AdobeConnectMeeting meeting = (AdobeConnectMeeting)confirmDelete.getUserObject(); + doDelete(meeting); + } + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(confirmDelete); + confirmDelete = null; + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(tableEl == source) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("resource".equals(se.getCommand())) { + doOpenResource(ureq, tableModel.getObject(se.getIndex())); + } else if("delete".equals(se.getCommand())) { + doConfirmDelete(ureq, tableModel.getObject(se.getIndex())); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void doDispose() { + // + } + + private void updateModel() { + List<AdobeConnectMeeting> meetings = adobeConnectManager.getAllMeetings(); + tableModel.setObjects(meetings); + tableEl.reset(true, true, true); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doOpenResource(UserRequest ureq, AdobeConnectMeeting meeting) { + if(meeting.getEntry() != null) { + String businessPath = "[RepositoryEntry:" + meeting.getEntry().getKey() + "]"; + if(StringHelper.containsNonWhitespace(meeting.getSubIdent())) { + businessPath += "[CourseNode:" + meeting.getSubIdent() + "]"; + } + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } else if(meeting.getBusinessGroup() != null) { + String businessPath = "[BusinessGroup:" + meeting.getBusinessGroup().getKey() + "]"; + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } + } + + private void doConfirmDelete(UserRequest ureq, AdobeConnectMeeting meeting) { + String confirmDeleteTitle = translate("confirm.delete.meeting.title", new String[]{ meeting.getName() }); + String confirmDeleteText = translate("confirm.delete.meeting", new String[]{ meeting.getName() }); + confirmDelete = activateYesNoDialog(ureq, confirmDeleteTitle, confirmDeleteText, confirmDelete); + confirmDelete.setUserObject(meeting); + } + + private void doDelete(AdobeConnectMeeting meeting) { + AdobeConnectErrors errors = new AdobeConnectErrors(); + adobeConnectManager.deleteMeeting(meeting, errors); + updateModel(); + if(errors.hasErrors()) { + getWindowControl().setError(AdobeConnectErrorHelper.formatErrors(getTranslator(), errors)); + } + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectConfigurationController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectConfigurationController.java new file mode 100644 index 00000000000..4fa2ce0035b --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectConfigurationController.java @@ -0,0 +1,297 @@ +/** + * <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.adobeconnect.ui; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.olat.collaboration.CollaborationToolsFactory; +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.FormLink; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; +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.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectModule; +import org.olat.modules.adobeconnect.manager.AdobeConnectSPI; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.openmeetings.manager.OpenMeetingsException; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 28 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectConfigurationController extends FormBasicController { + + private static final String PLACEHOLDER = "xxx-placeholder-xxx"; + + private FormLink checkLink; + private TextElement urlEl; + private TextElement loginEl; + private TextElement passwordEl; + private SpacerElement spacerEl; + private SingleSelection providerEl; + private MultipleSelectionElement moduleEnabled; + + private static final String[] enabledKeys = new String[]{"on"}; + private final String[] enabledValues; + + private String replacedValue; + + @Autowired + private AdobeConnectModule adobeConnectModule; + @Autowired + private AdobeConnectManager adobeConnectManager; + @Autowired + private List<AdobeConnectSPI> providers; + + public AdobeConnectConfigurationController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + enabledValues = new String[]{translate("enabled")}; + initForm(ureq); + updateUI(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + setFormTitle("adobeconnect.title"); + setFormInfo("adobeconnect.intro"); + setFormContextHelp("Communication and Collaboration#_openmeeting_config"); + + moduleEnabled = uifactory.addCheckboxesHorizontal("adobeconnect.module.enabled", formLayout, enabledKeys, enabledValues); + moduleEnabled.select(enabledKeys[0], adobeConnectModule.isEnabled()); + moduleEnabled.addActionListener(FormEvent.ONCHANGE); + + //spacer + spacerEl = uifactory.addSpacerElement("spacer", formLayout, false); + + //account configuration + String[] providerKeys = new String[providers.size()]; + String[] providerValues = new String[providers.size()]; + for(int i=providers.size(); i-->0; ) { + AdobeConnectSPI provider = providers.get(i); + providerKeys[i] = provider.getId(); + providerValues[i] = provider.getName(); + } + providerEl = uifactory.addDropdownSingleselect("adobeconnect.module.provider", formLayout, providerKeys, providerValues); + String providerId = adobeConnectModule.getProviderId(); + if(providerId != null) { + for(String providerKey:providerKeys) { + if(providerId.equals(providerKey)) { + providerEl.select(providerKey, true); + } + } + } + + URI uri = adobeConnectModule.getAdobeConnectURI(); + String uriStr = uri == null ? "" : uri.toString(); + urlEl = uifactory.addTextElement("aconnect-url", "option.baseurl", 255, uriStr, formLayout); + urlEl.setDisplaySize(60); + urlEl.setExampleKey("option.baseurl.example", null); + String login = adobeConnectModule.getAdminLogin(); + loginEl = uifactory.addTextElement("aconnect-login", "option.adminlogin", 32, login, formLayout); + String credential = adobeConnectModule.getAdminPassword(); + if(StringHelper.containsNonWhitespace(credential)) { + replacedValue = credential; + credential = PLACEHOLDER; + } + passwordEl = uifactory.addPasswordElement("aconnect-password", "option.adminpassword", 32, credential, formLayout); + passwordEl.setAutocomplete("new-password"); + + //buttons save - check + FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("save", getTranslator()); + formLayout.add(buttonLayout); + uifactory.addFormSubmitButton("save", buttonLayout); + checkLink = uifactory.addFormLink("check", buttonLayout, Link.BUTTON); + } + + @Override + protected void doDispose() { + // + } + + private void updateUI() { + boolean enabled = moduleEnabled.isAtLeastSelected(1); + checkLink.setVisible(enabled); + urlEl.setVisible(enabled); + loginEl.setVisible(enabled); + passwordEl.setVisible(enabled); + spacerEl.setVisible(enabled); + providerEl.setVisible(enabled); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = super.validateFormLogic(ureq); + + //validate only if the module is enabled + if(moduleEnabled.isAtLeastSelected(1)) { + providerEl.clearError(); + if(!providerEl.isOneSelected()) { + providerEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + allOk &= validateUrlFields(); + if(allOk) { + allOk &= validateConnection(); + } + } + + return allOk; + } + + private boolean validateUrlFields() { + boolean allOk = true; + + String url = urlEl.getValue(); + urlEl.clearError(); + if(StringHelper.containsNonWhitespace(url)) { + try { + URI uri = new URI(url); + uri.getHost(); + } catch(Exception e) { + urlEl.setErrorKey("error.url.invalid", null); + allOk &= false; + } + } else { + urlEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + String login = loginEl.getValue(); + loginEl.clearError(); + if(!StringHelper.containsNonWhitespace(login)) { + loginEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + String password = passwordEl.getValue(); + passwordEl.clearError(); + if(!StringHelper.containsNonWhitespace(password)) { + passwordEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + return allOk; + } + + private boolean validateConnection() { + boolean allOk = true; + try { + AdobeConnectErrors errors = new AdobeConnectErrors(); + boolean ok = checkConnection(errors); + if(!ok || errors.hasErrors()) { + passwordEl.setValue(""); + urlEl.setErrorKey("error.customerDoesntExist", null); + allOk &= false; + } + } catch (Exception e) { + showError(OpenMeetingsException.SERVER_NOT_I18N_KEY); + allOk &= false; + } + return allOk; + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == moduleEnabled) { + updateUI(); + } else if(source == checkLink) { + if(validateUrlFields()) { + doCheckConnection(); + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + try { + boolean enabled = moduleEnabled.isSelected(0); + adobeConnectModule.setEnabled(enabled); + // update collaboration tools list + if(enabled) { + String url = urlEl.getValue(); + adobeConnectModule.setAdobeConnectURI(new URI(url)); + adobeConnectModule.setAdminLogin(loginEl.getValue()); + adobeConnectModule.setProviderId(providerEl.getSelectedKey()); + String credential = passwordEl.getValue(); + if(!PLACEHOLDER.equals(credential)) { + adobeConnectModule.setAdminPassword(credential); + passwordEl.setValue(PLACEHOLDER); + } else if(StringHelper.containsNonWhitespace(replacedValue)) { + adobeConnectModule.setAdminPassword(replacedValue); + } + } else { + adobeConnectModule.setAdobeConnectURI(null); + adobeConnectModule.setAdminLogin(null); + adobeConnectModule.setAdminPassword(null); + } + CollaborationToolsFactory.getInstance().initAvailableTools(); + } catch (URISyntaxException e) { + logError("", e); + urlEl.setErrorKey("error.url.invalid", null); + } + } + + private void doCheckConnection() { + AdobeConnectErrors errors = new AdobeConnectErrors(); + boolean loginOk = checkConnection(errors); + if(errors.hasErrors()) { + getWindowControl().setError(AdobeConnectErrorHelper.formatErrors(getTranslator(), errors)); + } else if(loginOk) { + showInfo("connection.successful"); + } else { + showError("connection.failed"); + } + } + + private boolean checkConnection(AdobeConnectErrors errors) { + String url = urlEl.getValue(); + String login = loginEl.getValue(); + String credential = passwordEl.getValue(); + if(PLACEHOLDER.equals(credential)) { + if(StringHelper.containsNonWhitespace(replacedValue)) { + credential = replacedValue; + } else { + credential = adobeConnectModule.getAdminPassword(); + } + } else { + replacedValue = credential; + passwordEl.setValue(PLACEHOLDER); + } + return adobeConnectManager.checkConnection(url, login, credential, errors); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRedirectResource.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRedirectResource.java new file mode 100644 index 00000000000..cb8ee2849e1 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRedirectResource.java @@ -0,0 +1,103 @@ +/** + * <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.adobeconnect.ui; + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.http.HttpServletResponse; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.media.MediaResource; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectContentRedirectResource implements MediaResource { + + private static final OLog log = Tracing.createLoggerFor(AdobeConnectContentRedirectResource.class); + + private final Identity identity; + private final AdobeConnectSco sco; + + /** + * @param redirectURL + */ + public AdobeConnectContentRedirectResource(Identity identity, AdobeConnectSco sco) { + this.sco = sco; + this.identity = identity; + } + + @Override + public long getCacheControlDuration() { + return 0; + } + + @Override + public boolean acceptRanges() { + return false; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public Long getSize() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public void prepare(HttpServletResponse hres) { + try { + AdobeConnectManager adobeConnectManager = CoreSpringFactory.getImpl(AdobeConnectManager.class); + AdobeConnectErrors error = new AdobeConnectErrors(); + String redirectUrl = adobeConnectManager.linkTo(sco, identity, error); + hres.sendRedirect(redirectUrl); + } catch (IOException | IllegalStateException ise){ + log.error("redirect failedto adobe connect failed", ise); + } + } + + @Override + public void release() { + // nothing to do + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java new file mode 100644 index 00000000000..974bf271cb7 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentRow.java @@ -0,0 +1,51 @@ +/** + * <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.adobeconnect.ui; + +import org.olat.core.gui.components.form.flexible.elements.DownloadLink; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectContentRow { + + private final AdobeConnectSco sco; + private DownloadLink openLink; + + public AdobeConnectContentRow(AdobeConnectSco sco) { + this.sco = sco; + } + + public AdobeConnectSco getSco() { + return sco; + } + + public DownloadLink getOpenLink() { + return openLink; + } + + public void setOpenLink(DownloadLink openLink) { + this.openLink = openLink; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java new file mode 100644 index 00000000000..f727270899f --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectContentTableModel.java @@ -0,0 +1,108 @@ +/** + * <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.adobeconnect.ui; + +import java.util.List; +import java.util.Locale; + +import org.olat.core.commons.persistence.SortKey; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectContentTableModel extends DefaultFlexiTableDataModel<AdobeConnectContentRow> +implements SortableFlexiTableDataModel<AdobeConnectContentRow> { + + private final Locale locale; + + public AdobeConnectContentTableModel(FlexiTableColumnModel columnsModel, Locale locale) { + super(columnsModel); + this.locale = locale; + } + + @Override + public void sort(SortKey orderBy) { + if(orderBy != null) { + List<AdobeConnectContentRow> views = new SortableFlexiTableModelDelegate<AdobeConnectContentRow>(orderBy, this, locale).sort(); + super.setObjects(views); + } + } + + @Override + public Object getValueAt(int row, int col) { + AdobeConnectContentRow content = getObject(row); + return getValueAt(content, col) ; + } + + @Override + public Object getValueAt(AdobeConnectContentRow row, int col) { + switch(ACContentsCols.values()[col]) { + case icon: return row.getSco(); + case dateBegin: return row.getSco().getDateBegin(); + case type: return row.getSco().getType(); + case name: return row.getSco().getName(); + case resource: return row.getOpenLink(); + default: return "ERROR"; + } + } + + @Override + public DefaultFlexiTableDataModel<AdobeConnectContentRow> createCopyWithEmptyList() { + return new AdobeConnectContentTableModel(getTableColumnModel(), locale); + } + + public enum ACContentsCols implements FlexiSortableColumnDef { + + icon("content.icon"), + dateBegin("content.begin"), + type("content.type"), + name("content.name"), + resource("content.resource"); + + private final String i18nHeaderKey; + + private ACContentsCols(String i18nHeaderKey) { + this.i18nHeaderKey = i18nHeaderKey; + } + + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return name(); + } + + @Override + public String i18nHeaderKey() { + return i18nHeaderKey; + } + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectEditMeetingsController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectEditMeetingsController.java new file mode 100644 index 00000000000..929491e6f31 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectEditMeetingsController.java @@ -0,0 +1,228 @@ +/** + * <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.adobeconnect.ui; + +import java.util.List; + +import org.olat.core.commons.persistence.SortKey; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +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.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.components.form.flexible.impl.elements.table.SelectionEvent; +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; +import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.group.BusinessGroup; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; +import org.olat.modules.adobeconnect.ui.AdobeConnectMeetingTableModel.ACMeetingsCols; +import org.olat.modules.gotomeeting.ui.GoToMeetingTableModel.MeetingsCols; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectEditMeetingsController extends FormBasicController { + + private FlexiTableElement tableEl; + private FormLink addMeetingButton; + private AdobeConnectMeetingTableModel tableModel; + + private CloseableModalController cmc; + private DialogBoxController confirmDelete; + private EditAdobeConnectMeetingController editMeetingCtlr; + + private final boolean readOnly; + private final String subIdent; + private final RepositoryEntry entry; + private final BusinessGroup businessGroup; + private final AdobeConnectMeetingDefaultConfiguration configuration; + + @Autowired + private AdobeConnectManager adobeConnectManager; + + public AdobeConnectEditMeetingsController(UserRequest ureq, WindowControl wControl, + RepositoryEntry entry, String subIdentifier, BusinessGroup group, + AdobeConnectMeetingDefaultConfiguration configuration, boolean readOnly) { + super(ureq, wControl, "meetings_admin"); + this.readOnly = readOnly; + this.entry = entry; + this.subIdent = subIdentifier; + this.businessGroup = group; + this.configuration = configuration; + initForm(ureq); + updateModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(!readOnly) { + addMeetingButton = uifactory.addFormLink("add.meeting", formLayout, Link.BUTTON); + } + + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.name)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.start)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.end)); + if(!readOnly) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete")); + } + + tableModel = new AdobeConnectMeetingTableModel(columnsModel, getLocale()); + tableEl = uifactory.addTableElement(getWindowControl(), "meetings", tableModel, getTranslator(), formLayout); + tableEl.setEmtpyTableMessageKey("no.meeting.configured"); + + FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(); + sortOptions.setDefaultOrderBy(new SortKey(MeetingsCols.start.name(), false)); + tableEl.setSortSettings(sortOptions); + tableEl.setAndLoadPersistedPreferences(ureq, "adobe-connect-edit-meetings-list"); + } + + public void updateModel() { + List<AdobeConnectMeeting> meetings = adobeConnectManager.getMeetings(entry, subIdent, businessGroup); + tableModel.setObjects(meetings); + tableEl.reset(true, true, true); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == editMeetingCtlr) { + if(event == Event.DONE_EVENT) { + updateModel(); + } else if(event instanceof AdobeConnectErrorEvent) { + updateModel(); + showError(((AdobeConnectErrorEvent)event).getErrors()); + } + cmc.deactivate(); + cleanUp(); + } else if(confirmDelete == source) { + if(DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { + AdobeConnectMeeting meeting = (AdobeConnectMeeting)confirmDelete.getUserObject(); + doDelete(meeting); + } + cleanUp(); + } else if(cmc == source) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(editMeetingCtlr); + removeAsListenerAndDispose(confirmDelete); + removeAsListenerAndDispose(cmc); + editMeetingCtlr = null; + confirmDelete = null; + cmc = null; + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(addMeetingButton == source) { + doAddMeeting(ureq); + } else if(tableEl == source) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("edit".equals(se.getCommand())) { + doEditMeeting(ureq, tableModel.getObject(se.getIndex())); + } else if("delete".equals(se.getCommand())) { + doConfirmDelete(ureq, tableModel.getObject(se.getIndex())); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doAddMeeting(UserRequest ureq) { + if(editMeetingCtlr != null) return; + + editMeetingCtlr = new EditAdobeConnectMeetingController(ureq, getWindowControl(), entry, subIdent, businessGroup, configuration); + listenTo(editMeetingCtlr); + + cmc = new CloseableModalController(getWindowControl(), "close", editMeetingCtlr.getInitialComponent(), + true, translate("add.meeting")); + cmc.activate(); + listenTo(cmc); + } + + private void doEditMeeting(UserRequest ureq, AdobeConnectMeeting meeting) { + if(editMeetingCtlr != null) return; + + editMeetingCtlr = new EditAdobeConnectMeetingController(ureq, getWindowControl(), meeting, configuration); + listenTo(editMeetingCtlr); + + cmc = new CloseableModalController(getWindowControl(), "close", editMeetingCtlr.getInitialComponent(), + true, translate("add.meeting")); + cmc.activate(); + listenTo(cmc); + } + + private void doConfirmDelete(UserRequest ureq, AdobeConnectMeeting meeting) { + String confirmDeleteTitle = translate("confirm.delete.meeting.title", new String[]{ meeting.getName() }); + String confirmDeleteText = translate("confirm.delete.meeting", new String[]{ meeting.getName() }); + confirmDelete = activateYesNoDialog(ureq, confirmDeleteTitle, confirmDeleteText, confirmDelete); + confirmDelete.setUserObject(meeting); + } + + private void doDelete(AdobeConnectMeeting meeting) { + AdobeConnectErrors errors = new AdobeConnectErrors(); + adobeConnectManager.deleteMeeting(meeting, errors); + updateModel(); + + if(errors.hasErrors()) { + showError(errors); + } else { + showInfo("meeting.deleted"); + } + } + + private void showError(AdobeConnectErrors errors) { + getWindowControl().setError(AdobeConnectErrorHelper.formatErrors(getTranslator(), errors)); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorEvent.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorEvent.java new file mode 100644 index 00000000000..92269ce53fe --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorEvent.java @@ -0,0 +1,47 @@ +/** + * <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.adobeconnect.ui; + +import org.olat.core.gui.control.Event; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; + +/** + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectErrorEvent extends Event { + private static final long serialVersionUID = -798524427050432858L; + + private static final String ERROR = "adobe-connect-error-event"; + + private final AdobeConnectErrors errors; + + public AdobeConnectErrorEvent(AdobeConnectErrors errors) { + super(ERROR); + this.errors = errors; + } + + public AdobeConnectErrors getErrors() { + return errors; + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorHelper.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorHelper.java new file mode 100644 index 00000000000..c6b8b82a8e0 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectErrorHelper.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.adobeconnect.ui; + +import org.olat.core.gui.translator.Translator; +import org.olat.modules.adobeconnect.model.AdobeConnectError; +import org.olat.modules.adobeconnect.model.AdobeConnectErrors; + +/** + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectErrorHelper { + + public static final String formatErrors(Translator translator, AdobeConnectErrors errors) { + StringBuilder sb = new StringBuilder(1024); + sb.append(translator.translate("error.prefix")) + .append("<ul>"); + for(AdobeConnectError error:errors.getErrors()) { + sb.append("<li>") + .append(translator.translate("error." + error.getCode().name(), error.getArguments())) + .append("</li>"); + } + return sb.append("</ul>").toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectIconRenderer.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectIconRenderer.java new file mode 100644 index 00000000000..f2b583453b0 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectIconRenderer.java @@ -0,0 +1,85 @@ +/** + * <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.adobeconnect.ui; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.gui.util.CSSHelper; +import org.olat.core.util.StringHelper; +import org.olat.modules.adobeconnect.model.AdobeConnectSco; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectIconRenderer implements FlexiCellRenderer { + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator translator) { + if(cellValue instanceof String) { + String icon = getIcon((String)cellValue); + if(StringHelper.containsNonWhitespace(icon)) { + target.append("<i class='o_icon ").append(icon).append("'> </i>"); + } + } else if(cellValue instanceof AdobeConnectSco) { + String icon = getIcon((AdobeConnectSco)cellValue); + if(StringHelper.containsNonWhitespace(icon)) { + target.append("<i class='o_icon ").append(icon).append("'> </i>"); + } + } + } + + private String getIcon(AdobeConnectSco sco) { + String icon = "o_filetype_file"; + + String scoIcon = sco.getIcon(); + if("attachment".equals(scoIcon)) { + String name = sco.getName(); + if(StringHelper.containsNonWhitespace(name)) { + int lastIndex = name.lastIndexOf('.'); + if(lastIndex != -1 && lastIndex > (name.length() - 10)) { + icon = CSSHelper.createFiletypeIconCssClassFor(name); + } else if(name.startsWith("/") && name.endsWith("/")) { + icon = "o_icon_link"; + } + } + } else if(StringHelper.containsNonWhitespace(scoIcon)) { + icon = getIcon(scoIcon); + } + return icon; + } + + private String getIcon(String val) { + switch(val) { + case "producer": return "o_icon_user"; + case "folder": return "o_filetype_folder"; + case "meeting": return "o_vc_icon"; + case "archive": return "o_filetype_mp4"; + default: return "o_filetype_file"; + } + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java new file mode 100644 index 00000000000..4721bd98b57 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingController.java @@ -0,0 +1,222 @@ +/** + * <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.adobeconnect.ui; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +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.DownloadLink; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +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.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.components.link.Link; +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.media.MediaResource; +import org.olat.core.gui.media.RedirectMediaResource; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.AdobeConnectMeetingPermission; +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: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectMeetingController extends FormBasicController { + + private final boolean readOnly; + private final boolean moderator; + private final boolean administrator; + private final AdobeConnectMeeting meeting; + + private boolean registered; + + private int counter; + private Link joinButton; + private FormLink registerButton; + private FlexiTableElement contentTableEl; + private AdobeConnectContentTableModel contentModel; + + @Autowired + private AdobeConnectManager adobeConnectManager; + + public AdobeConnectMeetingController(UserRequest ureq, WindowControl wControl, + AdobeConnectMeeting meeting, boolean administrator, boolean moderator, boolean readOnly) { + super(ureq, wControl, "meeting"); + this.meeting = meeting; + this.readOnly = readOnly; + this.moderator = moderator; + this.administrator = administrator; + initForm(ureq); + + AdobeConnectErrors error = new AdobeConnectErrors(); + registered = adobeConnectManager.isRegistered(meeting, getIdentity(), getPermission(), error); + updateButtons(); + + loadModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + layoutCont.contextPut("title", meeting.getName()); + if(StringHelper.containsNonWhitespace(meeting.getDescription())) { + layoutCont.contextPut("description", meeting.getDescription()); + } + if(meeting.getStartDate() != null) { + String start = Formatter.getInstance(getLocale()).formatDateAndTime(meeting.getStartDate()); + layoutCont.contextPut("start", start); + } + if(meeting.getEndDate() != null) { + String end = Formatter.getInstance(getLocale()).formatDateAndTime(meeting.getEndDate()); + layoutCont.contextPut("end", end); + if(new Date().after(meeting.getEndDate())) { + layoutCont.contextPut("ended", Boolean.TRUE); + } + } + } + + registerButton = uifactory.addFormLink("meeting.register.button", flc, Link.BUTTON); + + joinButton = LinkFactory.createButtonLarge("meeting.join.button", flc.getFormItemComponent(), this); + joinButton.setTarget("_blank"); + + initContent(formLayout); + } + + protected void initContent(FormItemContainer formLayout) { + 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.setNumOfRowsEnabled(false); + contentTableEl.setEmtpyTableMessageKey("no.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); + } + rows.add(row); + } + contentModel.setObjects(rows); + contentTableEl.reset(true, true, true); + } + + private void updateButtons() { + registerButton.setVisible(!registered && !readOnly); + joinButton.setVisible(registered); + joinButton.setEnabled(!readOnly); + } + + @Override + protected void doDispose() { + // + } + + @Override + public void event(UserRequest ureq, Component source, Event event) { + if(joinButton == source) { + doJoin(ureq); + } + super.event(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(registerButton == source) { + doRegister(); + } + super.formInnerEvent(ureq, source, event); + } + + private void doJoin(UserRequest ureq) { + AdobeConnectErrors errors = new AdobeConnectErrors(); + String meetingUrl = adobeConnectManager.join(meeting, getIdentity(), errors); + if(errors.hasErrors()) { + getWindowControl().setError(AdobeConnectErrorHelper.formatErrors(getTranslator(), errors)); + } else { + MediaResource redirect = new RedirectMediaResource(meetingUrl); + ureq.getDispatchResult().setResultingMediaResource(redirect); + } + } + + private void doRegister() { + AdobeConnectErrors errors = new AdobeConnectErrors(); + registered = adobeConnectManager.registerFor(meeting, getIdentity(), getPermission(), errors); + if(registered) { + showInfo("meeting.successfully.registered"); + updateButtons(); + } else if(errors.hasErrors()) { + getWindowControl().setError(AdobeConnectErrorHelper.formatErrors(getTranslator(), errors)); + } else { + showInfo("meeting.registration.failed"); + } + } + + private AdobeConnectMeetingPermission getPermission() { + AdobeConnectMeetingPermission permission; + if(administrator || moderator) { + permission = AdobeConnectMeetingPermission.host; + } else { + permission = AdobeConnectMeetingPermission.view; + } + return permission; + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java new file mode 100644 index 00000000000..1b6e4cadede --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java @@ -0,0 +1,21 @@ +package org.olat.modules.adobeconnect.ui; + +/** + * + * Initial date: 23 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectMeetingDefaultConfiguration { + + private final boolean allowGuestAccess; + + public AdobeConnectMeetingDefaultConfiguration(boolean allowGuestAccess) { + this.allowGuestAccess = allowGuestAccess; + } + + public boolean isAllowGuestAccess() { + return allowGuestAccess; + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingTableModel.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingTableModel.java new file mode 100644 index 00000000000..5d9d53efc6b --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingTableModel.java @@ -0,0 +1,117 @@ +/** + * <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.adobeconnect.ui; + +import java.util.List; +import java.util.Locale; + +import org.olat.core.commons.persistence.SortKey; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectMeetingTableModel extends DefaultFlexiTableDataModel<AdobeConnectMeeting> +implements SortableFlexiTableDataModel<AdobeConnectMeeting> { + + private final Locale locale; + + public AdobeConnectMeetingTableModel(FlexiTableColumnModel columnsModel, Locale locale) { + super(columnsModel); + this.locale = locale; + } + + @Override + public void sort(SortKey orderBy) { + if(orderBy != null) { + List<AdobeConnectMeeting> views = new SortableFlexiTableModelDelegate<AdobeConnectMeeting>(orderBy, this, locale).sort(); + super.setObjects(views); + } + } + + @Override + public Object getValueAt(int row, int col) { + AdobeConnectMeeting meeting = getObject(row); + return getValueAt(meeting, col); + } + + @Override + public Object getValueAt(AdobeConnectMeeting row, int col) { + switch(ACMeetingsCols.values()[col]) { + case name: return row.getName(); + case start: return row.getStartDate(); + case end: return row.getEndDate(); + case resource: return getResourceName(row); + default: return "ERROR"; + } + } + + private String getResourceName(AdobeConnectMeeting row) { + String displayName = null; + if(row.getEntry() != null) { + displayName = row.getEntry().getDisplayname(); + } else if(row.getBusinessGroup() != null) { + displayName = row.getBusinessGroup().getName(); + } + return displayName; + } + + @Override + public DefaultFlexiTableDataModel<AdobeConnectMeeting> createCopyWithEmptyList() { + return new AdobeConnectMeetingTableModel(getTableColumnModel(), locale); + } + + public enum ACMeetingsCols implements FlexiSortableColumnDef { + + name("meeting.name"), + start("meeting.start"), + end("meeting.end"), + resource("meeting.resource"); + + private final String i18nHeaderKey; + + private ACMeetingsCols(String i18nHeaderKey) { + this.i18nHeaderKey = i18nHeaderKey; + } + + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return name(); + } + + @Override + public String i18nHeaderKey() { + return i18nHeaderKey; + } + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingsController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingsController.java new file mode 100644 index 00000000000..25807613256 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingsController.java @@ -0,0 +1,167 @@ +/** + * <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.adobeconnect.ui; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.olat.core.commons.persistence.SortKey; +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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions; +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.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.components.form.flexible.impl.elements.table.SelectionEvent; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.group.BusinessGroup; +import org.olat.modules.adobeconnect.AdobeConnectManager; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.modules.adobeconnect.ui.AdobeConnectMeetingTableModel.ACMeetingsCols; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectMeetingsController extends FormBasicController { + + private FlexiTableElement pastTableEl; + private FlexiTableElement upcomingTableEl; + private AdobeConnectMeetingTableModel pastTableModel; + private AdobeConnectMeetingTableModel upcomingTableModel; + + private final RepositoryEntry entry; + private final String subIdent; + private final BusinessGroup businessGroup; + + @Autowired + private AdobeConnectManager adobeConnectManager; + + public AdobeConnectMeetingsController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, String subIdent, + BusinessGroup businessGroup) { + super(ureq, wControl, "meetings"); + this.entry = entry; + this.subIdent = subIdent; + this.businessGroup = businessGroup; + + initForm(ureq); + updateModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // upcoming meetings table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.name)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.start)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.end)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); + + upcomingTableModel = new AdobeConnectMeetingTableModel(columnsModel, getLocale()); + upcomingTableEl = uifactory.addTableElement(getWindowControl(), "upcomingMeetings", upcomingTableModel, getTranslator(), formLayout); + upcomingTableEl.setEmtpyTableMessageKey("no.upcoming.meetings"); + + FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(); + sortOptions.setDefaultOrderBy(new SortKey(ACMeetingsCols.start.name(), false)); + upcomingTableEl.setSortSettings(sortOptions); + upcomingTableEl.setAndLoadPersistedPreferences(ureq, "adobe-connect-upcoming-meetings-list"); + + // past meetings + FlexiTableColumnModel pastColumnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.name)); + pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.start)); + pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ACMeetingsCols.end)); + pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); + + pastTableModel = new AdobeConnectMeetingTableModel(pastColumnsModel, getLocale()); + pastTableEl = uifactory.addTableElement(getWindowControl(), "pastMeetings", pastTableModel, getTranslator(), formLayout); + + FlexiTableSortOptions pastSortOptions = new FlexiTableSortOptions(); + pastSortOptions.setDefaultOrderBy(new SortKey(ACMeetingsCols.start.name(), false)); + pastTableEl.setSortSettings(pastSortOptions); + pastTableEl.setAndLoadPersistedPreferences(ureq, "adobe-connect-past-meetings-list"); + } + + @Override + protected void doDispose() { + // + } + + public void updateModel() { + List<AdobeConnectMeeting> meetings = adobeConnectManager.getMeetings(entry, subIdent, businessGroup); + + Date now = new Date(); + List<AdobeConnectMeeting> pastMeetings = new ArrayList<>(); + List<AdobeConnectMeeting> upcomingMeetings = new ArrayList<>(); + for(AdobeConnectMeeting meeting:meetings) { + if(meeting.getStartDate() == null || meeting.getEndDate() == null + || now.compareTo(meeting.getEndDate()) <= 0) { + upcomingMeetings.add(meeting); + } else { + pastMeetings.add(meeting); + } + } + + upcomingTableModel.setObjects(upcomingMeetings); + upcomingTableEl.reset(true, true, true); + pastTableModel.setObjects(pastMeetings); + pastTableEl.reset(true, true, true); + pastTableEl.setVisible(!pastMeetings.isEmpty()); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(upcomingTableEl == source) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("select".equals(se.getCommand())) { + doSelect(ureq, upcomingTableModel.getObject(se.getIndex())); + } + } + } else if(pastTableEl == source) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + if("select".equals(se.getCommand())) { + doSelect(ureq, pastTableModel.getObject(se.getIndex())); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doSelect(UserRequest ureq, AdobeConnectMeeting meeting) { + fireEvent(ureq, new SelectAdobeConnectMeetingEvent(meeting)); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectRunController.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectRunController.java new file mode 100644 index 00000000000..899fb9eba45 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectRunController.java @@ -0,0 +1,167 @@ +/** + * <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.adobeconnect.ui; + +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.segmentedview.SegmentViewComponent; +import org.olat.core.gui.components.segmentedview.SegmentViewEvent; +import org.olat.core.gui.components.segmentedview.SegmentViewFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +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.group.BusinessGroup; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 1 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectRunController extends BasicController { + + private Link adminLink; + private Link meetingsLink; + private final Link backLink; + + private final VelocityContainer mainVC; + private SegmentViewComponent segmentView; + + private AdobeConnectMeetingController meetingCtrl; + private AdobeConnectMeetingsController meetingsCtrl; + private AdobeConnectEditMeetingsController adminCtrl; + + private final String subIdent; + private final BusinessGroup group; + private final RepositoryEntry entry; + private final AdobeConnectMeetingDefaultConfiguration configuration; + + private final boolean readOnly; + private final boolean moderator; + private final boolean administrator; + + public AdobeConnectRunController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, String subIdentifier, + BusinessGroup group, AdobeConnectMeetingDefaultConfiguration configuration, boolean admin, boolean moderator, boolean readOnly) { + super(ureq, wControl); + + this.entry = entry; + this.subIdent = subIdentifier; + this.group = group; + this.configuration = configuration; + + this.administrator = admin; + this.moderator = moderator; + this.readOnly = readOnly; + + if(ureq.getUserSession().getRoles().isGuestOnly()) { + //no accessible to guests + mainVC = createVelocityContainer("run"); + } else if(administrator) { + mainVC = createVelocityContainer("run_admin"); + + segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); + meetingsLink = LinkFactory.createLink("meetings.title", mainVC, this); + segmentView.addSegment(meetingsLink, true); + + adminLink = LinkFactory.createLink("meetings.admin.title", mainVC, this); + segmentView.addSegment(adminLink, false); + + doOpenMeetings(ureq); + } else { + mainVC = createVelocityContainer("run"); + meetingsCtrl = new AdobeConnectMeetingsController(ureq, wControl, entry, subIdent, group); + listenTo(meetingsCtrl); + mainVC.put("meetings", meetingsCtrl.getInitialComponent()); + } + backLink = LinkFactory.createLinkBack(mainVC, this); + + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(backLink == source) { + mainVC.remove(meetingCtrl.getInitialComponent()); + removeAsListenerAndDispose(meetingCtrl); + meetingCtrl = null; + } else if(source == segmentView) { + if(event instanceof SegmentViewEvent) { + SegmentViewEvent sve = (SegmentViewEvent)event; + String segmentCName = sve.getComponentName(); + Component clickedLink = mainVC.getComponent(segmentCName); + if (clickedLink == meetingsLink) { + doOpenMeetings(ureq); + } else if (clickedLink == adminLink){ + doOpenAdmin(ureq); + } + } + } + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(meetingsCtrl == source) { + if(event instanceof SelectAdobeConnectMeetingEvent) { + SelectAdobeConnectMeetingEvent se = (SelectAdobeConnectMeetingEvent)event; + doSelectMeeting(ureq, se.getMeeting()); + } + } + } + + private void doOpenMeetings(UserRequest ureq) { + if(meetingsCtrl == null) { + meetingsCtrl = new AdobeConnectMeetingsController(ureq, getWindowControl(), + entry, subIdent, group); + listenTo(meetingsCtrl); + } else if(adminCtrl != null) { + meetingsCtrl.updateModel(); + } + mainVC.put("segmentCmp", meetingsCtrl.getInitialComponent()); + } + + private void doOpenAdmin(UserRequest ureq) { + if(adminCtrl == null) { + adminCtrl = new AdobeConnectEditMeetingsController(ureq, getWindowControl(), + entry, subIdent, group, configuration, readOnly); + listenTo(adminCtrl); + } + mainVC.put("segmentCmp", adminCtrl.getInitialComponent()); + } + + private void doSelectMeeting(UserRequest ureq, AdobeConnectMeeting meeting) { + removeAsListenerAndDispose(meetingCtrl); + + meetingCtrl = new AdobeConnectMeetingController(ureq, getWindowControl(), + meeting, administrator, moderator, readOnly); + listenTo(meetingCtrl); + mainVC.put("meeting", meetingCtrl.getInitialComponent()); + } +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/EditAdobeConnectMeetingController.java b/src/main/java/org/olat/modules/adobeconnect/ui/EditAdobeConnectMeetingController.java new file mode 100644 index 00000000000..bf55f5577d9 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/EditAdobeConnectMeetingController.java @@ -0,0 +1,228 @@ +/** + * <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.adobeconnect.ui; + +import java.util.Date; +import java.util.List; + +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.DateChooser; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +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.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.olat.group.BusinessGroup; +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.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class EditAdobeConnectMeetingController extends FormBasicController { + + private static final String[] permKeys = new String[] { "on" }; + + private TextElement nameEl; + private TextElement descriptionEl; + private DateChooser startDateEl; + private DateChooser endDateEl; + private MultipleSelectionElement permanentEl; + private SingleSelection templateEl; + + private final String subIdent; + private final RepositoryEntry entry; + private final BusinessGroup businessGroup; + private final AdobeConnectMeetingDefaultConfiguration configuration; + private AdobeConnectMeeting meeting; + + @Autowired + private AdobeConnectManager adobeConnectManager; + + public EditAdobeConnectMeetingController(UserRequest ureq, WindowControl wControl, + RepositoryEntry entry, String subIdent, BusinessGroup businessGroup, + AdobeConnectMeetingDefaultConfiguration configuration) { + super(ureq, wControl); + this.entry = entry; + this.subIdent = subIdent; + this.businessGroup = businessGroup; + this.configuration = configuration; + + initForm(ureq); + } + + public EditAdobeConnectMeetingController(UserRequest ureq, WindowControl wControl, + AdobeConnectMeeting meeting, AdobeConnectMeetingDefaultConfiguration configuration) { + super(ureq, wControl); + entry = meeting.getEntry(); + subIdent = meeting.getSubIdent(); + businessGroup = meeting.getBusinessGroup(); + this.meeting = meeting; + this.configuration = configuration; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String name = meeting == null ? "" : meeting.getName(); + nameEl = uifactory.addTextElement("meeting.name", "meeting.name", 128, name, formLayout); + nameEl.setMandatory(true); + String description = meeting == null ? "" : meeting.getDescription(); + descriptionEl = uifactory.addTextAreaElement("meeting.description", "meeting.description", 2000, 8, 72, false, false, description, formLayout); + + List<AdobeConnectSco> templates = adobeConnectManager.getTemplates(); + String[] theKeys = new String[templates.size() + 1]; + String[] theValues = new String[templates.size() + 1]; + theKeys[0] = ""; + theValues[0] = translate("no.template"); + for(int i=0; i<templates.size(); i++) { + AdobeConnectSco template = templates.get(i); + theKeys[i + 1] = template.getScoId(); + theValues[i + 1] = template.getName(); + } + templateEl = uifactory.addDropdownSingleselect("meeting.templates", formLayout, theKeys, theValues); + templateEl.setVisible(!templates.isEmpty()); + + String[] permValues = new String[] { translate("meeting.permanent.on") }; + permanentEl = uifactory.addCheckboxesHorizontal("meeting.permanent", formLayout, permKeys, permValues); + permanentEl.addActionListener(FormEvent.ONCHANGE); + + Date startDate = meeting == null ? null : meeting.getStartDate(); + startDateEl = uifactory.addDateChooser("meeting.start", "meeting.start", startDate, formLayout); + startDateEl.setMandatory(true); + startDateEl.setDateChooserTimeEnabled(true); + Date endDate = meeting == null ? null : meeting.getEndDate(); + endDateEl = uifactory.addDateChooser("meeting.end", "meeting.end", endDate, formLayout); + endDateEl.setMandatory(true); + endDateEl.setDefaultValue(startDateEl); + endDateEl.setDateChooserTimeEnabled(true); + + FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add("buttons", buttonLayout); + uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); + uifactory.addFormSubmitButton("ok", buttonLayout); + } + + private void updateUI() { + boolean permanent = permanentEl.isAtLeastSelected(1); + startDateEl.setVisible(!permanent); + endDateEl.setVisible(!permanent); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = super.validateFormLogic(ureq); + + nameEl.clearError(); + if(!StringHelper.containsNonWhitespace(nameEl.getValue())) { + nameEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + startDateEl.clearError(); + endDateEl.clearError(); + if(!permanentEl.isAtLeastSelected(1)) { + if(startDateEl.getDate() == null) { + startDateEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + if(endDateEl.getDate() == null) { + endDateEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + if(startDateEl.getDate() != null && endDateEl.getDate() != null) { + Date start = startDateEl.getDate(); + Date end = endDateEl.getDate(); + if(end.before(start)) { + endDateEl.setErrorKey("error.start.after.end", null); + allOk &= false; + } + } + } + + return allOk; + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(permanentEl == source) { + updateUI(); + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + AdobeConnectErrors errors = new AdobeConnectErrors(); + + Date startDate = null; + Date endDate = null; + if(!permanentEl.isAtLeastSelected(1)) { + startDate = startDateEl.getDate(); + endDate = endDateEl.getDate(); + } + String templateId = null; + if(templateEl.isVisible() && StringHelper.containsNonWhitespace(templateEl.getSelectedKey())) { + templateId = templateEl.getSelectedKey(); + } + + if(meeting == null) { + adobeConnectManager.createMeeting(nameEl.getValue(), descriptionEl.getValue(), templateId, + startDate, endDate, getLocale(), configuration.isAllowGuestAccess(), entry, subIdent, businessGroup, getIdentity(), errors); + } else { + adobeConnectManager.updateMeeting(meeting, nameEl.getValue(), descriptionEl.getValue(), + templateId, startDate, endDate, errors); + } + + if(errors.hasErrors()) { + fireEvent(ureq, new AdobeConnectErrorEvent(errors)); + } else { + fireEvent(ureq, Event.DONE_EVENT); + } + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } + + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/SelectAdobeConnectMeetingEvent.java b/src/main/java/org/olat/modules/adobeconnect/ui/SelectAdobeConnectMeetingEvent.java new file mode 100644 index 00000000000..7753baa1c2d --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/SelectAdobeConnectMeetingEvent.java @@ -0,0 +1,48 @@ +/** + * <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.adobeconnect.ui; + +import org.olat.core.gui.control.Event; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class SelectAdobeConnectMeetingEvent extends Event { + + private static final long serialVersionUID = 8960848450970463915L; + + public static final String SELECT = "select-adobeconnect-meeting"; + + private final AdobeConnectMeeting meeting; + + public SelectAdobeConnectMeetingEvent(AdobeConnectMeeting meeting) { + super(SELECT); + this.meeting = meeting; + } + + public AdobeConnectMeeting getMeeting() { + return meeting; + } + +} diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/adminconfig.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/adminconfig.html new file mode 100644 index 00000000000..3d83a46cace --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/adminconfig.html @@ -0,0 +1,6 @@ +<fieldset> + <legend>$r.contextHelpWithWrapper("Communication and Collaboration#_openmeeting_config") + $r.translate("adobeconnect.title")</legend> + <p class="o_info">$r.translate("adobeconnect.intro")</p> + $r.render("flc_module") +</fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/adobeconnect_admin.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/adobeconnect_admin.html new file mode 100644 index 00000000000..8354fa82212 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/adobeconnect_admin.html @@ -0,0 +1,7 @@ +<div class="clearfix"> + $r.render("segments")<br> + + #if($r.available("segmentCmp")) + $r.render("segmentCmp") + #end +</div> \ No newline at end of file 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 new file mode 100644 index 00000000000..ba485989428 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meeting.html @@ -0,0 +1,28 @@ +<h3>$r.escapeHtml($title)</h3> +#if($errorMessage && !${errorMessage.isEmpty()}) + <div class="o_error">$errorMessage</div> +#end +#if($r.isNotNull($start) || $r.isNotNull($end)) +<div><i class="o_icon o_icon_lifecycle_date"> </i> #if($r.isNotNull($start))$start#end - #if($r.isNotNull($end))$end#end</div> +#end +#if($description && !${description.isEmpty()}) + <div class="o_block_large o_info">$r.xssScan($description)</div> +#end +#if($r.isTrue($ended)) + <div class="o_block_large o_warning">$r.translate("meeting.ended")</div> +#end +<div class="o_button_group"> +#if($r.available("meeting.start.button") && $r.visible("meeting.start.button")) + $r.render("meeting.start.button") +#end +#if($r.available("meeting.register.button") && $r.visible("meeting.register.button")) + $r.render("meeting.register.button") +#end +#if($r.available("meeting.join.button") && $r.visible("meeting.join.button")) + $r.render("meeting.join.button") +#end +</div> +<fieldset> + <legend>$r.translate("meetings.content")</legend> + $r.render("meetingContents") +</fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings.html new file mode 100644 index 00000000000..ea913fe6bd8 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings.html @@ -0,0 +1,6 @@ +<h3>$r.translate("meetings.upcoming")</h3> +$r.render("upcomingMeetings") +#if($r.visible("pastMeetings")) + <h3>$r.translate("meetings.past")</h3> + $r.render("pastMeetings") +#end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings_admin.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings_admin.html new file mode 100644 index 00000000000..d38da72edd2 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/meetings_admin.html @@ -0,0 +1,6 @@ +#if($r.available("add.meeting")) +<div class="o_button_group o_button_group_right"> + $r.render("add.meeting") +</div> +#end +$r.render("meetings") \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/run.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/run.html new file mode 100644 index 00000000000..25de423a882 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/run.html @@ -0,0 +1,8 @@ +<div class="clearfix"> +#if($r.available("meeting")) + $r.render("backLink") + $r.render("meeting") +#else + $r.render("meetings") +#end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_content/run_admin.html b/src/main/java/org/olat/modules/adobeconnect/ui/_content/run_admin.html new file mode 100644 index 00000000000..3d9903e0f19 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_content/run_admin.html @@ -0,0 +1,11 @@ +<div class="clearfix"> +#if($r.available("meeting")) + $r.render("backLink") + $r.render("meeting") +#else + $r.render("segments") <br/> + #if($r.available("segmentCmp")) + $r.render("segmentCmp") + #end +#end +</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 new file mode 100644 index 00000000000..da4ebadeb81 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_de.properties @@ -0,0 +1,59 @@ +#Tue Apr 23 14:44:31 CEST 2019 +add.meeting=Add meeting +admin.menu.title=Adobe Connect +admin.menu.title.alt=Adobe Connect +adobeconnect.account.configuration=Konfiguration +adobeconnect.intro=Konfiguration von Adobe Connect +adobeconnect.module.enabled=Modul "Adobe Connect" +adobeconnect.module.provider=Provider +adobeconnect.title=Adobe Connect +check=Serververbindung testen +confirm.delete.meeting=Wollen Sie wirklich den Meeting "{0}" l\u00F6schen? +confirm.delete.meeting.title=Meeting "{0}" l\u00F6schen +connection.failed=Login fehlgeschlagen. +connection.successful=Login erfolgreich\! +content.begin=Beginndatum +content.icon=<i class\='o_icon o_filetype_file'> </i> +content.name=Name +content.open=\u00D6ffnen +content.resource=Ressource +content.type=Typ +error.duplicateField=Der Wert "{0}" ist schon in Einsatz. +error.formatError=Der Format von "{0}" ist nicht g\u00FCltig. +error.illegalOperation=Operation verboten +error.invalidField=Der Wert "{0}" ist nicht g\u00FCltig. +error.missingParameter=Fehlende Informationen +error.noAccessDenied=Zugang verbotten +error.noSuchItem=Existiert nicht +error.prefix=Ein Fehler ist aufgetreten\: +error.rangeError=Bereich ist nicht g\u00FCltig. +error.start.after.end=Das Datum f\u00FCr das Ende des Meetings darf nicht vor dem Beginn Datum sein. +error.unkown=Unerwartete Fehler +meeting.description=Beschreibung +meeting.end=Enddatum +meeting.ended=Meeting ist schon beendet. +meeting.join.button=Meeting beitreten +meeting.name=Name +meeting.permanent=Typ +meeting.permanent.on=Dauernd +meeting.register.button=Anmelden +meeting.resource=Resource +meeting.start=Beginndatum +meeting.start.button=Meeting starten +meeting.successfully.registered=Erfolgreich angemeldet. +meeting.templates=Vorlage +meetings.admin.title=Konfiguration +meetings.content=Inhalt +meetings.past=Alte Meetings +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.template=Keine Vorlage +no.upcoming.meetings=Sie haben kein zuk\u00FCnftige Meeting. +option.adminlogin=Benutzername +option.adminpassword=Passwort +option.baseurl=URL Adobe Connect Server +option.baseurl.example=https\://meet73287594.adobeconnect.com +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 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 new file mode 100644 index 00000000000..ea92e49e2b7 --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_en.properties @@ -0,0 +1,60 @@ +#Tue Apr 23 14:45:41 CEST 2019 +add.meeting=Add meeting +admin.menu.title=Adobe Connect +admin.menu.title.alt=Adobe Connect +adobeconnect.account.configuration=Configuration +adobeconnect.intro=Configuration of Adobe Connect +adobeconnect.module.enabled=Module "Adobe Connect" +adobeconnect.module.provider=Provider +adobeconnect.title=Adobe Connect +check=Check the connection +confirm.delete.meeting=Do you reallay want to delete the meeting "{0}"? +confirm.delete.meeting.title=Delete meeting "{0}" +connection.failed=Login failed. +connection.successful=Login successful\! +content.begin=Begin date +content.icon=<i class\='o_icon o_filetype_file'> </i> +content.name=Name +content.open=Open +content.resource=Resource +content.type=Type +error.duplicateField=The value of "{0}" is already used. +error.formatError=The format of "{0}" is not valid. +error.illegalOperation=Operation is not permitted. +error.invalidField=The value of "{0}" is not valid. +error.missingParameter=Missing informations +error.missingParameter0Fehlende=Informations +error.noAccessDenied=Access denied +error.noSuchItem=Doesn't exists +error.prefix=An error happened\: +error.rangeError=The range is not valid. +error.start.after.end=The end date of the meeting must not be before the start date. +error.unkown=Unkown error +meeting.description=Description +meeting.end=End date +meeting.ended=Meeting already ended. +meeting.join.button=Join the meeting +meeting.name=Name +meeting.permanent=Typ +meeting.permanent.on=Dauernd +meeting.register.button=Register +meeting.resource=Resource +meeting.start=Start date +meeting.start.button=Start the meeting +meeting.successfully.registered=Successfully registered. +meeting.templates=Template +meetings.admin.title=Configuration +meetings.content=Content +meetings.past=Old meetings +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.template=No template +no.upcoming.meetings=You don't have any upcoming meeting. +option.adminlogin=Username +option.adminpassword=Password +option.baseurl=URL Adobe Connect Server +option.baseurl.example=https\://meet73287594.adobeconnect.com +vc.access.open=Moderator must be in classroom to grant access to users +vc.access.start=Only moderators are allowed to open this classroom diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_fr.properties new file mode 100644 index 00000000000..1fe4b5919be --- /dev/null +++ b/src/main/java/org/olat/modules/adobeconnect/ui/_i18n/LocalStrings_fr.properties @@ -0,0 +1,7 @@ +#Tue Sep 11 18:23:17 CEST 2018 +admin.menu.title=Adobe Connect +admin.menu.title.alt=Configuration Adobe Connect +check=Tester la connection +content.icon=<i class='o_icon o_filetype_file'> </i> +error.start.after.end=La date de fin du rendez-vous ne peut se trouver avant la date de d\u00E9but. +option.baseurl.example=https://meet73287594.adobeconnect.com \ No newline at end of file diff --git a/src/main/java/org/olat/modules/gotomeeting/ui/GoToMeetingsController.java b/src/main/java/org/olat/modules/gotomeeting/ui/GoToMeetingsController.java index 64f83652b15..cc51da49dc0 100644 --- a/src/main/java/org/olat/modules/gotomeeting/ui/GoToMeetingsController.java +++ b/src/main/java/org/olat/modules/gotomeeting/ui/GoToMeetingsController.java @@ -131,7 +131,7 @@ public class GoToMeetingsController extends FormBasicController { pastTableModel.setObjects(pastMeetings); pastTableEl.reloadData(); pastTableEl.reset(); - pastTableEl.setVisible(pastMeetings.size() > 0); + pastTableEl.setVisible(!pastMeetings.isEmpty()); } @Override diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsLanguages.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsLanguages.java index ae517cb7d93..8a7ed3da75d 100644 --- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsLanguages.java +++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsLanguages.java @@ -54,8 +54,7 @@ public class OpenMeetingsLanguages extends DefaultHandler { public void read() { - try { - InputStream in = OpenMeetingsLanguages.class.getResourceAsStream("languages.xml"); + try(InputStream in = OpenMeetingsLanguages.class.getResourceAsStream("languages.xml")) { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); saxParser.parse(in, this); } catch (Exception e) { diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java index 6e5f70b43f1..b9336ec22cf 100644 --- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java +++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java @@ -76,7 +76,7 @@ import org.springframework.stereotype.Service; @Service public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDeletable, DeletableGroupData { - private final static OLog log = Tracing.createLoggerFor(OpenMeetingsManagerImpl.class); + private static final OLog log = Tracing.createLoggerFor(OpenMeetingsManagerImpl.class); @Autowired private OpenMeetingsDAO openMeetingsDao; @@ -141,7 +141,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel } } info.setNumOfUsers(numOfUsers); - realRooms.put(new Long(roomRet.getRoomId()), info); + realRooms.put(Long.valueOf(roomRet.getRoomId()), info); } } @@ -151,7 +151,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel List<OpenMeetingsRoom> rooms = new ArrayList<>(); for(OpenMeetingsRoomReference prop:props) { - Long roomId = new Long(prop.getRoomId()); + Long roomId = Long.valueOf(prop.getRoomId()); RoomReturnInfo infos = realRooms.get(roomId); if(infos != null) { OpenMeetingsRoom room = openMeetingsDao.deserializeRoom(prop.getConfig()); @@ -232,8 +232,8 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel String username = identity.getName(); String hashedUrl = userWs.setUserObjectAndGenerateRoomHashByURLAndRecFlag(sid, - username, firstname, lastname, profilePictureUrl, email, externalUserId, externalUserType, - roomId, becomeModeratorAsInt, 0, 1); + username, firstname, lastname, profilePictureUrl, email, externalUserId, externalUserType, + roomId, becomeModeratorAsInt, 0, 1); if(hashedUrl.startsWith("-") && hashedUrl.length() < 5) { throw new OpenMeetingsException(parseErrorCode(hashedUrl)); } @@ -443,7 +443,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel rec.setFilename(recording.getName()); rec.setDownloadName(recording.getFlvName()); rec.setDownloadNameAlt(recording.getAviName()); - //rec.setPreviewImage(recording.getPreviewImage()); + // preview image? rec.setWidth(recording.getWidth()); rec.setHeight(recording.getHeight()); recList.add(rec); diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsConfigurationController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsConfigurationController.java index 15442318838..aa5d5160559 100644 --- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsConfigurationController.java +++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsConfigurationController.java @@ -61,7 +61,7 @@ public class OpenMeetingsConfigurationController extends FormBasicController { private MultipleSelectionElement moduleEnabled; private static final String[] enabledKeys = new String[]{"on"}; - private String[] enabledValues; + private final String[] enabledValues; private String replacedValue; @@ -150,7 +150,7 @@ public class OpenMeetingsConfigurationController extends FormBasicController { @Override protected boolean validateFormLogic(UserRequest ureq) { - boolean allOk = true; + boolean allOk = super.validateFormLogic(ureq); //validate only if the module is enabled if(openMeetingsModule.isEnabled()) { @@ -179,7 +179,7 @@ public class OpenMeetingsConfigurationController extends FormBasicController { } } - return allOk && super.validateFormLogic(ureq); + return allOk; } private boolean validateURL() { diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java index e9099b34c30..52ba57d01c3 100644 --- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java +++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java @@ -19,7 +19,6 @@ */ package org.olat.modules.openmeetings.ui; -import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.download.DisplayOrDownloadComponent; @@ -39,6 +38,7 @@ import org.olat.modules.openmeetings.OpenMeetingsModule; import org.olat.modules.openmeetings.manager.OpenMeetingsException; import org.olat.modules.openmeetings.manager.OpenMeetingsManager; import org.olat.modules.openmeetings.model.OpenMeetingsRoom; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -64,12 +64,14 @@ public class OpenMeetingsRunController extends BasicController { private final boolean moderator; private final boolean readOnly; private OpenMeetingsRoom room; - private final OpenMeetingsModule openMeetingsModule; - private final OpenMeetingsManager openMeetingsManager; - private final BusinessGroup group; private final OLATResourceable ores; private final String subIdentifier; + + @Autowired + private OpenMeetingsModule openMeetingsModule; + @Autowired + private OpenMeetingsManager openMeetingsManager; public OpenMeetingsRunController(UserRequest ureq, WindowControl wControl, BusinessGroup group, OLATResourceable ores, String subIdentifier, boolean admin, boolean moderator, boolean readOnly) { @@ -82,9 +84,6 @@ public class OpenMeetingsRunController extends BasicController { this.ores = ores; this.subIdentifier = subIdentifier; - openMeetingsModule = CoreSpringFactory.getImpl(OpenMeetingsModule.class); - openMeetingsManager = CoreSpringFactory.getImpl(OpenMeetingsManager.class); - try { room = openMeetingsManager.getRoom(group, ores, subIdentifier); } catch (OpenMeetingsException e) { diff --git a/src/main/java/org/olat/modules/openmeetings/ui/_content/adminconfig.html b/src/main/java/org/olat/modules/openmeetings/ui/_content/adminconfig.html index b9debfc84ca..aedfb5a27bd 100644 --- a/src/main/java/org/olat/modules/openmeetings/ui/_content/adminconfig.html +++ b/src/main/java/org/olat/modules/openmeetings/ui/_content/adminconfig.html @@ -1,7 +1,6 @@ <fieldset> - <legend>$r.translate("openmeetings.title")</legend> - $r.contextHelpWithWrapper("Communication and Collaboration#_openmeeting_config") - <p>$r.translate("openmeetings.intro")</p> - + <legend>$r.contextHelpWithWrapper("Communication and Collaboration#_openmeeting_config") + $r.translate("openmeetings.title")</legend> + <p class="o_info">$r.translate("openmeetings.intro")</p> $r.render("flc_module") </fieldset> \ No newline at end of file diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index f19d1a7eba2..25362b7527b 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -164,6 +164,8 @@ <class>org.olat.ims.qti21.model.jpa.AssessmentTestSessionImpl</class> <class>org.olat.ims.qti21.model.jpa.AssessmentTestSessionExtraTime</class> <class>org.olat.ims.qti21.model.jpa.AssessmentTestMarksImpl</class> + <class>org.olat.modules.adobeconnect.model.AdobeConnectUserImpl</class> + <class>org.olat.modules.adobeconnect.model.AdobeConnectMeetingImpl</class> <class>org.olat.modules.assessment.model.AssessmentEntryImpl</class> <class>org.olat.modules.curriculum.model.CurriculumImpl</class> <class>org.olat.modules.curriculum.model.CurriculumElementImpl</class> @@ -269,7 +271,7 @@ <property name="hibernate.query.in_clause_parameter_padding" value="true"/> <property name="hibernate.connection.handling_mode" value="DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION"/> <property name="hibernate.session_factory.interceptor" value="org.olat.core.commons.persistence.AuditInterceptor"/> - <property name="jboss.as.jpa.providerModule" value="org.hibernate:5.3" /> + <property name="jboss.as.jpa.providerModule" value="org.hibernate:5.4" /> </properties> </persistence-unit> </persistence> \ No newline at end of file diff --git a/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql index 287f79d51e0..f30e238953e 100644 --- a/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql +++ b/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql @@ -109,4 +109,39 @@ alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_meta alter table o_vfs_metadata add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id); +-- Adobe Connect +create table o_aconnect_meeting ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date datetime default null, + a_end_date datetime default null, + fk_entry_id bigint default null, + a_sub_ident varchar(64) default null, + fk_group_id bigint default null, + primary key (id) +); + +alter table o_aconnect_meeting ENGINE = InnoDB; + +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); + + +create table o_aconnect_user ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_principal_id varchar(128) default null, + fk_identity_id bigint default null, + primary key (id) +); + +alter table o_aconnect_user ENGINE = InnoDB; + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 316c90da8b1..832550bbfbf 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -1155,6 +1155,32 @@ create table if not exists o_om_room_reference ( primary key (id) ); +-- Adobe Connect +create table o_aconnect_meeting ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date datetime default null, + a_end_date datetime default null, + fk_entry_id bigint default null, + a_sub_ident varchar(64) default null, + fk_group_id bigint default null, + primary key (id) +); + +create table o_aconnect_user ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + a_principal_id varchar(128) default null, + fk_identity_id bigint default null, + primary key (id) +); + -- assessment tables -- efficiency statments create table if not exists o_as_eff_statement ( @@ -3078,6 +3104,8 @@ alter table o_qp_edu_context ENGINE = InnoDB; alter table o_qp_item_type ENGINE = InnoDB; alter table o_qp_license ENGINE = InnoDB; alter table o_om_room_reference ENGINE = InnoDB; +alter table o_aconnect_meeting ENGINE = InnoDB; +alter table o_aconnect_user ENGINE = InnoDB; alter table o_im_message ENGINE = InnoDB; alter table o_im_notification ENGINE = InnoDB; alter table o_im_roster_entry ENGINE = InnoDB; @@ -3443,6 +3471,12 @@ create index o_co_db_name_idx on o_co_db_entry (name); alter table o_om_room_reference add constraint idx_omroom_to_bgroup foreign key (businessgroup) references o_gp_business (group_id); create index idx_omroom_residname on o_om_room_reference (resourcetypename,resourcetypeid); +-- Adobe Connect +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); + -- eportfolio alter table o_ep_artefact add constraint FKF26C8375236F28X foreign key (fk_artefact_auth_id) references o_bs_identity (id); alter table o_ep_artefact add constraint FKA0070D12316A97B4 foreign key (fk_struct_el_id) references o_ep_struct_el (structure_id); diff --git a/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql index bf49110c71f..44890b4de61 100644 --- a/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql +++ b/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql @@ -110,3 +110,37 @@ alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_ create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type); +-- Adobe Connect +create table o_aconnect_meeting ( + id number(20) generated always as identity, + creationdate timestamp not null, + lastmodified timestamp not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date timestamp default null, + a_end_date timestamp default null, + fk_entry_id number(20) default null, + a_sub_ident varchar(64) default null, + fk_group_id number(20) default null, + primary key (id) +); + +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +create index idx_aconnect_meet_entry_idx on o_aconnect_meeting(fk_entry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); +create index idx_aconnect_meet_grp_idx on o_aconnect_meeting(fk_group_id); + + +create table o_aconnect_user ( + id number(20) generated always as identity, + creationdate timestamp not null, + lastmodified timestamp not null, + a_principal_id varchar(128) default null, + fk_identity_id number(20) default null, + primary key (id) +); + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); +create index idx_aconn_ident_idx on o_aconnect_user (fk_identity_id); diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index 4ffb6191c37..1468d5c37d4 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -1221,6 +1221,31 @@ create table o_om_room_reference ( primary key (id) ); +create table o_aconnect_meeting ( + id number(20) generated always as identity, + creationdate timestamp not null, + lastmodified timestamp not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date timestamp default null, + a_end_date timestamp default null, + fk_entry_id number(20) default null, + a_sub_ident varchar(64) default null, + fk_group_id number(20) default null, + primary key (id) +); + +create table o_aconnect_user ( + id number(20) generated always as identity, + creationdate timestamp not null, + lastmodified timestamp not null, + a_principal_id varchar(128) default null, + fk_identity_id number(20) default null, + primary key (id) +); + create table o_as_eff_statement ( id number(20) not null, version number(20) not null, @@ -3475,6 +3500,15 @@ alter table o_om_room_reference add constraint idx_omroom_to_bgroup foreign key create index idx_omroom_group_idx on o_om_room_reference (businessgroup); create index idx_omroom_residname on o_om_room_reference (resourcetypename,resourcetypeid); +-- Adobe Connect +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +create index idx_aconnect_meet_entry_idx on o_aconnect_meeting(fk_entry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); +create index idx_aconnect_meet_grp_idx on o_aconnect_meeting(fk_group_id); + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); +create index idx_aconn_ident_idx on o_aconnect_user (fk_identity_id); + -- eportfolio alter table o_ep_artefact add constraint FKF26C8375236F28X foreign key (fk_artefact_auth_id) references o_bs_identity (id); create index idx_artfeact_to_auth_idx on o_ep_artefact (fk_artefact_auth_id); diff --git a/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql index e69b68d3410..d5ef3476749 100644 --- a/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql +++ b/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql @@ -111,5 +111,37 @@ alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_ create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type); +-- Adobe Connect +create table o_aconnect_meeting ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date timestamp default null, + a_end_date timestamp default null, + fk_entry_id int8 default null, + a_sub_ident varchar(64) default null, + fk_group_id int8 default null, + primary key (id) +); + +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +create index idx_aconnect_meet_entry_idx on o_aconnect_meeting(fk_entry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); +create index idx_aconnect_meet_grp_idx on o_aconnect_meeting(fk_group_id); +create table o_aconnect_user ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_principal_id varchar(128) default null, + fk_identity_id int8 default null, + primary key (id) +); + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); +create index idx_aconn_ident_idx on o_aconnect_user (fk_identity_id); diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index 9c885797eac..18495db4a0b 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -1180,6 +1180,32 @@ create table o_om_room_reference ( primary key (id) ); +-- Adobe Connect +create table o_aconnect_meeting ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_sco_id varchar(128) default null, + a_env_name varchar(128) default null, + a_name varchar(128) not null, + a_description varchar(2000) default null, + a_start_date timestamp default null, + a_end_date timestamp default null, + fk_entry_id int8 default null, + a_sub_ident varchar(64) default null, + fk_group_id int8 default null, + primary key (id) +); + +create table o_aconnect_user ( + id bigserial, + creationdate timestamp not null, + lastmodified timestamp not null, + a_principal_id varchar(128) default null, + fk_identity_id int8 default null, + primary key (id) +); + -- efficiency statments create table o_as_eff_statement ( id int8 not null, @@ -3364,11 +3390,20 @@ create index o_co_db_course_idx on o_co_db_entry (courseid); create index o_co_db_cat_idx on o_co_db_entry (category); create index o_co_db_name_idx on o_co_db_entry (name); --- open meeting +-- openmeeting alter table o_om_room_reference add constraint idx_omroom_to_bgroup foreign key (businessgroup) references o_gp_business (group_id); create index idx_omroom_group_idx on o_om_room_reference (businessgroup); create index idx_omroom_residname on o_om_room_reference (resourcetypename,resourcetypeid); +-- Adobe Connect +alter table o_aconnect_meeting add constraint aconnect_meet_entry_idx foreign key (fk_entry_id) references o_repositoryentry (repositoryentry_id); +create index idx_aconnect_meet_entry_idx on o_aconnect_meeting(fk_entry_id); +alter table o_aconnect_meeting add constraint aconnect_meet_grp_idx foreign key (fk_group_id) references o_gp_business (group_id); +create index idx_aconnect_meet_grp_idx on o_aconnect_meeting(fk_group_id); + +alter table o_aconnect_user add constraint aconn_ident_idx foreign key (fk_identity_id) references o_bs_identity (id); +create index idx_aconn_ident_idx on o_aconnect_user (fk_identity_id); + -- eportfolio alter table o_ep_artefact add constraint FKF26C8375236F28X foreign key (fk_artefact_auth_id) references o_bs_identity (id); create index idx_artfeact_to_auth_idx on o_ep_artefact (fk_artefact_auth_id); diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index ddb685524f8..0e7ff220cc1 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -1390,37 +1390,13 @@ vc.adobe.enabled=false vc.adobe.protocol=http vc.adobe.port=80 vc.adobe.baseurl=localhost -vc.adobe.adminlogin=login -vc.adobe.adminpassword=pass -#account-id is optional -vc.adobe.accountid=7410 -vc.adobe.showoptions=true +# The account used is defined by the following admin. account +vc.adobe.adminlogin= +vc.adobe.adminpassword= #The type of user accounts -vc.adobe.usertype=user -vc.adobe.usertype.values=guest,user - -vc.adobe.daysToKeep=1 -vc.adobe.cleanupMeetings=true -vc.adobe.cleanupModerators=false -vc.adobe.createMeetingImmediately=false +vc.adobe.providerid=connect9 +vc.adobe.providerid.values=connect9,dfn vc.adobe.guestAccessAllowed=true -vc.adobe.guestStartMeetingAllowed=true -vc.adobe.useMeetingDates=false - -vc.template.name.0=Standardmeetingvorlage -vc.template.key.0=4711 -vc.template.name.1=Standardmeetingvorlage 2 -vc.template.key.1=4712 -vc.template.name.2=Standardmeetingvorlage 3 -vc.template.key.2=4713 - -#Winba -vc.wimba.enabled=false -vc.wimba.protocol=http -vc.wimba.port=80 -vc.wimba.baseurl=localhost -vc.wimba.adminlogin=admin -vc.wimba.adminpassword=password #Vitero vc.vitero.enabled=false diff --git a/src/test/java/org/olat/core/util/EncoderTest.java b/src/test/java/org/olat/core/util/EncoderTest.java index e0180c0ad67..743ea48553e 100644 --- a/src/test/java/org/olat/core/util/EncoderTest.java +++ b/src/test/java/org/olat/core/util/EncoderTest.java @@ -19,11 +19,13 @@ */ package org.olat.core.util; +import java.security.Security; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.Assert; import org.junit.Test; import org.olat.core.commons.services.webdav.manager.WebDAVManagerImpl; @@ -37,6 +39,10 @@ import org.olat.core.util.Encoder.Algorithm; */ public class EncoderTest { + static { + Security.insertProviderAt(new BouncyCastleProvider(), 1); + } + @Test public void testCompatibility() { //the openolat password as saved on our database @@ -119,6 +125,30 @@ public class EncoderTest { Assert.assertEquals(hash, shaOutput); } + @Test + public void testAes() { + String password = "openolat#19"; + String key = "6afs6873l--q3ruiah"; + String salt = "Y4nY4VFWaiSnM6qe88ZxbQ=="; + int iteration = 2000; + + String aesOutput = Encoder.encodeAes(password, key, salt, iteration); + Assert.assertNotNull(aesOutput); + String decodedPassword = Encoder.decodeAes(aesOutput, key, salt, iteration); + Assert.assertEquals(password, decodedPassword); + } + + @Test + public void testAes_alt() { + String password = "openolat#19"; + String salt = "Y4nY4VFWaiSnM6qe88ZxbQ=="; + + String aesOutput = Encoder.encrypt(password, salt, Algorithm.aes); + Assert.assertNotNull(aesOutput); + String decodedPassword = Encoder.decrypt(aesOutput, salt, Algorithm.aes); + Assert.assertEquals(password, decodedPassword); + } + @Test public void testPBKDF2() { String password = "openolat#19"; diff --git a/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAOTest.java b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAOTest.java new file mode 100644 index 00000000000..8e681231524 --- /dev/null +++ b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectMeetingDAOTest.java @@ -0,0 +1,149 @@ +/** + * <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.adobeconnect.manager; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.group.BusinessGroup; +import org.olat.group.manager.BusinessGroupDAO; +import org.olat.modules.adobeconnect.AdobeConnectMeeting; +import org.olat.repository.RepositoryEntry; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectMeetingDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private BusinessGroupDAO businessGroupDao; + @Autowired + private AdobeConnectMeetingDAO adobeConnectMeetingDao; + + @Test + public void createMeeting() { + AdobeConnectMeeting meeting = adobeConnectMeetingDao.createMeeting("New meeting", "Very interessant", new Date(), new Date(), "sco-id", "DFN", null, null, null); + dbInstance.commit(); + Assert.assertNotNull(meeting); + Assert.assertNotNull(meeting.getKey()); + Assert.assertNotNull(meeting.getCreationDate()); + Assert.assertNotNull(meeting.getLastModified()); + Assert.assertEquals("sco-id", meeting.getScoId()); + Assert.assertEquals("DFN", meeting.getEnvName()); + Assert.assertEquals("New meeting", meeting.getName()); + Assert.assertEquals("Very interessant", meeting.getDescription()); + Assert.assertNotNull(meeting.getStartDate()); + Assert.assertNotNull(meeting.getEndDate()); + } + + @Test + public void createMeeting_courseLike() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + String subIdent = UUID.randomUUID().toString(); + + AdobeConnectMeeting meeting = adobeConnectMeetingDao.createMeeting("Course meeting", "Annoying", new Date(), new Date(), "sco-id", "DFN", entry, subIdent, null); + dbInstance.commit(); + Assert.assertNotNull(meeting); + Assert.assertNotNull(meeting.getKey()); + Assert.assertNotNull(meeting.getCreationDate()); + Assert.assertNotNull(meeting.getLastModified()); + Assert.assertEquals("sco-id", meeting.getScoId()); + Assert.assertEquals("DFN", meeting.getEnvName()); + Assert.assertEquals("Course meeting", meeting.getName()); + Assert.assertEquals("Annoying", meeting.getDescription()); + Assert.assertNotNull(meeting.getStartDate()); + Assert.assertNotNull(meeting.getEndDate()); + Assert.assertEquals(entry, meeting.getEntry()); + Assert.assertEquals(subIdent, meeting.getSubIdent()); + Assert.assertNull(meeting.getBusinessGroup()); + } + + @Test + public void loadByKey() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + String subIdent = UUID.randomUUID().toString(); + + AdobeConnectMeeting meeting = adobeConnectMeetingDao.createMeeting("Key meeting", "Primary", new Date(), new Date(), "sco-pid", null, entry, subIdent, null); + dbInstance.commitAndCloseSession(); + + // load the meeting + AdobeConnectMeeting reloadedMeeting = adobeConnectMeetingDao.loadByKey(meeting.getKey()); + // check + Assert.assertNotNull(reloadedMeeting); + Assert.assertNotNull(reloadedMeeting.getKey()); + Assert.assertNotNull(reloadedMeeting.getCreationDate()); + Assert.assertNotNull(reloadedMeeting.getLastModified()); + Assert.assertEquals("sco-pid", reloadedMeeting.getScoId()); + Assert.assertNull(meeting.getEnvName()); + Assert.assertEquals("Key meeting", meeting.getName()); + Assert.assertEquals("Primary", meeting.getDescription()); + Assert.assertNotNull(meeting.getStartDate()); + Assert.assertNotNull(meeting.getEndDate()); + Assert.assertEquals(entry, meeting.getEntry()); + Assert.assertEquals(subIdent, meeting.getSubIdent()); + Assert.assertNull(meeting.getBusinessGroup()); + } + + @Test + public void getMeetings_repositoryEntry() { + RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry(); + String subIdent = UUID.randomUUID().toString(); + + AdobeConnectMeeting meeting1 = adobeConnectMeetingDao.createMeeting("Course A", "Primary", new Date(), new Date(), "sco-cid-1", null, entry, subIdent, null); + AdobeConnectMeeting meeting2 = adobeConnectMeetingDao.createMeeting("Course A", "Primary", new Date(), new Date(), "sco-cid-2", null, entry, subIdent, null); + dbInstance.commitAndCloseSession(); + + // load meetings + List<AdobeConnectMeeting> meetings = adobeConnectMeetingDao.getMeetings(entry, subIdent); + Assert.assertEquals(2, meetings.size()); + Assert.assertTrue(meetings.contains(meeting1)); + Assert.assertTrue(meetings.contains(meeting2)); + } + + @Test + public void getMeetings_businessGroup() { + BusinessGroup group = businessGroupDao.createAndPersist(null, "Connected group", "Adobe connected group", -1, -1, false, false, false, false, false); + dbInstance.commit(); + + AdobeConnectMeeting meeting1 = adobeConnectMeetingDao.createMeeting("Course A", "Primary", new Date(), new Date(), "sco-cid-1", null, null, null, group); + AdobeConnectMeeting meeting2 = adobeConnectMeetingDao.createMeeting("Course A", "Primary", new Date(), new Date(), "sco-cid-2", null, null, null, group); + dbInstance.commitAndCloseSession(); + + // load meetings + List<AdobeConnectMeeting> meetings = adobeConnectMeetingDao.getMeetings(group); + Assert.assertEquals(2, meetings.size()); + Assert.assertTrue(meetings.contains(meeting1)); + Assert.assertTrue(meetings.contains(meeting2)); + } + + +} diff --git a/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectProviderTest.java b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectProviderTest.java new file mode 100644 index 00000000000..1146fb3195d --- /dev/null +++ b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectProviderTest.java @@ -0,0 +1,47 @@ +/** + * <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.adobeconnect.manager; + +import java.util.Calendar; +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; + +/** + * + * Initial date: 18 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectProviderTest { + + @Test + public void parseDate() { + String dateStr = "2019-04-18T12:28:28.587+02:00"; + Date date = AbstractAdobeConnectProvider.parseIsoDate(dateStr); + Assert.assertNotNull(date); + + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + Assert.assertEquals(12, cal.get(Calendar.HOUR_OF_DAY)); + } + +} diff --git a/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAOTest.java b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAOTest.java new file mode 100644 index 00000000000..5c45928d919 --- /dev/null +++ b/src/test/java/org/olat/modules/adobeconnect/manager/AdobeConnectUserDAOTest.java @@ -0,0 +1,98 @@ +/** + * <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.adobeconnect.manager; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.core.util.CodeHelper; +import org.olat.modules.adobeconnect.AdobeConnectUser; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + + +/** + * + * Initial date: 17 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AdobeConnectUserDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private AdobeConnectUserDAO adobeConnectUserDao; + + @Test + public void createAdobeConnectUser() { + String principalId = String.valueOf(CodeHelper.getForeverUniqueID()); + Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("aconnect-1"); + AdobeConnectUser user = adobeConnectUserDao.createUser(principalId, identity); + dbInstance.commitAndCloseSession(); + + Assert.assertNotNull(user); + Assert.assertEquals(identity, user.getIdentity()); + Assert.assertEquals(principalId, user.getPrincipalId()); + } + + @Test + public void getAdobeConnectUser() { + String principalId = String.valueOf(CodeHelper.getForeverUniqueID()); + Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("aconnect-1"); + AdobeConnectUser user = adobeConnectUserDao.createUser(principalId, identity); + dbInstance.commitAndCloseSession(); + + AdobeConnectUser loadedUser = adobeConnectUserDao.getUser(identity); + + Assert.assertNotNull(loadedUser); + Assert.assertEquals(identity, loadedUser.getIdentity()); + Assert.assertEquals(principalId, loadedUser.getPrincipalId()); + Assert.assertEquals(user, loadedUser); + } + + @Test + public void deleteAdobeConnectUser() { + // create 2 users + String principalId1 = String.valueOf(CodeHelper.getForeverUniqueID()); + Identity identity1 = JunitTestHelper.createAndPersistIdentityAsRndUser("aconnect-3"); + AdobeConnectUser user1 = adobeConnectUserDao.createUser(principalId1, identity1); + + String principalId2 = String.valueOf(CodeHelper.getForeverUniqueID()); + Identity identity2 = JunitTestHelper.createAndPersistIdentityAsRndUser("aconnect-4"); + AdobeConnectUser user2 = adobeConnectUserDao.createUser(principalId2, identity2); + dbInstance.commitAndCloseSession(); + Assert.assertNotNull(user1); + Assert.assertNotNull(user2); + + // delete data of user 1 + int rows = adobeConnectUserDao.deleteAdobeConnectUser(identity1); + Assert.assertEquals(1, rows); + + // check user 1 + AdobeConnectUser loadedUser1 = adobeConnectUserDao.getUser(identity1); + Assert.assertNull(loadedUser1); + // check user 2 has not lost its adobe connect principal + AdobeConnectUser loadedUser2 = adobeConnectUserDao.getUser(identity2); + Assert.assertNotNull(loadedUser2); + } +} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 7b19e86cb2f..22a107041e6 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -187,6 +187,9 @@ import org.junit.runners.Suite; org.olat.course.groupsandrights.CourseGroupManagementTest.class, org.olat.course.editor.PublishProcessTest.class, org.olat.course.CourseXStreamAliasesTest.class, + org.olat.modules.adobeconnect.manager.AdobeConnectProviderTest.class, + org.olat.modules.adobeconnect.manager.AdobeConnectUserDAOTest.class, + org.olat.modules.adobeconnect.manager.AdobeConnectMeetingDAOTest.class, org.olat.modules.iq.IQManagerTest.class, org.olat.modules.fo.ForumManagerTest.class,//fail org.olat.modules.wiki.WikiUnitTest.class, -- GitLab