427 lines
18 KiB
Ruby
427 lines
18 KiB
Ruby
|
|
class ContactsController < ApplicationController
|
||
|
|
unloadable
|
||
|
|
|
||
|
|
Mime::Type.register "text/x-vcard", :vcf
|
||
|
|
|
||
|
|
default_search_scope :contacts
|
||
|
|
|
||
|
|
before_filter :find_contact, :only => [:show, :edit, :update, :destroy, :edit_tags]
|
||
|
|
before_filter :find_project, :only => [:new, :create]
|
||
|
|
before_filter :authorize, :only => [:show, :edit, :update, :create, :new, :destroy, :edit_tags]
|
||
|
|
before_filter :find_optional_project, :only => [:index, :contacts_notes]
|
||
|
|
|
||
|
|
accept_rss_auth :index, :show
|
||
|
|
accept_api_auth :index, :show, :create, :update, :destroy
|
||
|
|
|
||
|
|
helper :attachments
|
||
|
|
helper :contacts
|
||
|
|
helper :watchers
|
||
|
|
helper :deals
|
||
|
|
helper :notes
|
||
|
|
helper :custom_fields
|
||
|
|
include WatchersHelper
|
||
|
|
|
||
|
|
def show
|
||
|
|
@open_issues = @contact.issues.visible.open(:order => "#{Issue.table_name}.due_date DESC")
|
||
|
|
source_id_cond = @contact.is_company ? Contact.order_by_name.find_all_by_company(@contact.first_name).map(&:id) << @contact.id : @contact.id
|
||
|
|
@note = ContactNote.new
|
||
|
|
@notes_pages, @notes = paginate :notes,
|
||
|
|
:per_page => 30,
|
||
|
|
:conditions => {:source_id => source_id_cond,
|
||
|
|
:source_type => 'Contact'},
|
||
|
|
:include => [:attachments],
|
||
|
|
:order => "created_on DESC"
|
||
|
|
|
||
|
|
respond_to do |format|
|
||
|
|
format.js if request.xhr?
|
||
|
|
format.html { @contact.viewed }
|
||
|
|
format.api
|
||
|
|
format.atom { render_feed(@notes, :title => "#{@contact.name || Setting.app_title}: #{l(:label_note_plural)}") }
|
||
|
|
format.xml { render :xml => @contact }
|
||
|
|
format.json { render :text => @contact.to_json, :layout => false }
|
||
|
|
format.vcf { send_data(contact_to_vcard(@contact), :filename => "#{@contact.name}.vcf", :type => 'text/x-vcard;', :disposition => 'attachment') }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def index
|
||
|
|
find_contacts
|
||
|
|
respond_to do |format|
|
||
|
|
format.html do
|
||
|
|
last_notes
|
||
|
|
find_tags
|
||
|
|
end
|
||
|
|
format.js { render :partial => "list", :layout => false }
|
||
|
|
format.api
|
||
|
|
format.xml { render :xml => find_contacts(false) }
|
||
|
|
format.json { render :text => find_contacts(false).to_json, :layout => false }
|
||
|
|
format.atom { render_feed(find_contacts(false), :title => "#{@project || Setting.app_title}: #{l(:label_contact_plural)}") }
|
||
|
|
format.csv { send_data(contacts_to_csv(find_contacts(false)), :type => 'text/csv; header=present', :filename => 'contacts.csv') }
|
||
|
|
format.vcf { send_data(contacts_to_vcard(find_contacts(false)), :filename => "contacts.vcf", :type => 'text/x-vcard;', :disposition => 'attachment') }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def edit
|
||
|
|
end
|
||
|
|
|
||
|
|
def update
|
||
|
|
if @contact.update_attributes(params[:contact])
|
||
|
|
flash[:notice] = l(:notice_successful_update)
|
||
|
|
attach_avatar
|
||
|
|
respond_to do |format|
|
||
|
|
format.html { redirect_to :action => "show", :project_id => params[:project_id], :id => @contact }
|
||
|
|
format.api { head :ok }
|
||
|
|
end
|
||
|
|
else
|
||
|
|
respond_to do |format|
|
||
|
|
format.html { render "edit", :project_id => params[:project_id], :id => @contact }
|
||
|
|
format.api { render_validation_errors(@contact) }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def destroy
|
||
|
|
if @contact.destroy
|
||
|
|
flash[:notice] = l(:notice_successful_delete)
|
||
|
|
else
|
||
|
|
flash[:error] = l(:notice_unsuccessful_save)
|
||
|
|
end
|
||
|
|
redirect_to :action => "index", :project_id => params[:project_id]
|
||
|
|
end
|
||
|
|
|
||
|
|
def new
|
||
|
|
@duplicates = []
|
||
|
|
@contact = Contact.new
|
||
|
|
|
||
|
|
@contact.attributes = params[:contact] if params[:contact] && params[:contact].is_a?(Hash)
|
||
|
|
|
||
|
|
# @contact.company = params[:company_name] if params[:company_name]
|
||
|
|
# @contact.first_name = params[:first_name] if params[:first_name]
|
||
|
|
# @contact.last_name = params[:last_name] if params[:last_name]
|
||
|
|
# @contact.middle_name = params[:middle_name] if params[:middle_name]
|
||
|
|
# @contact.email = params[:email] if params[:email]
|
||
|
|
end
|
||
|
|
|
||
|
|
def create
|
||
|
|
params[:contact].delete(:project_id)
|
||
|
|
@contact = Contact.new(params[:contact])
|
||
|
|
@contact.projects << @project
|
||
|
|
@contact.author = User.current
|
||
|
|
if @contact.save
|
||
|
|
flash[:notice] = l(:notice_successful_create)
|
||
|
|
attach_avatar
|
||
|
|
respond_to do |format|
|
||
|
|
format.html { redirect_to :action => "show", :project_id => @project, :id => @contact }
|
||
|
|
format.api { render :action => 'show', :status => :created, :location => contact_url(@contact) }
|
||
|
|
end
|
||
|
|
else
|
||
|
|
respond_to do |format|
|
||
|
|
format.api { render_validation_errors(@contact) }
|
||
|
|
format.html { render :action => "new" }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
def edit_tags
|
||
|
|
@contact.tags.clear
|
||
|
|
@contact.update_attributes(params[:contact])
|
||
|
|
redirect_to :action => 'show', :id => @contact, :project_id => @project
|
||
|
|
end
|
||
|
|
|
||
|
|
def contacts_notes
|
||
|
|
unless request.xhr?
|
||
|
|
find_tags
|
||
|
|
end
|
||
|
|
# @notes = Comment.find(:all,
|
||
|
|
# :conditions => { :commented_type => "Contact", :commented_id => find_contacts.map(&:id)},
|
||
|
|
# :order => "updated_on DESC")
|
||
|
|
|
||
|
|
contacts = find_contacts(false)
|
||
|
|
deals = find_deals
|
||
|
|
|
||
|
|
joins = " "
|
||
|
|
joins << " LEFT OUTER JOIN #{Contact.table_name} ON #{Note.table_name}.source_id = #{Contact.table_name}.id AND #{Note.table_name}.source_type = 'Contact' "
|
||
|
|
joins << " LEFT OUTER JOIN #{Deal.table_name} ON #{Note.table_name}.source_id = #{Deal.table_name}.id AND #{Note.table_name}.source_type = 'Deal' "
|
||
|
|
|
||
|
|
cond = "(1 = 1) "
|
||
|
|
cond << "and (#{Contact.table_name}.id in (#{contacts.any? ? contacts.map(&:id).join(', ') : 'NULL'})"
|
||
|
|
cond << " or #{Deal.table_name}.id in (#{deals.any? ? deals.map(&:id).join(', ') : 'NULL'}))"
|
||
|
|
cond << " and (#{Note.table_name}.content LIKE '%#{params[:search_note]}%')" if params[:search_note] and request.xhr?
|
||
|
|
cond << " and (#{Note.table_name}.author_id = #{params[:note_author_id]})" if !params[:note_author_id].blank?
|
||
|
|
|
||
|
|
|
||
|
|
@notes_pages, @notes = paginate :notes,
|
||
|
|
:per_page => 20,
|
||
|
|
:joins => joins,
|
||
|
|
:conditions => cond,
|
||
|
|
:order => "created_on DESC"
|
||
|
|
@notes.compact!
|
||
|
|
|
||
|
|
|
||
|
|
respond_to do |format|
|
||
|
|
format.html { render :partial => "notes/notes_list", :layout => false, :locals => {:notes => @notes, :notes_pages => @notes_pages} if request.xhr?}
|
||
|
|
format.xml { render :xml => @notes }
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def context_menu
|
||
|
|
@project = Project.find(params[:project_id]) unless params[:project_id].blank?
|
||
|
|
@contacts = Contact.visible.all(:conditions => {:id => params[:selected_contacts]})
|
||
|
|
@contact = @contacts.first if (@contacts.size == 1)
|
||
|
|
@can = {:edit => (@contact && @contact.editable?) || (@contacts && @contacts.collect{|c| c.editable?}.inject{|memo,d| memo && d}),
|
||
|
|
:create_deal => (@project && User.current.allowed_to?(:edit_deals, @project)),
|
||
|
|
:delete => @contacts.collect{|c| c.deletable?}.inject{|memo,d| memo && d},
|
||
|
|
:send_mails => @contacts.collect{|c| c.send_mail_allowed? && !c.emails.first.blank?}.inject{|memo,d| memo && d}
|
||
|
|
}
|
||
|
|
|
||
|
|
# @back = back_url
|
||
|
|
render :layout => false
|
||
|
|
end
|
||
|
|
|
||
|
|
def bulk_destroy
|
||
|
|
@contacts = Contact.deletable.find_all_by_id(params[:ids])
|
||
|
|
raise ActiveRecord::RecordNotFound if @contacts.empty?
|
||
|
|
@contacts.each(&:destroy)
|
||
|
|
redirect_to :action => "index", :project_id => params[:project_id]
|
||
|
|
end
|
||
|
|
|
||
|
|
def bulk_edit
|
||
|
|
@contacts = Contact.editable.find_all_by_id(params[:ids])
|
||
|
|
@projects = @contacts.collect{|p| p.projects.compact}.compact.flatten.uniq
|
||
|
|
raise ActiveRecord::RecordNotFound if @contacts.empty?
|
||
|
|
@tag_list = ActsAsTaggableOn::TagList.from(@contacts.map(&:tag_list).inject{|memo,t| memo | t})
|
||
|
|
@project = @projects.first
|
||
|
|
@assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
|
||
|
|
@add_projects = Project.visible.has_module(:contacts_module).find(:all, :order => 'lft')
|
||
|
|
end
|
||
|
|
|
||
|
|
def bulk_update
|
||
|
|
@contacts = Contact.editable.find_all_by_id(params[:ids])
|
||
|
|
raise ActiveRecord::RecordNotFound if @contacts.empty?
|
||
|
|
unsaved_contact_ids = []
|
||
|
|
@contacts.each do |contact|
|
||
|
|
contact.reload
|
||
|
|
params[:contact][:tag_list] = (contact.tag_list + ActsAsTaggableOn::TagList.from(params[:add_tag_list]) - ActsAsTaggableOn::TagList.from(params[:delete_tag_list])).uniq
|
||
|
|
|
||
|
|
add_project_ids = (!params[:add_projects_list].to_s.blank? && params[:add_projects_list].is_a?(Array)) ? Project.find(:all, :conditions => {:id => params[:add_projects_list].collect{|p| p.to_i}}).map(&:id) : []
|
||
|
|
delete_project_ids = (!params[:delete_projects_list].to_s.blank? && params[:delete_projects_list].is_a?(Array)) ? Project.find(:all, :conditions => {:id => params[:delete_projects_list].collect{|p| p.to_i}}).map(&:id) : []
|
||
|
|
project_ids = contact.project_ids + add_project_ids - delete_project_ids
|
||
|
|
params[:contact][:project_ids] = project_ids if project_ids.any?
|
||
|
|
|
||
|
|
contact.tags.clear
|
||
|
|
unless contact.update_attributes(parse_params_for_bulk_contact_attributes(params))
|
||
|
|
# Keep unsaved issue ids to display them in flash error
|
||
|
|
unsaved_contact_ids << contact.id
|
||
|
|
end
|
||
|
|
if !params[:note][:content].blank?
|
||
|
|
note = ContactNote.new(params[:note])
|
||
|
|
note.author = User.current
|
||
|
|
contact.notes << note
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
set_flash_from_bulk_issue_save(@contacts, unsaved_contact_ids)
|
||
|
|
redirect_back_or_default({:controller => 'contacts', :action => 'index', :project_id => @project})
|
||
|
|
end
|
||
|
|
|
||
|
|
def edit_mails
|
||
|
|
@contacts = Contact.visible.find_all_by_id(params[:ids]).reject{|c| c.email.blank?}
|
||
|
|
raise ActiveRecord::RecordNotFound if @contacts.empty?
|
||
|
|
if !@contacts.collect{|c| c.send_mail_allowed?}.inject{|memo,d| memo && d}
|
||
|
|
deny_access
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def send_mails
|
||
|
|
contacts = Contact.visible.find_all_by_id(params[:ids])
|
||
|
|
raise ActiveRecord::RecordNotFound if contacts.empty?
|
||
|
|
if !contacts.collect{|c| c.send_mail_allowed?}.inject{|memo,d| memo && d}
|
||
|
|
deny_access
|
||
|
|
return
|
||
|
|
end
|
||
|
|
raise_delivery_errors = ActionMailer::Base.raise_delivery_errors
|
||
|
|
# Force ActionMailer to raise delivery errors so we can catch it
|
||
|
|
ActionMailer::Base.raise_delivery_errors = true
|
||
|
|
delivered_contacts = []
|
||
|
|
error_contacts = []
|
||
|
|
contacts.each do |contact|
|
||
|
|
begin
|
||
|
|
params[:message] = mail_macro(contact, params[:"message-content"])
|
||
|
|
|
||
|
|
ContactsMailer.deliver_bulk_mail(contact, params)
|
||
|
|
delivered_contacts << contact
|
||
|
|
|
||
|
|
note = ContactNote.new
|
||
|
|
note.subject = params[:subject]
|
||
|
|
note.content = params[:message]
|
||
|
|
note.author = User.current
|
||
|
|
note.type_id = Note.note_types[:email]
|
||
|
|
contact.notes << note
|
||
|
|
Attachment.attach_files(note, params[:attachments])
|
||
|
|
render_attachment_warning_if_needed(note)
|
||
|
|
|
||
|
|
rescue Exception => e
|
||
|
|
error_contacts << [contact, e.message]
|
||
|
|
end
|
||
|
|
flash[:notice] = l(:notice_email_sent, delivered_contacts.map{|c| "#{c.name} (#{c.emails.first})"}.join(', ')) if delivered_contacts.any?
|
||
|
|
flash[:error] = l(:notice_email_error, error_contacts.map{|e| "#{e[0].name}: #{e[1]}"}.join(', ')) if error_contacts.any?
|
||
|
|
end
|
||
|
|
|
||
|
|
ActionMailer::Base.raise_delivery_errors = raise_delivery_errors
|
||
|
|
redirect_back_or_default({:controller => 'contacts', :action => 'index', :project_id => params[:project_id]})
|
||
|
|
end
|
||
|
|
|
||
|
|
def preview_email
|
||
|
|
@text = mail_macro(Contact.visible.first(:conditions => {:id => params[:ids][0]}), params[:"message-content"])
|
||
|
|
render :partial => 'common/preview'
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
private
|
||
|
|
def attach_avatar
|
||
|
|
if params[:contact_avatar]
|
||
|
|
params[:contact_avatar][:description] = 'avatar'
|
||
|
|
@contact.avatar.destroy if @contact.avatar
|
||
|
|
Attachment.attach_files(@contact, {"1" => params[:contact_avatar]})
|
||
|
|
render_attachment_warning_if_needed(@contact)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def last_notes(count=5)
|
||
|
|
# @last_notes = find_contacts(false).find(:all, :include => :notes, :limit => count, :order => 'notes.created_on DESC').map{|c| c.notes}.flatten.first(count)
|
||
|
|
scope = ContactNote.scoped({})
|
||
|
|
scope = scope.scoped(:conditions => ["#{Project.table_name}.id = ?", @project.id]) if @project
|
||
|
|
|
||
|
|
@last_notes = scope.visible.find(:all,
|
||
|
|
:limit => count,
|
||
|
|
:order => "#{ContactNote.table_name}.created_on DESC")
|
||
|
|
# @last_notes = []
|
||
|
|
end
|
||
|
|
|
||
|
|
def find_contact
|
||
|
|
@contact = Contact.find(params[:id])
|
||
|
|
@project = (@contact.projects.visible.find(params[:project_id]) rescue false) if params[:project_id]
|
||
|
|
@project ||= @contact.project
|
||
|
|
# if !(params[:project_id] == @project.identifier)
|
||
|
|
# params[:project_id] = @project.identifier
|
||
|
|
# redirect_to params
|
||
|
|
# end
|
||
|
|
rescue ActiveRecord::RecordNotFound
|
||
|
|
render_404
|
||
|
|
end
|
||
|
|
|
||
|
|
def find_tags
|
||
|
|
scope = ActsAsTaggableOn::Tag.scoped({})
|
||
|
|
scope = scope.scoped(:conditions => ["#{Project.table_name}.id = ?", @project.id]) if @project
|
||
|
|
scope = scope.scoped(:conditions => [Contact.allowed_to_condition(User.current, :view_contacts)])
|
||
|
|
|
||
|
|
joins = []
|
||
|
|
joins << "JOIN #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id "
|
||
|
|
joins << "JOIN #{Contact.table_name} ON #{Contact.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{Contact.name}' "
|
||
|
|
joins << Contact.projects_joins
|
||
|
|
|
||
|
|
options = {}
|
||
|
|
options[:select] = "#{ActsAsTaggableOn::Tag.table_name}.*, COUNT(DISTINCT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id) AS count"
|
||
|
|
# options[:conditions] = cond.conditions
|
||
|
|
options[:joins] = joins.flatten
|
||
|
|
options[:group] = "#{ActsAsTaggableOn::Tag.table_name}.id, #{ActsAsTaggableOn::Tag.table_name}.name, #{ActsAsTaggableOn::Tag.table_name}.created_at, #{ActsAsTaggableOn::Tag.table_name}.updated_at, #{ActsAsTaggableOn::Tag.table_name}.color"
|
||
|
|
options[:order] = "#{ActsAsTaggableOn::Tag.table_name}.name"
|
||
|
|
|
||
|
|
@tags = scope.find(:all, options)
|
||
|
|
end
|
||
|
|
|
||
|
|
def find_deals
|
||
|
|
scope = Deal.scoped({})
|
||
|
|
scope = scope.scoped(:conditions => ["#{Deal.table_name}.project_id = ?", @project.id]) if @project
|
||
|
|
scope = scope.scoped(:conditions => ["#{Deal.table_name}.name LIKE ? ", "%" + params[:search] + "%"]) if params[:search]
|
||
|
|
scope = scope.scoped(:conditions => ["1=0"]) if params[:tag]
|
||
|
|
@deals = scope.visible.find(:all) || []
|
||
|
|
end
|
||
|
|
|
||
|
|
def find_contacts(pages=true)
|
||
|
|
@tag = ActsAsTaggableOn::TagList.from(params[:tag]).map{|tag| ActsAsTaggableOn::Tag.find_by_name(tag) } unless params[:tag].blank?
|
||
|
|
|
||
|
|
scope = Contact.scoped({})
|
||
|
|
scope = scope.scoped(:conditions => ["#{Contact.table_name}.job_title = ?", params[:job_title]]) unless params[:job_title].blank?
|
||
|
|
scope = scope.scoped(:conditions => ["#{Contact.table_name}.assigned_to_id = ?", params[:assigned_to_id]]) unless params[:assigned_to_id].blank?
|
||
|
|
scope = scope.scoped(:conditions => ["#{Contact.table_name}.is_company = ?", params[:query]]) unless (params[:query].blank? || params[:query] == '2' || params[:query] == '3')
|
||
|
|
scope = scope.scoped(:conditions => ["#{Contact.table_name}.author_id = ?", User.current]) if params[:query] == '3'
|
||
|
|
|
||
|
|
case params[:query]
|
||
|
|
when '2' then scope = scope.order_by_creation
|
||
|
|
when '3' then scope = scope.order_by_creation
|
||
|
|
else scope = scope.order_by_name
|
||
|
|
end
|
||
|
|
|
||
|
|
scope = scope.in_project(@project.id) if @project
|
||
|
|
params[:search].split(' ').collect{ |search_string| scope = scope.live_search(search_string) } if !params[:search].blank?
|
||
|
|
scope = scope.visible
|
||
|
|
|
||
|
|
scope = scope.tagged_with(params[:tag]) if !params[:tag].blank?
|
||
|
|
|
||
|
|
|
||
|
|
@contacts_count = scope.count
|
||
|
|
@contacts = scope
|
||
|
|
|
||
|
|
if pages
|
||
|
|
page_size = params[:page_size].blank? ? 20 : params[:page_size].to_i
|
||
|
|
@contacts_pages = Paginator.new(self, @contacts_count, page_size, params[:page])
|
||
|
|
@offset = @contacts_pages.current.offset
|
||
|
|
@limit = @contacts_pages.items_per_page
|
||
|
|
|
||
|
|
@contacts = @contacts.scoped :include => [:tags, :avatar], :limit => @limit, :offset => @offset
|
||
|
|
|
||
|
|
fake_name = @contacts.first.name if @contacts.length > 0
|
||
|
|
end
|
||
|
|
@contacts
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
# Filter for bulk issue operations
|
||
|
|
def bulk_find_contacts
|
||
|
|
@contacts = Deal.find_all_by_id(params[:id] || params[:ids], :include => :project)
|
||
|
|
raise ActiveRecord::RecordNotFound if @contact.empty?
|
||
|
|
if @contacts.detect {|contact| !contact.visible?}
|
||
|
|
deny_access
|
||
|
|
return
|
||
|
|
end
|
||
|
|
@projects = @contacts.collect(&:projects).compact.uniq
|
||
|
|
@project = @projects.first if @projects.size == 1
|
||
|
|
rescue ActiveRecord::RecordNotFound
|
||
|
|
render_404
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
def parse_params_for_bulk_contact_attributes(params)
|
||
|
|
attributes = (params[:contact] || {}).reject {|k,v| v.blank?}
|
||
|
|
attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
|
||
|
|
attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
|
||
|
|
attributes
|
||
|
|
end
|
||
|
|
|
||
|
|
def mail_macro(contact, message)
|
||
|
|
message = message.gsub(/%%NAME%%/, contact.first_name)
|
||
|
|
message = message.gsub(/%%FULL_NAME%%/, contact.name)
|
||
|
|
message = message.gsub(/%%COMPANY%%/, contact.company) if contact.company
|
||
|
|
message = message.gsub(/%%LAST_NAME%%/, contact.last_name) if contact.last_name
|
||
|
|
message = message.gsub(/%%MIDDLE_NAME%%/, contact.middle_name) if contact.middle_name
|
||
|
|
message = message.gsub(/%%DATE%%/, Date.today.to_s)
|
||
|
|
|
||
|
|
contact.custom_field_values.each do |value|
|
||
|
|
message = message.gsub(/%%#{value.custom_field.name}%%/, value.value.to_s)
|
||
|
|
end
|
||
|
|
message
|
||
|
|
end
|
||
|
|
|
||
|
|
def find_project
|
||
|
|
project_id = (params[:contact] && params[:contact][:project_id]) || params[:project_id]
|
||
|
|
@project = Project.find(project_id)
|
||
|
|
rescue ActiveRecord::RecordNotFound
|
||
|
|
render_404
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
end
|