Files
2026-04-24 22:01:18 +00:00

207 lines
7.9 KiB
Ruby

class HelpdeskWidgetController < ApplicationController
unloadable
layout false
helper :custom_fields
protect_from_forgery :except => [:widget, :load_form, :load_custom_fields, :avatar, :create_ticket, :iframe]
skip_before_filter :check_if_login_required, :only => [:widget, :load_form, :load_custom_fields, :avatar, :create_ticket, :iframe]
before_filter :prepare_data, :only => [:load_custom_fields, :create_ticket]
after_filter :set_access_control_header
def load_form
render :json => schema.to_json
end
def load_custom_fields
@issue = @project.issues.build(:tracker => @tracker) if @tracker
@enabled_cf = HelpdeskSettings["helpdesk_widget_available_custom_fields", nil]
end
def avatar
user = User.where(:login => params[:login]).first
return render :nothing => true, :status => 404 unless user
if user.try(:avatar).nil?
avatar_thumb, avatar_type = gravatar_avatar(user) if Setting.gravatar_enabled?
else
avatar_thumb, avatar_type = local_avatar(user.avatar)
end
return render :nothing => true, :status => 404 unless avatar_thumb
send_avatar(avatar_thumb, avatar_type)
end
def send_avatar(avatar_thumb, avatar_type)
send_file avatar_thumb, :filename => (request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(params[:login]) : params[:login]),
:type => avatar_type,
:disposition => 'inline'
end
def gravatar_avatar(user)
email = user.mail if user.respond_to?(:mail)
email = user.to_s[/<(.+?)>/, 1] unless email
return [nil, nil] unless email
default = Setting.gravatar_default ? CGI::escape(Setting.gravatar_default) : ''
temp_file = Tempfile.new([user.login, '.jpeg'])
temp_file.binmode
open("http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}?rating=PG&size=54&default=#{default}") do |url_file|
temp_file.write(url_file.read)
end
temp_file.rewind
[temp_file, 'image/jpeg']
end
def local_avatar(user_avatar)
return nil unless user_avatar.readable? || user_avatar.thumbnailable?
if (defined?(RedmineContacts::Thumbnail) == 'constant') && Redmine::Thumbnail.convert_available?
target = File.join(user_avatar.class.thumbnails_storage_path, "#{user_avatar.id}_#{user_avatar.digest}_54x54.thumb")
thumbnail = RedmineContacts::Thumbnail.generate(user_avatar.diskfile, target, '54x54')
elsif Redmine::Thumbnail.convert_available?
thumbnail = user_avatar.thumbnail(:size => '54x54')
else
thumbnail = user_avatar.diskfile
end
[thumbnail, detect_content_type(user_avatar)]
end
def create_ticket
@issue = prepare_issue
@issue.helpdesk_ticket = prepare_helpdesk_ticket
result =
if valid_email? && @issue.save
save_attachment(@issue)
HelpdeskMailer.auto_answer(@issue.helpdesk_ticket.customer, @issue).deliver if HelpdeskSettings["helpdesk_send_notification", @project].to_i > 0
{ :result => true, :errors => [] }
else
{ :result => false, :errors => prepared_errors }
end
render :json => result
end
private
def prepare_data
@project = Project.find(params[:project_id])
@tracker = @project.trackers.where(:id => params[:tracker_id]).first
end
def schema
if HelpdeskSettings["helpdesk_widget_enable", nil].to_i > 0
projects = Project.has_module('contacts_helpdesk').where(:id => HelpdeskSettings[:helpdesk_widget_available_projects, nil])
else
projects = []
end
data_schema = {}
data_schema[:projects] = Hash[projects.map { |project| [project.name.capitalize, project.id] }]
data_schema[:projects_data] = {}
projects.each do |project|
data_schema[:projects_data][project.id] = {}
if HelpdeskSettings["helpdesk_tracker", project] && HelpdeskSettings["helpdesk_tracker", project] != 'all'
data_schema[:projects_data][project.id][:trackers] = Hash[Tracker.where(id: HelpdeskSettings["helpdesk_tracker", project])
.map { |tracker| [tracker.name, tracker.id] }]
else
data_schema[:projects_data][project.id][:trackers] = Hash[project.trackers.map { |tracker| [tracker.name, tracker.id] }]
end
end
data_schema[:custom_fields] = Hash[IssueCustomField.where(id: HelpdeskSettings["helpdesk_widget_available_custom_fields", nil])
.map { |custom_field| [custom_field.name, custom_field.id] }]
data_schema[:avatar] = HelpdeskSettings[:helpdesk_widget_avatar_login, nil]
data_schema
end
def prepared_errors
errors_hash = @issue.errors.dup
# Username
if errors_hash[:'helpdesk_ticket.customer.first_name'].present?
@issue.errors.delete(:'helpdesk_ticket.customer.first_name')
@issue.errors[:username] = errors_hash[:'helpdesk_ticket.customer.first_name'].collect { |error| ['Username', error].join(' ') }
end
# Subject
if errors_hash[:subject].present?
errors = errors_hash[:subject].collect { |error| ['Subject', error].join(' ') }
@issue.errors[:subject].clear
@issue.errors[:subject] = errors
end
# Description
if params[:issue][:description].empty?
@issue.errors[:description] = I18n.t(:label_helpdesk_widget_ticket_error_description)
end
# Nested objects
if errors_hash[:'helpdesk_ticket.customer.projects'].present?
@issue.errors.delete(:'helpdesk_ticket.customer.projects')
end
@issue.errors
end
def prepare_issue
redmine_user = User.where(id: params[:redmine_user]).first
author = redmine_user.present? && redmine_user.allowed_to?(:edit_helpdesk_tickets, @project) ? redmine_user : User.anonymous
issue = @project.issues.build(:tracker => @tracker, :author => author)
issue.safe_attributes = params[:issue].deep_dup
issue.assigned_to = widget_contact.find_assigned_user(@project, HelpdeskSettings["helpdesk_assigned_to", @project])
issue
end
def prepare_helpdesk_ticket
HelpdeskTicket.new(:from_address => params[:email],
:ticket_date => Time.now,
:customer => widget_contact,
:issue => @issue,
:source => HelpdeskTicket::HELPDESK_WEB_SOURCE)
end
def save_attachment(issue)
return unless params[:attachment].present?
attachment_hash = split_base64(params[:attachment])
attachment = Attachment.new(file: Base64.decode64(attachment_hash[:data]))
attachment.filename = params[:attachment_name] || [Redmine::Utils.random_hex(16), attachment_hash[:extension]].join('.')
attachment.content_type = attachment_hash[:type]
attachment.author = User.anonymous
issue.attachments << attachment
issue.save
end
def split_base64(uri)
matcher = uri.match(/^data:(.*?)\;(.*?),(.*)$/)
{ type: matcher[1],
encoder: matcher[2],
data: matcher[3],
extension: matcher[1].split('/')[1] }
end
def widget_contact
return @widget_contact if @widget_contact
contacts = Contact.find_by_emails([params[:email]])
return @widget_contact = contacts.first if contacts.any?
@widget_contact = Contact.new(:email => params[:email])
@widget_contact.first_name, @widget_contact.last_name = params[:username].split(' ')
@widget_contact.projects << @project
@widget_contact
end
def set_access_control_header
headers['Access-Control-Allow-Origin'] = '*'
headers['X-Frame-Options'] = '*'
end
def valid_email?
if params[:email].empty?
@issue.errors[:email] = 'Email cannot be empty'
return false
elsif params[:email].match(/\A([\w\.\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i).nil?
@issue.errors[:email] = 'Email is incorrect'
return false
end
true
end
def detect_content_type(attachment)
content_type = attachment.content_type
if content_type.blank?
content_type = Redmine::MimeType.of(attachment.filename)
end
content_type.to_s
end
end