Refactoring of ticket zoom (less rerendering, just rerender particular area's instant of whole view). Added live broadcasting of tag and links.

This commit is contained in:
Martin Edenhofer 2016-06-07 21:22:08 +02:00
parent 65e06eb614
commit 3d878a5547
19 changed files with 449 additions and 276 deletions

View file

@ -1117,7 +1117,7 @@ class App.ObserverController extends App.Controller
currentAttributes[key] = object[key]
if @observeNot
for key, value of object
if !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
currentAttributes[key] = value
if !@lastAttributres
@ -1128,13 +1128,13 @@ class App.ObserverController extends App.Controller
@log 'debug', 'maybeRender no diff, no rerender'
return
@log 'debug', 'maybeRender.diff', diff
@log 'debug', 'maybeRender.diff', diff, @observe, @model
@lastAttributres = currentAttributes
@render(object)
@render(object, diff)
render: (object) =>
@log 'debug', 'render', @template, object
render: (object, diff) =>
@log 'debug', 'render', @template, object, diff
@html App.view(@template)(
object: object
)
@ -1144,5 +1144,5 @@ class App.ObserverController extends App.Controller
release: =>
#console.trace()
@log 'debug', 'release', @object_id, @model
@log 'debug', 'release', @object_id, @model, @subscribeId
App[@model].unsubscribe(@subscribeId)

View file

@ -22,7 +22,6 @@ class App.TicketZoom extends App.Controller
@ticket_id = params.ticket_id
@article_id = params.article_id
@sidebarState = {}
@ticketLastAttributes = {}
# if we are in init task startup, ignore overview_id
if !params.init
@ -51,7 +50,7 @@ class App.TicketZoom extends App.Controller
update = =>
@fetch(@ticket_id, false)
if !@ticketUpdatedAtLastCall || ( new Date(data.updated_at).toString() isnt new Date(@ticketUpdatedAtLastCall).toString() )
@delay(update, 1200, "ticket-zoom-#{@ticket_id}")
@delay(update, 1100, "ticket-zoom-#{@ticket_id}")
)
# rerender view, e. g. on langauge change
@ -59,6 +58,98 @@ class App.TicketZoom extends App.Controller
@fetch(@ticket_id, true)
)
fetch: (ticket_id, force) ->
return if !@Session.get()
# get data
@ajax(
id: "ticket_zoom_#{ticket_id}"
type: 'GET'
url: "#{@apiPath}/tickets/#{ticket_id}?all=true"
processData: true
success: (data, status, xhr) =>
# check if ticket has changed
newTicketRaw = data.assets.Ticket[ticket_id]
if @ticketUpdatedAtLastCall && !force
# return if ticket hasnt changed
return if @ticketUpdatedAtLastCall is newTicketRaw.updated_at
# notify if ticket changed not by my self
if newTicketRaw.updated_by_id isnt @Session.get('id')
App.TaskManager.notify(@task_key)
# remember current data
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
@load(data)
App.SessionStorage(@key, data)
if !@doNotLog
@doNotLog = 1
@recentView('Ticket', ticket_id)
error: (xhr) =>
@renderDone = false
statusText = xhr.statusText
status = xhr.status
detail = xhr.responseText
# ignore if request is aborted
return if statusText is 'abort'
# if ticket is already loaded, ignore status "0" - network issues e. g. temp. not connection
if @ticketUpdatedAtLastCall && status is 0
console.log('network issues e. g. temp. not connection', status, statusText, detail)
return
# show error message
if status is 401 || statusText is 'Unauthorized'
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
@taskIconClass = 'diagonal-cross'
@renderScreenUnauthorized(objectName: 'Ticket')
else if status is 404 || statusText is 'Not Found'
@taskHead = '» ' + App.i18n.translateInline('Not Found') + ' «'
@taskIconClass = 'diagonal-cross'
@renderScreenNotFound(objectName: 'Ticket')
else
@taskHead = '» ' + App.i18n.translateInline('Error') + ' «'
@taskIconClass = 'diagonal-cross'
if !detail
detail = 'General communication error, maybe internet is not available!'
@renderScreenError(
status: status
detail: detail
objectName: 'Ticket'
)
)
load: (data) =>
# remember article ids
@ticket_article_ids = data.ticket_article_ids
# remember link
@links = data.links
# remember tags
@tags = data.tags
# get edit form attributes
@formMeta = data.form_meta
# load assets
App.Collection.loadAssets(data.assets)
# get data
@ticket = App.Ticket.fullLocal(@ticket_id)
@ticket.article = undefined
# render page
@render()
meta: =>
# default attributes
@ -73,14 +164,14 @@ class App.TicketZoom extends App.Controller
meta.head = @taskHead
# set icon and title based on ticket
if @ticket
@ticket = App.Ticket.fullLocal(@ticket.id)
meta.head = @ticket.title
meta.title = '#' + @ticket.number + ' - ' + @ticket.title
meta.class = "task-state-#{ @ticket.getState() }"
if @ticket_id && App.Ticket.exists(@ticket_id)
ticket = App.Ticket.find(@ticket_id)
meta.head = ticket.title
meta.title = "##{ticket.number} - #{ticket.title}"
meta.class = "task-state-#{ ticket.getState() }"
meta.type = 'task'
meta.iconTitle = @ticket.iconTitle()
meta.iconClass = @ticket.iconClass()
meta.iconTitle = ticket.iconTitle()
meta.iconClass = ticket.iconClass()
meta
url: =>
@ -137,107 +228,9 @@ class App.TicketZoom extends App.Controller
@autosaveStop()
@positionPageHeaderStop()
fetch: (ticket_id, force) ->
return if !@Session.get()
# get data
@ajax(
id: "ticket_zoom_#{ticket_id}"
type: 'GET'
url: "#{@apiPath}/tickets/#{ticket_id}?full=true"
processData: true
success: (data, status, xhr) =>
# check if ticket has changed
newTicketRaw = data.assets.Ticket[ticket_id]
if @ticketUpdatedAtLastCall && !force
# return if ticket hasnt changed
return if @ticketUpdatedAtLastCall is newTicketRaw.updated_at
# notify if ticket changed not by my self
if newTicketRaw.updated_by_id isnt @Session.get('id')
App.TaskManager.notify(@task_key)
# remember current data
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
@load(data, force)
App.SessionStorage(@key, data)
if !@doNotLog
@doNotLog = 1
@recentView('Ticket', ticket_id)
# scroll to end of page
if force
@scrollToBottom()
@positionPageHeaderUpdate()
error: (xhr) =>
statusText = xhr.statusText
status = xhr.status
detail = xhr.responseText
# ignore if request is aborted
if statusText is 'abort'
return
# if ticket is already loaded, ignore status "0" - network issues e. g. temp. not connection
if @ticketUpdatedAtLastCall && status is 0
console.log('network issues e. g. temp. not connection', status, statusText, detail)
return
# show error message
if status is 401 || statusText is 'Unauthorized'
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
@taskIconClass = 'diagonal-cross'
@renderScreenUnauthorized(objectName: 'Ticket')
else if status is 404 || statusText is 'Not Found'
@taskHead = '» ' + App.i18n.translateInline('Not Found') + ' «'
@taskIconClass = 'diagonal-cross'
@renderScreenNotFound(objectName: 'Ticket')
else
@taskHead = '» ' + App.i18n.translateInline('Error') + ' «'
@taskIconClass = 'diagonal-cross'
if !detail
detail = 'General communication error, maybe internet is not available!'
@renderScreenError(
status: status
detail: detail
objectName: 'Ticket'
)
)
muteTask: =>
App.TaskManager.mute(@task_key)
load: (data, force) =>
# remember article ids
@ticket_article_ids = data.ticket_article_ids
# remember link
@links = data.links
# remember tags
@tags = data.tags
# get edit form attributes
@formMeta = data.form_meta
# load assets
App.Collection.loadAssets(data.assets)
# get data
@ticket = App.Ticket.fullLocal(@ticket_id)
@ticket.article = undefined
# render page
@render()
positionPageHeaderStart: =>
# init header update needed for safari, scroll event is fired
@ -281,10 +274,9 @@ class App.TicketZoom extends App.Controller
# update taskbar with new meta data
App.TaskManager.touch(@task_key)
@formEnable( @$('.submit') )
if !@renderDone
@renderDone = true
@autosaveLast = {}
elLocal = $(App.view('ticket_zoom')
ticket: @ticket
nav: @nav
@ -294,24 +286,23 @@ class App.TicketZoom extends App.Controller
new App.TicketZoomOverviewNavigator(
el: elLocal.find('.overview-navigator')
ticket_id: @ticket.id
ticket_id: @ticket_id
overview_id: @overview_id
)
new App.TicketZoomTitle(
object_id: @ticket.id
object_id: @ticket_id
overview_id: @overview_id
el: elLocal.find('.ticket-title')
task_key: @task_key
)
new App.TicketZoomMeta(
object_id: @ticket.id
object_id: @ticket_id
el: elLocal.find('.ticket-meta')
)
new App.TicketZoomAttributeBar(
ticket: @ticket
el: elLocal.find('.js-attributeBar')
overview_id: @overview_id
callback: @submit
@ -322,7 +313,7 @@ class App.TicketZoom extends App.Controller
@articleNew = new App.TicketZoomArticleNew(
ticket: @ticket
ticket_id: @ticket.id
ticket_id: @ticket_id
el: elLocal.find('.article-new')
formMeta: @formMeta
form_id: @form_id
@ -333,7 +324,7 @@ class App.TicketZoom extends App.Controller
@highligher = new App.TicketZoomHighlighter(
el: elLocal.find('.highlighter')
ticket_id: @ticket.id
ticket_id: @ticket_id
)
@articleView = new App.TicketZoomArticleView(
@ -344,27 +335,20 @@ class App.TicketZoom extends App.Controller
ticket_article_ids: @ticket_article_ids
)
# rerender whole sidebar if customer or organization has changed
if @ticketLastAttributes.customer_id isnt @ticket.customer_id || @ticketLastAttributes.organization_id isnt @ticket.organization_id
if elLocal
el = elLocal
else
el = @el
new App.WidgetAvatar(
el: el.find('.ticketZoom-header .js-avatar')
object_id: @ticket.customer_id
size: 50
new App.TicketCustomerAvatar(
object_id: @ticket_id
el: elLocal.find('.ticketZoom-header')
)
@sidebar = new App.TicketZoomSidebar(
el: el.find('.tabsSidebar')
el: elLocal
sidebarState: @sidebarState
object_id: @ticket.id
object_id: @ticket_id
model: 'Ticket'
taskGet: @taskGet
task_key: @task_key
tags: @tags
links: @links
formMeta: @formMeta
markForm: @markForm
)
# render init content
@ -377,24 +361,34 @@ class App.TicketZoom extends App.Controller
ticket_article_ids: @ticket_article_ids
)
if @sidebar
# update tags
if @sidebar.tagWidget
@sidebar.tagWidget.reload(@tags)
# update links
if @sidebar.linkWidget
@sidebar.linkWidget.reload(@links)
# scroll to article if given
if @article_id && document.getElementById('article-' + @article_id)
offset = document.getElementById('article-' + @article_id).offsetTop
if @article_id && document.getElementById("article-#{@article_id}")
offset = document.getElementById("article-#{@article_id}").offsetTop
offset = offset - 45
scrollTo = ->
@scrollTo(0, offset)
@delay(scrollTo, 100, false)
@ticketLastAttributes = @ticket.attributes()
if @shown
if @shown && !@initDone
@initDone = true
# scroll to end of page
# scroll to end if new article has been added
if !@last_ticket_article_ids || !_.isEqual(_.sortBy(@last_ticket_article_ids), _.sortBy(@ticket_article_ids))
@last_ticket_article_ids = @ticket_article_ids
@scrollToBottom()
@positionPageHeaderUpdate()
# observe content header position
@positionPageHeaderStart()
return if @initDone
@initDone = true
# trigger shown if init shown render
App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
@ -403,20 +397,27 @@ class App.TicketZoom extends App.Controller
@main.scrollTop( @main.prop('scrollHeight') )
autosaveStop: =>
console.log('autosaveStop')
@clearDelay('ticket-zoom-form-update')
@autosaveLast = {}
@el.off('change.local blur.local keyup.local paste.local input.local')
autosaveStart: =>
console.log('autosaveStart')
@el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
@delay(@markForm, 250, 'ticket-zoom-form-update')
)
@delay(@markForm, 800, 'ticket-zoom-form-update')
markForm: (force) =>
if !@autosaveLast
@autosaveLast = @taskGet()
update = =>
return if !@ticket
currentParams = @formCurrent()
# check changed between last autosave
sameAsLastSave = _.isEqual(currentParams, @autosaveLast)
return if sameAsLastSave
return if !force && sameAsLastSave
@autosaveLast = clone(currentParams)
# update changes in ui
@ -425,11 +426,6 @@ class App.TicketZoom extends App.Controller
@markFormDiff(modelDiff)
@taskUpdateAll(modelDiff)
@el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
@delay(update, 250, 'ticket-zoom-form-update')
)
@delay(update, 800, 'ticket-zoom-form-update')
currentStore: =>
return if !@ticket
currentStoreTicket = @ticket.attributes()
@ -534,7 +530,7 @@ class App.TicketZoom extends App.Controller
ticketParams = @formParam( @$('.edit') )
# validate ticket
ticket = App.Ticket.fullLocal(@ticket.id)
ticket = App.Ticket.find(@ticket_id)
# reset article - should not be resubmited on next ticket update
ticket.article = undefined
@ -550,13 +546,13 @@ class App.TicketZoom extends App.Controller
# apply tag changes
if attributes[1] is 'tags'
if @sidebar && @sidebar.tagWidget
if @sidebar && @sidebar.edit && @sidebar.edit.tagWidget
tags = content.value.split(',')
for tag in tags
if content.operator is 'remove'
@sidebar.tagWidget.remove(tag)
@sidebar.edit.tagWidget.remove(tag)
else
@sidebar.tagWidget.add(tag)
@sidebar.edit.tagWidget.add(tag)
# apply user changes
else if attributes[1] is 'owner_id'
@ -671,7 +667,7 @@ class App.TicketZoom extends App.Controller
@autosaveStart()
@muteTask()
@fetch(ticket.id, true)
@fetch(ticket.id, false)
# enable form
@formEnable(e)
@ -701,7 +697,7 @@ class App.TicketZoom extends App.Controller
@$('.js-reset').addClass('hide')
# reset edit ticket / reset new article
App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket.id })
App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket_id })
# remove change flag on tab
@$('.tabsSidebar-tab[data-tab="ticket"]').removeClass('is-changed')
@ -744,7 +740,7 @@ class TicketZoomRouter extends App.ControllerPermanent
shown: true
App.TaskManager.execute(
key: 'Ticket-' + @ticket_id
key: "Ticket-#{@ticket_id}"
controller: 'TicketZoom'
params: clean_params
show: true

View file

@ -257,6 +257,7 @@ class App.TicketZoomArticleNew extends App.Controller
ticket: ticket
user: App.Session.get()
)
if !@subscribeIdTextModule
@subscribeIdTextModule = ticket.subscribe(callback)
params: =>

View file

@ -86,6 +86,8 @@ class ArticleViewItem extends App.ObserverController
@el.attr('id', "article-#{article.id}")
if article.internal
@el.addClass('is-internal')
else
@el.removeClass('is-internal')
# prepare html body
if article.content_type is 'text/html'

View file

@ -0,0 +1,11 @@
class App.TicketCustomerAvatar extends App.ObserverController
model: 'Ticket'
observe:
customer_id: true
render: (ticket) =>
new App.WidgetAvatar(
el: @el.find('.js-avatar')
object_id: ticket.customer_id
size: 50
)

View file

@ -1,28 +1,18 @@
class App.TicketZoomSidebar extends App.ObserverController
class Edit extends App.ObserverController
model: 'Ticket'
observeNot:
created_at: true
updated_at: true
render: (ticket) =>
editTicket = (el) =>
el.append('<form class="edit"></form>')
@editEl = el
show = (ticket) =>
el.find('.edit').html('')
render: (ticket, diff) =>
defaults = ticket.attributes()
delete defaults.article # ignore article infos
taskState = @taskGet('ticket')
modelDiff = App.Utils.formDiff(taskState, defaults)
if !_.isEmpty(taskState)
defaults = _.extend(defaults, taskState)
new App.ControllerForm(
el: el.find('.edit')
form = new App.ControllerForm(
model: App.Ticket
screen: 'edit'
handlers: [
@ -32,28 +22,45 @@ class App.TicketZoomSidebar extends App.ObserverController
params: defaults
#bookmarkable: true
)
#console.log('Ichanges', modelDiff, taskState, ticket.attributes(), defaults)
#@markFormDiff( modelDiff )
@html form.html()
show(ticket)
@bind(
'ui::ticket::taskReset'
(data) ->
if data.ticket_id is ticket.id
show(ticket)
@markForm(true)
return if @resetBind
@resetBind = true
@bind('ui::ticket::taskReset', (data) =>
return if data.ticket_id isnt ticket.id
@render(ticket)
)
class App.TicketZoomSidebar extends App.ObserverController
model: 'Ticket'
observe:
customer_id: true
organization_id: true
render: (ticket) =>
editTicket = (el) =>
el.append('<form><fieldset class="edit"></fieldset></form><div class="tags"></div><div class="links"></div>')
@edit = new Edit(
object_id: ticket.id
el: el.find('.edit')
taskGet: @taskGet
formMeta: @formMeta
markForm: @markForm
)
if !@isRole('Customer')
el.append('<div class="tags"></div>')
@tagWidget = new App.WidgetTag(
el: el.find('.tags')
el: @el.find('.tags')
object_type: 'Ticket'
object: ticket
tags: @tags
)
el.append('<div class="links"></div>')
@linkWidget = new App.WidgetLink(
el: el.find('.links')
el: @el.find('.links')
object_type: 'Ticket'
object: ticket
links: @links
@ -166,7 +173,7 @@ class App.TicketZoomSidebar extends App.ObserverController
callback: showOrganization
}
new App.Sidebar(
el: @el
el: @el.find('.tabsSidebar')
sidebarState: @sidebarState
items: @sidebarItems
)

View file

@ -30,7 +30,13 @@ class App.WidgetLink extends App.Controller
@render()
)
reload: (links) ->
@links = links
@render()
render: =>
return if @lastLinks && _.isEqual(@lastLinks, @links)
lastLinks = @links
list = {}
for item in @links
if !list[ item['link_type'] ]

View file

@ -29,7 +29,7 @@ class App.WidgetTag extends App.Controller
@ajax(
id: @key
type: 'GET'
url: @apiPath + '/tags'
url: "#{@apiPath}/tags"
data:
object: @object_type
o_id: @object.id
@ -39,7 +39,13 @@ class App.WidgetTag extends App.Controller
@render()
)
reload: (tags) ->
@tags = tags
@render()
render: ->
return if @lastTags && _.isEqual(@lastTags, @tags)
lastTags = @tags
@html App.view('widget/tag')(
tags: @tags || [],
)
@ -87,7 +93,7 @@ class App.WidgetTag extends App.Controller
@ajax(
type: 'GET'
url: @apiPath + '/tags/add'
url: "#{@apiPath}/tags/add"
data:
object: @object_type
o_id: @object.id
@ -110,7 +116,7 @@ class App.WidgetTag extends App.Controller
@ajax(
type: 'GET'
url: @apiPath + '/tags/remove'
url: "#{@apiPath}/tags/remove"
data:
object: @object_type
o_id: @object.id

View file

@ -65,8 +65,17 @@ class _collectionSingleton extends Spine.Module
loadAssets: (assets) ->
@log 'debug', 'loadAssets', assets
# proess not existing assets / to avoid not exising ref errors
loadAssetsLater = []
for type, collections of assets
@load(type: type, data: collections)
later = @load(type: type, data: collections, later: true)
if later
loadAssetsLater[type] = later
# proess existing assets
for type, collections of loadAssetsLater
App[type].refresh(collections)
load: (params) ->
@ -81,11 +90,13 @@ class _collectionSingleton extends Spine.Module
# load full array once
if _.isArray(params.data)
@log 'debug', 'refresh', params.data
appObject.refresh(params.data)
return
# load data from object
listToRefresh = []
listToRefreshLater = []
for key, object of params.data
if !params.refresh && appObject
@log 'debug', 'refrest try', params.type, key
@ -93,15 +104,22 @@ class _collectionSingleton extends Spine.Module
# check if new object is newer, just load newer objects
if object.updated_at && appObject.exists(key)
exists = appObject.find(key)
objectToLoad = undefined
if exists.updated_at
if exists.updated_at < object.updated_at
listToRefresh.push object
objectToLoad = object
@log 'debug', 'refrest newser', params.type, key
else
listToRefresh.push object
objectToLoad = object
@log 'debug', 'refrest try no updated_at', params.type, key
if objectToLoad
if params.later
listToRefreshLater.push objectToLoad
else
listToRefresh.push object
else
listToRefresh.push object
@log 'debug', 'refrest new', params.type, key
return if _.isEmpty(listToRefresh)
return listToRefreshLater if _.isEmpty(listToRefresh)
appObject.refresh(listToRefresh)
listToRefreshLater

View file

@ -347,7 +347,7 @@ class App.Model extends Spine.Model
clear: true
)
'Collection::Subscribe::' + @className
"Collection::Subscribe::#{@className}"
)
key = @className + '-' + Math.floor( Math.random() * 99999 )
@ -454,9 +454,9 @@ class App.Model extends Spine.Model
if !genericObject || new Date(item.updated_at) >= new Date(genericObject.updated_at)
App.Log.debug('Model', "request #{@className}.find(#{item.id}) from server")
@full(item.id, false, true)
App.Delay.set(callback, 500, item.id, "full-#{@className}")
App.Delay.set(callback, 500, item.id, "full-#{@className}-#{item.id}")
'Item::Subscribe::' + @className
"Item::Subscribe::#{@className}"
)
# remember item callback

View file

@ -339,6 +339,13 @@ class ApplicationController < ActionController::Base
false
end
def article_permission(article)
ticket = Ticket.lookup(id: article.ticket_id)
return true if ticket.permission(current_user: current_user)
response_access_deny
false
end
def deny_if_not_role(role_name)
return false if role?(role_name)
response_access_deny
@ -445,6 +452,12 @@ class ApplicationController < ActionController::Base
def model_show_render (object, params)
if params[:expand]
generic_object = object.find(params[:id])
model_show_render_item(generic_object)
return
end
if params[:full]
generic_object_full = object.full(params[:id])
render json: generic_object_full, status: :ok

View file

@ -113,7 +113,7 @@ curl http://localhost/api/v1/organizations/#{id} -v -u #{login}:#{password}
end
end
if params[:full]
full = Organization.full( params[:id] )
full = Organization.full(params[:id])
render json: full
return
end

View file

@ -5,13 +5,13 @@ class TaskbarController < ApplicationController
def index
current_user_tasks = Taskbar.where( user_id: current_user.id )
current_user_tasks = Taskbar.where(user_id: current_user.id)
model_index_render_result(current_user_tasks)
end
def show
taskbar = Taskbar.find( params[:id] )
taskbar = Taskbar.find(params[:id])
return if !access(taskbar)
model_show_render_item(taskbar)
@ -22,15 +22,15 @@ class TaskbarController < ApplicationController
end
def update
taskbar = Taskbar.find( params[:id] )
taskbar = Taskbar.find(params[:id])
return if !access(taskbar)
taskbar.update_attributes!( Taskbar.param_cleanup(params) )
taskbar.update_attributes!(Taskbar.param_cleanup(params))
model_update_render_item(taskbar)
end
def destroy
taskbar = Taskbar.find( params[:id] )
taskbar = Taskbar.find(params[:id])
return if !access(taskbar)
taskbar.destroy

View file

@ -19,19 +19,24 @@ class TicketArticlesController < ApplicationController
# POST /articles
def create
form_id = params[:ticket_article][:form_id]
params[:ticket_article].delete(:form_id)
@article = Ticket::Article.new(Ticket::Article.param_validation( params[:ticket_article]))
form_id = params[:form_id]
clean_params = Ticket::Article.param_association_lookup(params)
clean_params = Ticket::Article.param_cleanup(clean_params, true)
article = Ticket::Article.new(clean_params)
# permission check
return if !article_permission(article)
# find attachments in upload cache
if form_id
@article.attachments = Store.list(
article.attachments = Store.list(
object: 'UploadCache',
o_id: form_id,
)
end
if @article.save
if article.save
# remove attachments from upload cache
Store.remove(
@ -39,27 +44,34 @@ class TicketArticlesController < ApplicationController
o_id: form_id,
)
render json: @article, status: :created
render json: article, status: :created
else
render json: @article.errors, status: :unprocessable_entity
render json: article.errors, status: :unprocessable_entity
end
end
# PUT /articles/1
def update
@article = Ticket::Article.find(params[:id])
if @article.update_attributes(Ticket::Article.param_validation(params[:ticket_article]))
render json: @article, status: :ok
# permission check
article = Ticket::Article.find(params[:id])
return if !article_permission(article)
clean_params = Ticket::Article.param_association_lookup(params)
clean_params = Ticket::Article.param_cleanup(clean_params, true)
if article.update_attributes(clean_params)
render json: article, status: :ok
else
render json: @article.errors, status: :unprocessable_entity
render json: article.errors, status: :unprocessable_entity
end
end
# DELETE /articles/1
def destroy
@article = Ticket::Article.find(params[:id])
@article.destroy
article = Ticket::Article.find(params[:id])
return if !article_permission(article)
article.destroy
head :ok
end
@ -121,18 +133,18 @@ class TicketArticlesController < ApplicationController
}
end
# GET /ticket_attachment/1
# GET /ticket_attachment/:ticket_id/:article_id/:id
def attachment
# permission check
ticket = Ticket.lookup(id: params[:ticket_id])
if !ticket_permission(ticket)
render(json: 'No such ticket.', status: :unauthorized)
render json: 'No such ticket.', status: :unauthorized
return
end
article = Ticket::Article.find(params[:article_id])
if ticket.id != article.ticket_id
render(json: 'No access, article_id/ticket_id is not matching.', status: :unauthorized)
render json: 'No access, article_id/ticket_id is not matching.', status: :unauthorized
return
end
@ -144,7 +156,7 @@ class TicketArticlesController < ApplicationController
end
}
if !access
render(json: 'Requested file id is not linked with article_id.', status: :unauthorized)
render json: 'Requested file id is not linked with article_id.', status: :unauthorized
return
end
@ -163,7 +175,7 @@ class TicketArticlesController < ApplicationController
# permission check
article = Ticket::Article.find(params[:id])
return if !ticket_permission(article.ticket)
return if !article_permission(article)
list = Store.list(
object: 'Ticket::Article::Mail',

View file

@ -41,7 +41,13 @@ class TicketsController < ApplicationController
return if !ticket_permission(ticket)
if params[:full]
render json: ticket_full(ticket)
full = Ticket.full(params[:id])
render json: full
return
end
if params[:all]
render json: ticket_all(ticket)
return
end
@ -555,7 +561,7 @@ class TicketsController < ApplicationController
)
end
def ticket_full(ticket)
def ticket_all(ticket)
# get attributes to update
attributes_to_change = Ticket::ScreenOptions.attributes_to_change(user: current_user, ticket: ticket)

View file

@ -1280,6 +1280,24 @@ get assets and record_ids of selector
assets
end
=begin
touch references by params
Model.touch_reference_by_params(
object: 'Ticket',
o_id: 123,
)
=end
def self.touch_reference_by_params(data)
object_class = Kernel.const_get(data[:object])
object = object_class.lookup(id: data[:o_id])
return if !object
object.touch
end
private
def attachments_buffer

View file

@ -75,21 +75,29 @@ class Link < ApplicationModel
def self.add(data)
if data.key?(:link_type)
linktype = link_type_get( name: data[:link_type] )
linktype = link_type_get(name: data[:link_type])
data[:link_type_id] = linktype.id
data.delete( :link_type )
data.delete(:link_type)
end
if data.key?(:link_object_source)
linkobject = link_object_get( name: data[:link_object_source] )
linkobject = link_object_get(name: data[:link_object_source])
data[:link_object_source_id] = linkobject.id
data.delete( :link_object_source )
touch_reference_by_params(
object: data[:link_object_source],
o_id: data[:link_object_source_value],
)
data.delete(:link_object_source)
end
if data.key?(:link_object_target)
linkobject = link_object_get( name: data[:link_object_target] )
linkobject = link_object_get(name: data[:link_object_target])
data[:link_object_target_id] = linkobject.id
data.delete( :link_object_target )
touch_reference_by_params(
object: data[:link_object_target],
o_id: data[:link_object_target_value],
)
data.delete(:link_object_target)
end
Link.create(data)
@ -109,18 +117,18 @@ class Link < ApplicationModel
def self.remove(data)
if data.key?(:link_object_source)
linkobject = link_object_get( name: data[:link_object_source] )
linkobject = link_object_get(name: data[:link_object_source])
data[:link_object_source_id] = linkobject.id
end
if data.key?(:link_object_target)
linkobject = link_object_get( name: data[:link_object_target] )
linkobject = link_object_get(name: data[:link_object_target])
data[:link_object_target_id] = linkobject.id
end
# from one site
if data.key?(:link_type)
linktype = link_type_get( name: data[:link_type] )
linktype = link_type_get(name: data[:link_type])
data[:link_type_id] = linktype.id
end
links = Link.where(
@ -130,11 +138,23 @@ class Link < ApplicationModel
link_object_target_id: data[:link_object_target_id],
link_object_target_value: data[:link_object_target_value]
)
links.each(&:destroy)
# touch references
links.each {|link|
link.destroy
touch_reference_by_params(
object: Link::Object.lookup(id: link.link_object_source_id).name,
o_id: link.link_object_source_value,
)
touch_reference_by_params(
object: Link::Object.lookup(id: link.link_object_target_id).name,
o_id: link.link_object_target_value,
)
}
# from the other site
if data.key?(:link_type)
linktype = link_type_get( name: @map[ data[:link_type] ] )
linktype = link_type_get(name: @map[ data[:link_type] ])
data[:link_type_id] = linktype.id
end
links = Link.where(
@ -144,25 +164,33 @@ class Link < ApplicationModel
link_object_source_id: data[:link_object_target_id],
link_object_source_value: data[:link_object_target_value]
)
links.each(&:destroy)
# touch references
links.each {|link|
link.destroy
touch_reference_by_params(
object: Link::Object.lookup(id: link.link_object_source_id).name,
o_id: link.link_object_source_value,
)
touch_reference_by_params(
object: Link::Object.lookup(id: link.link_object_target_id).name,
o_id: link.link_object_target_value,
)
}
end
def self.link_type_get(data)
linktype = Link::Type.find_by( name: data[:name] )
linktype = Link::Type.find_by(name: data[:name])
if !linktype
linktype = Link::Type.create(
name: data[:name]
)
linktype = Link::Type.create(name: data[:name])
end
linktype
end
def self.link_object_get(data)
linkobject = Link::Object.find_by( name: data[:name] )
linkobject = Link::Object.find_by(name: data[:name])
if !linkobject
linkobject = Link::Object.create(
name: data[:name]
)
linkobject = Link::Object.create(name: data[:name])
end
linkobject
end

View file

@ -7,7 +7,20 @@ class Tag < ApplicationModel
# rubocop:disable Style/ClassVars
@@cache_item = {}
@@cache_object = {}
# rubocop:enable Style/ClassVars
# rubocop:enable Style/ClassVars
=begin
add tags for certain object
Tag.tag_add(
object: 'Ticket',
o_id: ticket.id,
item: 'some tag',
created_by_id: current_user.id,
)
=end
def self.tag_add(data)
@ -30,9 +43,25 @@ class Tag < ApplicationModel
o_id: data[:o_id],
created_by_id: data[:created_by_id],
)
# touch reference
touch_reference_by_params(data)
true
end
=begin
remove tags of certain object
Tag.tag_add(
object: 'Ticket',
o_id: ticket.id,
item: 'some tag',
created_by_id: current_user.id,
)
=end
def self.tag_remove(data)
# lookups
@ -50,9 +79,29 @@ class Tag < ApplicationModel
o_id: data[:o_id],
)
result.each(&:destroy)
# touch reference
touch_reference_by_params(data)
true
end
=begin
tag list for certain object
tags = Tag.tag_list(
object: 'Ticket',
o_id: ticket.id,
item: 'some tag',
created_by_id: current_user.id,
)
returns
['tag 1', 'tag2', ...]
=end
def self.tag_list(data)
tag_object_id_requested = tag_object_lookup(data[:object])
tag_search = Tag.where(

View file

@ -6,16 +6,16 @@ module Ticket::Assets
get all assets / related models for this ticket
ticket = Ticket.find(123)
result = ticket.assets( assets_if_exists )
result = ticket.assets(assets_if_exists)
returns
result = {
:users => {
123 => user_model_123,
1234 => user_model_1234,
}
:tickets => [ ticket_model1 ]
users: {
123: user_model_123,
1234: user_model_1234,
},
tickets: [ ticket_model1 ]
}
=end