From 91d3bb8965d17ddc3e8387d6e030307004c9b3c3 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 23 Jul 2013 18:45:28 +0200 Subject: [PATCH] Moved to new memory management, http://blog.alexmaccaw.com/jswebapps-memory-management --- .../_application_controller.js.coffee | 8 +- .../_application_controller_generic.js.coffee | 22 +--- .../controllers/agent_ticket_create.js.coffee | 9 +- .../agent_ticket_history.js.coffee | 2 +- .../controllers/agent_ticket_view.js.coffee | 13 --- .../app/controllers/task_widget.js.coffee | 2 +- .../app/controllers/template_widget.js.coffee | 32 ++---- .../controllers/text_module_widget.js.coffee | 45 +++----- .../app/controllers/ticket_zoom.js.coffee | 53 +++++---- .../controllers/user_info_widget.js.coffee | 11 +- .../app/lib/app_post/collection.js.coffee | 88 --------------- .../lib/app_post/interface_handle.js.coffee | 3 - .../app/lib/app_post/task_manager.js.coffee | 38 ++++--- .../app/models/_application_model.js.coffee | 102 ++++++++++++++++++ app/controllers/sessions/collection_ticket.rb | 7 +- app/controllers/templates_controller.rb | 5 + app/controllers/users_controller.rb | 5 +- app/models/template.rb | 7 +- test/browser_test_helper.rb | 4 +- 19 files changed, 225 insertions(+), 231 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_application_controller.js.coffee b/app/assets/javascripts/app/controllers/_application_controller.js.coffee index e804c2a4f..7f7afbfa4 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.js.coffee @@ -9,10 +9,16 @@ class App.Controller extends Spine.Controller super + # apply to release controller on dom remove + @el.on('remove', @release) + # create shortcuts @Config = App.Config @Session = App.Session + release: => + # release custom bindings after it got removed from dom + # add @title methode to set title title: (name) -> # $('html head title').html( @Config.get(product_name) + ' - ' + App.i18n.translateInline(name) ) @@ -206,7 +212,7 @@ class App.Controller extends Spine.Controller # remember requested url @Config.set( 'requested_url', window.location.hash ) - # redirect to login + # redirect to login @navigate '#login' return false diff --git a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee index 611dc0809..13085a58e 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee @@ -108,26 +108,11 @@ class App.ControllerGenericIndex extends App.ControllerContent # set title @title @pageData.title - # set nav bar + # set nav bar @navupdate @pageData.navupdate # bind render after a change is done - App.Collection.observe( - level: 'page', - collections: [ - { - collection: @genericObject, - event: 'refresh change', - callback: @render, - }, - ], - ) - App.Event.bind( - @genericObject+ ':created ' + @genericObject + ':updated ' + @genericObject + ':destroy' - => - App[ @genericObject ].fetch() - 'page' - ) + @subscribeId = App[ @genericObject ].subscribe(@render) App[ @genericObject ].bind 'ajaxError', (rec, msg) => @log 'error', 'ajax', msg.status @@ -143,6 +128,9 @@ class App.ControllerGenericIndex extends App.ControllerContent # fetch all App[ @genericObject ].fetch() + release: => + App[ @genericObject ].unsubscribe(@subscribeId) + render: => objects = App.Collection.all( diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index e75533e93..7fd940994 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -80,10 +80,7 @@ class App.TicketCreate extends App.Controller return true release: => -# @clearInterval( @key, 'ticket_zoom' ) - @el.remove() @clearInterval( @id, @auto_save_key ) - @textModule.release() autosave: => @auto_save_key = 'create' + @type + @id @@ -203,15 +200,15 @@ class App.TicketCreate extends App.Controller # show template UI new App.TemplateUI( - el: @el.find('[data-id="ticket_template"]'), - template_id: template['id'], + el: @el.find('[data-id="ticket_template"]') + template_id: template['id'] ) @formDefault = @formParam( @el.find('.ticket-create') ) # show text module UI @textModule = new App.TextModuleUI( - el: @el.find('.ticket-create') + el: @el.find('.ticket-create').find('textarea') ) localUserInfo: (params) => diff --git a/app/assets/javascripts/app/controllers/agent_ticket_history.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_history.js.coffee index 05c130a1f..81e254dc9 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_history.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_history.js.coffee @@ -34,7 +34,7 @@ class App.TicketHistory extends App.ControllerModal App.Collection.load( type: 'HistoryAttribute', data: data.history_attributes ) # load history collections - App.Collection.deleteAll( 'History' ) + App.History.deleteAll() App.Collection.load( type: 'History', data: data.history ) # render page diff --git a/app/assets/javascripts/app/controllers/agent_ticket_view.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_view.js.coffee index 261d2953a..9196fac7b 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_view.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_view.js.coffee @@ -86,19 +86,6 @@ class Index extends App.ControllerContent @log 'notice', 'refetch...', record @fetch() -# # bind render after a change is done -# App.Collection.observe( -# level: 'page', -# collections: [ -# { -# collection: @genericObject, -# event: 'refresh change', -# callback: @render, -# }, -# ], -# ) - - @ticket_list_show = [] for ticket_id in @ticket_list @ticket_list_show.push App.Collection.find( 'Ticket', ticket_id ) diff --git a/app/assets/javascripts/app/controllers/task_widget.js.coffee b/app/assets/javascripts/app/controllers/task_widget.js.coffee index 466a0fb5b..798a957b2 100644 --- a/app/assets/javascripts/app/controllers/task_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/task_widget.js.coffee @@ -1,6 +1,6 @@ class App.TaskWidget extends App.Controller events: - 'click [data-type="close"]': 'remove' + 'click [data-type="close"]': 'remove' constructor: -> super diff --git a/app/assets/javascripts/app/controllers/template_widget.js.coffee b/app/assets/javascripts/app/controllers/template_widget.js.coffee index ad7f80484..6ff904477 100644 --- a/app/assets/javascripts/app/controllers/template_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/template_widget.js.coffee @@ -6,22 +6,10 @@ class App.TemplateUI extends App.Controller constructor: -> super + @subscribeId = App.Template.subscribe(@render, initFetch: true ) - # fetch item on demand - fetch_needed = 1 - if App.Collection.count( 'Template' ) > 0 - fetch_needed = 0 - @render() - - if fetch_needed - @reload() - - reload: => - App.Template.bind 'refresh', => - @log 'notice', 'loading...' - @render() - App.Template.unbind 'refresh' - App.Collection.fetch( 'Template' ) + release: => + App.Template.unsubscribe(@subscribeId) render: => @configure_attributes = [ @@ -30,16 +18,16 @@ class App.TemplateUI extends App.Controller template = {} if @template_id - template = App.Collection.find( 'Template', @template_id ) + template = App.Template.find( @template_id ) # insert data @html App.view('template_widget')( template: template, ) new App.ControllerForm( - el: @el.find('#form-template'), - model: { configure_attributes: @configure_attributes, className: '' }, - autofocus: false, + el: @el.find('#form-template') + model: { configure_attributes: @configure_attributes, className: '' } + autofocus: false ) delete: (e) => @@ -47,9 +35,9 @@ class App.TemplateUI extends App.Controller # get params params = @formParam(e.target) - template = App.Collection.find( 'Template', params['template_id'] ) + template = App.Template.find( params['template_id'] ) if confirm('Sure?') - template.destroy() + template.destroy() @template_id = undefined @render() @@ -59,7 +47,7 @@ class App.TemplateUI extends App.Controller # get params params = @formParam(e.target) - template = App.Collection.find( 'Template', params['template_id'] ) + template = App.Template.find( params['template_id'] ) App.Event.trigger 'ticket_create_rerender', template.attributes() create: (e) => diff --git a/app/assets/javascripts/app/controllers/text_module_widget.js.coffee b/app/assets/javascripts/app/controllers/text_module_widget.js.coffee index 0b582d232..7681e1541 100644 --- a/app/assets/javascripts/app/controllers/text_module_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/text_module_widget.js.coffee @@ -10,36 +10,23 @@ class App.TextModuleUI extends App.Controller .text("(" + e.keywords + ")").end() element.append(template) - @el.find('textarea').sew( - values: @reload() - token: '::' - elementFactory: elementFactory + @el.parent().find('textarea').sew( + values: @reload(@data) + token: '::' + elementFactory: elementFactory ) - App.TextModule.bind( - 'refresh change' - => - @reload() - ) - - # subscribe and reload data / fetch new data if triggered - @bindLevel = 'TextModule-' + Math.floor( Math.random() * 99999 ) - App.Event.bind( - 'TextModule:updated TextModule:created TextModule:destroy' - => - App.TextModule.fetch() - @bindLevel - ) - - # fetch init collection - App.TextModule.fetch() + @subscribeId = App.TextModule.subscribe(@update, initFetch: true ) release: => - App.Event.unbindLevel(@bindLevel) + App.TextModule.unsubscribe(@subscribeId) reload: (data = false) => if data @lastData = data + @update() + + update: => all = App.TextModule.all() values = [{val: '-', keywords: '-'}] ui = @lastData || @ @@ -51,7 +38,7 @@ class App.TextModuleUI extends App.Controller try key = eval (varString) catch error - console.log( "tag replacement: " + error ) + #console.log( "tag replacement: " + error ) key = '' return key ) @@ -62,10 +49,10 @@ class App.TextModuleUI extends App.Controller values.shift() # set new data - if @el.find('textarea')[0] - if $(@el.find('textarea')[0]).data() - if $(@el.find('textarea')[0]).data().plugin_sew - $(@el.find('textarea')[0]).data().plugin_sew.options.values = values + if @el[0] + if $(@el[0]).data() + if $(@el[0]).data().plugin_sew + $(@el[0]).data().plugin_sew.options.values = values return values @@ -82,7 +69,7 @@ class App.TextModuleUIOld extends App.Controller # fetch item on demand fetch_needed = 1 - if App.Collection.count( 'TextModule' ) > 0 + if App.TextModule.count() > 0 fetch_needed = 0 @render() @@ -94,7 +81,7 @@ class App.TextModuleUIOld extends App.Controller @log 'notice', 'loading....' @render() App.TextModule.unbind 'refresh' - App.Collection.fetch( 'TextModule' ) + App.TextModule.fetch() render: => diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index 4837ce04f..f54d537a2 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -58,25 +58,8 @@ class App.TicketZoom extends App.Controller return true release: => - @textModule.release() App.Event.unbindLevel 'ticket-zoom-' + @ticket_id @clearInterval( @key, 'ticket_zoom' ) - @el.remove() - - autosave: => - @auto_save_key = 'zoom' + @id - - @autosaveLast = _.clone( @formDefault ) - update = => - currentData = @formParam( @el.find('.ticket-update') ) - diff = difference( @autosaveLast, currentData ) - if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) - @autosaveLast = currentData - @log 'notice', 'form hash changed', diff, currentData - @el.find('.ticket-update').parent().addClass('form-changed') - @el.find('.ticket-update').parent().parent().find('.reset-message').show() - App.TaskManager.update( @task_key, { 'state': currentData }) - @interval( update, 1500, @id, @auto_save_key ) fetch: (ticket_id, force) -> @@ -156,7 +139,6 @@ class App.TicketZoom extends App.Controller # update taskbar with new meta data App.Event.trigger 'task:render' - if !@renderDone @renderDone = true @html App.view('ticket_zoom')( @@ -185,8 +167,8 @@ class App.TicketZoom extends App.Controller # show text module UI if !@isRole('Customer') - @textModule = new App.TextModuleUI( - el: @el + new App.TextModuleUI( + el: @el.find('textarea') data: ticket: @ticket ) @@ -235,6 +217,7 @@ class App.TicketZoom extends App.Controller # show ticket action row new TicketAction( ticket: @ticket + task_key: @task_key el: @el.find('.ticket-action') ui: @ ) @@ -337,6 +320,9 @@ class Edit extends App.Controller super @render() + release: => + @autosaveStop() + render: -> ticket = App.Collection.find( 'Ticket', @ticket.id ) @@ -431,13 +417,32 @@ class Edit extends App.Controller @ui.formDefault = @formParam( @el.find('.ticket-update') ) # start auto save - @ui.autosave() + @autosaveStart() # enable user popups @userPopups() + autosaveStop: => + @clearInterval( @ticket.id, @auto_save_key ) + + autosaveStart: => + @auto_save_key = 'zoom' + @ticket.id + + @autosaveLast = _.clone( @ui.formDefault ) + update = => + currentData = @formParam( @el.find('.ticket-update') ) + diff = difference( @autosaveLast, currentData ) + if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) + @autosaveLast = currentData + @log 'notice', 'form hash changed', diff, currentData + @el.find('.ticket-update').parent().addClass('form-changed') + @el.find('.ticket-update').parent().parent().find('.reset-message').show() + App.TaskManager.update( @task_key, { 'state': currentData }) + @interval( update, 1500, @ticket.id, @auto_save_key ) + update: (e) => e.preventDefault() + @autosaveStop() params = @formParam(e.target) ticket = App.Collection.find( 'Ticket', @ticket.id ) @@ -477,7 +482,10 @@ class Edit extends App.Controller attachmentTranslated = App.i18n.translateContent('Attachment') attachmentTranslatedRegExp = new RegExp( attachmentTranslated, 'i' ) if params['body'].match(/attachment/i) || params['body'].match( attachmentTranslatedRegExp ) - return if !confirm( App.i18n.translateContent('You use attachment in text but no attachment is attached. Do you want to continue?') ) + if !confirm( App.i18n.translateContent('You use attachment in text but no attachment is attached. Do you want to continue?') ) + return + else + @autosaveStart() ticket.load( ticket_update ) @log 'notice', 'update ticket', ticket_update, ticket @@ -489,6 +497,7 @@ class Edit extends App.Controller if errors @log 'error', 'update', errors @formEnable(e) + @autosaveStart() ticket.save( success: (r) => diff --git a/app/assets/javascripts/app/controllers/user_info_widget.js.coffee b/app/assets/javascripts/app/controllers/user_info_widget.js.coffee index 5dd3b90fc..998fbb6f8 100644 --- a/app/assets/javascripts/app/controllers/user_info_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/user_info_widget.js.coffee @@ -6,14 +6,23 @@ class App.UserInfo extends App.Controller constructor: -> super + # show user callback = (user) => @render(user) if @callback @callback(user) - App.Collection.find( 'User', @user_id, callback ) + # subscribe and reload data / fetch new data if triggered + @subscribeId = user.subscribe(@render) + + App.User.retrieve( @user_id, callback ) + + release: => + App.User.unsubscribe(@subscribeId) render: (user) => + if !user + user = @u # get display data data = [] diff --git a/app/assets/javascripts/app/lib/app_post/collection.js.coffee b/app/assets/javascripts/app/lib/app_post/collection.js.coffee index 569a95470..b66793d95 100644 --- a/app/assets/javascripts/app/lib/app_post/collection.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/collection.js.coffee @@ -19,51 +19,16 @@ class App.Collection _instance ?= new _collectionSingleton _instance.find( type, id, callback, force ) - @get: ( args ) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.get( args ) - @all: ( args ) -> if _instance == undefined _instance ?= new _collectionSingleton _instance.all( args ) - @deleteAll: ( type ) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.deleteAll( type ) - @findByAttribute: ( type, key, value ) -> if _instance == undefined _instance ?= new _collectionSingleton _instance.findByAttribute( type, key, value ) - @count: ( type ) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.count( type ) - - @fetch: ( type ) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.fetch( type ) - - @observe: (args) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.observe(args) - - @observeUnbindLevel: (level) -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance.observeUnbindLevel(level) - - @_observeStats: -> - if _instance == undefined - _instance ?= new _collectionSingleton - _instance._observeStats() - class _collectionSingleton extends Spine.Module @include App.LogInclude @@ -263,14 +228,6 @@ class _collectionSingleton extends Spine.Module else return data - get: (params) -> - if !App[ params.type ] - @log 'error', 'get', 'no such collection', params - return - - @log 'debug', 'get', params - App[ params.type ].refresh( object, options: { clear: true } ) - all: (params) -> if !App[ params.type ] @log 'error', 'all', 'no such collection', params @@ -296,9 +253,6 @@ class _collectionSingleton extends Spine.Module return all_complied - deleteAll: (type) -> - App[type].deleteAll() - findByAttribute: ( type, key, value ) -> if !App[type] @log 'error', 'findByAttribute', 'no such collection', type, key, value @@ -309,18 +263,6 @@ class _collectionSingleton extends Spine.Module return item - count: ( type ) -> - if !App[type] - @log 'error', 'count', 'no such collection', type, key, value - return - App[type].count() - - fetch: ( type ) -> - if !App[type] - @log 'error', 'fetch', 'no such collection', type, key, value - return - App[type].fetch() - _sortBy: ( collection, attribute ) -> _.sortBy( collection, (item) -> return '' if item[ attribute ] is undefined || item[ attribute ] is null @@ -365,33 +307,3 @@ class _collectionSingleton extends Spine.Module ) return collection - observeUnbindLevel: (level) -> - return if !@observeCurrent - return if !@observeCurrent[level] - for observers in @observeCurrent[level] - @_observeUnbind( observers ) - @observeCurrent[level] = [] - - observe: (data) -> - if !@observeCurrent - @observeCurrent = {} - - if !@observeCurrent[ data.level ] - @observeCurrent[ data.level ] = [] - - @observeCurrent[ data.level ].push data.collections - for observe in data.collections - events = observe.event.split(' ') - for event in events - if App[ observe.collection ] - App[ observe.collection ].bind( event, observe.callback ) - - _observeUnbind: (observers) -> - for observe in observers - events = observe.event.split(' ') - for event in events - if App[ observe.collection ] - App[ observe.collection ].unbind( event, observe.callback ) - - _observeStats: -> - @observeCurrent diff --git a/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee b/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee index 0695a305b..e46a890f0 100644 --- a/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee @@ -59,9 +59,6 @@ class App.Content extends App.Controller @log 'notice', 'execute page controller', route, params - # remove observers for page - App.Collection.observeUnbindLevel('page') - # remove events for page App.Event.unbindLevel('page') diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee index 34230921b..f1ff56f70 100644 --- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee @@ -232,7 +232,9 @@ class _taskManagerSingleton extends App.Controller get: ( key ) => for task in @allTasks - return task if task.key is key + if task.key is key + return task +# return task if task.key is key return # throw "No such task with '#{key}'" @@ -249,10 +251,23 @@ class _taskManagerSingleton extends App.Controller if !task throw "No such task with '#{key}' to remove" - worker = @worker( key ) - if worker && worker.release - worker.release() + allTasks = _.filter( + @allTasks + (taskLocal) -> + return task if task.key isnt taskLocal.key + return + ) + @allTasks = allTasks || [] + + $('#content_permanent_' + key ).html('') + $('#content_permanent_' + key ).remove() + delete @workersStarted[ key ] + delete @workers[ key ] + + App.Event.trigger 'task:render' + + # destroy in backend @taskDestroy(task) notify: ( key ) => @@ -277,10 +292,11 @@ class _taskManagerSingleton extends App.Controller # release tasks for task in @allTasks - worker = @worker( task.key ) - if worker && worker.release - worker.release() + $('#content_permanent_' + task.key ).html('') + $('#content_permanent_' + task.key ).remove() + delete @workersStarted[ task.key ] + delete @workers[ task.key ] # clear instance vars @tasksToUpdate = {} @@ -324,14 +340,6 @@ class _taskManagerSingleton extends App.Controller ) taskDestroy: (task) -> - allTasks = _.filter( - @allTasks - (taskLocal) -> - return task if task.key isnt taskLocal.key - return - ) - @allTasks = allTasks || [] - App.Event.trigger 'task:render' # check if update is still in process if @tasksToUpdate[ task.key ] is 'inProgress' diff --git a/app/assets/javascripts/app/models/_application_model.js.coffee b/app/assets/javascripts/app/models/_application_model.js.coffee index 888fc2647..73a73c545 100644 --- a/app/assets/javascripts/app/models/_application_model.js.coffee +++ b/app/assets/javascripts/app/models/_application_model.js.coffee @@ -87,3 +87,105 @@ class App.Model extends Spine.Model return true if typeof @id is 'number' # in case of real database id return true if @id[0] isnt 'c' return false + + @retrieve: ( id, callback, force ) -> + if !force && App[ @className ].exists( id ) + data = App[ @className ].find( id ) +# data = @_fillUp( @className, data ) + if callback + callback( data ) + return data + else + if force + console.log 'debug', 'find forced to load!', @className, id + else + console.log 'debug', 'find not loaded!', @className, id + if callback + + # execute callback if record got loaded + col = @ + App[ @className ].one 'refresh', (record) -> + delay = => + data = App[ @className ].find( id ) + if callback + callback( data ) + window.setTimeout(delay, 200) + + # fetch object + console.log 'debug', 'loading..' + @className + '..', id + App[ @className ].fetch( id: id ) + return true + return false + + @subscribe: (callback, param = {}) -> + if !@SUBSCRIPTION_COLLECTION + @SUBSCRIPTION_COLLECTION = {} + + # subscribe and render data / fetch new data if triggered + @bind( + 'refresh change' + => + for key, callbackSingle of @SUBSCRIPTION_COLLECTION + callbackSingle() + ) + + # trigger deleteAll() and fetch() on network notify + events = "#{@className}:created #{@className}:updated #{@className}:destroy" + App.Event.bind( + events + => + @deleteAll() +# callbacks = => +# for key, callbackSingle of @SUBSCRIPTION_COLLECTION +# callbackSingle() +# @one 'refresh', (collection) => +# callbacks(collection) + @fetch() + + 'Collection::Subscribe::' + @className + ) + + + key = @className + '-' + Math.floor( Math.random() * 99999 ) + @SUBSCRIPTION_COLLECTION[key] = callback + + # fetch init collection + if param['initFetch'] is true + @one 'refresh', (collection) => + callback(collection) + @fetch() + + return key + + subscribe: (callback) -> + if !App[ @constructor.className ]['SUBSCRIPTION_ITEM'] + App[ @constructor.className ]['SUBSCRIPTION_ITEM'] = {} + if !App[ @constructor.className ]['SUBSCRIPTION_ITEM'][@id] + App[ @constructor.className ]['SUBSCRIPTION_ITEM'][@id] = {} + + events = "#{@constructor.className}:created #{@constructor.className}:updated #{@constructor.className}:destroy" + App.Event.bind( + events + (record) => + if @id.toString() is record.id.toString() + App[ @constructor.className ].one 'refresh', (record) => + user = App[ @constructor.className ].find(@id) + for key, callback of App[ @constructor.className ]['SUBSCRIPTION_ITEM'][@id] + callback(user) + App[ @constructor.className ].fetch( id: @id ) + 'Item::Subscribe::' + @constructor.className + ) + + key = @constructor.className + '-' + Math.floor( Math.random() * 99999 ) + App[ @constructor.className ]['SUBSCRIPTION_ITEM'][@id][key] = callback + return key + + @unsubscribe: (data) -> + if @SUBSCRIPTION_ITEM + for id, keys of @SUBSCRIPTION_ITEM + if keys[data] + delete keys[data] + + if @SUBSCRIPTION_COLLECTION + if @SUBSCRIPTION_COLLECTION[data] + delete @SUBSCRIPTION_COLLECTION[data] diff --git a/app/controllers/sessions/collection_ticket.rb b/app/controllers/sessions/collection_ticket.rb index a05f24a4c..5742c048e 100644 --- a/app/controllers/sessions/collection_ticket.rb +++ b/app/controllers/sessions/collection_ticket.rb @@ -31,13 +31,10 @@ module ExtraCollection if !user.is_role('Customer') # all signatures - collections['Signature'] = Signature.all + collections['Signature'] = Signature.all # all email addresses - collections['EmailAddress'] = EmailAddress.all - - # all templates - collections['Template'] = Template.all + collections['EmailAddress'] = EmailAddress.all end end diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index 01e169a02..f4006309f 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -47,6 +47,7 @@ curl http://localhost/api/templates.json -v -u #{login}:#{password} =end def index + return if deny_if_not_role('Agent') model_index_render(Template, params) end @@ -68,6 +69,7 @@ curl http://localhost/api/templates/#{id}.json -v -u #{login}:#{password} =end def show + return if deny_if_not_role('Agent') model_show_render(Template, params) end @@ -95,6 +97,7 @@ curl http://localhost/api/templates.json -v -u #{login}:#{password} -H "Content- =end def create + return if deny_if_not_role('Agent') model_create_render(Template, params) end @@ -122,6 +125,7 @@ curl http://localhost/api/templates.json -v -u #{login}:#{password} -H "Content- =end def update + return if deny_if_not_role('Agent') model_update_render(Template, params) end @@ -139,6 +143,7 @@ curl http://localhost/api/templates.json -v -u #{login}:#{password} -H "Content- =end def destroy + return if deny_if_not_role('Agent') model_destory_render(Template, params) end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 653470bd4..bfd49a9c0 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -318,10 +318,7 @@ curl http://localhost/api/users/2.json -v -u #{login}:#{password} -H "Content-Ty # DELETE /api/users/1 def destroy - if !is_role('Admin') - response_access_deny - return - end + return if deny_if_not_role('Admin') model_destory_render(User, params) end diff --git a/app/models/template.rb b/app/models/template.rb index d0ab235f3..d18bb3ec3 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -1,6 +1,9 @@ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ class Template < ApplicationModel - store :options - validates :name, :presence => true + store :options + validates :name, :presence => true + after_create :notify_clients_after_create + after_update :notify_clients_after_update + after_destroy :notify_clients_after_destroy end diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index ccd4a9a54..760e9d4a6 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -172,6 +172,7 @@ class TestCase < Test::Unit::TestCase def browser_element_action(test, action, instance) #puts "NOTICE: " + action.inspect + sleep 0.2 if action[:css] if action[:css].match '###stack###' action[:css].gsub! '###stack###', @stack @@ -221,7 +222,8 @@ class TestCase < Test::Unit::TestCase elsif action[:element] == :alert element = instance.switch_to.alert elsif action[:execute] == 'close_all_tasks' - while true +# while true + for i in 1..100 begin element = instance.find_element( { :css => '.taskbar [data-type="close"]' } ) if element