diff --git a/app/assets/javascripts/app/controllers/_channel/form.js.coffee b/app/assets/javascripts/app/controllers/_channel/form.js.coffee new file mode 100644 index 000000000..ebc5442a3 --- /dev/null +++ b/app/assets/javascripts/app/controllers/_channel/form.js.coffee @@ -0,0 +1,15 @@ +class App.ChannelForm extends App.Controller + constructor: -> + super + @title 'Form' + @render() + + new App.SettingsArea( + el: @el.find('.js-settings') + area: 'Form::Base' + ) + + render: -> + @html App.view('channel/form')( + baseurl: window.location.origin + ) diff --git a/app/assets/javascripts/app/controllers/channel.js.coffee b/app/assets/javascripts/app/controllers/channel.js.coffee index 50de9697a..3171311aa 100644 --- a/app/assets/javascripts/app/controllers/channel.js.coffee +++ b/app/assets/javascripts/app/controllers/channel.js.coffee @@ -6,8 +6,9 @@ #App.Config.set( 'Channels', { prio: 2500, parent: '#admin', name: 'Channels', target: '#channels', role: ['Admin'] }, 'NavBar' ) App.Config.set( 'Web', { prio: 1000, name: 'Web', parent: '#channels', target: '#channels/web', controller: App.ChannelWeb, role: ['Admin'] }, 'NavBarAdmin' ) -App.Config.set( 'Email', { prio: 2000, name: 'Email', parent: '#channels', target: '#channels/email', controller: App.ChannelEmail, role: ['Admin'] }, 'NavBarAdmin' ) -App.Config.set( 'Chat', { prio: 3000, name: 'Chat', parent: '#channels', target: '#channels/chat', controller: App.ChannelChat, role: ['Admin'] }, 'NavBarAdmin' ) -App.Config.set( 'Twitter', { prio: 4000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: App.ChannelTwitter, role: ['Admin'] }, 'NavBarAdmin' ) -App.Config.set( 'Facebook', { prio: 5000, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: App.ChannelFacebook, role: ['Admin'] }, 'NavBarAdmin' ) +App.Config.set( 'Form', { prio: 2000, name: 'Form', parent: '#channels', target: '#channels/form', controller: App.ChannelForm, role: ['Admin'] }, 'NavBarAdmin' ) +App.Config.set( 'Email', { prio: 3000, name: 'Email', parent: '#channels', target: '#channels/email', controller: App.ChannelEmail, role: ['Admin'] }, 'NavBarAdmin' ) +App.Config.set( 'Chat', { prio: 4000, name: 'Chat', parent: '#channels', target: '#channels/chat', controller: App.ChannelChat, role: ['Admin'] }, 'NavBarAdmin' ) +App.Config.set( 'Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: App.ChannelTwitter, role: ['Admin'] }, 'NavBarAdmin' ) +App.Config.set( 'Facebook', { prio: 6000, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: App.ChannelFacebook, role: ['Admin'] }, 'NavBarAdmin' ) diff --git a/app/assets/javascripts/app/views/channel/form.jst.eco b/app/assets/javascripts/app/views/channel/form.jst.eco new file mode 100644 index 000000000..bd8ce9853 --- /dev/null +++ b/app/assets/javascripts/app/views/channel/form.jst.eco @@ -0,0 +1,42 @@ + +
+

<%- @T('With form you can add a formular to your web page witch directly generates a Ticket for you.') %>

+ +
+ +

<%- @T('Settings') %>

+ + + + + + + + + + + + + + + + + +
<%- @T('Option') %>
+ +

<%- @T('You need to add the following Java Script code snipped to your web page') %>: + +

+<script id="zammad_form_script" src="<%= @baseurl %>/assets/form/form.js"></script>
+<script>
+$('#feedback-form').zammad_form({
+  lang: 'de-de',
+  debug: true,
+  modal: false,
+});
+</script>
+
\ No newline at end of file diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb new file mode 100644 index 000000000..6adbc3358 --- /dev/null +++ b/app/controllers/form_controller.rb @@ -0,0 +1,99 @@ +# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ + +class FormController < ApplicationController + + def config + return if !enabled? + + api_path = Rails.configuration.api_path + http_type = Setting.get('http_type') + fqdn = Setting.get('fqdn') + + endpoint = "#{http_type}://#{fqdn}#{api_path}/form_submit" + + config = { + enabled: Setting.get('form_ticket_create'), + endpoint: endpoint, + } + + render json: config, status: :ok + end + + def submit + return if !enabled? + + # validate input + errors = {} + if !params[:name] || params[:name].empty? + errors['name'] = 'required' + end + if !params[:email] || params[:email].empty? + errors['email'] = 'required' + end + if params[:email] !~ /@/ + errors['email'] = 'invalid' + end + if !params[:body] || params[:body].empty? + errors['body'] = 'required' + end + + if errors && !errors.empty? + render json: { + errors: errors + }, status: :ok + return + end + + name = params[:name].strip + email = params[:email].strip.downcase + + customer = User.find_by(email: email) + if !customer + roles = Role.where( name: 'Customer' ) + customer = User.create( + firstname: name, + lastname: '', + email: email, + password: '', + active: true, + roles: roles, + updated_by_id: 1, + created_by_id: 1, + ) + end + + ticket = Ticket.create( + group_id: 1, + customer_id: customer.id, + title: '', + state_id: Ticket::State.find_by( name: 'new' ).id, + priority_id: Ticket::Priority.find_by( name: '2 normal' ).id, + updated_by_id: customer.id, + created_by_id: customer.id, + ) + + article = Ticket::Article.create( + ticket_id: ticket.id, + type_id: Ticket::Article::Type.find_by( name: 'web' ).id, + sender_id: Ticket::Article::Sender.find_by( name: 'Customer' ).id, + body: params[:body], + from: email, + subject: '', + internal: false, + updated_by_id: customer.id, + created_by_id: customer.id, + ) + + result = {} + render json: result, status: :ok + end + + private + + def enabled? + return true if Setting.get('form_ticket_create') + response_access_deny + false + end + +end diff --git a/config/routes/form.rb b/config/routes/form.rb new file mode 100644 index 000000000..70fac4fde --- /dev/null +++ b/config/routes/form.rb @@ -0,0 +1,8 @@ +Zammad::Application.routes.draw do + api_path = Rails.configuration.api_path + + # forms + match api_path + '/form_submit', to: 'form#submit', via: :post + match api_path + '/form_config', to: 'form#config', via: :get + +end diff --git a/db/migrate/20150810000001_update_form.rb b/db/migrate/20150810000001_update_form.rb new file mode 100644 index 000000000..3c69e6b52 --- /dev/null +++ b/db/migrate/20150810000001_update_form.rb @@ -0,0 +1,30 @@ +class UpdateForm < ActiveRecord::Migration + def up + + Setting.create_if_not_exists( + title: 'Enable Ticket creation', + name: 'form_ticket_create', + area: 'Form::Base', + description: 'Defines if ticket can get created via web form.', + options: { + form: [ + { + display: '', + null: true, + name: 'form_ticket_create', + tag: 'boolean', + options: { + true => 'yes', + false => 'no', + }, + }, + ], + }, + state: false, + frontend: false, + updated_by_id: 1, + created_by_id: 1, + ) + + end +end diff --git a/db/seeds.rb b/db/seeds.rb index a28b1e794..5f96d478e 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -992,6 +992,29 @@ Setting.create_if_not_exists( frontend: true ) +Setting.create_if_not_exists( + title: 'Enable Ticket creation', + name: 'form_ticket_create', + area: 'Form::Base', + description: 'Defines if ticket can get created via web form.', + options: { + form: [ + { + display: '', + null: true, + name: 'form_ticket_create', + tag: 'boolean', + options: { + true => 'yes', + false => 'no', + }, + }, + ], + }, + state: false, + frontend: false, +) + Setting.create_if_not_exists( title: 'Sender Format', name: 'ticket_define_email_from', diff --git a/public/assets/form/form.css b/public/assets/form/form.css new file mode 100644 index 000000000..c6ac53fe2 --- /dev/null +++ b/public/assets/form/form.css @@ -0,0 +1,19 @@ +.zammad-form { + width: 300px; +} + +.zammad-form .form-group { + margin-bottom: 15px; +} + +.zammad-form .form-control { + display: block; + width: 100%; +} + +.zammad-form .has-error .form-control { + border-color: #a94442; +} +.zammad-form .has-error label { + color: #a94442; +} \ No newline at end of file diff --git a/public/assets/form/form.html b/public/assets/form/form.html new file mode 100644 index 000000000..5a1a9ec04 --- /dev/null +++ b/public/assets/form/form.html @@ -0,0 +1,19 @@ + + + + Example Form + + + +
+ + + + + + + + + \ No newline at end of file diff --git a/public/assets/form/form.js b/public/assets/form/form.js new file mode 100644 index 000000000..182a9c313 --- /dev/null +++ b/public/assets/form/form.js @@ -0,0 +1,179 @@ +(function ($) { + +/* + provides feedback form for zammad +*/ + + var pluginName = 'zammad_form', + defaults = { + debug: false, + loadCss: true, + }; + + function Plugin( element, options ) { + this.element = element; + this.$element = $(element) + + this.options = $.extend( {}, defaults, options) ; + + this._defaults = defaults; + this._name = pluginName; + + this._endpoint_config = '/api/v1/form_config' + this._script_location = '/assets/form/form.js' + + this._config = {} + + this.attributes = [ + { + display: 'Name', + name: 'name', + tag: 'input', + type: 'text', + placeholder: 'Your Name', + }, + { + display: 'Email', + name: 'email', + tag: 'input', + type: 'email', + placeholder: 'Your Email', + }, + { + display: 'Message', + name: 'body', + tag: 'textarea', + placeholder: 'Your Message...', + }, + ] + + this.init(); + } + + + Plugin.prototype.init = function () { + var _this = this, + src = document.getElementById("zammad_form_script").src, + endpoint_config = src.replace(this._script_location, this._endpoint_config) + + _this.log('init') + + if (_this.options.loadCss) { + _this.loadCss('form.css') + } + + _this.log('endpoint_config: ' + endpoint_config) + + // load config + $.ajax({ + url: endpoint_config, + }).done(function(data) { + _this.log('config:', data) + _this._config = data + _this.render() + }).fail(function() { + alert('Faild to load form config!') + }); + + // bind form submit + this.$element.on('submit', function (e) { + e.preventDefault() + _this.submit() + return true + }) + } + + // load css + Plugin.prototype.loadCss = function(filename) { + if (document.createStyleSheet) { + document.createStyleSheet(filename) + } + else { + $('').appendTo('head') + } + } + + // send + Plugin.prototype.submit = function() { + var _this = this + + _this.log('submit form', _this.getParams()) + + $.ajax({ + method: 'post', + url: _this._config.endpoint, + data: _this.getParams(), + }).done(function(data) { + _this.log('ok done', _this._config.endpoint) + + // removed errors + _this.$element.find('.has-error').removeClass('has-error') + + // set errors + if (data.errors) { + $.each(data.errors, function( key, value ) { + _this.$element.find('[name=' + key + ']').closest('.form-group').addClass('has-error') + }) + return + } + + // ticket has been created + _this.thanks() + }).fail(function() { + alert('Faild to submit form!') + }); + } + + // get params + Plugin.prototype.getParams = function() { + var _this = this, + params = {} + + $.each( _this.$element.find('form').serializeArray(), function( index, item ) { + params[item.name] = item.value + }) + return params + } + + // render form + Plugin.prototype.render = function(e) { + var form = $('
') + $.each(this.attributes, function( index, value ) { + var item = $('
') + if (value.tag == 'input') { + item.append('') + } + else if (value.tag == 'textarea') { + item.append('') + } + form.append(item) + }) + form.append('