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