Added general support of attachments.

This commit is contained in:
Martin Edenhofer 2012-12-02 11:18:55 +01:00
parent 4e1d519575
commit 5ca42745ab
13 changed files with 129 additions and 86 deletions

View file

@ -284,6 +284,20 @@ class App.ControllerForm extends App.Controller
# textarea # textarea
else if attribute.tag is 'textarea' else if attribute.tag is 'textarea'
item = $( App.view('generic/textarea')( attribute: attribute ) ) item = $( App.view('generic/textarea')( attribute: attribute ) )
if attribute.upload
fileUploaderId = 'file-uploader-' + new Date().getTime() + '-' + Math.floor( Math.random() * 99999 )
item.after('<div class="' + attribute.class + '" id="' + fileUploaderId + '"></div>')
# add file uploader
u = =>
uploader = new qq.FileUploader(
element: document.getElementById(fileUploaderId)
action: '/api/ticket_attachment_new'
debug: false
params:
form_id: @form_id
)
@delay( u, 200 )
# tag # tag
else if attribute.tag is 'tag' else if attribute.tag is 'tag'
@ -643,6 +657,9 @@ class App.ControllerForm extends App.Controller
App.Log.log 'ControllerForm', 'notice', 'formParam', form, param App.Log.log 'ControllerForm', 'notice', 'formParam', form, param
return param return param
@formId: ->
formId = new Date().getTime() + Math.floor( Math.random() * 99999 )
formId.toString().substr formId.toString().length-9, 9
@disable: (form) -> @disable: (form) ->
App.Log.log 'ControllerForm', 'notice', 'disable...', $(form.target).parent() App.Log.log 'ControllerForm', 'notice', 'disable...', $(form.target).parent()

View file

@ -15,6 +15,7 @@ class Index extends App.Controller
# set title # set title
@title 'New Ticket' @title 'New Ticket'
@form_id = App.ControllerForm.formId()
@fetch(params) @fetch(params)
@navupdate '#ticket_create' @navupdate '#ticket_create'
@ -105,20 +106,20 @@ class Index extends App.Controller
{ 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: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', },
{ name: 'tags', display: 'Tags', tag: 'tag', type: 'text', null: true, default: defaults['tags'], class: 'span7', }, { name: 'tags', display: 'Tags', tag: 'tag', type: 'text', null: true, default: defaults['tags'], class: 'span7', },
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 200, null: false, default: defaults['subject'], class: 'span7', }, { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 200, null: false, default: defaults['subject'], class: 'span7', },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 6, null: false, default: defaults['body'], class: 'span7', }, { name: 'body', display: 'Text', tag: 'textarea', rows: 8, null: false, default: defaults['body'], class: 'span7', upload: true },
{ 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_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' }, { 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: 'New Ticket' ) @html App.view('agent_ticket_create')( head: 'New Ticket' )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form_create'), el: @el.find('#form_create')
model: { form_id: @form_id
configure_attributes: configure_attributes, model:
className: 'create', configure_attributes: configure_attributes
}, className: 'create'
autofocus: true, autofocus: true
form_data: @edit_form, form_data: @edit_form
) )
# add elastic to textarea # add elastic to textarea
@ -176,15 +177,14 @@ class Index extends App.Controller
# create article # create article
params['article'] = { params['article'] = {
from: params.customer_id_autocompletion, from: params.customer_id_autocompletion
to: (group && group.name) || '', to: (group && group.name) || ''
subject: params.subject, subject: params.subject
body: params.body, body: params.body
ticket_article_type_id: type.id, ticket_article_type_id: type.id
ticket_article_sender_id: sender.id, ticket_article_sender_id: sender.id
created_by_id: params.customer_id, form_id: @form_id
} }
# console.log('params', params)
object.load(params) object.load(params)

View file

@ -20,6 +20,7 @@ class Index extends App.Controller
@navupdate '#' @navupdate '#'
@form_id = App.ControllerForm.formId()
@edit_form = undefined @edit_form = undefined
@ticket_id = params.ticket_id @ticket_id = params.ticket_id
@article_id = params.article_id @article_id = params.article_id
@ -105,7 +106,7 @@ class Index extends App.Controller
{ name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: true, class: 'span7', item_class: '' }, { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
{ name: 'internal', display: 'Visability', tag: 'select', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '' }, { name: 'internal', display: 'Visability', tag: 'select', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '' },
] ]
if @isRole('Customer') if @isRole('Customer')
@ -114,7 +115,7 @@ class Index extends App.Controller
{ name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
{ name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: true, class: 'span7', item_class: '' }, { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
] ]
@html App.view('agent_ticket_zoom')( @html App.view('agent_ticket_zoom')(
@ -125,6 +126,7 @@ class Index extends App.Controller
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-ticket-update') el: @el.find('#form-ticket-update')
form_id: @form_id
model: model:
configure_attributes: @configure_attributes_ticket configure_attributes: @configure_attributes_ticket
className: 'create' className: 'create'
@ -134,6 +136,7 @@ class Index extends App.Controller
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form-article-update') el: @el.find('#form-article-update')
form_id: @form_id
model: model:
configure_attributes: @configure_attributes_article configure_attributes: @configure_attributes_article
form_data: @edit_form form_data: @edit_form
@ -158,18 +161,6 @@ class Index extends App.Controller
@scrollTo( 0, offset ) @scrollTo( 0, offset )
@delay( scrollTo, 100 ) @delay( scrollTo, 100 )
@delay(@u, 200)
u: =>
uploader = new qq.FileUploader(
element: document.getElementById('file-uploader')
action: '/api/ticket_attachment_new'
params:
form: 'TicketZoom'
form_id: @ticket.id
debug: false
)
ticket_action_row: => ticket_action_row: =>
# start customer info controller # start customer info controller
@ -410,8 +401,10 @@ class Index extends App.Controller
# create article # create article
if params['body'] if params['body']
article = new App.TicketArticle article = new App.TicketArticle
params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' ) params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' )
params.ticket_id = @ticket.id params.ticket_id = @ticket.id
params.form_id = @form_id
if !params['internal'] if !params['internal']
params['internal'] = false params['internal'] = false

View file

@ -14,6 +14,7 @@ class Index extends App.Controller
# set title # set title
@title 'New Ticket' @title 'New Ticket'
@form_id = App.ControllerForm.formId()
@fetch(params) @fetch(params)
@navupdate '#customer_ticket_new' @navupdate '#customer_ticket_new'
@ -98,20 +99,20 @@ class Index extends App.Controller
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: groupFilter, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', }, { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: groupFilter, 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: '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: '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: 'body', display: 'Text', tag: 'textarea', rows: 10, null: false, default: defaults['body'], class: 'span7', upload: true },
# { 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_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' }, # { 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: 'New Ticket' ) @html App.view('agent_ticket_create')( head: 'New Ticket' )
new App.ControllerForm( new App.ControllerForm(
el: @el.find('#form_create'), el: @el.find('#form_create')
model: { form_id: @form_id
configure_attributes: configure_attributes, model:
className: 'create', configure_attributes: configure_attributes
}, className: 'create'
autofocus: true, autofocus: true
form_data: @edit_form, form_data: @edit_form
) )
# add elastic to textarea # add elastic to textarea
@ -157,13 +158,13 @@ class Index extends App.Controller
# create article # create article
params['article'] = { params['article'] = {
from: "#{ @Session.get('firstname') } #{ @Session.get('lastname') }", from: "#{ @Session.get('firstname') } #{ @Session.get('lastname') }"
to: (group && group.name) || '', to: (group && group.name) || ''
subject: params.subject, subject: params.subject
body: params.body, body: params.body
ticket_article_type_id: type.id, ticket_article_type_id: type.id
ticket_article_sender_id: sender.id, ticket_article_sender_id: sender.id
created_by_id: @Session.get('id'), form_id: @form_id
} }
# console.log('params', params) # console.log('params', params)

View file

@ -485,8 +485,8 @@ qq.FileUploader = function(o){
listElement: null, listElement: null,
template: '<div class="qq-uploader">' + template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area btn"><i class="icon-attachment"></i> Drop to attach files</div>' + '<div class="qq-upload-icon qq-upload-drop-area btn keepright"><i class="icon-attachment"></i> Drop to attach files</div>' +
'<div class="qq-upload-button btn"><i class="icon-attachment"></i> Attach files</div>' + '<div class="qq-upload-icon qq-upload-button btn keepright"><i class="icon-attachment"></i></div>' +
'<ul class="qq-upload-list"></ul>' + '<ul class="qq-upload-list"></ul>' +
'</div>', '</div>',

View file

@ -1,5 +1,5 @@
class App.TicketArticle extends App.Model class App.TicketArticle extends App.Model
@configure 'TicketArticle', 'from', 'to', 'cc', 'subject', 'body', 'ticket_id', 'ticket_article_type_id', 'ticket_article_sender_id', 'internal', 'in_reply_to' @configure 'TicketArticle', 'from', 'to', 'cc', 'subject', 'body', 'ticket_id', 'ticket_article_type_id', 'ticket_article_sender_id', 'internal', 'in_reply_to', 'form_id'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: '/api/ticket_articles' @url: '/api/ticket_articles'
@configure_attributes = [ @configure_attributes = [

View file

@ -81,8 +81,6 @@
<form class="form-stacked keepleft"> <form class="form-stacked keepleft">
<div id="form-ticket-update"></div> <div id="form-ticket-update"></div>
<div id="form-article-update"></div> <div id="form-article-update"></div>
<div class="keepleft" id="file-uploader"></div>
&nbsp;
<button type="submit" class="btn btn-primary submit"><%- @T( 'Submit' ) %></button> <button type="submit" class="btn btn-primary submit"><%- @T( 'Submit' ) %></button>
</form> </form>
</div> </div>

View file

@ -7,6 +7,27 @@ label, input, button, select, textarea {
font-size: 13px; font-size: 13px;
} }
select,
textarea,
input[type="text"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="week"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="search"],
input[type="tel"],
input[type="color"],
.uneditable-input {
margin-bottom: 1px;
}
.spinner { .spinner {
float: left; float: left;
background:url("/assets/spinner.gif") no-repeat; background:url("/assets/spinner.gif") no-repeat;
@ -351,3 +372,12 @@ footer {
text-shadow: 0 1px 0 #fff; text-shadow: 0 1px 0 #fff;
opacity: 0.9; opacity: 0.9;
} }
.qq-upload-list {
margin: 5px 10px 0px;
padding: 0;
list-style: disc;
}
.qq-upload-icon {
margin: 0px 20px;
}

View file

@ -17,22 +17,26 @@ class TicketArticlesController < ApplicationController
# POST /articles # POST /articles
def create def create
@article = Ticket::Article.new(params[:ticket_article]) form_id = params[:ticket_article][:form_id]
params[:ticket_article].delete(:form_id)
@article = Ticket::Article.new( params[:ticket_article] )
@article.created_by_id = current_user.id @article.created_by_id = current_user.id
@article.updated_by_id = current_user.id @article.updated_by_id = current_user.id
# find attachments in upload cache # find attachments in upload cache
@article['attachments'] = Store.list( if form_id
:object => 'UploadCache::TicketZoom::' + current_user.id.to_s, @article['attachments'] = Store.list(
:o_id => @article.ticket_id :object => 'UploadCache',
) :o_id => form_id,
)
end
if @article.save if @article.save
# remove attachments from upload cache # remove attachments from upload cache
Store.remove( Store.remove(
:object => 'UploadCache::TicketZoom::' + current_user.id.to_s, :object => 'UploadCache',
:o_id => @article.ticket_id :o_id => form_id,
) )
render :json => @article, :status => :created render :json => @article, :status => :created
@ -61,12 +65,8 @@ class TicketArticlesController < ApplicationController
head :ok head :ok
end end
# POST /ticket_attachment/new # POST /ticket_attachment/new
def attachment_new def attachment_new
# puts '-------'
# puts params.inspect
# store file # store file
# content_type = request.content_type # content_type = request.content_type
@ -83,7 +83,7 @@ class TicketArticlesController < ApplicationController
'Content-Type' => content_type 'Content-Type' => content_type
} }
Store.add( Store.add(
:object => 'UploadCache::' + params[:form] + '::' + current_user.id.to_s, :object => 'UploadCache',
:o_id => params[:form_id], :o_id => params[:form_id],
:data => request.body.read, :data => request.body.read,
:filename => params[:qqfile], :filename => params[:qqfile],

View file

@ -51,26 +51,32 @@ class TicketsController < ApplicationController
# create article if given # create article if given
if params[:article] if params[:article]
@article = Ticket::Article.new(params[:article]) form_id = params[:article][:form_id]
params[:article].delete(:form_id)
@article = Ticket::Article.new( params[:article] )
@article.created_by_id = params[:article][:created_by_id] || current_user.id @article.created_by_id = params[:article][:created_by_id] || current_user.id
@article.updated_by_id = params[:article][:updated_by_id] || current_user.id @article.updated_by_id = params[:article][:updated_by_id] || current_user.id
@article.ticket_id = @ticket.id @article.ticket_id = @ticket.id
# find attachments in upload cache # find attachments in upload cache
@article['attachments'] = Store.list( if form_id
:object => 'UploadCache::TicketZoom::' + current_user.id.to_s, @article['attachments'] = Store.list(
:o_id => @article.ticket_id :object => 'UploadCache',
) :o_id => form_id,
)
end
if !@article.save if !@article.save
render :json => @article.errors, :status => :unprocessable_entity render :json => @article.errors, :status => :unprocessable_entity
return return
end end
# remove attachments from upload cache # remove attachments from upload cache
Store.remove( if params[:form_id]
:object => 'UploadCache::TicketZoom::' + current_user.id.to_s, Store.remove(
:o_id => @article.ticket_id :object => 'UploadCache',
) :o_id => form_id,
)
end
end end
render :json => @ticket, :status => :created render :json => @ticket, :status => :created

View file

@ -53,8 +53,7 @@ class Store < ActiveRecord::Base
def self.list(data) def self.list(data)
# search # search
stores = Store.where( :store_object_id => Store::Object.where( :name => data[:object] ) ). stores = Store.where( :store_object_id => Store::Object.where( :name => data[:object] ), :o_id => data[:o_id].to_i ).
where( :o_id => data[:o_id] ).
order('created_at ASC, id ASC') order('created_at ASC, id ASC')
return stores return stores
end end
@ -67,10 +66,9 @@ class Store < ActiveRecord::Base
stores.each do |store| stores.each do |store|
store.destroy store.destroy
end end
return 1 return true
end end
class Object < ActiveRecord::Base class Object < ActiveRecord::Base
validates :name, :presence => true validates :name, :presence => true
end end

View file

@ -3,7 +3,7 @@ class CreateStorage < ActiveRecord::Migration
create_table :stores do |t| create_table :stores do |t|
t.references :store_object, :null => false t.references :store_object, :null => false
t.references :store_file, :null => false t.references :store_file, :null => false
t.column :o_id, :integer, :null => false t.column :o_id, :integer, :limit => 8, :null => false
t.column :preferences, :string, :limit => 2500, :null => true t.column :preferences, :string, :limit => 2500, :null => true
t.column :size, :string, :limit => 50, :null => true t.column :size, :string, :limit => 50, :null => true
t.column :filename, :string, :limit => 250, :null => false t.column :filename, :string, :limit => 250, :null => false

View file

@ -1812,7 +1812,7 @@ Translation.create( :locale => 'de', :source => "The way to communicate with us
Translation.create( :locale => 'de', :source => "or", :target => "oder", :updated_by_id => 1, :created_by_id => 1 ) Translation.create( :locale => 'de', :source => "or", :target => "oder", :updated_by_id => 1, :created_by_id => 1 )
Translation.create( :locale => 'de', :source => "yes", :target => "ja", :updated_by_id => 1, :created_by_id => 1 ) Translation.create( :locale => 'de', :source => "yes", :target => "ja", :updated_by_id => 1, :created_by_id => 1 )
Translation.create( :locale => 'de', :source => "no", :target => "nein", :updated_by_id => 1, :created_by_id => 1 ) Translation.create( :locale => 'de', :source => "no", :target => "nein", :updated_by_id => 1, :created_by_id => 1 )
Translation.create( :locale => 'de', :source => "Attachment", :target => "Anhang", :updated_by_id => 1, :created_by_id => 1 ) Translation.create( :locale => 'de', :source => "Attachment", :target => "Anhang", :updated_by_id => 1, :created_by_id => 1 )
#Translation.create( :locale => 'de', :source => "", :target => "", :updated_by_id => 1, :created_by_id => 1 ) #Translation.create( :locale => 'de', :source => "", :target => "", :updated_by_id => 1, :created_by_id => 1 )