Init version of customer panel.
This commit is contained in:
parent
010bdecca7
commit
4c824992ee
20 changed files with 276 additions and 257 deletions
|
@ -20,8 +20,8 @@ class Index extends App.Controller
|
|||
@title ''
|
||||
@navupdate '#ticket_view/' + @view
|
||||
|
||||
@meta = {}
|
||||
@bulk = {}
|
||||
@meta = {}
|
||||
@bulk = {}
|
||||
|
||||
# set controller to active
|
||||
Config['ActiveController'] = '#ticket_overview_' + @view
|
||||
|
@ -126,19 +126,24 @@ class Index extends App.Controller
|
|||
@html html
|
||||
|
||||
# create table/overview
|
||||
checkbox = true
|
||||
edit = true
|
||||
if @isRole('Customer')
|
||||
checkbox = false
|
||||
edit = false
|
||||
table = ''
|
||||
if @view_mode is 'm'
|
||||
table = App.view('agent_ticket_view/detail')(
|
||||
overview: @overview,
|
||||
objects: @ticket_list_show,
|
||||
checkbox: true
|
||||
checkbox: checkbox,
|
||||
)
|
||||
table = $(table)
|
||||
table.delegate('[name="bulk_all"]', 'click', (e) ->
|
||||
if $(e.target).attr('checked')
|
||||
$(e.target).parents().find('[name="bulk"]').attr('checked', true);
|
||||
$(e.target).parents().find('[name="bulk"]').attr('checked', true)
|
||||
else
|
||||
$(e.target).parents().find('[name="bulk"]').attr('checked', false);
|
||||
$(e.target).parents().find('[name="bulk"]').attr('checked', false)
|
||||
)
|
||||
else
|
||||
shown_all_attributes = @ticketTableAttributes( App.Overview.find(@overview.id).view.s.overview )
|
||||
|
@ -146,7 +151,8 @@ class Index extends App.Controller
|
|||
overview_extended: shown_all_attributes,
|
||||
model: App.Ticket,
|
||||
objects: @ticket_list_show,
|
||||
checkbox: true,
|
||||
checkbox: checkbox,
|
||||
edit: edit,
|
||||
)
|
||||
|
||||
# append content table
|
||||
|
@ -209,7 +215,6 @@ class Index extends App.Controller
|
|||
# render init page
|
||||
html = App.view('agent_ticket_view/bulk')(
|
||||
meta: @overview.meta,
|
||||
checkbox: true
|
||||
form_ticket: form_ticket,
|
||||
# form_article: form_article,
|
||||
)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class Index extends App.Controller
|
||||
events:
|
||||
'submit form': 'submit',
|
||||
'click .submit': 'submit',
|
||||
'click .cancel': 'cancel',
|
||||
# events:
|
||||
# 'submit form': 'submit',
|
||||
# 'click .submit': 'submit',
|
||||
# 'click .cancel': 'cancel',
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
@ -14,186 +14,18 @@ class Index extends App.Controller
|
|||
|
||||
# set title
|
||||
@title 'My Tickets'
|
||||
@fetch(params)
|
||||
# @fetch(params)
|
||||
@navupdate '#customer_tickets'
|
||||
|
||||
@edit_form = undefined
|
||||
|
||||
# lisen if view need to be rerendert
|
||||
Spine.bind 'ticket_create_rerender', (defaults) =>
|
||||
@log 'rerender', defaults
|
||||
@render(defaults)
|
||||
|
||||
# get data / in case also ticket data for split
|
||||
fetch: (params) ->
|
||||
|
||||
# use cache
|
||||
cache = App.Store.get( 'ticket_create_attributes' )
|
||||
|
||||
if cache && !params.ticket_id && !params.article_id
|
||||
|
||||
# get edit form attributes
|
||||
@edit_form = cache.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: cache.users )
|
||||
|
||||
@render()
|
||||
else
|
||||
App.Com.ajax(
|
||||
id: 'ticket_create',
|
||||
type: 'GET',
|
||||
url: '/ticket_create',
|
||||
data: {
|
||||
ticket_id: params.ticket_id,
|
||||
article_id: params.article_id,
|
||||
},
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# cache request
|
||||
App.Store.write( 'ticket_create_attributes', data )
|
||||
|
||||
# get edit form attributes
|
||||
@edit_form = data.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
if data.ticket && data.articles
|
||||
@loadCollection( type: 'Ticket', data: [data.ticket] )
|
||||
|
||||
# load article collections
|
||||
@loadCollection( type: 'TicketArticle', data: data.articles || [] )
|
||||
|
||||
# render page
|
||||
t = App.Ticket.find(params.ticket_id).attributes()
|
||||
a = App.TicketArticle.find(params.article_id)
|
||||
|
||||
# reset owner
|
||||
t.owner_id = 0
|
||||
t.customer_id_autocompletion = a.from
|
||||
t.subject = a.subject || t.title
|
||||
t.body = a.body
|
||||
@log '11111', t
|
||||
@render( options: t )
|
||||
)
|
||||
|
||||
render: (template = {}) ->
|
||||
|
||||
# set defaults
|
||||
defaults = template['options'] || {}
|
||||
if !( 'ticket_state_id' of defaults )
|
||||
defaults['ticket_state_id'] = App.TicketState.findByAttribute( 'name', 'new' )
|
||||
if !( 'ticket_priority_id' of defaults )
|
||||
defaults['ticket_priority_id'] = App.TicketPriority.findByAttribute( 'name', '2 normal' )
|
||||
|
||||
# remember customers
|
||||
if $('#create_customer_id').val()
|
||||
defaults['customer_id'] = $('#create_customer_id').val()
|
||||
defaults['customer_id_autocompletion'] = $('#create_customer_id_autocompletion').val()
|
||||
else
|
||||
# defaults['customer_id'] = '2'
|
||||
# defaults['customer_id_autocompletion'] = '12312313'
|
||||
|
||||
# generate form
|
||||
configure_attributes = [
|
||||
# { name: 'customer_id', display: 'Customer', tag: 'autocompletion', type: 'text', limit: 100, null: false, relation: 'User', class: 'span7', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', link: '<a href="" class="customer_new">»</a>', callback: @userInfo },
|
||||
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', },
|
||||
# { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', },
|
||||
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: false, default: defaults['subject'], class: 'span7', },
|
||||
{ name: 'body', display: 'Text', tag: 'textarea', rows: 10, null: false, default: defaults['body'], class: 'span7', },
|
||||
# { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketState', default: defaults['ticket_state_id'], translate: true, class: 'medium' },
|
||||
# { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketPriority', default: defaults['ticket_priority_id'], translate: true, class: 'medium' },
|
||||
]
|
||||
@html App.view('agent_ticket_create')(
|
||||
head: 'My Ticket',
|
||||
form: @formGen( model: { configure_attributes: configure_attributes, className: 'create' } ),
|
||||
)
|
||||
|
||||
# add elastic to textarea
|
||||
@el.find('textarea').elastic()
|
||||
|
||||
# update textarea size
|
||||
@el.find('textarea').trigger('change')
|
||||
|
||||
# start customer info controller
|
||||
if defaults['customer_id']
|
||||
$('#create_customer_id').val( defaults['customer_id'] )
|
||||
$('#create_customer_id_autocompletion').val( defaults['customer_id_autocompletion'] )
|
||||
@userInfo( user_id: defaults['customer_id'] )
|
||||
|
||||
cancel: ->
|
||||
@render()
|
||||
|
||||
submit: (e) ->
|
||||
e.preventDefault()
|
||||
render: ->
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
@html App.view('agent_ticket_view')(
|
||||
head: 'My Ticket',
|
||||
# form: @formGen( model: { configure_attributes: configure_attributes, className: 'create' } ),
|
||||
)
|
||||
|
||||
# fillup params
|
||||
if !params.title
|
||||
params.title = params.subject
|
||||
|
||||
# create ticket
|
||||
object = new App.Ticket
|
||||
@log 'updateAttributes', params
|
||||
|
||||
# find sender_id
|
||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
|
||||
type = App.TicketArticleType.findByAttribute( 'name', 'phone' )
|
||||
if params.group_id
|
||||
group = App.Group.find(params.group_id)
|
||||
|
||||
# create article
|
||||
params['article'] = {
|
||||
from: params.customer_id_autocompletion,
|
||||
to: (group && group.name) || '',
|
||||
subject: params.subject,
|
||||
body: params.body,
|
||||
ticket_article_type_id: type.id,
|
||||
ticket_article_sender_id: sender.id,
|
||||
created_by_id: params.customer_id,
|
||||
}
|
||||
# console.log('params', params)
|
||||
|
||||
object.load(params)
|
||||
|
||||
# validate form
|
||||
errors = object.validate()
|
||||
|
||||
# show errors in form
|
||||
if errors
|
||||
@log 'error new', errors
|
||||
@validateForm( form: e.target, errors: errors )
|
||||
|
||||
# save ticket, create article
|
||||
else
|
||||
|
||||
# disable form
|
||||
@formDisable(e)
|
||||
ui = @
|
||||
object.save(
|
||||
success: ->
|
||||
|
||||
# notify UI
|
||||
ui.notify
|
||||
type: 'success',
|
||||
msg: T('Ticket %s created!', @.number),
|
||||
link: "#ticket/zoom/#{@.id}"
|
||||
timeout: 12000,
|
||||
|
||||
# create new create screen
|
||||
ui.render()
|
||||
|
||||
# scroll to top
|
||||
ui.scrollTo()
|
||||
|
||||
error: ->
|
||||
ui.log 'save failed!'
|
||||
ui.formEnable(e)
|
||||
)
|
||||
|
||||
Config.Routes['customer_tickets'] = Index
|
||||
|
|
|
@ -8,6 +8,11 @@ class Index extends App.Controller
|
|||
# check authentication
|
||||
return if !@authenticate()
|
||||
|
||||
# check role
|
||||
if @isRole('Customer')
|
||||
@navigate '#ticket_view/my_tickets'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Dashboard'
|
||||
@navupdate '#/'
|
||||
|
|
|
@ -58,7 +58,7 @@ Config.NavBar['TicketOverview'] = { prio: 1000, parent: '', name: 'Overviews', t
|
|||
#Config.NavBar[''] = { prio: 1600, parent: '', name: 'anybody+agent', target: '#aa', role: ['Anybody', 'Agent'] }
|
||||
#Config.NavBar[''] = { prio: 1600, parent: '', name: 'Anybody', target: '#anybody', role: ['Anybody'] }
|
||||
Config.NavBar['CustomerTicketNew'] = { prio: 1600, parent: '', name: 'New Ticket', target: '#customer_ticket_new', role: ['Customer'] }
|
||||
Config.NavBar['CustomerTickets'] = { prio: 1700, parent: '', name: 'My Tickets', target: '#customer_tickets', role: ['Customer'] }
|
||||
Config.NavBar['CustomerTickets'] = { prio: 1700, parent: '', name: 'My Tickets', target: '#ticket_view/my_tickets', role: ['Customer'] }
|
||||
|
||||
Config.NavBarRight['TicketNew'] = { prio: 8000, parent: '', name: 'New', target: '#ticket_create', role: ['Agent'] }
|
||||
Config.NavBarRight['User'] = {
|
||||
|
|
|
@ -2,10 +2,13 @@ class App.Group extends App.Model
|
|||
@configure 'Group', 'name', 'note', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'assignment_timeout', display: 'Assignment Timout', tag: 'input', note: 'Assignment timout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'follow_up_possible', display: 'Follow possible', tag: 'select', default: 'yes', options: { yes: 'yes', reject: 'reject follow up/do not reopen Ticket', 'new_ticket': 'do not reopen Ticket but create new Ticket' }, 'null': false, note: 'Follow up for closed ticket possible or not.', 'class': 'span4' },
|
||||
{ name: 'follow_up_assignment', display: 'Assign Follow Ups', tag: 'select', default: 'yes', options: { yes: 'yes', no: 'no' }, 'null': false, note: 'Assign follow up to latest agent again.', 'class': 'span4' },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
|
||||
]
|
||||
@configure_overview = [
|
||||
'name',
|
||||
|
|
|
@ -2,11 +2,11 @@ class App.Organization extends App.Model
|
|||
@configure 'Organization', 'name', 'shared', 'note', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' },
|
||||
{ name: 'shared', display: 'Shared organiztion', note: 'Customers in the organiztion can view each other items.', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'shared', display: 'Shared organiztion', tag: 'boolean', note: 'Customers in the organiztion can view each other items.', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
|
||||
]
|
||||
@configure_overview = [
|
||||
'name', 'shared',
|
||||
|
|
|
@ -2,10 +2,10 @@ class App.Role extends App.Model
|
|||
@configure 'Role', 'name', 'note', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' },
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
|
||||
]
|
||||
@configure_overview = [
|
||||
'name',
|
||||
|
|
|
@ -3,23 +3,23 @@ class App.User extends App.Model
|
|||
@extend Spine.Model.Ajax
|
||||
# @hasMany 'roles', 'App.Role'
|
||||
@configure_attributes = [
|
||||
{ name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, class: 'xlarge', autocapitalize: false, signup: false, quick: false },
|
||||
{ name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'xlarge', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, class: 'xlarge', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'xlarge', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'xlarge', signup: false, quick: true, info: true },
|
||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'xlarge', signup: true, quick: false, },
|
||||
{ name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'xlarge' },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'xlarge', quick: true, info: true },
|
||||
{ name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role', class: 'xlarge' },
|
||||
{ name: 'group_ids', display: 'Groups', tag: 'checkbox', multiple: true, null: true, relation: 'Group', class: 'xlarge', invite_agent: true },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', default: true, null: true, class: 'xlarge' },
|
||||
{ name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', autocapitalize: false, signup: false, quick: false },
|
||||
{ name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true },
|
||||
{ name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true },
|
||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, quick: false, },
|
||||
{ name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4' },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'span4', quick: true, info: true },
|
||||
{ name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role', class: 'span4' },
|
||||
{ name: 'group_ids', display: 'Groups', tag: 'checkbox', multiple: true, null: true, relation: 'Group', class: 'span4', invite_agent: true },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', default: true, null: true, class: 'span4' },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
]
|
||||
@configure_overview = [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="page-header">
|
||||
<div class="row">
|
||||
<div class="span9">
|
||||
<h1><%- T(@overview.meta.name) %> <small><a href="#" data-type="settings" class="icon-edit"></a></small></h1>
|
||||
<h1><%- T(@overview.meta.name) %> <% if @edit: %><small><a href="#" data-type="settings" class="icon-edit"></a></small><% end %></h1>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="pagination keepright">
|
||||
|
|
|
@ -129,9 +129,17 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def is_role( role_name )
|
||||
return false if !current_user
|
||||
current_user.roles.each { |role|
|
||||
return true if role.name == role_name
|
||||
}
|
||||
return true if current_user.is_role( role_name )
|
||||
return false
|
||||
end
|
||||
|
||||
def ticket_permission(ticket)
|
||||
return true if ticket.permission( :current_user => current_user )
|
||||
|
||||
render(
|
||||
:json => {},
|
||||
:status => :unauthorized
|
||||
)
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class TicketOverviewsController < ApplicationController
|
|||
# get navbar overview data
|
||||
if !params[:view]
|
||||
result = Ticket.overview(
|
||||
:current_user_id => current_user.id,
|
||||
:current_user => current_user,
|
||||
)
|
||||
render :json => result
|
||||
return
|
||||
|
@ -17,9 +17,9 @@ class TicketOverviewsController < ApplicationController
|
|||
# get real overview data
|
||||
if params[:array]
|
||||
overview = Ticket.overview(
|
||||
:view => params[:view],
|
||||
:current_user_id => current_user.id,
|
||||
:array => true,
|
||||
:view => params[:view],
|
||||
:current_user => current_user,
|
||||
:array => true,
|
||||
)
|
||||
tickets = []
|
||||
overview[:tickets].each {|ticket|
|
||||
|
@ -157,7 +157,10 @@ class TicketOverviewsController < ApplicationController
|
|||
|
||||
# GET /ticket_full/1
|
||||
def ticket_full
|
||||
|
||||
# permission check
|
||||
ticket = Ticket.find(params[:id])
|
||||
return if !ticket_permission(ticket)
|
||||
|
||||
# get related users
|
||||
users = {}
|
||||
|
@ -260,6 +263,8 @@ class TicketOverviewsController < ApplicationController
|
|||
def ticket_attachment
|
||||
|
||||
# permissin check
|
||||
ticket = Ticket.find( params[:ticket_id] )
|
||||
return if !ticket_permission(ticket)
|
||||
|
||||
# find file
|
||||
file = Store.find(params[:id])
|
||||
|
@ -275,10 +280,14 @@ class TicketOverviewsController < ApplicationController
|
|||
def ticket_article_plain
|
||||
|
||||
# permissin check
|
||||
article = Ticket::Article.find( params[:id] )
|
||||
return if !ticket_permission( article.ticket )
|
||||
|
||||
list = Store.list(
|
||||
:object => 'Ticket::Article::Mail',
|
||||
:o_id => params[:id],
|
||||
)
|
||||
|
||||
# find file
|
||||
if list
|
||||
file = Store.find(list.first)
|
||||
|
@ -354,6 +363,9 @@ class TicketOverviewsController < ApplicationController
|
|||
# get ticket data
|
||||
ticket = Ticket.find(params[:id])
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(ticket)
|
||||
|
||||
# get history of ticket
|
||||
history = History.history_list( 'Ticket', params[:id], 'Ticket::Article' )
|
||||
|
||||
|
@ -397,6 +409,9 @@ class TicketOverviewsController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(ticket_master)
|
||||
|
||||
# check slave ticket
|
||||
ticket_slave = Ticket.where( :id => params[:slave_ticket_id] ).first
|
||||
if !ticket_slave
|
||||
|
@ -407,6 +422,9 @@ class TicketOverviewsController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(ticket_slave)
|
||||
|
||||
# check diffetent ticket ids
|
||||
if ticket_slave.id == ticket_master.id
|
||||
render :json => {
|
||||
|
|
|
@ -12,6 +12,9 @@ class TicketsController < ApplicationController
|
|||
def show
|
||||
@ticket = Ticket.find(params[:id])
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(@ticket)
|
||||
|
||||
render :json => @ticket
|
||||
end
|
||||
|
||||
|
@ -62,6 +65,9 @@ class TicketsController < ApplicationController
|
|||
def update
|
||||
@ticket = Ticket.find(params[:id])
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(@ticket)
|
||||
|
||||
if @ticket.update_attributes(params[:ticket])
|
||||
render :json => @ticket, :status => :ok
|
||||
else
|
||||
|
@ -72,6 +78,10 @@ class TicketsController < ApplicationController
|
|||
# DELETE /tickets/1
|
||||
def destroy
|
||||
@ticket = Ticket.find(params[:id])
|
||||
|
||||
# permissin check
|
||||
return if !ticket_permission(@ticket)
|
||||
|
||||
@ticket.destroy
|
||||
|
||||
head :ok
|
||||
|
|
|
@ -134,24 +134,55 @@ class Ticket < ApplicationModel
|
|||
return subject
|
||||
end
|
||||
|
||||
# ticket.permission(
|
||||
# :current_user => 123
|
||||
# )
|
||||
def permission (data)
|
||||
|
||||
# check customer
|
||||
if data[:current_user].is_role('Customer')
|
||||
return true if self.customer_id == data[:current_user].id
|
||||
return false
|
||||
end
|
||||
|
||||
# check agent
|
||||
return true if self.owner_id == data[:current_user].id
|
||||
data[:current_user].groups.each {|group|
|
||||
return true if self.group.id == group.id
|
||||
}
|
||||
return false
|
||||
end
|
||||
|
||||
# Ticket.overview_list(
|
||||
# :current_user_id => 123,
|
||||
# :current_user => 123,
|
||||
# )
|
||||
def self.overview_list (data)
|
||||
Overview.all
|
||||
# get user role
|
||||
if data[:current_user].is_role('Customer')
|
||||
role = data[:current_user].is_role( 'Customer' )
|
||||
else
|
||||
role = data[:current_user].is_role( 'Agent' )
|
||||
end
|
||||
Overview.where( :role_id => role.id )
|
||||
end
|
||||
|
||||
# Ticket.overview(
|
||||
# :view => 'some_view_url',
|
||||
# :current_user_id => 123,
|
||||
# :view => 'some_view_url',
|
||||
# :current_user => OBJECT,
|
||||
# )
|
||||
def self.overview (data)
|
||||
|
||||
# get user role
|
||||
if data[:current_user].is_role('Customer')
|
||||
role = data[:current_user].is_role( 'Customer' )
|
||||
else
|
||||
role = data[:current_user].is_role( 'Agent' )
|
||||
end
|
||||
|
||||
# build up attributes hash
|
||||
overview_selected = nil
|
||||
overview_selected_raw = nil
|
||||
overviews = Overview.all
|
||||
overviews = Overview.where( :role_id => role.id )
|
||||
overviews.each { |overview|
|
||||
|
||||
# for cleanup reasons, remove me later!
|
||||
|
@ -170,7 +201,7 @@ class Ticket < ApplicationModel
|
|||
# replace 'current_user.id' with current_user.id
|
||||
overview.condition.each { |item, value |
|
||||
if value == 'current_user.id'
|
||||
overview.condition[item] = data[:current_user_id]
|
||||
overview.condition[item] = data[:current_user].id
|
||||
end
|
||||
}
|
||||
}
|
||||
|
@ -196,10 +227,16 @@ class Ticket < ApplicationModel
|
|||
|
||||
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
|
||||
# get only tickets with permissions
|
||||
group_ids = Group.select( 'groups.id' ).joins(:users).
|
||||
where( 'groups_users.user_id = ?', [ data[:current_user_id] ] ).
|
||||
where( 'groups.active = ?', true ).
|
||||
map( &:id )
|
||||
if data[:current_user].is_role('Customer')
|
||||
group_ids = Group.select( 'groups.id' ).
|
||||
where( 'groups.active = ?', true ).
|
||||
map( &:id )
|
||||
else
|
||||
group_ids = Group.select( 'groups.id' ).joins(:users).
|
||||
where( 'groups_users.user_id = ?', [ data[:current_user].id ] ).
|
||||
where( 'groups.active = ?', true ).
|
||||
map( &:id )
|
||||
end
|
||||
|
||||
# overview meta for navbar
|
||||
if !overview_selected
|
||||
|
|
|
@ -30,6 +30,13 @@ class User < ApplicationModel
|
|||
return fullname
|
||||
end
|
||||
|
||||
def is_role( role_name )
|
||||
self.roles.each { |role|
|
||||
return role if role.name == role_name
|
||||
}
|
||||
return false
|
||||
end
|
||||
|
||||
def self.authenticate( username, password )
|
||||
|
||||
# do not authenticate with nothing
|
||||
|
|
|
@ -42,11 +42,25 @@ class CreateBase < ActiveRecord::Migration
|
|||
add_index :users, [:source]
|
||||
add_index :users, [:created_by_id]
|
||||
|
||||
create_table :signatures do |t|
|
||||
t.column :name, :string, :limit => 100, :null => false
|
||||
t.column :body, :string, :limit => 5000, :null => true
|
||||
t.column :active, :boolean, :null => false, :default => true
|
||||
t.column :note, :string, :limit => 250, :null => true
|
||||
t.column :created_by_id, :integer, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :signatures, [:name], :unique => true
|
||||
|
||||
create_table :groups do |t|
|
||||
t.column :name, :string, :limit => 100, :null => false
|
||||
t.column :active, :boolean, :null => false, :default => true
|
||||
t.column :note, :string, :limit => 250, :null => true
|
||||
t.column :created_by_id, :integer, :null => false
|
||||
t.references :signature, :null => false
|
||||
t.column :name, :string, :limit => 100, :null => false
|
||||
t.column :assignment_timeout, :integer, :null => true
|
||||
t.column :follow_up_possible, :string, :limit => 100, :default => 'yes', :null => true
|
||||
t.column :follow_up_assignment, :boolean, :default => 1
|
||||
t.column :active, :boolean, :null => false, :default => true
|
||||
t.column :note, :string, :limit => 250, :null => true
|
||||
t.column :created_by_id, :integer, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :groups, [:name], :unique => true
|
||||
|
|
|
@ -135,6 +135,7 @@ class CreateTicket < ActiveRecord::Migration
|
|||
|
||||
create_table :overviews do |t|
|
||||
t.references :user, :null => true
|
||||
t.references :role, :null => false
|
||||
t.column :name, :string, :limit => 250, :null => false
|
||||
t.column :meta, :string, :limit => 1000, :null => false
|
||||
t.column :condition, :string, :limit => 2500, :null => false
|
||||
|
|
22
db/migrate/20120825005823_group_update.rb
Normal file
22
db/migrate/20120825005823_group_update.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
class GroupUpdate < ActiveRecord::Migration
|
||||
def up
|
||||
# t.references :signature, :null => true
|
||||
add_column :groups, :signature_id, :integer, :null => true
|
||||
add_column :groups, :assignment_timeout, :integer, :null => true
|
||||
add_column :groups, :follow_up_possible, :string, :limit => 100, :default => 'yes', :null => true
|
||||
add_column :groups, :follow_up_assignment, :boolean, :default => 1
|
||||
|
||||
create_table :signatures do |t|
|
||||
t.column :name, :string, :limit => 100, :null => false
|
||||
t.column :body, :string, :limit => 5000, :null => true
|
||||
t.column :active, :boolean, :null => false, :default => true
|
||||
t.column :note, :string, :limit => 250, :null => true
|
||||
t.column :created_by_id, :integer, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :signatures, [:name], :unique => true
|
||||
end
|
||||
|
||||
def down
|
||||
end
|
||||
end
|
8
db/migrate/20120904192450_overview_update.rb
Normal file
8
db/migrate/20120904192450_overview_update.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class OverviewUpdate < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :overviews, :role_id, :integer, :null => true
|
||||
end
|
||||
|
||||
def down
|
||||
end
|
||||
end
|
61
db/seeds.rb
61
db/seeds.rb
|
@ -1149,6 +1149,7 @@ Ticket::Article::Type.create( :name => 'twitter status', :communication => true
|
|||
Ticket::Article::Type.create( :name => 'twitter direct-message', :communication => true )
|
||||
Ticket::Article::Type.create( :name => 'facebook', :communication => true )
|
||||
Ticket::Article::Type.create( :name => 'note', :communication => false )
|
||||
Ticket::Article::Type.create( :name => 'web', :communication => true )
|
||||
|
||||
Ticket::Article::Sender.create( :name => 'Agent' )
|
||||
Ticket::Article::Sender.create( :name => 'Customer' )
|
||||
|
@ -1184,8 +1185,10 @@ The Zammad.org Project
|
|||
:internal => false
|
||||
)
|
||||
|
||||
overview_role = Role.where( :name => 'Agent' ).first
|
||||
Overview.create(
|
||||
:name => 'my_assigned',
|
||||
:name => 'my_assigned',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:ticket_state_id => [ 1,2,3 ],
|
||||
:owner_id => 'current_user.id',
|
||||
|
@ -1223,7 +1226,8 @@ Overview.create(
|
|||
)
|
||||
|
||||
Overview.create(
|
||||
:name => 'all_unassigned',
|
||||
:name => 'all_unassigned',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:ticket_state_id => [1,2,3],
|
||||
:owner_id => 1,
|
||||
|
@ -1261,7 +1265,8 @@ Overview.create(
|
|||
)
|
||||
|
||||
Overview.create(
|
||||
:name => 'all_open',
|
||||
:name => 'all_open',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:ticket_state_id => [1,2,3],
|
||||
},
|
||||
|
@ -1298,7 +1303,8 @@ Overview.create(
|
|||
)
|
||||
|
||||
Overview.create(
|
||||
:name => 'all_escalated',
|
||||
:name => 'all_escalated',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:ticket_state_id => [1,2,3],
|
||||
},
|
||||
|
@ -1335,7 +1341,8 @@ Overview.create(
|
|||
)
|
||||
|
||||
Overview.create(
|
||||
:name => 'my_pending_reached',
|
||||
:name => 'my_pending_reached',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:ticket_state_id => [3],
|
||||
:owner_id => 'current_user.id',
|
||||
|
@ -1373,7 +1380,8 @@ Overview.create(
|
|||
)
|
||||
|
||||
Overview.create(
|
||||
:name => 'all',
|
||||
:name => 'all',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
# :ticket_state_id => [3],
|
||||
# :owner_id => current_user.id,
|
||||
|
@ -1410,6 +1418,45 @@ Overview.create(
|
|||
}
|
||||
)
|
||||
|
||||
overview_role = Role.where( :name => 'Customer' ).first
|
||||
Overview.create(
|
||||
:name => 'My Tickets',
|
||||
:role_id => overview_role.id,
|
||||
:condition => {
|
||||
:customer_id => 'current_user.id',
|
||||
},
|
||||
:order => {
|
||||
:by => 'created_at',
|
||||
:direction => 'ASC',
|
||||
},
|
||||
:meta => {
|
||||
:url => 'my_tickets',
|
||||
:name => 'My Tickets',
|
||||
:prio => 1000,
|
||||
},
|
||||
:view => {
|
||||
:d => {
|
||||
:overview => [
|
||||
'title', 'customer', 'ticket_state', 'created_at'
|
||||
],
|
||||
:per_page => 5,
|
||||
},
|
||||
:s => {
|
||||
:overview => [
|
||||
'number', 'title', 'ticket_state', 'ticket_priority', 'created_at'
|
||||
],
|
||||
:per_page => 30,
|
||||
},
|
||||
:m => {
|
||||
:overview => [
|
||||
'number', 'title', 'ticket_state', 'ticket_priority', 'created_at'
|
||||
],
|
||||
:per_page => 20,
|
||||
},
|
||||
:view_mode_default => 's',
|
||||
}
|
||||
)
|
||||
|
||||
Channel.create(
|
||||
:adapter => 'SMTP',
|
||||
:area => 'Email::Outbound',
|
||||
|
@ -1658,5 +1705,7 @@ Translation.create( :locale => 'de', :source => "child", :target => "Kind" )
|
|||
Translation.create( :locale => 'de', :source => "parent", :target => "Eltern" )
|
||||
Translation.create( :locale => 'de', :source => "normal", :target => "Normal" )
|
||||
Translation.create( :locale => 'de', :source => "Linked Objects", :target => "Verknüpfte Objekte" )
|
||||
Translation.create( :locale => 'de', :source => "Links", :target => "Verknüpftungen" )
|
||||
Translation.create( :locale => 'de', :source => "Change Customer", :target => "Kunden ändern" )
|
||||
Assignment Timout
|
||||
#Translation.create( :locale => 'de', :source => "", :target => "" )
|
||||
|
|
|
@ -234,7 +234,7 @@ class UserState
|
|||
cache_key = @cache_key + '_overview'
|
||||
if CacheIn.expired(cache_key)
|
||||
overview = Ticket.overview(
|
||||
:current_user_id => user.id,
|
||||
:current_user => user,
|
||||
)
|
||||
overview_cache = CacheIn.get( cache_key, { :re_expire => true } )
|
||||
self.log 'fetch overview - ' + cache_key
|
||||
|
@ -249,16 +249,16 @@ class UserState
|
|||
|
||||
# overview lists
|
||||
overviews = Ticket.overview_list(
|
||||
:current_user_id => user.id,
|
||||
:current_user => user,
|
||||
)
|
||||
overviews.each { |overview|
|
||||
cache_key = @cache_key + '_overview_data_' + overview.meta[:url]
|
||||
if CacheIn.expired(cache_key)
|
||||
overview_data = Ticket.overview(
|
||||
:view => overview.meta[:url],
|
||||
# :view_mode => params[:view_mode],
|
||||
:current_user_id => user.id,
|
||||
:array => true,
|
||||
:view => overview.meta[:url],
|
||||
# :view_mode => params[:view_mode],
|
||||
:current_user => user,
|
||||
:array => true,
|
||||
)
|
||||
overview_data_cache = CacheIn.get( cache_key, { :re_expire => true } )
|
||||
self.log 'fetch overview_data - ' + cache_key
|
||||
|
@ -386,7 +386,7 @@ class ClientState
|
|||
|
||||
# overview_data
|
||||
overviews = Ticket.overview_list(
|
||||
:current_user_id => user.id,
|
||||
:current_user => user,
|
||||
)
|
||||
overviews.each { |overview|
|
||||
cache_key = 'user_' + user.id.to_s + '_overview_data_' + overview.meta[:url]
|
||||
|
|
Loading…
Reference in a new issue