=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/message/MessageService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/message/MessageService.java 2014-11-18 12:55:20 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/message/MessageService.java 2015-01-06 16:21:58 +0000 @@ -102,7 +102,7 @@ List getMessageConversations( boolean followUpOnly, boolean unreadOnly, int first, int max ); - Collection getMessageConversations( String[] messageConversationUids ); + Collection getMessageConversations( User user, String[] messageConversationUids ); int getMessageConversationCount(); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/DefaultMessageService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/DefaultMessageService.java 2014-12-21 17:57:33 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/DefaultMessageService.java 2015-01-06 16:21:58 +0000 @@ -327,9 +327,20 @@ } @Override - public Collection getMessageConversations( String[] messageConversationUids ) + public Collection getMessageConversations( User user, String[] messageConversationUids ) { - return messageConversationStore.getMessageConversations( messageConversationUids ); + Collection conversations = messageConversationStore.getMessageConversations( messageConversationUids ); + + // Set transient properties + // TODO See getMessageConversation(String) + + for ( MessageConversation mc : conversations ) + { + mc.setFollowUp( mc.isFollowUp( user ) ); + mc.setRead( mc.isRead( user ) ); + } + + return conversations; } @Override === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/hibernate/HibernateMessageConversationStore.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/hibernate/HibernateMessageConversationStore.java 2014-10-16 06:17:19 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/hibernate/HibernateMessageConversationStore.java 2015-01-07 12:59:57 +0000 @@ -29,6 +29,7 @@ */ import org.hibernate.Query; +import org.hibernate.criterion.Restrictions; import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore; import org.hisp.dhis.jdbc.StatementBuilder; import org.hisp.dhis.message.MessageConversation; @@ -40,6 +41,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -128,15 +130,12 @@ } @Override - @SuppressWarnings("unchecked") - public Collection getMessageConversations( String[] messageConversationUids ) + @SuppressWarnings( "unchecked" ) + public Collection getMessageConversations( String[] uids ) { - String hql = ( "FROM MessageConversation where uid in :messageConversationUids" ); - - Query query = getQuery( hql ); - query.setParameterList( "messageConversationUids", messageConversationUids ); - - return query.list(); + return getSharingCriteria() + .add( Restrictions.in( "uid", uids ) ) + .list(); } @Override @@ -259,4 +258,4 @@ return recipients; } -} \ No newline at end of file +} === modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/message/MessageServiceTest.java' --- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/message/MessageServiceTest.java 2014-10-16 06:17:19 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/message/MessageServiceTest.java 2015-01-06 16:21:58 +0000 @@ -229,7 +229,7 @@ String[] uids = { uidA, uidB }; - Collection conversations = messageService.getMessageConversations( uids ); + Collection conversations = messageService.getMessageConversations( sender, uids ); assertTrue( conversations.contains( conversationA ) ); assertTrue( conversations.contains( conversationB ) ); === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/MessageConversationController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/MessageConversationController.java 2014-12-30 17:28:02 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/MessageConversationController.java 2015-01-07 12:59:57 +0000 @@ -293,7 +293,7 @@ throw new UpdateAccessDeniedException( "Not authorized to modify this object." ); } - Collection messageConversations = messageService.getMessageConversations( uids ); + Collection messageConversations = messageService.getMessageConversations( user, uids ); if ( messageConversations.isEmpty() ) { @@ -344,7 +344,7 @@ throw new UpdateAccessDeniedException( "Not authorized to modify this object." ); } - Collection messageConversations = messageService.getMessageConversations( uids ); + Collection messageConversations = messageService.getMessageConversations( user, uids ); if ( messageConversations.isEmpty() ) { @@ -371,6 +371,110 @@ } //-------------------------------------------------------------------------- + // Mark conversations for follow up + //-------------------------------------------------------------------------- + + @RequestMapping( value = "followup", method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE } ) + public @ResponseBody RootNode markMessageConversationFollowup( + @RequestParam( value = "user", required = false ) String userUid, @RequestBody String[] uids, HttpServletResponse response ) + { + RootNode responseNode = new RootNode( "response" ); + + User currentUser = currentUserService.getCurrentUser(); + User user = userUid != null ? userService.getUser( userUid ) : currentUser; + + if ( user == null ) + { + response.setStatus( HttpServletResponse.SC_NOT_FOUND ); + responseNode.addChild( new SimpleNode( "message", "No user with uid: " + userUid ) ); + return responseNode; + } + + if ( !canModifyUserConversation( currentUser, user ) ) + { + throw new UpdateAccessDeniedException( "Not authorized to modify this object." ); + } + + Collection messageConversations = messageService.getMessageConversations( user, uids ); + + if ( messageConversations.isEmpty() ) + { + response.setStatus( HttpServletResponse.SC_NOT_FOUND ); + responseNode.addChild( new SimpleNode( "message", "No MessageConversations found for the given UIDs" ) ); + return responseNode; + } + + CollectionNode marked = responseNode.addChild( new CollectionNode( "markedFollowup" ) ); + marked.setWrapping( false ); + + for ( org.hisp.dhis.message.MessageConversation conversation : messageConversations ) + { + if ( !conversation.isFollowUp() ) + { + conversation.toggleFollowUp( user ); + messageService.updateMessageConversation( conversation ); + } + marked.addChild( new SimpleNode( "uid", conversation.getUid() ) ); + } + + response.setStatus( HttpServletResponse.SC_OK ); + + return responseNode; + } + + //-------------------------------------------------------------------------- + // Clear follow up + //-------------------------------------------------------------------------- + + @RequestMapping( value = "unfollowup", method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE } ) + public @ResponseBody RootNode unmarkMessageConversationFollowup( + @RequestParam( value = "user", required = false ) String userUid, @RequestBody String[] uids, HttpServletResponse response ) + { + RootNode responseNode = new RootNode( "response" ); + + User currentUser = currentUserService.getCurrentUser(); + User user = userUid != null ? userService.getUser( userUid ) : currentUser; + + if ( user == null ) + { + response.setStatus( HttpServletResponse.SC_NOT_FOUND ); + responseNode.addChild( new SimpleNode( "message", "No user with uid: " + userUid ) ); + return responseNode; + } + + if ( !canModifyUserConversation( currentUser, user ) ) + { + throw new UpdateAccessDeniedException( "Not authorized to modify this object." ); + } + + Collection messageConversations = messageService.getMessageConversations( user, uids ); + + if ( messageConversations.isEmpty() ) + { + response.setStatus( HttpServletResponse.SC_NOT_FOUND ); + responseNode.addChild( new SimpleNode( "message", "No MessageConversations found for the given UIDs" ) ); + return responseNode; + } + + CollectionNode marked = responseNode.addChild( new CollectionNode( "unmarkedFollowup" ) ); + marked.setWrapping( false ); + + for ( org.hisp.dhis.message.MessageConversation conversation : messageConversations ) + { + if ( conversation.isFollowUp() ) + { + conversation.toggleFollowUp( user ); + messageService.updateMessageConversation( conversation ); + } + marked.addChild( new SimpleNode( "uid", conversation.getUid() ) ); + } + + response.setStatus( HttpServletResponse.SC_OK ); + + return responseNode; + } + + //-------------------------------------------------------------------------- // Delete a MessageConversation (requires override auth) //-------------------------------------------------------------------------- @@ -465,7 +569,7 @@ throw new DeleteAccessDeniedException( "Not authorized to modify user: " + user.getUid() ); } - Collection messageConversations = messageService.getMessageConversations( mcUids ); + Collection messageConversations = messageService.getMessageConversations( user, mcUids ); if ( messageConversations.isEmpty() ) { === modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/jQuery/jquery.dhisCheckboxMenu.js' --- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/jQuery/jquery.dhisCheckboxMenu.js 2014-10-03 12:12:40 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/jQuery/jquery.dhisCheckboxMenu.js 2015-01-06 18:19:11 +0000 @@ -68,6 +68,16 @@ return checked; } + function executeNamedFn(fnName, ctx ) { + var args = [].slice.call(arguments).splice(2); + var namespaces = fnName.split("."); + var func = namespaces.pop(); + for( var i = 0; i < namespaces.length; i++ ) { + ctx = ctx[ namespaces[ i ] ]; + } + return ctx[func].apply( this, args ); + } + var multiCheckboxMenu = $.fn.multiCheckboxMenu; $.fn.multiCheckboxMenu = function( $checkboxContainer, options ) { @@ -130,7 +140,7 @@ } el.click( function() { - return window[ el.action ]( getCheckedValues( $checkboxContainer ) ); + return executeNamedFn( el.action, window, getCheckedValues( $checkboxContainer ) ); }); }); === modified file 'dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/resources/org/hisp/dhis/dashboard/i18n_module.properties' --- dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/resources/org/hisp/dhis/dashboard/i18n_module.properties 2014-12-18 11:41:20 +0000 +++ dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/resources/org/hisp/dhis/dashboard/i18n_module.properties 2015-01-07 13:32:22 +0000 @@ -26,6 +26,8 @@ recipients=Recipients mark_unread=Mark as unread mark_read=Mark as read +mark_followup=Mark for followup +clear_followup=Clear followup read=Read delete=Delete confirm_delete_message=Are you sure you want to delete the message? === modified file 'dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/message.js' --- dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/message.js 2014-10-03 11:32:55 +0000 +++ dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/message.js 2015-01-07 13:02:00 +0000 @@ -8,101 +8,6 @@ removeItem( id, "", i18n_confirm_delete_message, "removeMessage.action" ); } -function removeMessages( messages ) -{ - if( typeof messages === "undefined" || messages.length < 1 ) - { - return; - } - - var confirmed = window.confirm( i18n_confirm_delete_all_selected_messages ); - - if( confirmed ) - { - setHeaderWaitMessage( i18n_deleting ); - - $.ajax( - { - url: "../api/messageConversations?" + $.param( { mc: messages }, true ), - contentType: "application/json", - dataType: "json", - type: "DELETE", - success: function( response ) - { - for( var i = 0; i < response.removed.length; i++ ) - { - $( "#messages" ).find( "[name='" + response.removed[i] + "']" ).remove(); - } - setHeaderDelayMessage( i18n_messages_were_deleted ); - }, - error: function( response ) - { - showErrorMessage( response.message, 3 ); - } - } ); - } -} - -function markMessagesRead( messages ) -{ - if( messages.length < 1 ) - { - return; - } - - $.ajax( - { - url: "../api/messageConversations/read", - type: "POST", - data: JSON.stringify( messages ), - contentType: "application/json", - dataType: "json", - success: function( response ) - { - toggleMessagesRead( response.markedRead ); - }, - error: function( response ) - { - showErrorMessage( response.message, 3 ); - } - } ); -} - -function markMessagesUnread( messages ) -{ - if( messages.length < 1 ) - { - return; - } - - $.ajax( - { - url: "../api/messageConversations/unread", - type: "POST", - data: JSON.stringify( messages ), - contentType: "application/json", - dataType: "json", - success: function( response ) - { - toggleMessagesRead( response.markedUnread ); - }, - error: function( response ) - { - showErrorMessage( response.message, 3 ); - } - } ); -} - -function toggleMessagesRead( messageUids ) -{ - var messages = $( "#messages" ); - - for( var i = 0; i < messageUids.length; i++ ) - { - messages.find( "[name='" + messageUids[i] + "']" ).toggleClass( "unread bold" ); - } -} - function toggleRowSelected( element ) { $( element ).closest( "tr" ).toggleClass( "list-row-selected", element.checked ); @@ -197,3 +102,119 @@ return item.text; } } + +var messageOperations = ( function() { + + // + // Private + // + + var removeMessages = function( messages ) { + if( typeof messages === "undefined" || messages.length < 1 ) { + return; + } + + var confirmed = window.confirm( i18n_confirm_delete_all_selected_messages ); + + if( confirmed ) { + setHeaderWaitMessage( i18n_deleting ); + + $.ajax( { + url: "../api/messageConversations?" + $.param( { mc: messages }, true ), + contentType: "application/json", + dataType: "json", + type: "DELETE", + success: function( response ) { + for( var i = 0; i < response.removed.length; i++ ) { + $( "#messages" ).find( "[name='" + response.removed[i] + "']" ).remove(); + } + setHeaderDelayMessage( i18n_messages_were_deleted ); + }, + error: function( response ) { + showErrorMessage( response.message, 3 ); + } + } ); + } + }; + + var propertyRegExp = new RegExp( "[read|unread|followup|unfollowup]" ); + + /** + * Workhorse function to mark/unmark messages read, unread, followup or unfollowup. + * + * @param messages {array} UID of messages to mark + * @param property {string} property to mark. String values are read|unread|followup|unfollowup + */ + var markMessages = function( messages, property ) { + if( typeof messages === "undefined" || messages.length < 1 ) { + return; + } + + if( !_.isString( property ) || !propertyRegExp.test( property ) ) { + throw "Property string must be set."; + } + + $.ajax( { + url: "../api/messageConversations/" + property, + type: "POST", + data: JSON.stringify( messages ), + contentType: "application/json", + dataType: "json", + success: function( response ) { + switch( property ) { + case "read": + toggleMessagesRead( response.markedRead ); + break; + case "unread": + toggleMessagesRead( response.markedUnread ); + break; + case "followup": + setFollowupIndicator( response.markedFollowup, true); + break; + case "unfollowup": + setFollowupIndicator( response.unmarkedFollowup, false ); + break; + } + }, + error: function( response ) { + showErrorMessage( response.message, 3); + } + } ); + }; + + var setFollowupIndicator = function( messageUids, marked ) { + var messages = $( "#messages" ); + var imgSrc = marked ? "../images/marked.png" : "../images/unmarked.png"; + + for( var i = 0; i < messageUids.length; i++ ) { + messages.find( "[name='" + messageUids[i] + "'] .followup-icon img" ).attr( "src", imgSrc ); + } + }; + + var toggleMessagesRead = function( messageUids ) { + var messages = $( "#messages" ); + + for( var i = 0; i < messageUids.length; i++ ) { + messages.find( "[name='" + messageUids[i] + "']" ).toggleClass( "unread bold" ); + } + }; + + // + // Public + // + return { + unmarkMessagesFollowup: function( messages ) { + return markMessages( messages, "unfollowup" ); + }, + markMessagesFollowup: function( messages) { + return markMessages( messages, "followup" ); + }, + markMessagesRead: function( messages ) { + return markMessages( messages, "read" ); + }, + markMessagesUnread: function( messages ) { + return markMessages( messages, "unread" ); + }, + removeMessages: removeMessages + }; +})( window ); \ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/message.vm' --- dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/message.vm 2014-10-03 11:32:55 +0000 +++ dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/message.vm 2015-01-07 13:32:22 +0000 @@ -12,9 +12,11 @@
    -
  • Delete
  • -
  • Mark read
  • -
  • Mark unread
  • +
  • $i18n.getString( "delete" )
  • +
  • $i18n.getString( "mark_read")
  • +
  • $i18n.getString( "mark_unread" )
  • +
  • $i18n.getString( "mark_followup")
  • +
  • $i18n.getString( "clear_followup" )
@@ -43,7 +45,7 @@ - + #if( $conversation.lastSenderName )$!encoder.htmlEncode( $conversation.lastSenderName )#else $i18n.getString( "system_notification" )#end