From 10f13cb61847908afa4e6aae7880e7644489f8c0 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 22 Feb 2016 20:58:23 +0100 Subject: [PATCH] Improved activity stream messages. --- .../_application_controller.coffee | 9 +++--- .../widget/online_notification.coffee | 11 +++++-- .../javascripts/app/lib/app_post/i18n.coffee | 32 ++++++++++++------- .../app/models/_application_model.coffee | 3 ++ .../javascripts/app/models/group.coffee | 7 ++++ .../app/models/organization.coffee | 7 ++++ app/assets/javascripts/app/models/role.coffee | 7 ++++ .../javascripts/app/models/ticket.coffee | 11 +++++++ .../app/models/ticket_article.coffee | 9 +++++- app/assets/javascripts/app/models/user.coffee | 19 +++++++++++ .../views/dashboard/activity_stream.jst.eco | 6 +++- .../online_notification_content.jst.eco | 6 +++- app/models/activity_stream.rb | 30 ++++++++--------- app/models/application_model.rb | 4 +-- .../application_model/activity_stream_base.rb | 6 ++-- .../ticket/notification/background_job.rb | 5 ++- app/models/ticket/activity_stream_log.rb | 2 +- .../ticket/article/activity_stream_log.rb | 6 ++-- ...160222000001_improved_activity_messages.rb | 5 +++ public/assets/tests/core.js | 14 +++++--- test/unit/activity_stream_test.rb | 26 +++++++-------- 21 files changed, 163 insertions(+), 62 deletions(-) create mode 100644 db/migrate/20160222000001_improved_activity_messages.rb diff --git a/app/assets/javascripts/app/controllers/_application_controller.coffee b/app/assets/javascripts/app/controllers/_application_controller.coffee index 89f87ead2..bf526ae87 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.coffee @@ -480,14 +480,15 @@ class App.Controller extends Spine.Controller item.object = item.object.replace('::', '') # lookup real data - if App[item.object] && App[item.object].exists( item.o_id ) - object = App[item.object].find( item.o_id ) + if App[item.object] && App[item.object].exists(item.o_id) + object = App[item.object].find(item.o_id) + item.objectNative = object item.link = object.uiUrl() item.title = object.displayName() item.object_name = object.objectDisplayName() - item.cssIcon = object.iconActivity( @Session.get() ) + item.cssIcon = object.iconActivity(@Session.get()) - item.created_by = App.User.find( item.created_by_id ) + item.created_by = App.User.find(item.created_by_id) items # central method, is getting called on every ticket form change diff --git a/app/assets/javascripts/app/controllers/widget/online_notification.coffee b/app/assets/javascripts/app/controllers/widget/online_notification.coffee index 7bc4fb792..73e4e0651 100644 --- a/app/assets/javascripts/app/controllers/widget/online_notification.coffee +++ b/app/assets/javascripts/app/controllers/widget/online_notification.coffee @@ -40,6 +40,11 @@ class App.OnlineNotificationWidget extends App.Controller @createContainer() @subscribeId = App.OnlineNotification.subscribe(@updateContent) + @bind('ui:rerender', => + @updateContent() + 'popover' + ) + release: -> @removeContainer() $(window).off 'click.notifications' @@ -141,8 +146,10 @@ class App.OnlineNotificationWidget extends App.Controller if !@alreadyShown[item.id] @alreadyShown[item.id] = true if @fetchedData - word = "#{item.type}d" - title = "#{item.created_by.displayName()} #{App.i18n.translateInline(word)} #{App.i18n.translateInline(item.object_name)} \"#{item.title}\"" + if item.objectNative && item.objectNative.activityMessage + title = item.objectNative.activityMessage(item) + else + title = "Need objectNative in item #{item.object}.find(#{item.o_id})" @notifyDesktop( url: item.link title: title diff --git a/app/assets/javascripts/app/lib/app_post/i18n.coffee b/app/assets/javascripts/app/lib/app_post/i18n.coffee index a754c0ade..aa3ed464f 100644 --- a/app/assets/javascripts/app/lib/app_post/i18n.coffee +++ b/app/assets/javascripts/app/lib/app_post/i18n.coffee @@ -174,7 +174,7 @@ class _i18nSingleton extends Spine.Module translateInline: (string, args) => return string if !string - App.Utils.htmlEscape(@translate(string, args)) + @translate(string, args, true) translateContent: (string, args) => return string if !string @@ -182,19 +182,12 @@ class _i18nSingleton extends Spine.Module if App.Config.get('translation_inline') return '' + App.Utils.htmlEscape(@translate(string)) + '' - translated = App.Utils.htmlEscape(@translate(string, args)) - - # apply inline markup - translated - .replace(/\|\|(.+?)\|\|/gm, '$1') - .replace(/\|(.+?)\|/gm, '$1') - .replace(/_(.+?)_/gm, '$1') - .replace(/§(.+?)§/gm, '$1') + translated = @translate(string, args, true, true) translatePlain: (string, args) => @translate(string, args) - translate: (string, args) => + translate: (string, args, quote, markup) => # type convertation if typeof string isnt 'string' @@ -221,10 +214,27 @@ class _i18nSingleton extends Spine.Module @log 'notice', "translation for '#{string}' in '#{@locale}' is missing" @_notTranslated[@locale][string] = true + # apply html quote + if quote + translated = App.Utils.htmlEscape(translated) + + # apply inline markup + if markup + translated = translated + .replace(/\|\|(.+?)\|\|/gm, '$1') + .replace(/\|(.+?)\|/gm, '$1') + .replace(/_(.+?)_/gm, '$1') + .replace(/§(.+?)§/gm, '$1') + # search %s if args for arg in args - translated = translated.replace(/%s/, arg) + if quote + argNew = App.Utils.htmlEscape(arg) + else + argNew = arg + + translated = translated.replace(/%s/, argNew) @log 'debug', 'translate', string, args, translated diff --git a/app/assets/javascripts/app/models/_application_model.coffee b/app/assets/javascripts/app/models/_application_model.coffee index d1d182880..a16907879 100644 --- a/app/assets/javascripts/app/models/_application_model.coffee +++ b/app/assets/javascripts/app/models/_application_model.coffee @@ -643,3 +643,6 @@ class App.Model extends Spine.Model return ) collection + + activityMessage: (item) -> + return "Need own activityMessage() in model to generate text (#{@objectDisplayName()}/#{item.type})." diff --git a/app/assets/javascripts/app/models/group.coffee b/app/assets/javascripts/app/models/group.coffee index b8690e110..b2bcad9a0 100644 --- a/app/assets/javascripts/app/models/group.coffee +++ b/app/assets/javascripts/app/models/group.coffee @@ -20,3 +20,10 @@ class App.Group extends App.Model uiUrl: -> '#group/zoom/' + @id + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created Group |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated Group |%s|', item.created_by.displayName(), item.title) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/models/organization.coffee b/app/assets/javascripts/app/models/organization.coffee index 129cd6160..d45041a99 100644 --- a/app/assets/javascripts/app/models/organization.coffee +++ b/app/assets/javascripts/app/models/organization.coffee @@ -45,3 +45,10 @@ Mit **Organisationen** können Sie Kunden **gruppieren**. Dies hat u. a. zwei be class: 'organization organization-popover' url: @uiUrl() icon: 'organization' + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created Organization |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated Organization |%s|', item.created_by.displayName(), item.title) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/models/role.coffee b/app/assets/javascripts/app/models/role.coffee index a78a6c103..0800e15b1 100644 --- a/app/assets/javascripts/app/models/role.coffee +++ b/app/assets/javascripts/app/models/role.coffee @@ -14,3 +14,10 @@ class App.Role extends App.Model @configure_overview = [ 'name', ] + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created Role |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated Role |%s|', item.created_by.displayName(), item.title) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/models/ticket.coffee b/app/assets/javascripts/app/models/ticket.coffee index f30d4876d..053c50254 100644 --- a/app/assets/javascripts/app/models/ticket.coffee +++ b/app/assets/javascripts/app/models/ticket.coffee @@ -77,3 +77,14 @@ class App.Ticket extends App.Model url: @uiUrl() icon: 'task-state' iconClass: @getState() + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created Ticket |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated Ticket |%s|', item.created_by.displayName(), item.title) + else if item.type is 'reminder_reached' + return App.i18n.translateContent('Pending reminder reached for Ticket |%s|', item.title) + else if item.type is 'escalation' + return App.i18n.translateContent('Ticket |%s| is escalated!', item.title) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/models/ticket_article.coffee b/app/assets/javascripts/app/models/ticket_article.coffee index 3ac3bf28a..881e0433d 100644 --- a/app/assets/javascripts/app/models/ticket_article.coffee +++ b/app/assets/javascripts/app/models/ticket_article.coffee @@ -37,4 +37,11 @@ class App.TicketArticle extends App.Model ticket = App.Ticket.find(@ticket_id) if ticket.owner_id == user.id return 'important' - '' \ No newline at end of file + '' + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created Article for |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated Article for |%s|', item.created_by.displayName(), item.title) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/models/user.coffee b/app/assets/javascripts/app/models/user.coffee index 6a52d4388..b5869527d 100644 --- a/app/assets/javascripts/app/models/user.coffee +++ b/app/assets/javascripts/app/models/user.coffee @@ -142,3 +142,22 @@ class App.User extends App.Model class: 'user user-popover' url: @uiUrl() icon: 'user' + + activityMessage: (item) -> + if item.type is 'create' + return App.i18n.translateContent('%s created User |%s|', item.created_by.displayName(), item.title) + else if item.type is 'update' + return App.i18n.translateContent('%s updated User |%s|', item.created_by.displayName(), item.title) + else if item.type is 'session started' + return App.i18n.translateContent('%s started a new session', item.created_by.displayName()) + else if item.type is 'switch to' + to = item.title + if item.objectNative + to = item.objectNative.displayName() + return App.i18n.translateContent('%s switched to |%s|!', item.created_by.displayName(), to) + else if item.type is 'ended switch to' + to = item.title + if item.objectNative + to = item.objectNative.displayName() + return App.i18n.translateContent('%s ended switch to |%s|!', item.created_by.displayName(), to) + return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model." diff --git a/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco b/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco index 9c339caaf..d6785cc9b 100644 --- a/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco +++ b/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco @@ -3,7 +3,11 @@ - <%= @item.created_by.displayName() %> <%- @T( @item.type ) %> <%- @T( @item.object_name ) %><% if @item.title: %> <%= @item.title %><% end %> + <% if @item.objectNative && @item.objectNative.activityMessage: %> + <%- @item.objectNative.activityMessage(@item) %> + <% else: %> + Need objectNative in item <%= item.object %>.find(<%= item.o_id %>) + <% end %> <%- @humanTime(@item.created_at, false, 'activity-time') %> diff --git a/app/assets/javascripts/app/views/widget/online_notification_content.jst.eco b/app/assets/javascripts/app/views/widget/online_notification_content.jst.eco index 78244ee6b..12605f565 100644 --- a/app/assets/javascripts/app/views/widget/online_notification_content.jst.eco +++ b/app/assets/javascripts/app/views/widget/online_notification_content.jst.eco @@ -7,7 +7,11 @@
- <%= item.created_by.displayName() %> <%- @T( "#{item.type}d" ) %> <%- @T( item.object_name ) %><% if item.title: %> <%= item.title %><% end %> + <% if item.objectNative && item.objectNative.activityMessage: %> + <%- item.objectNative.activityMessage(item) %> + <% else: %> + Need objectNative in item <%= item.object %>.find(<%= item.o_id %>) + <% end %> <%- @humanTime(item.created_at, false, 'activity-time') %> diff --git a/app/models/activity_stream.rb b/app/models/activity_stream.rb index 363bb5bcd..65393eb40 100644 --- a/app/models/activity_stream.rb +++ b/app/models/activity_stream.rb @@ -10,12 +10,12 @@ class ActivityStream < ApplicationModel add a new activity entry for an object ActivityStream.add( - :type => 'updated', - :object => 'Ticket', - :role => 'Admin', - :o_id => ticket.id, - :created_by_id => 1, - :created_at => '2013-06-04 10:00:00', + type: 'update', + object: 'Ticket', + role: 'Admin', + o_id: ticket.id, + created_by_id: 1, + created_at: '2013-06-04 10:00:00', ) =end @@ -24,15 +24,15 @@ add a new activity entry for an object # lookups if data[:type] - type_id = TypeLookup.by_name( data[:type] ) + type_id = TypeLookup.by_name(data[:type]) end if data[:object] - object_id = ObjectLookup.by_name( data[:object] ) + object_id = ObjectLookup.by_name(data[:object]) end role_id = nil if data[:role] - role = Role.lookup( name: data[:role] ) + role = Role.lookup(name: data[:role]) if !role fail "No such Role #{data[:role]}" end @@ -49,7 +49,7 @@ add a new activity entry for an object ).order('created_at DESC, id DESC').first # resturn if old entry is really fresh - return result if result && result.created_at.to_i >= ( data[:created_at].to_i - 12 ) + return result if result && result.created_at.to_i >= ( data[:created_at].to_i - 20 ) # create history record = { @@ -69,12 +69,12 @@ add a new activity entry for an object remove whole activity entries of an object - ActivityStream.remove( 'Ticket', 123 ) + ActivityStream.remove('Ticket', 123) =end - def self.remove( object_name, o_id ) - object_id = ObjectLookup.by_name( object_name ) + def self.remove(object_name, o_id) + object_id = ObjectLookup.by_name(object_name) ActivityStream.where( activity_stream_object_id: object_id, o_id: o_id, @@ -85,7 +85,7 @@ remove whole activity entries of an object return all activity entries of an user - activity_stream = ActivityStream.list( user ) + activity_stream = ActivityStream.list(user) =end @@ -94,7 +94,7 @@ return all activity entries of an user group_ids = user.group_ids # do not return an activity stream for custoers - customer_role = Role.lookup( name: 'Customer' ) + customer_role = Role.lookup(name: 'Customer') return [] if role_ids.include?(customer_role.id) stream = if group_ids.empty? diff --git a/app/models/application_model.rb b/app/models/application_model.rb index 6f7313a60..68b038abb 100644 --- a/app/models/application_model.rb +++ b/app/models/application_model.rb @@ -826,7 +826,7 @@ log object create activity stream, if configured - will be executed automaticall def activity_stream_create return if !self.class.activity_stream_support_config - activity_stream_log('created', self['created_by_id']) + activity_stream_log('create', self['created_by_id']) end =begin @@ -867,7 +867,7 @@ log object update activity stream, if configured - will be executed automaticall return if !log - activity_stream_log('updated', self['updated_by_id']) + activity_stream_log('update', self['updated_by_id']) end =begin diff --git a/app/models/application_model/activity_stream_base.rb b/app/models/application_model/activity_stream_base.rb index e4233237b..85173eaf9 100644 --- a/app/models/application_model/activity_stream_base.rb +++ b/app/models/application_model/activity_stream_base.rb @@ -6,10 +6,10 @@ module ApplicationModel::ActivityStreamBase log activity for this object article = Ticket::Article.find(123) - result = article.activity_stream_log( 'created', user_id ) + result = article.activity_stream_log('create', user_id) # force log - result = article.activity_stream_log( 'created', user_id, true ) + result = article.activity_stream_log('create', user_id, true) returns @@ -17,7 +17,7 @@ returns =end - def activity_stream_log (type, user_id, force = false) + def activity_stream_log(type, user_id, force = false) # return if we run import mode return if Setting.get('import_mode') diff --git a/app/models/observer/ticket/notification/background_job.rb b/app/models/observer/ticket/notification/background_job.rb index 304987106..78c0b9b41 100644 --- a/app/models/observer/ticket/notification/background_job.rb +++ b/app/models/observer/ticket/notification/background_job.rb @@ -151,9 +151,12 @@ class Observer::Ticket::Notification::BackgroundJob if channels['online'] used_channels.push 'online' + created_by_id = ticket.updated_by_id || 1 + # delete old notifications if @p[:type] == 'reminder_reached' || @p[:type] == 'escalation' seen = false + created_by_id = 1 OnlineNotification.remove_by_type('Ticket', ticket.id, @p[:type], user) # on updates without state changes create unseen messages @@ -168,7 +171,7 @@ class Observer::Ticket::Notification::BackgroundJob object: 'Ticket', o_id: ticket.id, seen: seen, - created_by_id: ticket.updated_by_id || 1, + created_by_id: created_by_id, user_id: user.id, ) Rails.logger.debug "sent ticket online notifiaction to agent (#{@p[:type]}/#{ticket.id}/#{user.email})" diff --git a/app/models/ticket/activity_stream_log.rb b/app/models/ticket/activity_stream_log.rb index 47c924d67..14f0f4897 100644 --- a/app/models/ticket/activity_stream_log.rb +++ b/app/models/ticket/activity_stream_log.rb @@ -6,7 +6,7 @@ module Ticket::ActivityStreamLog log activity for this object ticket = Ticket.find(123) - result = ticket.activity_stream_log( 'created', user_id ) + result = ticket.activity_stream_log('create', user_id) returns diff --git a/app/models/ticket/article/activity_stream_log.rb b/app/models/ticket/article/activity_stream_log.rb index 07365d6c7..18d723c8f 100644 --- a/app/models/ticket/article/activity_stream_log.rb +++ b/app/models/ticket/article/activity_stream_log.rb @@ -6,7 +6,7 @@ module Ticket::Article::ActivityStreamLog log activity for this object article = Ticket::Article.find(123) - result = article.activity_stream_log( 'created', user_id ) + result = article.activity_stream_log('create', user_id) returns @@ -14,7 +14,7 @@ returns =end - def activity_stream_log (type, user_id) + def activity_stream_log(type, user_id) # return if we run import mode return if Setting.get('import_mode') @@ -24,7 +24,7 @@ returns return if !self.class.activity_stream_support_config role = self.class.activity_stream_support_config[:role] - ticket = Ticket.lookup( id: ticket_id ) + ticket = Ticket.lookup(id: ticket_id) ActivityStream.add( o_id: self['id'], type: type, diff --git a/db/migrate/20160222000001_improved_activity_messages.rb b/db/migrate/20160222000001_improved_activity_messages.rb new file mode 100644 index 000000000..66c318c8e --- /dev/null +++ b/db/migrate/20160222000001_improved_activity_messages.rb @@ -0,0 +1,5 @@ +class ImprovedActivityMessages < ActiveRecord::Migration + def up + ActivityStream.destroy_all + end +end diff --git a/public/assets/tests/core.js b/public/assets/tests/core.js index 110f66947..606e71bb1 100644 --- a/public/assets/tests/core.js +++ b/public/assets/tests/core.js @@ -271,8 +271,11 @@ test( "i18n", function() { translated = App.i18n.translateContent('%s ago', 123); equal( translated, 'vor 123', 'de-de - %s' ); - translated = App.i18n.translateContent('%s %s test', 123, 'xxx'); - equal( translated, '123 xxx test', 'de-de - %s %s' ); + translated = App.i18n.translateContent('%s ago', 'quote'); + equal( translated, 'vor <b>quote</b>', 'de-de - %s - quote' ); + + translated = App.i18n.translateContent('%s %s test', 123, 'xxx |B|'); + equal( translated, '123 xxx |B| test', 'de-de - %s %s' ); translated = App.i18n.translateContent('|%s| %s test', 123, 'xxx'); equal( translated, '123 xxx test', 'de-de - *%s* %s' ); @@ -311,11 +314,14 @@ test( "i18n", function() { translated = App.i18n.translateContent('%s ago', 123); equal( translated, '123 ago', 'en-us - %s' ); + translated = App.i18n.translateContent('%s ago', 'quote'); + equal( translated, '<b>quote</b> ago', 'en-us - %s - qupte' ); + translated = App.i18n.translateContent('%s %s test', 123, 'xxx'); equal( translated, '123 xxx test', 'en-us - %s %s' ); - translated = App.i18n.translateContent('|%s| %s test', 123, 'xxx'); - equal( translated, '123 xxx test', 'en-us - *%s* %s' ); + translated = App.i18n.translateContent('|%s| %s test', 123, 'xxx |B|'); + equal( translated, '123 xxx |B| test', 'en-us - *%s* %s' ); translated = App.i18n.translateContent('||%s|| %s test', 123, 'xxx'); equal( translated, '123 xxx test', 'en-us - *%s* %s' ); diff --git a/test/unit/activity_stream_test.rb b/test/unit/activity_stream_test.rb index 31ba7443c..ef29b0c96 100644 --- a/test/unit/activity_stream_test.rb +++ b/test/unit/activity_stream_test.rb @@ -61,22 +61,22 @@ class ActivityStreamTest < ActiveSupport::TestCase { result: true, object: 'Ticket', - type: 'updated', + type: 'update', }, { result: true, object: 'Ticket::Article', - type: 'created', + type: 'create', }, { result: true, object: 'Ticket', - type: 'created', + type: 'create', }, { result: false, object: 'User', - type: 'updated', + type: 'update', o_id: current_user.id, }, ] @@ -118,7 +118,7 @@ class ActivityStreamTest < ActiveSupport::TestCase article.update_attributes(test[:update][:article]) end - sleep 15 + sleep 21 if test[:update][:ticket] ticket.update_attributes(test[:update][:ticket]) end @@ -168,12 +168,12 @@ class ActivityStreamTest < ActiveSupport::TestCase { result: true, object: 'Organization', - type: 'updated', + type: 'update', }, { result: true, object: 'Organization', - type: 'created', + type: 'create', }, ] }, @@ -194,7 +194,7 @@ class ActivityStreamTest < ActiveSupport::TestCase test[:check][1][:o_id] = organization.id test[:check][1][:updated_at] = organization.updated_at test[:check][1][:created_by_id] = current_user.id - sleep 13 + sleep 19 end if test[:update2][:organization] @@ -240,12 +240,12 @@ class ActivityStreamTest < ActiveSupport::TestCase { result: true, object: 'User', - type: 'created', + type: 'create', }, { result: false, object: 'User', - type: 'updated', + type: 'update', }, ] }, @@ -312,12 +312,12 @@ class ActivityStreamTest < ActiveSupport::TestCase { result: true, object: 'User', - type: 'updated', + type: 'update', }, { result: true, object: 'User', - type: 'created', + type: 'create', }, ] }, @@ -340,7 +340,7 @@ class ActivityStreamTest < ActiveSupport::TestCase end # to verify update which need to be logged - sleep 14 + sleep 21 if test[:update2][:user] user.update_attributes(test[:update2][:user])