diff --git a/api/src/java/org/sakaiproject/bbb/api/BBBMeetingManager.java b/api/src/java/org/sakaiproject/bbb/api/BBBMeetingManager.java index c002735e..4265d3c2 100644 --- a/api/src/java/org/sakaiproject/bbb/api/BBBMeetingManager.java +++ b/api/src/java/org/sakaiproject/bbb/api/BBBMeetingManager.java @@ -68,6 +68,8 @@ public interface BBBMeetingManager { public final static String CFG_GROUPSESSIONS_DEFAULT = "bbb.groupsessions.default"; public final static String CFG_RECORDINGSTATS_ENABLED = "bbb.recordingstats.enabled"; public final static String CFG_RECORDINGSTATS_USERID = "bbb.recordingstats.userid"; + public final static String CFG_RECORDINGFORMATFILTER_ENABLED = "bbb.recordingformatfilter.enabled"; + public final static String CFG_RECORDINGFORMATFILTER_WHITELIST = "bbb.recordingformatfilter.whitelist"; // Permissions public static final String FN_PREFIX = "bbb."; @@ -82,10 +84,13 @@ public interface BBBMeetingManager { public static final String FN_RECORDING_EDIT_ANY = "bbb.recording.edit.any"; public static final String FN_RECORDING_DELETE_OWN = "bbb.recording.delete.own"; public static final String FN_RECORDING_DELETE_ANY = "bbb.recording.delete.any"; + public static final String FN_RECORDING_EXTENDEDFORMATS_OWN = "bbb.recording.extendedformats.own"; + public static final String FN_RECORDING_EXTENDEDFORMATS_ANY = "bbb.recording.extendedformats.any"; public static final String[] FUNCTIONS = new String[] { FN_CREATE, FN_EDIT_OWN, FN_EDIT_ANY, FN_DELETE_OWN, FN_DELETE_ANY, FN_PARTICIPATE, FN_RECORDING_VIEW, FN_RECORDING_EDIT_OWN, FN_RECORDING_EDIT_ANY, - FN_RECORDING_DELETE_OWN, FN_RECORDING_DELETE_ANY }; + FN_RECORDING_DELETE_OWN, FN_RECORDING_DELETE_ANY, + FN_RECORDING_EXTENDEDFORMATS_OWN, FN_RECORDING_EXTENDEDFORMATS_ANY }; // Extra function used to enable admin interface in the client public static final String FN_ADMIN = "bbb.admin"; @@ -175,7 +180,7 @@ public Map getMeetingInfo(String meetingID, String groupId) /** * Get playback recordings from BBB server. */ - public Map getRecordings(String meetingID, String groupId) + public Map getRecordings(String meetingID, String groupId, String siteId) throws BBBException; /** @@ -375,4 +380,7 @@ public String getJoinUrl(BBBMeeting meeting, User user) public List getUserGroupIdsInSite(String userId, String siteId); + public boolean isRecordingFormatFilterEnabled(); + + public String getRecordingFormatFilterWhitelist(); } diff --git a/bundle/src/resources/ToolMessages.properties b/bundle/src/resources/ToolMessages.properties index ff4cbc4a..0581dfa8 100644 --- a/bundle/src/resources/ToolMessages.properties +++ b/bundle/src/resources/ToolMessages.properties @@ -61,7 +61,11 @@ bbb_recording_status_hidden = Unpublished bbb_recording_status_shown = Published bbb_recording_thumbnails_hidden = Only for published recordings bbb_recording_type.presentation = Presentation +bbb_recording_type.video = Video +bbb_recording_type.statistics = Statistics bbb_recording_view_tooltip.presentation = View the presentation +bbb_recording_view_tooltip.video = View the video +bbb_recording_view_tooltip.statistics = View the statistics ##################################### @@ -160,6 +164,8 @@ bbb_permissions_recordings_edit_own = Edit own recordings bbb_permissions_recordings_edit_any = Edit any recordings bbb_permissions_recordings_delete_own = Delete own recordings bbb_permissions_recordings_delete_any = Delete any recordings +bbb_permissions_recordings_extendedformats_own = View extended formats in own recordings +bbb_permissions_recordings_extendedformats_any = View extended formats in any recordings ##################################### diff --git a/bundle/src/resources/ToolMessages_ca_ES.properties b/bundle/src/resources/ToolMessages_ca_ES.properties index c3d04d1d..e2d8ebdf 100644 --- a/bundle/src/resources/ToolMessages_ca_ES.properties +++ b/bundle/src/resources/ToolMessages_ca_ES.properties @@ -315,9 +315,11 @@ bbb_recording_thumbnails_hidden = Nom\u00E9s per gravacions publicades bbb_recording_type.presentation = Presentaci\u00F3 bbb_recording_type.video = V\u00EDdeo +bbb_recording_type.statistics = Estad\u00EDsticas bbb_recording_view_tooltip.presentation = Mostra la presentaci\u00F3 bbb_recording_view_tooltip.video = Mostra el V\u00EDdeo +bbb_recording_view_tooltip.statistics = Mostra las Estad\u00EDsticas bbb_recordings_label = Gravacions diff --git a/bundle/src/resources/ToolMessages_en.properties b/bundle/src/resources/ToolMessages_en.properties index ff4cbc4a..0581dfa8 100644 --- a/bundle/src/resources/ToolMessages_en.properties +++ b/bundle/src/resources/ToolMessages_en.properties @@ -61,7 +61,11 @@ bbb_recording_status_hidden = Unpublished bbb_recording_status_shown = Published bbb_recording_thumbnails_hidden = Only for published recordings bbb_recording_type.presentation = Presentation +bbb_recording_type.video = Video +bbb_recording_type.statistics = Statistics bbb_recording_view_tooltip.presentation = View the presentation +bbb_recording_view_tooltip.video = View the video +bbb_recording_view_tooltip.statistics = View the statistics ##################################### @@ -160,6 +164,8 @@ bbb_permissions_recordings_edit_own = Edit own recordings bbb_permissions_recordings_edit_any = Edit any recordings bbb_permissions_recordings_delete_own = Delete own recordings bbb_permissions_recordings_delete_any = Delete any recordings +bbb_permissions_recordings_extendedformats_own = View extended formats in own recordings +bbb_permissions_recordings_extendedformats_any = View extended formats in any recordings ##################################### diff --git a/bundle/src/resources/ToolMessages_en_US.properties b/bundle/src/resources/ToolMessages_en_US.properties index ff4cbc4a..0581dfa8 100644 --- a/bundle/src/resources/ToolMessages_en_US.properties +++ b/bundle/src/resources/ToolMessages_en_US.properties @@ -61,7 +61,11 @@ bbb_recording_status_hidden = Unpublished bbb_recording_status_shown = Published bbb_recording_thumbnails_hidden = Only for published recordings bbb_recording_type.presentation = Presentation +bbb_recording_type.video = Video +bbb_recording_type.statistics = Statistics bbb_recording_view_tooltip.presentation = View the presentation +bbb_recording_view_tooltip.video = View the video +bbb_recording_view_tooltip.statistics = View the statistics ##################################### @@ -160,6 +164,8 @@ bbb_permissions_recordings_edit_own = Edit own recordings bbb_permissions_recordings_edit_any = Edit any recordings bbb_permissions_recordings_delete_own = Delete own recordings bbb_permissions_recordings_delete_any = Delete any recordings +bbb_permissions_recordings_extendedformats_own = View extended formats in own recordings +bbb_permissions_recordings_extendedformats_any = View extended formats in any recordings ##################################### diff --git a/bundle/src/resources/ToolMessages_es.properties b/bundle/src/resources/ToolMessages_es.properties index feb7b0ef..0f15a51f 100644 --- a/bundle/src/resources/ToolMessages_es.properties +++ b/bundle/src/resources/ToolMessages_es.properties @@ -62,7 +62,11 @@ bbb_recording_status_hidden = No publicada bbb_recording_status_shown = Publicada bbb_recording_thumbnails_hidden = Solo para grabaciones publicadas bbb_recording_type.presentation = Presentaci\u00F3n +bbb_recording_type.video = Video +bbb_recording_type.statistics = Estad\u00EDsticas bbb_recording_view_tooltip.presentation = Ver la presentaci\u00F3n +bbb_recording_view_tooltip.video = Ver el V\u00EDdeo +bbb_recording_view_tooltip.statistics = Ver las Estad\u00EDsticas ##################################### @@ -161,6 +165,8 @@ bbb_permissions_recordings_edit_own = Editar grabaciones propias bbb_permissions_recordings_edit_any = Editar cualquier grabaci\u00F3n bbb_permissions_recordings_delete_own = Eliminar grabaciones propias bbb_permissions_recordings_delete_any = Eliminar cualquier grabaci\u00F3n +bbb_permissions_recordings_extendedformats_own = Ver formatos extendidos de grabaciones propias +bbb_permissions_recordings_extendedformats_any = Ver formatos extendidos de cualquier grabaci\u00F3n ##################################### diff --git a/bundle/src/resources/ToolMessages_es_MX.properties b/bundle/src/resources/ToolMessages_es_MX.properties index 9a3f63a4..077fceed 100644 --- a/bundle/src/resources/ToolMessages_es_MX.properties +++ b/bundle/src/resources/ToolMessages_es_MX.properties @@ -54,7 +54,11 @@ bbb_action_delete_recording_question = \u003FEst\u00E1s segura(o) de querer elim bbb_recording_status_hidden = No publicada bbb_recording_status_shown = Publicada bbb_recording_type.presentation = Presentaci\u00F3n +bbb_recording_type.video = Video +bbb_recording_type.statistics = Estad\u00EDsticas bbb_recording_view_tooltip.presentation = Ver la presentaci\u00F3n +bbb_recording_view_tooltip.video = Ver el V\u00EDdeo +bbb_recording_view_tooltip.statistics = Ver las Estad\u00EDsticas ##################################### @@ -143,6 +147,13 @@ bbb_permissions_delete_own = Eliminar las propias bbb_permissions_edit_any = Editar cualquiera bbb_permissions_edit_own = Editar las propias bbb_permissions_participate = Participar +bbb_permissions_recordings_view = Ver grabaciones +bbb_permissions_recordings_edit_own = Editar grabaciones propias +bbb_permissions_recordings_edit_any = Editar cualquier grabaci\u00F3n +bbb_permissions_recordings_delete_own = Eliminar grabaciones propias +bbb_permissions_recordings_delete_any = Eliminar cualquier grabaci\u00F3n +bbb_permissions_recordings_extendedformats_own = Ver formatos extendidos de grabaciones propias +bbb_permissions_recordings_extendedformats_any = Ver formatos extendidos de cualquier grabaci\u00F3n ##################################### diff --git a/default.sakai.properties b/default.sakai.properties index 262d1371..cf85490c 100644 --- a/default.sakai.properties +++ b/default.sakai.properties @@ -69,24 +69,24 @@ # DEFAULT: fckeditor # bbb.descriptiontype= -# Set up to [true/false] to enable or disable the recording capability for all meetings. +# Set up to [true|false] to enable or disable the recording capability for all meetings. # When enabled, its setting can be changed for each meeting using the Add/Edit user interface. # This parameter replaces the bbb.recording parameter introduced in 1.0.7. # DEFAULT: true # bbb.recording.enabled= -# Set up to [true/false] to show or hide the 'recording' checkbox for meetings when created/edited. +# Set up to [true|false] to show or hide the 'recording' checkbox for meetings when created/edited. # This feature can be used to enforce recordings for all meetings (by setting enabled and default to true and, editable to false), # however this will not enforce recordings for meetings created before this change. # DEFAULT: true # bbb.recording.editable= -# Set up to [true/false] the default 'recording' setting for the meetings when created. +# Set up to [true|false] the default 'recording' setting for the meetings when created. # When a meeting has this setting enabled, the sessions will be created with recording capabilities. # DEFAULT: false # bbb.recording.default= -# Set up to [true/false] to enable or disable the duration capability for all meetings. When enabled, its value can be changed for each meeting using the Add/Edit user interface. +# Set up to [true|false] to enable or disable the duration capability for all meetings. When enabled, its value can be changed for each meeting using the Add/Edit user interface. # DEFAULT: false # bbb.duration.enabled= @@ -96,67 +96,67 @@ # DEFAULT: 120 # bbb.duration.default= -# Set up to [true/false] to enable or disable the waiting for moderator capability for all meetings. +# Set up to [true|false] to enable or disable the waiting for moderator capability for all meetings. # When enabled, its value can be changed for each meeting using the Add/Edit user interface. # DEFAULT: true # bbb.waitmoderator.enabled= -# Set up to [true/false] to show or hide the 'wait for moderator' checkbox for meetings when created/edited. +# Set up to [true|false] to show or hide the 'wait for moderator' checkbox for meetings when created/edited. # This feature can be used to enforce 'wait for moderator' for all meetings (by setting enabled and default to true and, editable to false), # however this will not enforce 'wait for moderator' for meetings created before this change. # DEFAULT: true # bbb.waitmoderator.editable= -# Set up to [true/false] the default 'wait for moderator' setting for the meetings when created. +# Set up to [true|false] the default 'wait for moderator' setting for the meetings when created. # When a meeting has this setting enabled, all users in the viewer role will not be able to join the session until a user with the moderator role joins. # DEFAULT: true # bbb.waitmoderator.default= -# Set up to [true/false] to enable or disable the 'multiple sessions allowed' capability for all meetings. +# Set up to [true|false] to enable or disable the 'multiple sessions allowed' capability for all meetings. # When enabled, its value can be changed for each meeting using the Add/Edit user interface. # DEFAULT: false # bbb.multiplesessionsallowed.enabled= -# Set up to [true/false] to show or hide the 'multiple sessions allowed' checkbox for meetings when created/edited. +# Set up to [true|false] to show or hide the 'multiple sessions allowed' checkbox for meetings when created/edited. # This feature can be used to enforce 'multiple sessions allowed' for all meetings (by setting enabled and default to true, and editable to false), # however this will not enforce 'multiple sessions allowed' for meetings created before this change. # DEFAULT: true # bbb.multiplesessionsallowed.editable= -# Set up to [true/false] the default 'multiple sessions allowed' setting for the meetings when created. +# Set up to [true|false] the default 'multiple sessions allowed' setting for the meetings when created. # When a meeting has this setting enabled, users will be able to join the same sessions in multiple tabs. # DEFAULT: false # bbb.multiplesessionsallowed.default= -# Set up to [true/false] to enable or disable the 'preupload presentation' capability for all meetings. +# Set up to [true|false] to enable or disable the 'preupload presentation' capability for all meetings. # When enabled, presentations can be preuploaded to the meeting if a file is chosen in the Add/Edit user interface. # DEFAULT: true # bbb.preuploadpresentation.enabled= -# Set up to [true/false] to enable or disable the 'group sessions' capability for all meetings. +# Set up to [true|false] to enable or disable the 'group sessions' capability for all meetings. # When enabled, its value can be changed for each meeting using the Add/Edit user interface. # DEFAULT: true # bbb.groupsessions.enabled= -# Set up to [true/false] to show or hide the 'group sessions' checkbox for meetings when created/edited. +# Set up to [true|false] to show or hide the 'group sessions' checkbox for meetings when created/edited. # This feature can be used to enforce 'group sessions' for all meetings (by setting enabled and default to true, and editable to false), # however this will not enforce 'group sessions' for meetings created before this change. # DEFAULT: true # bbb.groupsessions.editable= -# Set up to [true/false] the default 'group sessions' setting for the meetings when created. +# Set up to [true|false] the default 'group sessions' setting for the meetings when created. # When a meeting has this setting enabled, users will be able to join group-only sessions for the meeting. # DEFAULT: false # bbb.groupsessions.default= ## Special settings -# ######### +# ################################################################################################################################################ # # BigBlueButton can be extended in many different ways. A common way to gain some extra capabilities is by adding ruby scripts that are executed # while the recording is processed http://docs.bigbluebutton.org/dev/recording.html#post-scripts. # Common uses for this are: sending messages when the recording is ready, gattering information that may be used for analitycs etc. # Although these features are not standard, there are a few minor tweaks that can be enabled by configuration in Sakai so BigBlueButton # administrators can implement actions over extra information received through the meta parameters. -# ######### +# ################################################################################################################################################ # # Send a messages through Sakai when the recording is ready. # When enabled, a meta_bn-recording-ready-url parameter is included as part of the create request. It contains an URL that can be used by BigBlueButton @@ -173,3 +173,13 @@ # The default value for userid is the Sakai user.eid but also the user_id could be used instead. # DEFAULT: eid [eid|user_id] # bbb.recordingstats.userid= + +# Set up to [true|false] a filter to be applied to recording formats when the BBB server provides more than one +# DEFAULT: true +# bbb.recordingformatfilter.enabled= + +# List (comma separated) of recording formats that will be whitelisted. +# The whitelisted formats are shown to all the users who have permissions to view recordings. All the other formats +# are considered as Extra Formats and have to be enabled per role through the permissions. +# DEFAULT: presentation,video +# bbb.recordingformatfilter.whitelist= diff --git a/impl/src/java/org/sakaiproject/bbb/impl/BBBAPIWrapper.java b/impl/src/java/org/sakaiproject/bbb/impl/BBBAPIWrapper.java index 6a86fe54..754f1e2d 100644 --- a/impl/src/java/org/sakaiproject/bbb/impl/BBBAPIWrapper.java +++ b/impl/src/java/org/sakaiproject/bbb/impl/BBBAPIWrapper.java @@ -97,6 +97,10 @@ public class BBBAPIWrapper/* implements Runnable */{ private boolean bbbRecordingStatsEnabled = false; /** Sakai userid used for linking events with users when 'recording status' feature is enabled (default to eid) */ private String bbbRecordingStatsUserId = "eid"; + /** BBB flag to activate/deactivate 'recording format filter' feature for managing permissions on extended formats (default to true) */ + private boolean bbbRecordingFormatFilterEnabled = true; + /** BBB list of formats allowed to be seen whotout applying a permissions filter (default to presentation,video) */ + private String bbbRecordingFormatFilterWhitelist = "presentation,video"; /** BBB API */ private BBBAPI api = null; @@ -169,7 +173,8 @@ public void start() { bbbGroupSessionsEditable = (boolean) config.getBoolean(BBBMeetingManager.CFG_GROUPSESSIONS_EDITABLE, bbbGroupSessionsEditable); bbbGroupSessionsDefault = (boolean) config.getBoolean(BBBMeetingManager.CFG_GROUPSESSIONS_DEFAULT, bbbGroupSessionsDefault); bbbRecordingStatsEnabled = (boolean) config.getBoolean(BBBMeetingManager.CFG_RECORDINGSTATS_ENABLED, bbbRecordingStatsEnabled); - bbbRecordingStatsUserId = (String) config.getString(BBBMeetingManager.CFG_RECORDINGSTATS_USERID, bbbRecordingStatsUserId); + bbbRecordingFormatFilterEnabled = (boolean) config.getBoolean(BBBMeetingManager.CFG_RECORDINGFORMATFILTER_ENABLED, bbbRecordingFormatFilterEnabled); + bbbRecordingFormatFilterWhitelist = (String) config.getString(BBBMeetingManager.CFG_RECORDINGFORMATFILTER_WHITELIST, bbbRecordingFormatFilterWhitelist); } public void destroy() { @@ -293,20 +298,6 @@ public Map getRecordings(String meetingID) return recordingsResponse; } - public Map getSiteRecordings(String meetingIDs) - throws BBBException { - if (logger.isDebugEnabled()) logger.debug("getSiteRecordings(): for meetingIDs=" + meetingIDs); - - return getRecordings(meetingIDs); - } - - public Map getAllRecordings() - throws BBBException { - if (logger.isDebugEnabled()) logger.debug("getAllRecordings()"); - - return getRecordings(""); - } - public boolean endMeeting(String meetingID, String password) throws BBBException { if (logger.isDebugEnabled()) logger.debug("endMeeting()"); @@ -468,6 +459,14 @@ public String getRecordingStatsUserId() { return bbbRecordingStatsUserId; } + public boolean isRecordingFormatFilterEnabled() { + return bbbRecordingFormatFilterEnabled; + } + + public String getRecordingFormatFilterWhitelist() { + return bbbRecordingFormatFilterWhitelist; + } + private Map responseError(String messageKey, String message) { logger.debug("responseError: " + messageKey + ":" + message); diff --git a/impl/src/java/org/sakaiproject/bbb/impl/BBBMeetingManagerImpl.java b/impl/src/java/org/sakaiproject/bbb/impl/BBBMeetingManagerImpl.java index 19805551..a3069d8c 100644 --- a/impl/src/java/org/sakaiproject/bbb/impl/BBBMeetingManagerImpl.java +++ b/impl/src/java/org/sakaiproject/bbb/impl/BBBMeetingManagerImpl.java @@ -332,90 +332,143 @@ public Map getMeetingInfo(String meetingID, String groupId) return bbbAPI.getMeetingInfo(meeting.getId(), meeting.getModeratorPassword()); } - public Map getRecordings(String meetingID, String groupId) + public Map getRecordings(String meetingID, String groupId, String siteId) throws BBBException { BBBMeeting meeting = storageManager.getMeeting(meetingID); - if( meeting.getRecording() ) { - if(meeting.getGroupSessions() && groupId != "" && groupId != null) - return bbbAPI.getRecordings(meeting.getId() + "[" + groupId + "]"); - - return bbbAPI.getRecordings(meeting.getId()); - } else { + Map recordings; + if (!meeting.getRecording()) { //Mimic empty recordings object - Map recordings = new HashMap(); + recordings = new HashMap(); recordings.put("recordings", ""); return recordings; } + + Map ownerIDs = new HashMap(); + String ownerID = meeting.getOwnerId(); + ownerIDs.put(meetingID, ownerID); + String meetingIDs = meetingID; + if (meeting.getGroupSessions() && groupId != null && groupId != "") { + ownerIDs.put(meetingID + "[" + groupId + "]", ownerID); + meetingIDs += "," + meetingID + "[" + groupId + "]"; + + } + recordings = bbbAPI.getRecordings(meetingIDs); + // Post-process recordings + Object recordingList = recordings.get("recordings"); + if ("SUCCESS".equals(recordings.get("returncode")) && recordingList != null && recordingList.getClass().equals(ArrayList.class)) { + boolean recordingFilterEnabled = this.isRecordingFormatFilterEnabled(); + User user = userDirectoryService.getCurrentUser(); + String userId = user.getId(); + for (Map recordingItem : (List>)recordingList) { + // Add meeting ownerId to the recording + recordingItem.put("ownerId", ownerIDs.get((String)recordingItem.get("meetingID"))); + // Filter formats that are not allowed to be shown, only if filter is enabled. + if (recordingFilterEnabled) { + recordingsFilterFormats(recordingItem, siteId, userId); + } + } + } + return recordings; } public Map getSiteRecordings(String siteId) throws SecurityException, Exception { + List meetings = storageManager.getSiteMeetings(siteId, INCLUDE_DELETED_MEETINGS); + if (meetings.size() == 0 || !bbbAPI.isRecordingEnabled()) { + // Set an empty List of recordings and a SUCCESS key as default response values. + Map response = new HashMap(); + response.put("recordings", new ArrayList()); + response.put("returncode", "SUCCESS"); + response.put("messageKey", "noRecordings"); + return response; + } - Map response = new HashMap(); - //Set an empty List of recordings and a SUCCESS key as default response values - response.put("recordings", new ArrayList() ); - response.put("returncode", "SUCCESS"); - response.put("messageKey", "noRecordings"); - + Map ownerIDs = new HashMap(); + String meetingID; + String ownerID; String meetingIDs = ""; - - List meetings = storageManager.getSiteMeetings(siteId, INCLUDE_DELETED_MEETINGS); - if ( meetings.size() > 0 && bbbAPI.isRecordingEnabled() ) { - for (BBBMeeting meeting : meetings) { - if ( meeting.getRecording() ) { - if ( !meetingIDs.equals("") ) { - meetingIDs += ","; - } - meetingIDs += meeting.getId(); - if ( meeting.getGroupSessions() ) { - Site site; - try { - site = siteService.getSite(siteId); - Collection userGroups = site.getGroups(); - for (Group g : userGroups) { - meetingIDs += "," + meeting.getId() + "[" + g.getId() + "]"; - } - } catch (IdUnusedException e) { - logger.error("Unable to get recordings for group sessions in meeting '" + meeting.getName() + "'.", e); - } + for (BBBMeeting meeting : meetings) { + if (!meeting.getRecording()) { + // Meeting is not set to be recorded + continue; + } + meetingID = meeting.getId(); + ownerID = meeting.getOwnerId(); + ownerIDs.put(meetingID, ownerID); + if (!meetingIDs.equals("")) { + meetingIDs += ","; + } + meetingIDs += meetingID; + if (meeting.getGroupSessions()) { + try { + Site site = siteService.getSite(siteId); + Collection userGroups = site.getGroups(); + for (Group g : userGroups) { + ownerIDs.put(meetingID + "[" + g.getId() + "]", ownerID); + meetingIDs += "," + meetingID + "[" + g.getId() + "]"; } + } catch (IdUnusedException e) { + logger.error("Unable to get recordings for group sessions in meeting '" + meeting.getName() + "'.", e); } } + } - if ( !meetingIDs.equals("") ) { - Map recordingsResponse = bbbAPI.getSiteRecordings(meetingIDs); - - String returncode = (String)recordingsResponse.get("returncode"); - Object recordings = recordingsResponse.get("recordings"); - - if ( "SUCCESS".equals(returncode) && recordings!= null && recordings.getClass().equals(java.util.ArrayList.class) ){ - List> recordingList = (List>)recordingsResponse.get("recordings"); - for (Map recordingItem : recordingList) { - recordingItem.put("ownerId", locateOwnerIdOnMeetingList((String)recordingItem.get("meetingID"), meetings)); - } - response = recordingsResponse; + Map recordings = bbbAPI.getRecordings(meetingIDs); + // Post-process recordings + Object recordingList = recordings.get("recordings"); + if ("SUCCESS".equals(recordings.get("returncode")) && recordingList != null && recordingList.getClass().equals(ArrayList.class)) { + boolean recordingFilterEnabled = this.isRecordingFormatFilterEnabled(); + User user = userDirectoryService.getCurrentUser(); + String userId = user.getId(); + for (Map recordingItem : (List>)recordingList) { + // Add meeting ownerId to the recording + recordingItem.put("ownerId", ownerIDs.get((String)recordingItem.get("meetingID"))); + // Filter formats that are not allowed to be shown, only if filter is enabled. + if (recordingFilterEnabled) { + recordingsFilterFormats(recordingItem, siteId, userId); } } } - - return response; + return recordings; } - private String locateOwnerIdOnMeetingList(String meetingId, List meetings){ - - for (BBBMeeting meeting : meetings) { - if( meetingId.equals(meeting.getId()) ){ - return meeting.getOwnerId(); + private void recordingsFilterFormats(Map recordingItem, String siteId, String userId) { + List> playback = (List>)recordingItem.get("playback"); + for (Iterator> iterator = playback.iterator(); iterator.hasNext(); ) { + Map format = iterator.next(); + if ( recordingsFilterFormatRemovable( (String)format.get("type"), siteId, (String)recordingItem.get("ownerId"), userId ) ) { + iterator.remove(); } } - return ""; + } + private boolean recordingsFilterFormatRemovable(String type, String siteId, String ownerId, String userId) { + // Validate if type is whitelisted. + List whiltelist = Arrays.asList(this.getRecordingFormatFilterWhitelist().split(",")); + if (whiltelist.contains(type)) { + // It is whitelisted, don't remove. + return false; + } + // Validate if user is allowed to view extended formats + if (ownerId.equals(userId)) { + if (isUserAllowedInLocation(userId, FN_RECORDING_EXTENDEDFORMATS_OWN, siteId)) { + // User allowed, don't remove. + return false; + } + } + if (isUserAllowedInLocation(userId, FN_RECORDING_EXTENDEDFORMATS_ANY, siteId)) { + // User allowed, don't remove. + return false; + } + // Remove it + return true; } public Map getAllRecordings() - throws BBBException { - return bbbAPI.getAllRecordings(); + throws BBBException { + Map recordings = bbbAPI.getRecordings(""); + return recordings; } public void logMeetingJoin(String meetingId) { @@ -1443,6 +1496,14 @@ public List getUserGroupIdsInSite(String userId, String siteId) { return groupIds; } + public boolean isRecordingFormatFilterEnabled() { + return bbbAPI.isRecordingFormatFilterEnabled(); + } + + public String getRecordingFormatFilterWhitelist() { + return "" + bbbAPI.getRecordingFormatFilterWhitelist(); + } + /** * Generate an iCal file in tmp dir, an return the file path on the * filesystem diff --git a/pom.xml b/pom.xml index 670058c2..e46ac565 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ yyMMdd_HHmm ${maven.build.timestamp} - 2016112002 + 2016112003 diff --git a/tool/src/java/org/sakaiproject/bbb/tool/entity/BBBMeetingEntityProvider.java b/tool/src/java/org/sakaiproject/bbb/tool/entity/BBBMeetingEntityProvider.java index 70801309..b9959a4e 100644 --- a/tool/src/java/org/sakaiproject/bbb/tool/entity/BBBMeetingEntityProvider.java +++ b/tool/src/java/org/sakaiproject/bbb/tool/entity/BBBMeetingEntityProvider.java @@ -167,7 +167,6 @@ public Object getEntity(EntityReference ref) { logger.debug("getEntity(" + ref.getId() + ")"); String id = ref.getId(); - if (id == null || "".equals(id)) { return new BBBMeeting(); } @@ -217,6 +216,7 @@ public Object getSampleEntity() { public String createEntity(EntityReference ref, Object entity, Map params) { if (logger.isDebugEnabled()) logger.debug("createMeeting"); + logger.debug("EntityReference:" + ref.toString() + ", Entity:" + entity.toString() + ", params:" + params.toString()); BBBMeeting meeting = (BBBMeeting) entity; @@ -421,6 +421,7 @@ public void updateEntity(EntityReference ref, Object entity, public List getEntities(EntityReference ref, Search search) { if (logger.isDebugEnabled()) logger.debug("getEntities"); + List meetings = null; Restriction locRes = search.getRestrictionByProperty(CollectionResolvable.SEARCH_LOCATION_REFERENCE); @@ -459,6 +460,7 @@ public List getEntities(EntityReference ref, Search search) { public void deleteEntity(EntityReference ref, Map params) { if (logger.isDebugEnabled()) logger.debug("deleteEntity"); + if (ref == null) { throw new EntityNotFoundException("Meeting not found", null); } @@ -476,6 +478,7 @@ public void deleteEntity(EntityReference ref, Map params) { public ActionReturn getSettings(Map params) { if (logger.isDebugEnabled()) logger.debug("getSettings"); + Map settings = new LinkedHashMap(); String siteId = params.containsKey("siteId")? (String) params.get("siteId"): null; @@ -490,6 +493,7 @@ public ActionReturn getSettings(Map params) { config.put("addUpdateFormParameters", getAddUpdateFormConfigParameters()); config.put("serverTimeInDefaultTimezone", getServerTimeInDefaultTimezone()); config.put("serverTimeInUserTimezone", getServerTimeInUserTimezone()); + config.put("recordingFormatFilterEnabled", meetingManager.isRecordingFormatFilterEnabled()); settings.put("config", config); settings.put("toolVersion", getToolVersion()); return new ActionReturn(settings); @@ -535,6 +539,10 @@ private List getUserPermissionsInSite(String userId, String siteId) { permissions.add(meetingManager.FN_RECORDING_DELETE_OWN); if( meetingManager.isUserAllowedInLocation(userId, meetingManager.FN_RECORDING_DELETE_ANY, siteId) ) permissions.add(meetingManager.FN_RECORDING_DELETE_ANY); + if( meetingManager.isUserAllowedInLocation(userId, meetingManager.FN_RECORDING_EXTENDEDFORMATS_OWN, siteId) ) + permissions.add(meetingManager.FN_RECORDING_EXTENDEDFORMATS_OWN); + if( meetingManager.isUserAllowedInLocation(userId, meetingManager.FN_RECORDING_EXTENDEDFORMATS_ANY, siteId) ) + permissions.add(meetingManager.FN_RECORDING_EXTENDEDFORMATS_ANY); if( meetingManager.isUserAllowedInLocation(userId, "calendar.new", siteId) ) permissions.add("calendar.new"); if( meetingManager.isUserAllowedInLocation(userId, "calendar.revise.own", siteId) ) @@ -664,6 +672,7 @@ private Map getToolVersion() { public String isMeetingRunning(Map params) { if (logger.isDebugEnabled()) logger.debug("isMeetingRunning"); + String meetingID = (String) params.get("meetingID"); if (meetingID == null) { throw new IllegalArgumentException("Missing required parameters meetingId"); @@ -681,6 +690,7 @@ public String isMeetingRunning(Map params) { public String endMeeting(Map params) { if (logger.isDebugEnabled()) logger.debug("endMeeting"); + String meetingID = (String) params.get("meetingID"); if (meetingID == null) { throw new IllegalArgumentException("Missing required parameter [meetingID]"); @@ -702,7 +712,9 @@ else if (endAll != null) @EntityCustomAction(viewKey = EntityView.VIEW_LIST) public ActionReturn getMeetings(Map params) { - if (logger.isDebugEnabled()) logger.debug("getMeetings"); + if (logger.isDebugEnabled()) + logger.debug("getMeetings"); + try { return new ActionReturn(meetingManager.getMeetings()); } catch (BBBException e) { @@ -712,17 +724,17 @@ public ActionReturn getMeetings(Map params) { @EntityCustomAction(viewKey = EntityView.VIEW_SHOW) public ActionReturn getMeetingInfo(OutputStream out, EntityView view, EntityReference ref, Map params) { - if (logger.isDebugEnabled()) logger.debug("getMeetingInfo"); + if (logger.isDebugEnabled()) + logger.debug("getMeetingInfo"); + if (ref == null) { throw new EntityNotFoundException("Meeting not found", null); } - String groupId = (String) params.get("groupId"); try { - if (groupId != null) - return new ActionReturn(meetingManager.getMeetingInfo(ref.getId(), groupId)); - - return new ActionReturn(meetingManager.getMeetingInfo(ref.getId(), "")); + String groupId = (String) params.get("groupId"); + Map meetingInfoResponse = meetingManager.getMeetingInfo(ref.getId(), groupId); + return new ActionReturn(meetingInfoResponse); } catch (BBBException e) { return new ActionReturn(new HashMap()); } @@ -730,21 +742,18 @@ public ActionReturn getMeetingInfo(OutputStream out, EntityView view, EntityRefe @EntityCustomAction(viewKey = EntityView.VIEW_SHOW) public ActionReturn getRecordings(OutputStream out, EntityView view, EntityReference ref, Map params) { - if(logger.isDebugEnabled()) logger.debug("getRecordings"); + if(logger.isDebugEnabled()) + logger.debug("getRecordings"); - if (ref == null) + if (ref == null) { throw new EntityNotFoundException("Meeting not found", null); + } + String groupId = (String) params.get("groupId"); + String siteId = (String) params.get("siteId"); try { - Map recordingsResponse = null; - String groupId = (String) params.get("groupId"); - if (groupId != null) { - recordingsResponse = meetingManager.getRecordings(ref.getId(), groupId); - } else { - recordingsResponse = meetingManager.getRecordings(ref.getId(), ""); - } + Map recordingsResponse = meetingManager.getRecordings(ref.getId(), groupId, siteId); return new ActionReturn(recordingsResponse); - } catch (BBBException e) { return new ActionReturn(new HashMap()); } @@ -752,29 +761,28 @@ public ActionReturn getRecordings(OutputStream out, EntityView view, EntityRefer @EntityCustomAction(viewKey = EntityView.VIEW_LIST) public ActionReturn getSiteRecordings(Map params) { - if (logger.isDebugEnabled()) logger.debug("getSiteRecordings"); + if (logger.isDebugEnabled()) + logger.debug("getSiteRecordings"); String siteId = (String) params.get("siteId"); - if(!meetingManager.getCanView(siteId)){ + if (!meetingManager.getCanView(siteId)) { throw new SecurityException("You are not allowed to view recordings"); } try { Map recordingsResponse = meetingManager.getSiteRecordings(siteId); - return new ActionReturn(recordingsResponse); - } catch (Exception e) { return new ActionReturn(new HashMap()); } - } @EntityCustomAction(viewKey = EntityView.VIEW_LIST) public String publishRecordings(Map params) { if (logger.isDebugEnabled()) logger.debug("publishRecordings"); + String meetingID = (String) params.get("meetingID"); String recordID = (String) params.get("recordID"); String publish = (String) params.get("publish"); @@ -789,20 +797,18 @@ public String publishRecordings(Map params) { } try { - return Boolean.toString(meetingManager.publishRecordings(meetingID, - recordID, publish)); + return Boolean.toString(meetingManager.publishRecordings(meetingID, recordID, publish)); } catch (BBBException e) { - String ref = Entity.SEPARATOR + BBBMeetingManager.ENTITY_PREFIX - + Entity.SEPARATOR + meetingID; + String ref = Entity.SEPARATOR + BBBMeetingManager.ENTITY_PREFIX + Entity.SEPARATOR + meetingID; throw new EntityException(e.getPrettyMessage(), ref, 400); } - } @EntityCustomAction(viewKey = EntityView.VIEW_LIST) public String protectRecordings(Map params) { if (logger.isDebugEnabled()) logger.debug("protectRecordings"); + String meetingID = (String) params.get("meetingID"); String recordID = (String) params.get("recordID"); String protect = (String) params.get("protect"); @@ -824,13 +830,13 @@ public String protectRecordings(Map params) { + Entity.SEPARATOR + meetingID; throw new EntityException(e.getPrettyMessage(), ref, 400); } - } @EntityCustomAction(viewKey = EntityView.VIEW_LIST) public String deleteRecordings(Map params) { if (logger.isDebugEnabled()) logger.debug("deleteRecordings"); + String meetingID = (String) params.get("meetingID"); String recordID = (String) params.get("recordID"); if (meetingID == null) { @@ -854,6 +860,7 @@ public String deleteRecordings(Map params) { public String getJoinMeetingUrl(OutputStream out, EntityView view, EntityReference ref) { if (logger.isDebugEnabled()) logger.debug("getJoinUrl"); + if (ref == null) { throw new EntityNotFoundException("Meeting not found", null); } @@ -885,7 +892,6 @@ public String getJoinMeetingUrl(OutputStream out, EntityView view, EntityReferen // log meeting join event meetingManager.logMeetingJoin(ref.getId()); return joinUrl; - } catch (Exception e) { throw new EntityException(e.getMessage(), ref.getReference(), 400); } @@ -899,6 +905,7 @@ public String getJoinMeetingUrl(OutputStream out, EntityView view, EntityReferen public String joinMeeting(OutputStream out, EntityView view, EntityReference ref, Map params) { if (logger.isDebugEnabled()) logger.debug("joinMeeting"); + if (ref == null) { throw new EntityNotFoundException("Meeting not found", null); } @@ -1114,6 +1121,7 @@ public ActionReturn getGroups(Map params) { public ActionReturn getUserSelectionOptions(Map params) { if (logger.isDebugEnabled()) logger.debug("getUserSelectionOptions"); + String siteId = (String) params.get("siteId"); if (siteId == null) { throw new IllegalArgumentException("Missing required parameter siteId"); @@ -1181,6 +1189,7 @@ public ActionReturn getUserSelectionOptions(Map params) { public ActionReturn getNoticeText(Map params) { if (logger.isDebugEnabled()) logger.debug("getNoticeText"); + Map map = new HashMap(); String noticeText = meetingManager.getNoticeText(); if (noticeText != null) { diff --git a/tool/src/webapp/WEB-INF/bootstrap.vm b/tool/src/webapp/WEB-INF/bootstrap.vm index dcd352c3..162508b7 100644 --- a/tool/src/webapp/WEB-INF/bootstrap.vm +++ b/tool/src/webapp/WEB-INF/bootstrap.vm @@ -18,8 +18,8 @@ - @@ -67,7 +67,7 @@