Init version of customer panel.

This commit is contained in:
Martin Edenhofer 2012-09-04 23:28:49 +02:00
parent 010bdecca7
commit 4c824992ee
20 changed files with 276 additions and 257 deletions

View file

@ -20,8 +20,8 @@ class Index extends App.Controller
@title '' @title ''
@navupdate '#ticket_view/' + @view @navupdate '#ticket_view/' + @view
@meta = {} @meta = {}
@bulk = {} @bulk = {}
# set controller to active # set controller to active
Config['ActiveController'] = '#ticket_overview_' + @view Config['ActiveController'] = '#ticket_overview_' + @view
@ -126,19 +126,24 @@ class Index extends App.Controller
@html html @html html
# create table/overview # create table/overview
checkbox = true
edit = true
if @isRole('Customer')
checkbox = false
edit = false
table = '' table = ''
if @view_mode is 'm' if @view_mode is 'm'
table = App.view('agent_ticket_view/detail')( table = App.view('agent_ticket_view/detail')(
overview: @overview, overview: @overview,
objects: @ticket_list_show, objects: @ticket_list_show,
checkbox: true checkbox: checkbox,
) )
table = $(table) table = $(table)
table.delegate('[name="bulk_all"]', 'click', (e) -> table.delegate('[name="bulk_all"]', 'click', (e) ->
if $(e.target).attr('checked') if $(e.target).attr('checked')
$(e.target).parents().find('[name="bulk"]').attr('checked', true); $(e.target).parents().find('[name="bulk"]').attr('checked', true)
else else
$(e.target).parents().find('[name="bulk"]').attr('checked', false); $(e.target).parents().find('[name="bulk"]').attr('checked', false)
) )
else else
shown_all_attributes = @ticketTableAttributes( App.Overview.find(@overview.id).view.s.overview ) 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, overview_extended: shown_all_attributes,
model: App.Ticket, model: App.Ticket,
objects: @ticket_list_show, objects: @ticket_list_show,
checkbox: true, checkbox: checkbox,
edit: edit,
) )
# append content table # append content table
@ -209,7 +215,6 @@ class Index extends App.Controller
# render init page # render init page
html = App.view('agent_ticket_view/bulk')( html = App.view('agent_ticket_view/bulk')(
meta: @overview.meta, meta: @overview.meta,
checkbox: true
form_ticket: form_ticket, form_ticket: form_ticket,
# form_article: form_article, # form_article: form_article,
) )

View file

@ -1,10 +1,10 @@
$ = jQuery.sub() $ = jQuery.sub()
class Index extends App.Controller class Index extends App.Controller
events: # events:
'submit form': 'submit', # 'submit form': 'submit',
'click .submit': 'submit', # 'click .submit': 'submit',
'click .cancel': 'cancel', # 'click .cancel': 'cancel',
constructor: (params) -> constructor: (params) ->
super super
@ -14,186 +14,18 @@ class Index extends App.Controller
# set title # set title
@title 'My Tickets' @title 'My Tickets'
@fetch(params) # @fetch(params)
@navupdate '#customer_tickets' @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">&raquo;</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() @render()
submit: (e) -> render: ->
e.preventDefault()
# get params @html App.view('agent_ticket_view')(
params = @formParam(e.target) 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 Config.Routes['customer_tickets'] = Index

View file

@ -8,6 +8,11 @@ class Index extends App.Controller
# check authentication # check authentication
return if !@authenticate() return if !@authenticate()
# check role
if @isRole('Customer')
@navigate '#ticket_view/my_tickets'
return
# set title # set title
@title 'Dashboard' @title 'Dashboard'
@navupdate '#/' @navupdate '#/'

View file

@ -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+agent', target: '#aa', role: ['Anybody', 'Agent'] }
#Config.NavBar[''] = { prio: 1600, parent: '', name: 'Anybody', target: '#anybody', role: ['Anybody'] } #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['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['TicketNew'] = { prio: 8000, parent: '', name: 'New', target: '#ticket_create', role: ['Agent'] }
Config.NavBarRight['User'] = { Config.NavBarRight['User'] = {

View file

@ -2,10 +2,13 @@ class App.Group extends App.Model
@configure 'Group', 'name', 'note', 'active' @configure 'Group', 'name', 'note', 'active'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' }, { 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: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { 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: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' }, { 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 = [ @configure_overview = [
'name', 'name',

View file

@ -2,11 +2,11 @@ class App.Organization extends App.Model
@configure 'Organization', 'name', 'shared', 'note', 'active' @configure 'Organization', 'name', 'shared', 'note', 'active'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
{ 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', tag: 'boolean', note: 'Customers in the organiztion can view each other items.', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
{ 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: '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: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' }, { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
] ]
@configure_overview = [ @configure_overview = [
'name', 'shared', 'name', 'shared',

View file

@ -2,10 +2,10 @@ class App.Role extends App.Model
@configure 'Role', 'name', 'note', 'active' @configure 'Role', 'name', 'note', 'active'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'xlarge' }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
{ name: 'note', display: 'Note', note: 'Notes are visible to agents only, never to customers.', tag: 'textarea', limit: 250, 'null': true, 'class': 'xlarge' }, { 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: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
{ name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'xlarge' }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
] ]
@configure_overview = [ @configure_overview = [
'name', 'name',

View file

@ -3,23 +3,23 @@ class App.User extends App.Model
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
# @hasMany 'roles', 'App.Role' # @hasMany 'roles', 'App.Role'
@configure_attributes = [ @configure_attributes = [
{ name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, class: 'xlarge', autocapitalize: false, signup: false, quick: false }, { 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: 'xlarge', signup: true, quick: true, info: true, invite_agent: true }, { 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', signup: false, quick: true, info: 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', 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: 'xlarge', signup: true, quick: false, }, { 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: 'xlarge' }, { 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: 'xlarge', quick: true, info: true }, { 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: 'xlarge' }, { 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: 'xlarge', invite_agent: true }, { 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: 'xlarge' }, { name: 'active', display: 'Active', tag: 'boolean', default: true, null: true, class: 'span4' },
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
] ]
@configure_overview = [ @configure_overview = [

View file

@ -1,7 +1,7 @@
<div class="page-header"> <div class="page-header">
<div class="row"> <div class="row">
<div class="span9"> <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>
<div class="span3"> <div class="span3">
<div class="pagination keepright"> <div class="pagination keepright">

View file

@ -129,9 +129,17 @@ class ApplicationController < ActionController::Base
def is_role( role_name ) def is_role( role_name )
return false if !current_user return false if !current_user
current_user.roles.each { |role| return true if current_user.is_role( role_name )
return true if role.name == role_name return false
} end
def ticket_permission(ticket)
return true if ticket.permission( :current_user => current_user )
render(
:json => {},
:status => :unauthorized
)
return false return false
end end

View file

@ -8,7 +8,7 @@ class TicketOverviewsController < ApplicationController
# get navbar overview data # get navbar overview data
if !params[:view] if !params[:view]
result = Ticket.overview( result = Ticket.overview(
:current_user_id => current_user.id, :current_user => current_user,
) )
render :json => result render :json => result
return return
@ -17,9 +17,9 @@ class TicketOverviewsController < ApplicationController
# get real overview data # get real overview data
if params[:array] if params[:array]
overview = Ticket.overview( overview = Ticket.overview(
:view => params[:view], :view => params[:view],
:current_user_id => current_user.id, :current_user => current_user,
:array => true, :array => true,
) )
tickets = [] tickets = []
overview[:tickets].each {|ticket| overview[:tickets].each {|ticket|
@ -157,7 +157,10 @@ class TicketOverviewsController < ApplicationController
# GET /ticket_full/1 # GET /ticket_full/1
def ticket_full def ticket_full
# permission check
ticket = Ticket.find(params[:id]) ticket = Ticket.find(params[:id])
return if !ticket_permission(ticket)
# get related users # get related users
users = {} users = {}
@ -260,6 +263,8 @@ class TicketOverviewsController < ApplicationController
def ticket_attachment def ticket_attachment
# permissin check # permissin check
ticket = Ticket.find( params[:ticket_id] )
return if !ticket_permission(ticket)
# find file # find file
file = Store.find(params[:id]) file = Store.find(params[:id])
@ -275,10 +280,14 @@ class TicketOverviewsController < ApplicationController
def ticket_article_plain def ticket_article_plain
# permissin check # permissin check
article = Ticket::Article.find( params[:id] )
return if !ticket_permission( article.ticket )
list = Store.list( list = Store.list(
:object => 'Ticket::Article::Mail', :object => 'Ticket::Article::Mail',
:o_id => params[:id], :o_id => params[:id],
) )
# find file # find file
if list if list
file = Store.find(list.first) file = Store.find(list.first)
@ -354,6 +363,9 @@ class TicketOverviewsController < ApplicationController
# get ticket data # get ticket data
ticket = Ticket.find(params[:id]) ticket = Ticket.find(params[:id])
# permissin check
return if !ticket_permission(ticket)
# get history of ticket # get history of ticket
history = History.history_list( 'Ticket', params[:id], 'Ticket::Article' ) history = History.history_list( 'Ticket', params[:id], 'Ticket::Article' )
@ -397,6 +409,9 @@ class TicketOverviewsController < ApplicationController
return return
end end
# permissin check
return if !ticket_permission(ticket_master)
# check slave ticket # check slave ticket
ticket_slave = Ticket.where( :id => params[:slave_ticket_id] ).first ticket_slave = Ticket.where( :id => params[:slave_ticket_id] ).first
if !ticket_slave if !ticket_slave
@ -407,6 +422,9 @@ class TicketOverviewsController < ApplicationController
return return
end end
# permissin check
return if !ticket_permission(ticket_slave)
# check diffetent ticket ids # check diffetent ticket ids
if ticket_slave.id == ticket_master.id if ticket_slave.id == ticket_master.id
render :json => { render :json => {

View file

@ -12,6 +12,9 @@ class TicketsController < ApplicationController
def show def show
@ticket = Ticket.find(params[:id]) @ticket = Ticket.find(params[:id])
# permissin check
return if !ticket_permission(@ticket)
render :json => @ticket render :json => @ticket
end end
@ -62,6 +65,9 @@ class TicketsController < ApplicationController
def update def update
@ticket = Ticket.find(params[:id]) @ticket = Ticket.find(params[:id])
# permissin check
return if !ticket_permission(@ticket)
if @ticket.update_attributes(params[:ticket]) if @ticket.update_attributes(params[:ticket])
render :json => @ticket, :status => :ok render :json => @ticket, :status => :ok
else else
@ -72,6 +78,10 @@ class TicketsController < ApplicationController
# DELETE /tickets/1 # DELETE /tickets/1
def destroy def destroy
@ticket = Ticket.find(params[:id]) @ticket = Ticket.find(params[:id])
# permissin check
return if !ticket_permission(@ticket)
@ticket.destroy @ticket.destroy
head :ok head :ok

View file

@ -134,24 +134,55 @@ class Ticket < ApplicationModel
return subject return subject
end 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( # Ticket.overview_list(
# :current_user_id => 123, # :current_user => 123,
# ) # )
def self.overview_list (data) 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 end
# Ticket.overview( # Ticket.overview(
# :view => 'some_view_url', # :view => 'some_view_url',
# :current_user_id => 123, # :current_user => OBJECT,
# ) # )
def self.overview (data) 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 # build up attributes hash
overview_selected = nil overview_selected = nil
overview_selected_raw = nil overview_selected_raw = nil
overviews = Overview.all overviews = Overview.where( :role_id => role.id )
overviews.each { |overview| overviews.each { |overview|
# for cleanup reasons, remove me later! # for cleanup reasons, remove me later!
@ -170,7 +201,7 @@ class Ticket < ApplicationModel
# replace 'current_user.id' with current_user.id # replace 'current_user.id' with current_user.id
overview.condition.each { |item, value | overview.condition.each { |item, value |
if value == 'current_user.id' if value == 'current_user.id'
overview.condition[item] = data[:current_user_id] overview.condition[item] = data[:current_user].id
end end
} }
} }
@ -196,10 +227,16 @@ class Ticket < ApplicationModel
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit]) # @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
# get only tickets with permissions # get only tickets with permissions
group_ids = Group.select( 'groups.id' ).joins(:users). if data[:current_user].is_role('Customer')
where( 'groups_users.user_id = ?', [ data[:current_user_id] ] ). group_ids = Group.select( 'groups.id' ).
where( 'groups.active = ?', true ). where( 'groups.active = ?', true ).
map( &:id ) 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 # overview meta for navbar
if !overview_selected if !overview_selected

View file

@ -30,6 +30,13 @@ class User < ApplicationModel
return fullname return fullname
end 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 ) def self.authenticate( username, password )
# do not authenticate with nothing # do not authenticate with nothing

View file

@ -42,11 +42,25 @@ class CreateBase < ActiveRecord::Migration
add_index :users, [:source] add_index :users, [:source]
add_index :users, [:created_by_id] 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| create_table :groups do |t|
t.column :name, :string, :limit => 100, :null => false t.references :signature, :null => false
t.column :active, :boolean, :null => false, :default => true t.column :name, :string, :limit => 100, :null => false
t.column :note, :string, :limit => 250, :null => true t.column :assignment_timeout, :integer, :null => true
t.column :created_by_id, :integer, :null => false 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 t.timestamps
end end
add_index :groups, [:name], :unique => true add_index :groups, [:name], :unique => true

View file

@ -135,6 +135,7 @@ class CreateTicket < ActiveRecord::Migration
create_table :overviews do |t| create_table :overviews do |t|
t.references :user, :null => true t.references :user, :null => true
t.references :role, :null => false
t.column :name, :string, :limit => 250, :null => false t.column :name, :string, :limit => 250, :null => false
t.column :meta, :string, :limit => 1000, :null => false t.column :meta, :string, :limit => 1000, :null => false
t.column :condition, :string, :limit => 2500, :null => false t.column :condition, :string, :limit => 2500, :null => false

View 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

View file

@ -0,0 +1,8 @@
class OverviewUpdate < ActiveRecord::Migration
def up
add_column :overviews, :role_id, :integer, :null => true
end
def down
end
end

View file

@ -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 => 'twitter direct-message', :communication => true )
Ticket::Article::Type.create( :name => 'facebook', :communication => true ) Ticket::Article::Type.create( :name => 'facebook', :communication => true )
Ticket::Article::Type.create( :name => 'note', :communication => false ) 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 => 'Agent' )
Ticket::Article::Sender.create( :name => 'Customer' ) Ticket::Article::Sender.create( :name => 'Customer' )
@ -1184,8 +1185,10 @@ The Zammad.org Project
:internal => false :internal => false
) )
overview_role = Role.where( :name => 'Agent' ).first
Overview.create( Overview.create(
:name => 'my_assigned', :name => 'my_assigned',
:role_id => overview_role.id,
:condition => { :condition => {
:ticket_state_id => [ 1,2,3 ], :ticket_state_id => [ 1,2,3 ],
:owner_id => 'current_user.id', :owner_id => 'current_user.id',
@ -1223,7 +1226,8 @@ Overview.create(
) )
Overview.create( Overview.create(
:name => 'all_unassigned', :name => 'all_unassigned',
:role_id => overview_role.id,
:condition => { :condition => {
:ticket_state_id => [1,2,3], :ticket_state_id => [1,2,3],
:owner_id => 1, :owner_id => 1,
@ -1261,7 +1265,8 @@ Overview.create(
) )
Overview.create( Overview.create(
:name => 'all_open', :name => 'all_open',
:role_id => overview_role.id,
:condition => { :condition => {
:ticket_state_id => [1,2,3], :ticket_state_id => [1,2,3],
}, },
@ -1298,7 +1303,8 @@ Overview.create(
) )
Overview.create( Overview.create(
:name => 'all_escalated', :name => 'all_escalated',
:role_id => overview_role.id,
:condition => { :condition => {
:ticket_state_id => [1,2,3], :ticket_state_id => [1,2,3],
}, },
@ -1335,7 +1341,8 @@ Overview.create(
) )
Overview.create( Overview.create(
:name => 'my_pending_reached', :name => 'my_pending_reached',
:role_id => overview_role.id,
:condition => { :condition => {
:ticket_state_id => [3], :ticket_state_id => [3],
:owner_id => 'current_user.id', :owner_id => 'current_user.id',
@ -1373,7 +1380,8 @@ Overview.create(
) )
Overview.create( Overview.create(
:name => 'all', :name => 'all',
:role_id => overview_role.id,
:condition => { :condition => {
# :ticket_state_id => [3], # :ticket_state_id => [3],
# :owner_id => current_user.id, # :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( Channel.create(
:adapter => 'SMTP', :adapter => 'SMTP',
:area => 'Email::Outbound', :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 => "parent", :target => "Eltern" )
Translation.create( :locale => 'de', :source => "normal", :target => "Normal" ) Translation.create( :locale => 'de', :source => "normal", :target => "Normal" )
Translation.create( :locale => 'de', :source => "Linked Objects", :target => "Verknüpfte Objekte" ) 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" ) Translation.create( :locale => 'de', :source => "Change Customer", :target => "Kunden ändern" )
Assignment Timout
#Translation.create( :locale => 'de', :source => "", :target => "" ) #Translation.create( :locale => 'de', :source => "", :target => "" )

View file

@ -234,7 +234,7 @@ class UserState
cache_key = @cache_key + '_overview' cache_key = @cache_key + '_overview'
if CacheIn.expired(cache_key) if CacheIn.expired(cache_key)
overview = Ticket.overview( overview = Ticket.overview(
:current_user_id => user.id, :current_user => user,
) )
overview_cache = CacheIn.get( cache_key, { :re_expire => true } ) overview_cache = CacheIn.get( cache_key, { :re_expire => true } )
self.log 'fetch overview - ' + cache_key self.log 'fetch overview - ' + cache_key
@ -249,16 +249,16 @@ class UserState
# overview lists # overview lists
overviews = Ticket.overview_list( overviews = Ticket.overview_list(
:current_user_id => user.id, :current_user => user,
) )
overviews.each { |overview| overviews.each { |overview|
cache_key = @cache_key + '_overview_data_' + overview.meta[:url] cache_key = @cache_key + '_overview_data_' + overview.meta[:url]
if CacheIn.expired(cache_key) if CacheIn.expired(cache_key)
overview_data = Ticket.overview( overview_data = Ticket.overview(
:view => overview.meta[:url], :view => overview.meta[:url],
# :view_mode => params[:view_mode], # :view_mode => params[:view_mode],
:current_user_id => user.id, :current_user => user,
:array => true, :array => true,
) )
overview_data_cache = CacheIn.get( cache_key, { :re_expire => true } ) overview_data_cache = CacheIn.get( cache_key, { :re_expire => true } )
self.log 'fetch overview_data - ' + cache_key self.log 'fetch overview_data - ' + cache_key
@ -386,7 +386,7 @@ class ClientState
# overview_data # overview_data
overviews = Ticket.overview_list( overviews = Ticket.overview_list(
:current_user_id => user.id, :current_user => user,
) )
overviews.each { |overview| overviews.each { |overview|
cache_key = 'user_' + user.id.to_s + '_overview_data_' + overview.meta[:url] cache_key = 'user_' + user.id.to_s + '_overview_data_' + overview.meta[:url]