From 4e2288e9a4b690fef2e36b9d165d7fb71a6ea448 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sat, 28 Sep 2013 02:07:11 +0200 Subject: [PATCH] Added generic activity stream support. --- .../_dashboard/activity_stream.js.coffee | 23 +- .../views/dashboard/activity_stream.jst.eco | 4 +- ...oller.rb => activity_stream_controller.rb} | 6 +- app/controllers/sessions_controller.rb | 2 + app/models/activity_stream.rb | 179 ++++++++++++++++ app/models/application_model.rb | 62 ++++++ .../application_model/activity_stream_base.rb | 30 +++ app/models/group.rb | 11 +- app/models/history.rb | 53 +---- app/models/observer/history.rb | 10 - app/models/organization.rb | 5 +- app/models/role.rb | 5 +- app/models/ticket.rb | 1 + app/models/ticket/article.rb | 4 +- app/models/user.rb | 50 ++++- app/models/user/assets.rb | 6 + config/application.rb | 4 +- config/routes/activity_stream.rb | 2 +- .../20130925000001_create_activity_stream.rb | 41 ++++ lib/sessions/backend/activity_stream.rb | 4 +- test/unit/activity_stream_test.rb | 199 ++++++++++++++++++ 21 files changed, 611 insertions(+), 90 deletions(-) rename app/controllers/{activity_controller.rb => activity_stream_controller.rb} (57%) create mode 100644 app/models/activity_stream.rb create mode 100644 app/models/application_model/activity_stream_base.rb create mode 100644 db/migrate/20130925000001_create_activity_stream.rb create mode 100644 test/unit/activity_stream_test.rb diff --git a/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee b/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee index d66715bdc..0f1fcfd27 100644 --- a/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee +++ b/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee @@ -40,21 +40,26 @@ class App.DashboardActivityStream extends App.Controller render: (items) -> for item in items - if item.history_object is 'Ticket' + if item.object is 'Ticket' ticket = App.Ticket.find( item.o_id ) item.link = '#ticket/zoom/' + ticket.id item.title = ticket.title - item.type = 'Ticket' - item.updated_by_id = ticket.updated_by_id - item.updated_by = App.User.find( ticket.updated_by_id ) - else if item.history_object is 'Ticket::Article' + item.object = 'Ticket' + + else if item.object is 'Ticket::Article' article = App.TicketArticle.find( item.o_id ) ticket = App.Ticket.find( article.ticket_id ) item.link = '#ticket/zoom/' + ticket.id + '/' + article.id item.title = article.subject || ticket.title - item.type = 'Article' - item.updated_by_id = article.updated_by_id - item.updated_by = App.User.find( article.updated_by_id ) + item.object = 'Article' + + else if item.object is 'User' + user = App.User.find( item.o_id ) + item.link = '#user/zoom/' + item.o_id + item.title = user.displayName() + item.object = 'User' + + item.created_by = App.User.find( item.created_by_id ) html = App.view('dashboard/activity_stream')( head: 'Activity Stream', @@ -67,3 +72,5 @@ class App.DashboardActivityStream extends App.Controller # start user popups @userPopups('right') + # update time + @frontendTimeUpdate() 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 76597cf3b..3bbedf280 100644 --- a/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco +++ b/app/assets/javascripts/app/views/dashboard/activity_stream.jst.eco @@ -2,8 +2,8 @@

<%- @T( @head ) %>

<% for item in @items: %> -
"<%= item.updated_by.displayName() %>"
-
<%- @T( item.history_type ) %> <%= item.type %><% if item.title: %> (<%= item.title %>)<% end %>.
+
"<%= item.created_by.displayName() %>"
+
<%- @T( item.type ) %> <%= item.object %><% if item.title: %> (<%= item.title %>)<% end %> ? <%- @T('ago') %>.
<% end %>
diff --git a/app/controllers/activity_controller.rb b/app/controllers/activity_stream_controller.rb similarity index 57% rename from app/controllers/activity_controller.rb rename to app/controllers/activity_stream_controller.rb index d85f73aed..33f01b5b0 100644 --- a/app/controllers/activity_controller.rb +++ b/app/controllers/activity_stream_controller.rb @@ -1,11 +1,11 @@ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ -class ActivityController < ApplicationController +class ActivityStreamController < ApplicationController before_filter :authentication_check # GET /api/v1/activity_stream - def activity_stream - activity_stream = History.activity_stream_fulldata( current_user, params[:limit] ) + def show + activity_stream = current_user.activity_stream( params[:limit], true ) # return result render :json => activity_stream diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index d76b6857a..cfb6fa9db 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -14,6 +14,8 @@ class SessionsController < ApplicationController return end + user.activity_stream_log( 'session started', user.id ) + # auto population of default collections default_collection = SessionHelper::default_collections(user) diff --git a/app/models/activity_stream.rb b/app/models/activity_stream.rb new file mode 100644 index 000000000..6ff5682fe --- /dev/null +++ b/app/models/activity_stream.rb @@ -0,0 +1,179 @@ +# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ + +class ActivityStream < ApplicationModel + self.table_name = 'activity_streams' + belongs_to :activity_stream_type, :class_name => 'ActivityStream::Type' + belongs_to :activity_stream_object, :class_name => 'ActivityStream::Object' + + @@cache_type = {} + @@cache_object = {} + +=begin + +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', + ) + +=end + + def self.add(data) + + # lookups + if data[:type] + type = self.type_lookup( data[:type] ) + end + if data[:object] + object = self.object_lookup( data[:object] ) + end + + role_id = nil + if data[:role] + role_id = Role.lookup( :name => data[:role] ) + if !role_id + raise "No such Role #{data[:role]}" + end + end + + # check if entry is needed + result = ActivityStream.where( + :o_id => data[:o_id], + # :activity_stream_type_id => type.id, + :role_id => role_id, + :activity_stream_object_id => object.id, + :created_by_id => data[:created_by_id] + ).last + + # resturn if old entry is really freash + return result if result && result.created_at >= (data[:created_at] - 10.seconds) + puts "AS: #{data[:type]} #{data[:object]} #{data[:o_id]}" + + # create history + record = { + :o_id => data[:o_id], + :activity_stream_type_id => type.id, + :activity_stream_object_id => object.id, + :created_at => data[:created_at], + :created_by_id => data[:created_by_id] + } + ActivityStream.create(record) + end + +=begin + +remove whole activity entries of an object + + ActivityStream.remove( 'Ticket', 123 ) + +=end + + def self.remove( object_name, o_id ) + object = self.object_lookup( object_name ) + ActivityStream.where( + :activity_stream_object_id => object.id, + :o_id => o_id, + ).destroy_all + end + +=begin + +return all activity entries of an user + + activity_stream = ActivityStream.list( user ) + +=end + + def self.list(user,limit) +# stream = ActivityStream.where( :role_id => user.roles, :group_id => user.groups ) + stream = ActivityStream.where('1=1'). + order( 'created_at DESC, id DESC' ). + limit( limit ) + list = [] + stream.each do |item| + data = item.attributes + data['object'] = self.object_lookup_id( data['activity_stream_object_id'] ).name + data['type'] = self.type_lookup_id( data['activity_stream_type_id'] ).name + data.delete('activity_stream_object_id') + data.delete('activity_stream_type_id') + list.push data + end + list + end + + private + + def self.type_lookup_id( id ) + + # use cache + return @@cache_type[ id ] if @@cache_type[ id ] + + # lookup + type = ActivityStream::Type.find(id) + @@cache_type[ id ] = type + type + end + + def self.type_lookup( name ) + + # use cache + return @@cache_type[ name ] if @@cache_type[ name ] + + # lookup + type = ActivityStream::Type.where( :name => name ).first + if type + @@cache_type[ name ] = type + return type + end + + # create + type = ActivityStream::Type.create( + :name => name + ) + @@cache_type[ name ] = type + type + end + + def self.object_lookup_id( id ) + + # use cache + return @@cache_object[ id ] if @@cache_object[ id ] + + # lookup + object = ActivityStream::Object.find(id) + @@cache_object[ id ] = object + object + end + + def self.object_lookup( name ) + + # use cache + return @@cache_object[ name ] if @@cache_object[ name ] + + # lookup + object = ActivityStream::Object.where( :name => name ).first + if object + @@cache_object[ name ] = object + return object + end + + # create + object = ActivityStream::Object.create( + :name => name + ) + @@cache_object[ name ] = object + object + end + + class Object < ApplicationModel + end + + class Type < ApplicationModel + end + +end diff --git a/app/models/application_model.rb b/app/models/application_model.rb index b1782c518..ee8ae1cdb 100644 --- a/app/models/application_model.rb +++ b/app/models/application_model.rb @@ -2,6 +2,7 @@ class ApplicationModel < ActiveRecord::Base include ApplicationModel::HistoryLogBase + include ApplicationModel::ActivityStreamBase self.abstract_class = true @@ -14,6 +15,13 @@ class ApplicationModel < ActiveRecord::Base after_update :cache_delete after_destroy :cache_delete + after_create :activity_stream_create + after_update :activity_stream_update + after_destroy :activity_stream_destroy + + # create instance accessor + class << self; attr_accessor :activity_stream_support_config end + @@import_class_list = ['Ticket', 'Ticket::Article', 'History', 'Ticket::State', 'Ticket::Priority', 'Group', 'User' ] def check_attributes_protected @@ -410,6 +418,59 @@ class OwnModel < ApplicationModel =begin +serve methode to configure activity stream support for this model + +class Model < ApplicationModel + activity_stream_support :role => 'Admin' +end + +=end + + def self.activity_stream_support(data = {}) + @activity_stream_support_config = data + end + +=begin + +log object create activity stream + + model = Model.find(123) + model.activity_stream_create + +=end + + def activity_stream_create + activity_stream_log( 'created', self['created_by_id'] ) + end + +=begin + +log object update activity stream + + model = Model.find(123) + model.activity_stream_update + +=end + + def activity_stream_update + activity_stream_log( 'updated', self['updated_by_id'] ) + end + +=begin + +delete object activity stream + + model = Model.find(123) + model.activity_stream_destroy + +=end + + def activity_stream_destroy + ActivityStream.remove( self.class.to_s, self.id ) + end + +=begin + destory object dependencies, will be executed automatically =end @@ -418,6 +479,7 @@ destory object dependencies, will be executed automatically # delete history History.remove( self.class.to_s, self.id ) + end end diff --git a/app/models/application_model/activity_stream_base.rb b/app/models/application_model/activity_stream_base.rb new file mode 100644 index 000000000..91aaaeaaa --- /dev/null +++ b/app/models/application_model/activity_stream_base.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ + +module ApplicationModel::ActivityStreamBase + +=begin + +log activity for this object + + article = Ticket::Article.find(123) + result = article.activity_stream_log( 'created', user_id ) + +returns + + result = true # false + +=end + + def activity_stream_log (type, user_id) + return if !self.class.activity_stream_support_config + ActivityStream.add( + :o_id => self['id'], + :type => type, + :object => self.class.name, +# :role => self.activity_stream_role, + :created_at => self.updated_at, + :created_by_id => user_id, + ) + end + +end \ No newline at end of file diff --git a/app/models/group.rb b/app/models/group.rb index 707f55197..98c23770f 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -1,8 +1,9 @@ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ class Group < ApplicationModel - has_and_belongs_to_many :users, :after_add => :cache_update, :after_remove => :cache_update - belongs_to :email_address - belongs_to :signature - validates :name, :presence => true -end + has_and_belongs_to_many :users, :after_add => :cache_update, :after_remove => :cache_update + belongs_to :email_address + belongs_to :signature + validates :name, :presence => true + activity_stream_support :role => 'Admin' +end \ No newline at end of file diff --git a/app/models/history.rb b/app/models/history.rb index 581877682..97c5863b5 100644 --- a/app/models/history.rb +++ b/app/models/history.rb @@ -95,6 +95,7 @@ remove whole history entries of an object def self.remove( requested_object, requested_object_id ) history_object = History::Object.where( :name => requested_object ).first + return if !history_object History.where( :history_object_id => history_object.id, :o_id => requested_object_id, @@ -103,7 +104,7 @@ remove whole history entries of an object =begin -return all histoy entries of an object +return all history entries of an object history_list = History.list( 'Ticket', 123 ) @@ -133,56 +134,6 @@ return all histoy entries of an object return history end - def self.activity_stream( user, limit = 10 ) - # g = Group.where( :active => true ).joins(:users).where( 'users.id' => user.id ) - # stream = History.select("distinct(histories.o_id), created_by_id, history_attribute_id, history_type_id, history_object_id, value_from, value_to"). - # where( :history_type_id => History::Type.where( :name => ['created', 'updated']) ). - stream = History.select("distinct(histories.o_id), created_by_id, history_type_id, history_object_id"). - where( :history_object_id => History::Object.where( :name => [ 'Ticket', 'Ticket::Article' ] ) ). - where( :history_type_id => History::Type.where( :name => [ 'created', 'updated' ]) ). - order('created_at DESC, id DESC'). - limit(limit) - datas = [] - stream.each do |item| - data = item.attributes - data['history_object'] = self.object_lookup_id( data['history_object_id'] ).name - data['history_type'] = self.type_lookup_id( data['history_type_id'] ).name - data.delete('history_object_id') - data.delete('history_type_id') - datas.push data - # item['history_attribute'] = item.history_attribute - end - return datas - end - - def self.activity_stream_fulldata( user, limit = 10 ) - activity_stream = History.activity_stream( user, limit ) - - # get related users - assets = {} - activity_stream.each {|item| - - # load article ids - if item['history_object'] == 'Ticket' - ticket = Ticket.find( item['o_id'] ) - assets = ticket.assets(assets) - end - if item['history_object'] == 'Ticket::Article' - article = Ticket::Article.find( item['o_id'] ) - assets = article.assets(assets) - end - if item['history_object'] == 'User' - user = User.find( item['o_id'] ) - assets = user.assets(assets) - end - } - - return { - :activity_stream => activity_stream, - :assets => assets, - } - end - private def self.type_lookup_id( id ) diff --git a/app/models/observer/history.rb b/app/models/observer/history.rb index 15ceff027..2010685ca 100644 --- a/app/models/observer/history.rb +++ b/app/models/observer/history.rb @@ -20,10 +20,6 @@ class Observer::History < ActiveRecord::Observer record.history_create( 'created', user_id ) end - # log activity stream - if record.respond_to?('activity_stream') - record.activity_stream( 'created', user_id ) - end end def before_update(record) @@ -149,12 +145,6 @@ class Observer::History < ActiveRecord::Observer end end - # log activity stream - if history_logged - if record.respond_to?('activity_stream') - record.activity_stream( 'updated', user_id ) - end - end end def differences_from?(one, other) diff --git a/app/models/organization.rb b/app/models/organization.rb index 4fba65cc5..a86772d4b 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -4,7 +4,8 @@ class Organization < ApplicationModel include Organization::Assets extend Organization::Search - has_and_belongs_to_many :users - validates :name, :presence => true + has_and_belongs_to_many :users + validates :name, :presence => true + activity_stream_support :role => 'Admin' end \ No newline at end of file diff --git a/app/models/role.rb b/app/models/role.rb index bd9580925..cfaa3e030 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,6 +1,7 @@ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ class Role < ApplicationModel - has_and_belongs_to_many :users, :after_add => :cache_update, :after_remove => :cache_update - validates :name, :presence => true + has_and_belongs_to_many :users, :after_add => :cache_update, :after_remove => :cache_update + validates :name, :presence => true + activity_stream_support :role => 'Admin' end diff --git a/app/models/ticket.rb b/app/models/ticket.rb index b9a54a5a0..182b99bff 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -7,6 +7,7 @@ class Ticket < ApplicationModel after_create :notify_clients_after_create after_update :notify_clients_after_update after_destroy :notify_clients_after_destroy + activity_stream_support :role => 'User' belongs_to :group has_many :articles, :class_name => 'Ticket::Article', :after_add => :cache_update, :after_remove => :cache_update diff --git a/app/models/ticket/article.rb b/app/models/ticket/article.rb index cc2b0f2fa..fc6e97cce 100644 --- a/app/models/ticket/article.rb +++ b/app/models/ticket/article.rb @@ -4,15 +4,17 @@ class Ticket::Article < ApplicationModel include Ticket::Article::Assets include Ticket::Article::HistoryLog - after_create :attachment_check belongs_to :ticket belongs_to :ticket_article_type, :class_name => 'Ticket::Article::Type' belongs_to :ticket_article_sender, :class_name => 'Ticket::Article::Sender' belongs_to :created_by, :class_name => 'User' + after_create :attachment_check after_create :notify_clients_after_create after_update :notify_clients_after_update after_destroy :notify_clients_after_destroy + activity_stream_support + attr_accessor :attachments private diff --git a/app/models/user.rb b/app/models/user.rb index d25505e69..c148d6bf9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -19,6 +19,8 @@ class User < ApplicationModel store :preferences + activity_stream_support :role => 'Admin' + =begin fullname of user @@ -43,7 +45,7 @@ returns end fullname = fullname + self.lastname end - return fullname + fullname end =begin @@ -68,6 +70,52 @@ returns =begin +get users activity stream + + user = User.find(123) + result = user.activity_stream( 20 ) + +returns + + result = [ + { + :id =>2, + :o_id =>2, + :created_by_id => 3, + :created_at => '2013-09-28 00:57:21', + :object => "User", + :type => "created", + }, + { + :id =>2, + :o_id =>2, + :created_by_id => 3, + :created_at => '2013-09-28 00:59:21', + :object => "User", + :type => "updated", + }, + ] + +=end + + def activity_stream( limit, fulldata = false ) + activity_stream = ActivityStream.list( self, limit ) + return activity_stream if !fulldata + + # get related objects + assets = {} + activity_stream.each {|item| + record = Kernel.const_get( item['object'] ).find( item['o_id'] ) + assets = record.assets(assets) + } + return { + :activity_stream => activity_stream, + :assets => assets, + } + end + +=begin + authenticate user result = User.authenticate(username, password) diff --git a/app/models/user/assets.rb b/app/models/user/assets.rb index 307d46b62..b66069003 100644 --- a/app/models/user/assets.rb +++ b/app/models/user/assets.rb @@ -28,6 +28,12 @@ returns if !data[ User.to_app_model ][ self.id ] data[ User.to_app_model ][ self.id ] = User.user_data_full( self.id ) end + if !data[ User.to_app_model ][ self['created_by_id'] ] + data[ User.to_app_model ][ self['created_by_id'] ] = User.user_data_full( self['created_by_id'] ) + end + if !data[ User.to_app_model ][ self['updated_by_id'] ] + data[ User.to_app_model ][ self['updated_by_id'] ] = User.user_data_full( self['updated_by_id'] ) + end data end diff --git a/config/application.rb b/config/application.rb index 9655249a6..df6b5cf24 100644 --- a/config/application.rb +++ b/config/application.rb @@ -16,8 +16,8 @@ module Zammad # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. - config.autoload_paths += Dir["#{config.root}/lib/*", "#{config.root}/lib/**/"] -# config.autoload_paths += %W(#{config.root}/lib) +# config.autoload_paths += Dir["#{config.root}/lib/*", "#{config.root}/lib/**/"] + config.autoload_paths += %W(#{config.root}/lib) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. diff --git a/config/routes/activity_stream.rb b/config/routes/activity_stream.rb index d43837358..0d7194c6d 100644 --- a/config/routes/activity_stream.rb +++ b/config/routes/activity_stream.rb @@ -1,6 +1,6 @@ Zammad::Application.routes.draw do api_path = Rails.configuration.api_path - match api_path + '/activity_stream', :to => 'activity#activity_stream', :via => :get + match api_path + '/activity_stream', :to => 'activity_stream#show', :via => :get end \ No newline at end of file diff --git a/db/migrate/20130925000001_create_activity_stream.rb b/db/migrate/20130925000001_create_activity_stream.rb new file mode 100644 index 000000000..027a3cbdb --- /dev/null +++ b/db/migrate/20130925000001_create_activity_stream.rb @@ -0,0 +1,41 @@ +class CreateActivityStream < ActiveRecord::Migration + def up + + create_table :activity_streams do |t| + t.references :activity_stream_type, :null => false + t.references :activity_stream_object, :null => false + t.references :role, :null => true + t.references :group, :null => true + t.column :o_id, :integer, :null => false + t.column :created_by_id, :integer, :null => false + t.timestamps + end + add_index :activity_streams, [:o_id] + add_index :activity_streams, [:created_by_id] + add_index :activity_streams, [:role_id] + add_index :activity_streams, [:group_id] + add_index :activity_streams, [:created_at] + add_index :activity_streams, [:activity_stream_object_id] + add_index :activity_streams, [:activity_stream_type_id] + + create_table :activity_stream_types do |t| + t.column :name, :string, :limit => 250, :null => false + t.timestamps + end + add_index :activity_stream_types, [:name], :unique => true + + create_table :activity_stream_objects do |t| + t.column :name, :string, :limit => 250, :null => false + t.column :note, :string, :limit => 250, :null => true + t.timestamps + end + add_index :activity_stream_objects, [:name], :unique => true + + end + + def down + drop_table :activity_streams + drop_table :activity_stream_objects + drop_table :activity_stream_types + end +end diff --git a/lib/sessions/backend/activity_stream.rb b/lib/sessions/backend/activity_stream.rb index 2164f8057..880324876 100644 --- a/lib/sessions/backend/activity_stream.rb +++ b/lib/sessions/backend/activity_stream.rb @@ -4,13 +4,13 @@ module Sessions::Backend::ActivityStream def self.worker( user, worker ) cache_key = 'user_' + user.id.to_s + '_activity_stream' if Sessions::CacheIn.expired(cache_key) - activity_stream = History.activity_stream( user, 20 ) + activity_stream = user.activity_stream( 20 ) activity_stream_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) worker.log 'notice', 'fetch activity_stream - ' + cache_key if activity_stream != activity_stream_cache worker.log 'notify', 'fetch activity_stream changed - ' + cache_key - activity_stream_full = History.activity_stream_fulldata( user, 20 ) + activity_stream_full = user.activity_stream( 20, true ) Sessions::CacheIn.set( cache_key, activity_stream, { :expires_in => 0.75.minutes } ) Sessions::CacheIn.set( cache_key + '_push', activity_stream_full ) end diff --git a/test/unit/activity_stream_test.rb b/test/unit/activity_stream_test.rb new file mode 100644 index 000000000..32db60f8b --- /dev/null +++ b/test/unit/activity_stream_test.rb @@ -0,0 +1,199 @@ +# encoding: utf-8 +require 'test_helper' + +class ActivityStreamTest < ActiveSupport::TestCase + test 'ticket+user' do + tests = [ + + # test 1 + { + :create => { + :ticket => { + :group_id => Group.lookup( :name => 'Users' ).id, + :customer_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + :owner_id => User.lookup( :login => '-' ).id, + :title => 'Unit Test 1 (äöüß)!', + :ticket_state_id => Ticket::State.lookup( :name => 'new' ).id, + :ticket_priority_id => Ticket::Priority.lookup( :name => '2 normal' ).id, + :updated_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + :created_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + }, + :article => { + :updated_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + :created_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + :ticket_article_type_id => Ticket::Article::Type.lookup( :name => 'phone' ).id, + :ticket_article_sender_id => Ticket::Article::Sender.lookup( :name => 'Customer' ).id, + :from => 'Unit Test ', + :body => 'Unit Test 123', + :internal => false + }, + }, + :update => { + :ticket => { + :title => 'Unit Test 1 (äöüß) - update!', + :ticket_state_id => Ticket::State.lookup( :name => 'open' ).id, + :ticket_priority_id => Ticket::Priority.lookup( :name => '1 low' ).id, + }, + }, + :check => [ + { + :object => 'Ticket', + :type => 'created', + }, + { + :object => 'Ticket::Article', + :type => 'created', + }, + { + :object => 'User', + :type => 'updated', + :o_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + }, + ] + }, + ] + tickets = [] + tests.each { |test| + + ticket = nil + article = nil + + # use transaction + ActiveRecord::Base.transaction do + ticket = Ticket.create( test[:create][:ticket] ) + test[:check][0][:o_id] = ticket.id + test[:check][0][:created_at] = ticket.created_at + test[:check][0][:created_by_id] = User.lookup( :login => 'nicole.braun@zammad.org' ).id + sleep 2 + + test[:create][:article][:ticket_id] = ticket.id + article = Ticket::Article.create( test[:create][:article] ) + test[:check][1][:o_id] = article.id + test[:check][1][:created_at] = article.created_at + test[:check][1][:created_by_id] = User.lookup( :login => 'nicole.braun@zammad.org' ).id + + assert_equal( ticket.class.to_s, 'Ticket' ) + assert_equal( article.class.to_s, 'Ticket::Article' ) + + # update ticket + if test[:update][:ticket] + ticket.update_attributes( test[:update][:ticket] ) + test[:check][2][:o_id] = ticket.id + test[:check][2][:created_at] = ticket.created_at + test[:check][2][:created_by_id] = User.lookup( :login => 'nicole.braun@zammad.org' ).id + end + if test[:update][:article] + article.update_attributes( test[:update][:article] ) + end + end + + # remember ticket + tickets.push ticket + + # check activity_stream + activity_stream_check( User.find(1).activity_stream(3), test[:check] ) + } + + # delete tickets + tickets.each { |ticket| + ticket_id = ticket.id + ticket.destroy + found = Ticket.where( :id => ticket_id ).first + assert( !found, "Ticket destroyed") + } + end + + test 'organization' do + tests = [ + + # test 1 + { + :create => { + :organization => { + :name => 'some name', + :updated_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + :created_by_id => User.lookup( :login => 'nicole.braun@zammad.org' ).id, + }, + }, + :update1 => { + :organization => { + :name => 'some name (äöüß)', + }, + }, + :update2 => { + :organization => { + :name => 'some name 2 (äöüß)', + }, + }, + :check => [ + { + :object => 'Organization', + :type => 'created', + }, + { + :object => 'Organization', + :type => 'updated', + }, + ] + }, + ] + organizations = [] + tests.each { |test| + + organization = Organization.create( test[:create][:organization] ) + test[:check][0][:o_id] = organization.id + test[:check][0][:created_at] = organization.created_at + test[:check][0][:created_by_id] = User.lookup( :login => 'nicole.braun@zammad.org' ).id + sleep 11 + + assert_equal( organization.class.to_s, 'Organization' ) + + if test[:update1][:organization] + organization.update_attributes( test[:update1][:organization] ) + test[:check][1][:o_id] = organization.id + test[:check][1][:updated_at] = organization.updated_at + test[:check][1][:created_by_id] = User.lookup( :login => 'nicole.braun@zammad.org' ).id + sleep 2 + end + + if test[:update2][:organization] + organization.update_attributes( test[:update2][:organization] ) + end + + # remember organization + organizations.push organization + + # check activity_stream + activity_stream_check( User.find(1).activity_stream(2), test[:check] ) + } + + # delete tickets + organizations.each { |organization| + organization_id = organization.id + organization.destroy + found = Organization.where( :id => organization_id ).first + assert( !found, "Organization destroyed") + } + end + + + def activity_stream_check( activity_stream_list, checks ) + checks.each { |check_item| +# puts '+++++++++++' +# puts check_item.inspect + match = false + activity_stream_list.each { |item| + next if match +# puts '--------' +# puts item.inspect +# puts item.object + next if item['object'] != check_item[:object] + next if item['type'] != check_item[:type] + next if item['o_id'] != check_item[:o_id] + match = true + } + assert( match, "activity stream check not matched! #{check_item.inspect}") + } + end + +end