Initial Redmine tooling and local plugin forks

This commit is contained in:
Jason Thistlethwaite
2026-04-24 22:01:18 +00:00
commit 9f682af0eb
683 changed files with 56878 additions and 0 deletions
@@ -0,0 +1,21 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require File.dirname(__FILE__) + '/lib/acts_as_priceable'
ActiveRecord::Base.send(:include, RedmineContacts::Acts::Priceable)
@@ -0,0 +1,66 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Acts
module Priceable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_priceable(*args)
priceable_options = args
priceable_options << :price if priceable_options.empty?
priceable_methods = ""
priceable_options.each do |priceable_attr|
priceable_methods << %(
def #{priceable_attr.to_s}_to_s
object_price(
self,
:#{priceable_attr},
{
:decimal_mark => ContactsSetting.decimal_separator,
:thousands_separator => ContactsSetting.thousands_delimiter
}
) if self.respond_to?(:#{priceable_attr})
end
)
end
class_eval <<-EOV
include RedmineCrm::MoneyHelper
include RedmineContacts::Acts::Priceable::InstanceMethods
#{priceable_methods}
EOV
end
end
module InstanceMethods
def self.included(base)
base.extend ClassMethods
end
end
end
end
end
@@ -0,0 +1,59 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require 'acts-as-taggable-on'
module ActsAsTaggableOn::Taggable
module Core
module InstanceMethods
def process_dirty_object(context, new_list)
value = new_list.is_a?(Array) ? ActsAsTaggableOn::TagList.new(new_list) : new_list
attrib = "#{context.to_s.singularize}_list"
if changed_attributes.include?(attrib)
old = changed_attributes[attrib]
@changed_attributes.delete(attrib) if old.to_s == value.to_s
else
old = tag_list_on(context)
if self.class.preserve_tag_order
@changed_attributes[attrib] = old if old.to_s != value.to_s
else
@changed_attributes[attrib] = old.to_s if old.sort != ActsAsTaggableOn::TagList.new(value.split(',')).sort
end
end
end
def attributes_for_update(attribute_names)
filter_tag_lists(super)
end
def attributes_for_create(attribute_names)
filter_tag_lists(super)
end
def filter_tag_lists(attributes)
tag_lists = tag_types.map {|tags_type| "#{tags_type.to_s.singularize}_list"}
attributes.delete_if {|attr| tag_lists.include? attr }
end
end
end
end
@@ -0,0 +1,30 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "lib/acts_as_viewable"
$LOAD_PATH.shift
# Rails.configuration.to_prepare do
# unless ActiveRecord::Base.included_modules.include?(ActsAsViewable::Viewable)
ActiveRecord::Base.send(:include, ActsAsViewable::Viewable)
# end
# end
@@ -0,0 +1,59 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module ActsAsViewable
module Viewable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_viewable(options = {})
cattr_accessor :viewable_options
self.viewable_options = {}
viewable_options[:info] = options.delete(:info) || "info".to_sym
if ActiveRecord::VERSION::MAJOR >= 4
has_many :views, lambda { order("#{RecentlyViewed.table_name}.updated_at DESC") }, :class_name => "RecentlyViewed", :as => :viewed, :dependent => :delete_all
else
has_many :views, :order => "#{RecentlyViewed.table_name}.updated_at DESC", :class_name => "RecentlyViewed", :as => :viewed, :dependent => :delete_all
end
# attr_reader :info
send :include, ActsAsViewable::Viewable::InstanceMethods
end
end
module InstanceMethods
def self.included(base)
base.extend ClassMethods
end
def viewed(user = User.current)
rv = (self.views.where(:viewer_id => User.current.id).first || self.views.new(:viewer => user))
rv.increment(:views_count)
rv.save!
end
module ClassMethods
end
end
end
end
@@ -0,0 +1,60 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module Redmine
module FieldFormat
class CompanyFormat < RecordList
add 'company'
self.customized_class_names = nil
self.multiple_supported = false
def label
"label_crm_company"
end
def target_class
@target_class ||= Contact
end
def edit_tag(view, tag_id, tag_name, custom_value, options={})
contact = Contact.where(:id => custom_value.value).first unless custom_value.value.blank?
view.select_contact_tag(tag_name, contact, options.merge(:id => tag_id,
:is_company => true,
:add_contact => true,
:include_blank => !custom_value.custom_field.is_required))
end
def cast_single_value(custom_field, value, customized = nil)
Contact.where(:id => value).first unless value.blank?
end
def query_filter_options(custom_field, query)
super.merge({:field_format => 'company'})
end
def possible_values_options(custom_field, object = nil)
[]
end
end
end
end
Redmine::FieldFormat.add 'company', Redmine::FieldFormat::CompanyFormat
@@ -0,0 +1,121 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module CSVImportable
class << self; attr_accessor :klass end
def persisted?
false
end
def initialize(attributes = {})
attributes.each{|name, value| send("#{name}=", value)}
end
def save
if imported_instances.any? && imported_instances.map(&:valid?).all? && imported_instances.map{|c| c.new_record? ? true : (c.respond_to?('editable?') ? c.editable? : true)}.all?
begin
klass.transaction do
imported_instances.each(&:save!)
end
rescue
Rails.logger.info $!.message
Rails.logger.info $!.backtrace.join("\n")
return false
end
true
else
imported_instances.each_with_index do |instance, index|
if !instance.new_record? && !instance.editable?
errors.add :base, "Row #{index + 2}: Permission restricted for changing #{klass.name}"
else
instance.errors.full_messages.each do |message|
errors.add :base, "Row #{index + 2}: #{message}"
end
end
end
false
end
end
def imported_instances
@imported_instances ||= load_imported_instances
end
protected
def force_utf8(v)
if v.respond_to? :force_encoding then v.force_encoding('utf-8') else v end
end
private
def build_custom_fields
custom_fields_attributes = {}
klass.new.custom_field_values.each do |custom_field_value|
custom_fields_attributes[custom_field_value.custom_field.id.to_s] = custom_field_value.custom_field.cast_value(row[custom_field_value.custom_field.name]).to_s
end
custom_fields_attributes
end
def load_imported_instances
instance_rows = open_import_source
klass.transaction do
begin
line_counter = 0
instance_rows.map do |row|
line_counter += 1
instance = klass.find_by_id(row['#']) || klass.new
instance.attributes = build_from_fcsv_row(row)
if instance.respond_to?(:custom_field_values)
instance.custom_field_values.each do |custom_field_value|
custom_field_value.value = custom_field_value.custom_field.cast_value(row[custom_field_value.custom_field.name.underscore]).to_s
end
end
instance.project = project if instance.respond_to?(:project=)
puts instance.errors.full_messages unless instance.valid?
instance
end
rescue
Rails.logger.info $!.message
Rails.logger.info $!.backtrace.join("\n")
errors.add :base, I18n.t(:text_crm_error_on_line, :line => line_counter, :error => $!.message)
[]
end
end
end
def open_import_source
begin
content = file.read
FCSV.parse(content, :headers => true, :header_converters => [:downcase], :encoding => 'utf-8', :col_sep => guess_separator(force_utf8(content)), :quote_char => quotes_type)
rescue Exception => e
Rails.logger.info $!.message
Rails.logger.info $!.backtrace.join("\n")
errors.add :base, e.message
[]
end
end
def guess_separator(content)
first_line = content.split("\n").first
commas = first_line.count(",")
semicolons = first_line.count(";")
commas > semicolons ? ',' : ';'
end
end
@@ -0,0 +1,94 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require 'redmine_contacts/patches/action_controller_patch'
require 'redmine_contacts/patches/compatibility/application_helper_patch'
require 'redmine_contacts/helpers/contacts_helper'
require 'redmine_contacts/helpers/crm_calendar_helper'
# Plugins
require 'acts_as_viewable/init'
require 'acts_as_priceable/init'
require 'company_custom_field_format' if Redmine::VERSION.to_s > '2.5'
require 'redmine_contacts/utils/thumbnail'
require 'redmine_contacts/utils/check_mail'
require 'redmine_contacts/utils/date_utils'
require 'redmine_contacts/utils/csv_utils'
require 'redmine_contacts/contacts_project_setting'
# Patches
require 'redmine_contacts/patches/compatibility/active_record_base_patch'
require 'redmine_contacts/patches/compatibility/active_record_sanitization_patch.rb'
require 'redmine_contacts/patches/compatibility/user_patch.rb'
require 'redmine_contacts/patches/compatibility_patch'
require 'redmine_contacts/patches/issue_patch'
require 'redmine_contacts/patches/project_patch'
require 'redmine_contacts/patches/mailer_patch'
require 'redmine_contacts/patches/notifiable_patch'
require 'redmine_contacts/patches/application_controller_patch'
require 'redmine_contacts/patches/attachments_controller_patch'
require 'redmine_contacts/patches/auto_completes_controller_patch'
require 'redmine_contacts/patches/issue_query_patch'
require 'redmine_contacts/patches/time_entry_query_patch'
require 'redmine_contacts/patches/query_patch'
if Redmine::VERSION.to_s >= '3.4' || Redmine::VERSION::BRANCH != 'stable'
require 'redmine_contacts/patches/query_filter_patch'
require 'redmine_contacts/patches/issues_helper_patch'
end
require 'redmine_contacts/patches/users_controller_patch'
require 'redmine_contacts/patches/issues_controller_patch'
require 'redmine_contacts/patches/custom_fields_helper_patch'
require 'redmine_contacts/patches/time_report_patch'
require 'redmine_contacts/patches/queries_helper_patch'
require 'redmine_contacts/patches/timelog_helper_patch'
require 'redmine_contacts/patches/projects_helper_patch'
require 'redmine_contacts/wiki_macros/contacts_wiki_macros'
# Hooks
require 'redmine_contacts/hooks/views_projects_hook'
require 'redmine_contacts/hooks/views_issues_hook'
require 'redmine_contacts/hooks/views_layouts_hook'
require 'redmine_contacts/hooks/views_users_hook'
require 'redmine_contacts/hooks/views_custom_fields_hook'
require 'redmine_contacts/hooks/controllers_time_entry_reports_hook'
require 'redmine_contacts/liquid/liquid' if Object.const_defined?("Liquid") rescue false
module RedmineContacts
def self.companies_select
RedmineContacts.settings["select_companies_to_deal"]
end
def self.settings() Setting[:plugin_redmine_contacts].blank? ? {} : Setting[:plugin_redmine_contacts] end
def self.default_list_style
return (%w(list list_excerpt list_cards) && [RedmineContacts.settings["default_list_style"]]).first || "list_excerpt"
return 'list_excerpt'
end
def self.products_plugin_installed?
@@products_plugin_installed ||= (Redmine::Plugin.installed?(:redmine_products) && Redmine::Plugin.find(:redmine_products).version >= '2.0.2')
end
def self.unstable_branch?
Redmine::VERSION::BRANCH != 'stable'
end
end
@@ -0,0 +1,48 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class ContactsProjectSetting
unloadable
def initialize(project, plugin_name)
@project = project
@plugin_settings_name = plugin_name
Setting["plugin_" + @plugin_settings_name]
end
def method_missing(method_name, *args, &block)
return super if /^(.*=)$/ =~ method_name.to_s
setting_name = method_name.to_s.gsub(/\?|=/, '')
setting_value = if ContactsSetting[@plugin_settings_name + '_' + setting_name, @project].blank?
if ContactsSetting.respond_to?(method_name)
ContactsSetting.send(method_name)
else
Setting["plugin_" + @plugin_settings_name][setting_name]
end
else
ContactsSetting[@plugin_settings_name + '_' + setting_name, @project]
end
if /.*\?$/ =~ method_name.to_s
setting_value.to_i > 0
else
setting_value
end
end
end
@@ -0,0 +1,333 @@
# encoding: utf-8
#
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Helper
def contact_tag_url(tag_name, options = {})
{ :controller => 'contacts',
:action => 'index',
:set_filter => 1,
:project_id => @project,
:fields => [:tags],
:values => { :tags => [tag_name] },
:operators => { :tags => '=' } }.merge(options)
end
def skype_to(skype_name, _name = nil)
return link_to skype_name, 'skype:' + skype_name + '?call' unless skype_name.blank?
end
def tag_link(tag_name, options = {})
style = ContactsSetting.monochrome_tags? ? { :class => 'tag-label' } : { :class => 'tag-label-color', :style => "background-color: #{tag_color(tag_name)}" }
tag_count = options.delete(:count)
link = link_to tag_name, contact_tag_url(tag_name), options
link += content_tag(:span, "(#{tag_count})", :class => 'tag-count') if tag_count
content_tag(:span, link, {}.merge(style))
end
def tag_color(tag_name)
"##{'%06x' % (tag_name.unpack('H*').first.hex % 0xffffff)}"
# "##{"%06x" % (Digest::MD5.hexdigest(tag_name).hex % 0xffffff)}"
# "##{"%06x" % (tag_name.hash % 0xffffff).to_s}"
end
def tag_links(tag_list, options = {})
content_tag(:span, safe_join(tag_list.map { |tag| tag_link(tag, options) }, ContactsSetting.monochrome_tags? ? ', ' : ' ').html_safe,
:class => "tag_list#{' icon icon-tag' if ContactsSetting.monochrome_tags?}") if tag_list
end
def contacts_for_select(project, options = {})
scope = Contact.where(options[:where])
scope = scope.limit(options[:limit] || 500)
scope = scope.companies if options.delete(:is_company)
scope = scope.joins(:projects)
scope = Rails.version >= '5.1' ? scope.distinct : scope.uniq
scope = scope.where(Contact.visible_condition(User.current))
scope = scope.by_project(project) if project
scope.to_a.sort! { |x, y| x.name <=> y.name }.collect { |m| [options[:short_label] ? m.name : m.name_with_company, m.id.to_s] }
end
def link_to_remote_list_update(text, url_params)
link_to_remote(text, { :url => url_params, :method => :get, :update => 'contact_list', :complete => 'window.scrollTo(0,0)' },
{ :href => url_for(:params => url_params) }
)
end
def contacts_check_box_tags(name, contacts)
s = ''
contacts.each do |contact|
s << "<label>#{ check_box_tag name, contact.id, false, :id => nil } #{contact_tag(contact, :no_link => true)}#{' (' + contact.company + ')' unless contact.company.blank? || contact.is_company? }</label>\n"
end
s.html_safe
end
def note_source_url(note_source, options = {})
polymorphic_path(note_source, options.merge(:project_id => @project))
# return {:controller => note_source.class.name.pluralize.downcase, :action => 'show', :project_id => @project, :id => note_source.id }
end
def link_to_source(note_source, options = {})
link_to note_source.name, note_source_url(note_source, options)
end
def countries_options_for_select(selected = nil)
default_country = l(:label_crm_countries)[ContactsSetting.default_country.to_s.upcase.to_sym] if ContactsSetting.default_country
countries = countries_for_select
countries = [[default_country, ContactsSetting.default_country.to_s.upcase], ['---', '']] | countries if default_country
options_for_select(countries, :disabled => '', :selected => selected)
end
def countries_for_select
l(:label_crm_countries).map { |k, v| [v, k.to_s] }.sort
end
def select_contact_tag(name, contact, options={})
cross_project_contacts = ContactsSetting.cross_project_contacts? || !!options.delete(:cross_project_contacts)
field_id = sanitize_to_id(name)
include_blank = !!options[:include_blank]
is_company = !!options[:is_company]
add_contact = !!options[:add_contact]
s = ''
s << select_tag(name, options_for_select([[contact.try(:name_with_company), contact.try(:id)]], contact.try(:id)), :include_blank => true)
s << javascript_tag("$('##{field_id}').select2({
ajax: {
url: '#{auto_complete_contacts_path(:project_id => (cross_project_contacts ? nil : @project), :is_company => (options[:is_company] ? '1' : nil))}',
dataType: 'json',
delay: 250,
data: function (params) {
return { q: params.term };
},
processResults: function (data, params) {
return { results: data };
},
cache: true
},
placeholder: ' ',
allowClear: #{include_blank},
minimumInputLength: 0,
width: '60%',
templateResult: formatState
}).on('select2:open', function (e) {
$('.select2-search__field').val(' ').trigger($.Event('input', { which: 13 })).val('');
});
function formatState (opt) {
var $opt = $('<span>' + opt.avatar + '&nbsp;' + opt.text + '</span>');
return $opt;
};")
if add_contact
s << link_to(image_tag('add.png', :style => 'vertical-align: middle; margin-left: 5px;'),
new_project_contact_path(@project, :contact_field_name => name, :contacts_is_company => is_company),
:remote => true,
:method => 'get',
:title => l(:label_crm_contact_new),
:id => "#{field_id}_add_link",
:tabindex => 200) if authorize_for('contacts', 'new')
s << javascript_include_tag('attachments')
end
s.html_safe
end
# TODO: Need to add tests for this method (avatar_to).
def avatar_to(obj, options = {})
# "https://avt.appsmail.ru/mail/sin23matvey/_avatar"
options[:size] ||= '64'
if ActiveRecord::VERSION::MAJOR >= 4
unless options[:size].to_s.include?('x')
options[:size] = "#{options[:size]}x#{options[:size]}"
end
else
options[:width] ||= options[:size]
options[:height] ||= options[:size]
end
options[:class] = 'gravatar'
obj_icon = obj.is_a?(Contact) ? (obj.is_company ? 'company.png' : 'person.png') : (obj.is_a?(Deal) ? 'deal.png' : 'unknown.png')
return image_tag(obj_icon, options.merge(:plugin => 'redmine_contacts')) if ENV['NO_AVATAR']
if obj.is_a?(Deal)
if obj.contact
avatar_to(obj.contact, options)
else
image_tag(obj_icon, options.merge(:plugin => 'redmine_contacts'))
end
elsif obj.is_a?(Contact) && (avatar = obj.avatar) && avatar.readable?
avatar_url = url_for :controller => 'attachments', :action => 'contacts_thumbnail', :id => avatar, :size => options[:size]
if options[:full_size]
link_to(image_tag(avatar_url, options), :controller => 'attachments', :action => 'show', :id => avatar, :filename => avatar.filename)
else
image_tag(avatar_url, options)
end
elsif obj.respond_to?(:facebook) && !obj.facebook.blank?
image_tag("https://graph.facebook.com/#{obj.facebook.gsub('.*facebook.com\/', '')}/picture?type=square#{'&return_ssl_resources=1' if (request && request.ssl?)}", options)
elsif Setting.gravatar_enabled? && obj.is_a?(Contact) && obj.primary_email
# options.merge!({:ssl => (request && request.ssl?), :default => "#{request.protocol}#{request.host_with_port}/plugin_assets/redmine_contacts/images/#{obj_icon}"})
# gravatar(obj.primary_email.downcase, options) rescue image_tag(obj_icon, options.merge({:plugin => "redmine_contacts"}))
avatar("<#{obj.primary_email}>", options)
else
image_tag(obj_icon, options.merge(:plugin => 'redmine_contacts'))
end
end
def contact_tag(contact, options={})
avatar_size = options.delete(:size) || 16
if contact.visible? && !options[:no_link]
contact_avatar = link_to(avatar_to(contact, :size => avatar_size), contact_path(contact, :project_id => @project), :id => "avatar")
contact_name = link_to_source(contact, :project_id => @project)
else
contact_avatar = avatar_to(contact, :size => avatar_size)
contact_name = contact.name
end
case options.delete(:type).to_s
when 'avatar'
contact_avatar.html_safe
when 'plain'
contact_name.html_safe
else
content_tag(:span, "#{contact_avatar} #{contact_name}".html_safe, :class => 'contact')
end
end
def render_contact_tooltip(contact, options = {})
@cached_label_crm_company ||= l(:field_contact_company)
@cached_label_job_title = contact.is_company ? l(:field_company_field) : l(:field_contact_job_title)
@cached_label_phone ||= l(:field_contact_phone)
@cached_label_email ||= l(:field_contact_email)
emails = contact.emails.any? ? contact.emails.map { |email| "<span class=\"email\" style=\"white-space: nowrap;\">#{mail_to email}</span>" }.join(', ') : ''
phones = contact.phones.any? ? contact.phones.map { |phone| "<span class=\"phone\" style=\"white-space: nowrap;\">#{phone}</span>" }.join(', ') : ''
s = link_to_contact(contact, options) + '<br /><br />'.html_safe
s << "<strong>#{@cached_label_job_title}</strong>: #{contact.job_title}<br />".html_safe unless contact.job_title.blank?
s << "<strong>#{@cached_label_crm_company}</strong>: #{link_to(contact.contact_company.name, { :controller => 'contacts', :action => 'show', :id => contact.contact_company.id })}<br />".html_safe if !contact.contact_company.blank? && !contact.is_company
s << "<strong>#{@cached_label_email}</strong>: #{emails}<br />".html_safe if contact.emails.any?
s << "<strong>#{@cached_label_phone}</strong>: #{phones}<br />".html_safe if contact.phones.any?
s
end
def link_to_contact(contact, options = {})
s = ''
html_options = {}
html_options = { :class => 'icon icon-vcard' } if options[:icon] == true
s << avatar_to(contact, :size => '16') if options[:avatar] == true
s << link_to_source(contact, html_options)
s << "(#{contact.job_title}) " if (options[:job_title] == true) && !contact.job_title.blank?
s << " #{l(:label_crm_at_company)} " if (options[:job_title] == true) && !(contact.job_title.blank? || contact.company.blank?)
if (options[:company] == true) && contact.contact_company
s << link_to(contact.contact_company.name, { :controller => 'contacts', :action => 'show', :id => contact.contact_company.id })
else
h contact.company
end
s << "(#{l(:field_contact_tag_names)}: #{contact.tag_list.join(', ')}) " if (options[:tag_list] == true) && !contact.tag_list.blank?
s.html_safe
end
def tagsedit_with_source_for(field_id, url)
s = ''
unless @heads_for_tagsedit_included
s << javascript_include_tag(:"tag-it", :plugin => 'redmine_contacts')
s << stylesheet_link_tag(:"jquery.tagit.css", :plugin => 'redmine_contacts')
@heads_for_tagsedit_included = true
end
s << javascript_tag("$('#{field_id}').tagit({
tagSource: function(search, showChoices) {
var that = this;
$.ajax({
url: '#{url}',
data: {q: search.term},
success: function(choices) {
showChoices(that._subtractArray(jQuery.parseJSON(choices), that.assignedTags()));
}
});
},
allowSpaces: true,
placeholderText: '#{l(:label_crm_add_tag)}',
caseSensitive: false,
removeConfirmation: true
});")
s.html_safe
end
def tagsedit_for(field_id, available_tags='')
s = ''
unless @heads_for_tagsedit_included
s << javascript_include_tag(:"tag-it", :plugin => 'redmine_contacts')
s << stylesheet_link_tag(:"jquery.tagit.css", :plugin => 'redmine_contacts')
@heads_for_tagsedit_included = true
end
s << javascript_tag("$('#{field_id}').tagit({
availableTags: ['#{available_tags}'],
allowSpaces: true,
placeholderText: '#{l(:label_crm_add_tag)}',
caseSensitive: false,
removeConfirmation: true
});")
s.html_safe
end
def note_type_icon(note)
note_type_tag = ''
case note.type_id
when 0
note_type_tag = content_tag('span', '', :class => 'icon icon-email', :title => l(:label_crm_note_type_email))
when 1
note_type_tag = content_tag('span', '', :class => 'icon icon-call', :title => l(:label_crm_note_type_call))
when 2
note_type_tag = content_tag('span', '', :class => 'icon icon-meeting', :title => l(:label_crm_note_type_meeting))
end
context = { :type_tag => note_type_tag, :type_id => note.type_id }
call_hook(:helper_notes_note_type_tag, context)
context[:type_tag].html_safe
end
def deal_tag(deal, options = {})
return deal.name unless deal.visible?
deal_name = options[:no_contact] ? deal.name : deal.full_name
s = ''
s << avatar_to(deal, :size => options.delete(:size) || 16) unless options[:plain]
s << ' ' + link_to(deal_name, deal_path(deal))
s << " (#{deal.price_to_s}) " unless deal.price.blank? || options[:no_price]
s << (options[:plain] ? deal.status.name : deal_status_tag(deal.status)) if deal.status
s.html_safe
end
def deal_status_tag(deal_status)
status_tag = content_tag(:span, deal_status.name)
content_tag(:span, status_tag, :class => 'tag-label-color', :style => "background-color:#{deal_status.color_name};color:white;")
end
def deals_for_select(project, options = {})
scope = Deal.visible.where(options[:where]).limit(options[:limit] || 500)
scope = scope.by_project(project) if project
scope.order("#{Deal.table_name}.name")
.collect { |m| [m.name + (options[:short_label] || m.info.blank? ? '' : " - #{m.info}"), m.id.to_s] }
end
end
end
ActionView::Base.send :include, RedmineContacts::Helper
@@ -0,0 +1,91 @@
# encoding: utf-8
#
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Helpers
class CrmCalendar
include Redmine::I18n
attr_reader :startdt, :enddt
def initialize(date, options = {})
@date = date
@events = []
@ending_events_by_days = {}
@starting_events_by_days = {}
@start_date_field = options[:start_date_field] || "start_date"
@due_date_field = options[:due_date_field] || "due_date"
set_language_if_valid options[:language] || current_language
period = options[:period] || :month
case period
when :month
@startdt = Date.civil(date.year, date.month, 1)
@enddt = (@startdt >> 1)-1
# starts from the first day of the week
@startdt = @startdt - (@startdt.cwday - first_wday)%7
# ends on the last day of the week
@enddt = @enddt + (last_wday - @enddt.cwday)%7
when :week
@startdt = date - (date.cwday - first_wday)%7
@enddt = date + (last_wday - date.cwday)%7
else
raise 'Invalid period'
end
end
# Sets calendar events
def events=(events)
@events = events
@ending_events_by_days = @events.group_by {|event| event.send(@start_date_field).to_date if event.send(@start_date_field)}
@starting_events_by_days = @events.group_by {|event| event.send(@due_date_field).to_date if event.send(@due_date_field)}
end
# Returns events for the given day
def events_on(day)
((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq
end
# Calendar current month
def month
@date.month
end
# Return the first day of week
# 1 = Monday ... 7 = Sunday
def first_wday
case Setting.start_of_week.to_i
when 1
@first_dow ||= (1 - 1)%7 + 1
when 6
@first_dow ||= (6 - 1)%7 + 1
when 7
@first_dow ||= (7 - 1)%7 + 1
else
@first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1
end
end
def last_wday
@last_dow ||= (first_wday + 5)%7 + 1
end
end
end
end
@@ -0,0 +1,91 @@
# encoding: utf-8
#
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module MoneyHelper
def object_price(obj, price_field = :price)
price_to_currency(obj.try(price_field), obj.currency, :symbol => true).to_s if obj.respond_to?(:currency)
end
def prices_collection_by_currency(prices_collection, options={})
return [] if prices_collection.blank? || prices_collection == 0
prices = prices_collection
prices.reject!{|k, v| v.to_i == 0} if options[:hide_zeros]
prices.collect{|k, v| content_tag(:span, price_to_currency(v, k, :symbol => true), :style => "white-space: nowrap;")}.compact
end
def deal_currency_icon(currency)
case currency.to_s.upcase
when 'EUR'
"icon-money-euro"
when 'GBP'
"icon-money-pound"
when 'JPY'
"icon-money-yen"
else
"icon-money-dollar"
end
end
def collection_for_currencies_select(default_currency = ContactsSetting.default_currency)
major_currencies_collection(default_currency)
end
def major_currencies_collection(default_currency)
currencies = []
currencies << default_currency.to_s unless default_currency.blank?
currencies |= ContactsSetting.major_currencies
currencies.map do |c|
currency = RedmineCrm::Currency.find(c)
["#{currency.iso_code} (#{currency.symbol})", currency.iso_code] if currency
end.compact.uniq
end
def all_currencies
RedmineCrm::Currency.table.inject([]) do |array, (id, attributes)|
array ||= []
array << ["#{attributes[:name]}" + (attributes[:symbol].blank? ? "" : " (#{attributes[:symbol]})"), attributes[:iso_code]]
array
end.sort{|x, y| x[0] <=> y[0]}
end
def price_to_currency(price, currency, options={})
return '' if price.blank?
options[:decimal_mark] = ContactsSetting.decimal_separator unless options[:decimal_mark]
options[:thousands_separator] = ContactsSetting.thousands_delimiter unless options[:thousands_separator]
# RedmineCrm::Currency.from_float(price.to_f, currency).format(options) rescue ActionController::Base.helpers.number_with_delimiter(price.to_f, :separator => ContactsSetting.decimal_separator, :delimiter => ContactsSetting.thousands_delimiter, :precision => 2)
if currency
if currency.is_a? String
currency = RedmineCrm::Currency.find(currency)
end
else
currency = RedmineCrm::Currency.find("USD")
end
ActionController::Base.helpers.number_to_currency(price.to_f, :unit => currency.code)
end
end
end
unless ActionView::Base.included_modules.include?(RedmineContacts::MoneyHelper)
ActionView::Base.send(:include, RedmineContacts::MoneyHelper)
end
@@ -0,0 +1,34 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Hooks
class ControllersTimeEntryReportsHook < Redmine::Hook::ViewListener
def controller_timelog_available_criterias(context = {})
context[:available_criterias]['contacts'] = { :sql => 'contacts_issues.contact_id',
:klass => Contact,
:label => :label_crm_contact }
end
def controller_timelog_time_report_joins(context = {})
context[:sql] << " LEFT JOIN contacts_issues ON contacts_issues.issue_id = #{Issue.table_name}.id"
end
end
end
end
@@ -0,0 +1,27 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Hooks
class ViewsCustomFieldsHook < Redmine::Hook::ViewListener
render_on :view_custom_fields_form_deal_custom_field, :partial => "deals/custom_field_form"
render_on :view_custom_fields_form_contact_custom_field, :partial => "contacts/custom_field_form"
end
end
end
@@ -0,0 +1,28 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Hooks
class ViewsIssuesHook < Redmine::Hook::ViewListener
render_on :view_issues_sidebar_planning_bottom, :partial => "contacts_issues/contacts", :locals => {:contact_issue => @issue}
render_on :view_issues_form_details_bottom, :partial => 'deals_issues/form'
render_on :view_issues_show_details_bottom, :partial => 'deals_issues/show'
end
end
end
@@ -0,0 +1,27 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Hooks
class ViewsLayoutsHook < Redmine::Hook::ViewListener
render_on :view_layouts_base_body_bottom, :partial => 'common/contacts_select2_data'
render_on :view_layouts_base_html_head, :partial => 'contacts_issues/additional_assets'
end
end
end
@@ -0,0 +1,26 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Hooks
class ViewsUsersHook < Redmine::Hook::ViewListener
render_on :view_projects_show_left, :partial => "projects/contacts"
end
end
end
@@ -0,0 +1,28 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
# include ContactsHelper
module RedmineContacts
module Hooks
class ViewsUsersHook < Redmine::Hook::ViewListener
render_on :view_account_left_bottom, :partial => "users/contact", :locals => {:user => @user}
end
end
end
@@ -0,0 +1,64 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class AddressesDrop < Liquid::Drop
def initialize(addresses)
@addresses = addresses
end
def before_method(id)
address = @addresses.where(:id => id).first || Address.new
AddressDrop.new address
end
def all
@all ||= @addresses.map do |address|
AddressDrop.new address
end
end
def visible
@visible ||= @addresses.visible.map do |address|
AddressDrop.new address
end
end
def each(&block)
all.each(&block)
end
end
class AddressDrop < Liquid::Drop
delegate :id, :address_type, :street1, :street2, :city, :region, :postcode, :country_code, :country, :full_address, :post_address, :to => :@address
def initialize(address)
@address = address
end
private
def helpers
Rails.application.routes.url_helpers
end
end
@@ -0,0 +1,91 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class ContactsDrop < Liquid::Drop
def initialize(contacts)
@contacts = contacts
end
def before_method(id)
contact = @contacts.where(:id => id).first || Contact.new
ContactDrop.new contact
end
def all
@all ||= @contacts.map do |contact|
ContactDrop.new contact
end
end
def visible
@visible ||= @contacts.visible.map do |contact|
ContactDrop.new contact
end
end
def each(&block)
all.each(&block)
end
end
class ContactDrop < Liquid::Drop
delegate :id, :name, :first_name, :last_name, :middle_name, :company, :phones, :emails, :primary_email, :website, :skype_name, :birthday, :age, :background, :job_title, :is_company, :tag_list, :post_address, :to => :@contact
def initialize(contact)
@contact = contact
end
def contact_company
ContactDrop.new @contact.contact_company if @contact.contact_company
end
def company_contacts
@contact.company_contacts.map{|c| ContactDrop.new c } if @contact.company_contacts
end
def avatar_diskfile
@contact.avatar.diskfile
end
def avatar_url
helpers.url_for :controller => "attachments", :action => "contacts_thumbnail", :id => @contact.avatar, :size => '64', :only_path => true
end
def notes
@contact.notes.map{|n| NoteDrop.new(n) }
end
def address
AddressDrop.new(@contact.address) if @contact.address
end
def custom_field_values
@contact.custom_field_values
end
private
def helpers
Rails.application.routes.url_helpers
end
end
@@ -0,0 +1,77 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class DealsDrop < Liquid::Drop
def initialize(deals)
@deals = deals
end
def before_method(id)
deal = @deals.where(:id => id).first || Deal.new
DealDrop.new deal
end
def all
@all ||= @deals.map do |deal|
DealDrop.new deal
end
end
def visible
@visible ||= @deals.visible.map do |deal|
DealDrop.new deal
end
end
def each(&block)
all.each(&block)
end
end
class DealDrop < Liquid::Drop
delegate :id, :name, :created_on, :due_date, :price, :price_type, :currency, :background, :probability, :to => :@deal
def initialize(deal)
@deal = deal
end
def notes
@deal.notes.map{|n| NoteDrop.new(n) }
end
def category
@deal.category.name if @deal.category
end
def contact
ContactDrop.new @deal.contact if @deal.contact
end
def status
@deal.status.name if @deal.status
end
def custom_field_values
@deal.custom_field_values
end
end
@@ -0,0 +1,61 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class NotesDrop < Liquid::Drop
def initialize(notes)
@notes = notes
end
def before_method(id)
note = @notes.where(:id => id).first || Note.new
NoteDrop.new note
end
def all
@all ||= @notes.map do |note|
NoteDrop.new note
end
end
def visible
@visible ||= @notes.visible.map do |note|
NoteDrop.new note
end
end
def each(&block)
all.each(&block)
end
end
class NoteDrop < Liquid::Drop
delegate :id, :subject, :content, :type_id, :to => :@note
def initialize(note)
@note = note
end
def custom_field_values
@note.custom_field_values
end
end
@@ -0,0 +1,97 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require "redmine_contacts/liquid/drops/contacts_drop"
require "redmine_contacts/liquid/drops/deals_drop"
require "redmine_contacts/liquid/drops/notes_drop"
require "redmine_contacts/liquid/drops/addresses_drop"
module RedmineContacts
module Liquid
module Filters
include RedmineCrm::MoneyHelper
def underscore(input)
input.to_s.gsub(' ', '_').gsub('/', '_').underscore
end
def dasherize(input)
input.to_s.gsub(' ', '-').gsub('/', '-').dasherize
end
def encode(input)
Rack::Utils.escape(input)
end
# alias newline_to_br
def multi_line(input)
input.to_s.gsub("\n", '<br/>').html_safe
end
def concat(input, *args)
result = input.to_s
args.flatten.each { |a| result << a.to_s }
result
end
# right justify and padd a string
def rjust(input, integer, padstr = '')
input.to_s.rjust(integer, padstr)
end
# left justify and padd a string
def ljust(input, integer, padstr = '')
input.to_s.ljust(integer, padstr)
end
def textile(input)
::RedCloth3.new(input).to_html
end
def currency(input, currency_code=nil)
price_to_currency(input, currency_code || container_currency, :converted => false)
end
def custom_field(input, field_name)
if input.respond_to?(:custom_field_values)
input.custom_field_values.detect{|cfv| cfv.custom_field.name == field_name}.try(:value)
end
end
def attachment(input, file_name)
if input.respond_to?(:attachments)
input.attachments.detect{|a| a.file_name == file_name}.try(:diskfile)
end
end
private
def container
@container ||= @context.registers[:container]
end
def container_currency
container.currency if container.respond_to?(:currency)
end
end
::Liquid::Template.register_filter(RedmineContacts::Liquid::Filters)
end
end
@@ -0,0 +1,51 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ActionControllerPatch
def self.included(base)
base.extend(ClassMethods) if Rails::VERSION::MAJOR < 4
base.class_eval do
end
end
module ClassMethods
if Rails::VERSION::MAJOR < 4
def before_action(*filters, &block)
before_filter(*filters, &block)
end
def after_action(*filters, &block)
after_filter(*filters, &block)
end
def skip_before_action(*filters)
skip_before_filter(*filters)
end
end
end
end
end
end
unless ActionController::Base.included_modules.include?(RedmineContacts::Patches::ActionControllerPatch)
ActionController::Base.send(:include, RedmineContacts::Patches::ActionControllerPatch)
end
@@ -0,0 +1,44 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ApplicationControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :user_setup_without_contacts, :user_setup
alias_method :user_setup, :user_setup_with_contacts
end
end
module InstanceMethods
def user_setup_with_contacts
user_setup_without_contacts
ContactsSetting.check_cache
end
end
end
end
end
unless ApplicationController.included_modules.include?(RedmineContacts::Patches::ApplicationControllerPatch)
ApplicationController.send(:include, RedmineContacts::Patches::ApplicationControllerPatch)
end
@@ -0,0 +1,104 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'attachments_controller'
require_dependency 'attachment'
module RedmineContacts
module Patches
module AttachmentsControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
end
module InstanceMethods
def contacts_thumbnail
find_attachment
size = params[:size].to_i
size = 64 unless size > 0
if @attachment.readable? && @attachment.thumbnailable?
if Redmine::Thumbnail.convert_available?
target = File.join(@attachment.class.thumbnails_storage_path, "#{@attachment.id}_#{@attachment.digest}_#{size}.thumb")
thumbnail = RedmineContacts::Thumbnail.generate(@attachment.diskfile, target, size)
else
thumbnail = @attachment.diskfile
end
if stale?(:etag => @attachment.digest)
send_file thumbnail, :filename => (request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(@attachment.filename) : @attachment.filename),
:type => detect_content_type(@attachment),
:disposition => 'inline'
end
else
# No thumbnail for the attachment or thumbnail could not be created
render :nothing => true, :status => 404
end
rescue => e
logger.error "An error occured while generating contact thumbnail for #{@attachment.disk_filename} to #{target}\nException was: #{e.message}" if logger
return nil
end
private
def find_attachment
@attachment = Attachment.find(params[:id])
# Show 404 if the filename in the url is wrong
raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
@project = @attachment.project
rescue ActiveRecord::RecordNotFound
render_404
end
end
end
module AttachmentPatch
module InstanceMethods
def is_contacts_thumbnailable?
(self.is_pdf? && self.filesize < 600.kilobytes) || self.image?
end
def is_pdf?
self.filename =~ /\.(pdf)$/i
end
end
def self.included(base) # :nodoc:
base.send :include, InstanceMethods
end
end
end
end
unless Attachment.included_modules.include?(RedmineContacts::Patches::AttachmentPatch)
Attachment.send(:include, RedmineContacts::Patches::AttachmentPatch)
end
unless AttachmentsController.included_modules.include?(RedmineContacts::Patches::AttachmentsControllerPatch)
AttachmentsController.send(:include, RedmineContacts::Patches::AttachmentsControllerPatch)
end
@@ -0,0 +1,95 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'auto_completes_controller'
module RedmineContacts
module Patches
module AutoCompletesControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
end
end
module InstanceMethods
def deals
@deals = []
q = (params[:q] || params[:term]).to_s.strip
scope = Deal.joins(:project).where({})
scope = scope.limit(params[:limit] || 10)
scope = scope.by_project(@project) if @project
if q.match(/\A#?(\d+)\z/)
@deals << scope.visible.find_by_id($1.to_i)
end
scope = scope.live_search_with_contact(q) unless q.blank?
@deals += scope.visible.order("#{Deal.table_name}.name")
@deals.uniq! { |deal| deal.id }
render :layout => false, :partial => 'deals'
end
def contact_tags
@name = params[:q].to_s
@tags = Contact.available_tags :name_like => @name, :limit => 10
render :layout => false, :partial => 'crm_tag_list'
end
def taggable_tags
klass = Object.const_get(params[:taggable_type].camelcase)
@name = params[:q].to_s
@tags = klass.all_tag_counts(:conditions => ["#{RedmineCrm::Tag.table_name}.name LIKE ?", "%#{@name}%"], :limit => 10)
render :layout => false, :partial => 'crm_tag_list'
end
def contacts
@contacts = []
q = (params[:q] || params[:term]).to_s.strip
scope = Contact.includes(:avatar).where({})
scope = scope.limit(params[:limit] || 10)
scope = scope.companies if params[:is_company]
scope = scope.joins(:projects).where(Contact.visible_condition(User.current))
scope = Rails.version >= '5.1' ? scope.distinct : scope.uniq
q.split(' ').collect { |search_string| scope = scope.live_search(search_string) } unless q.blank?
scope = scope.by_project(@project) if @project
@contacts = scope.to_a.sort! { |x, y| x.name <=> y.name }
render :layout => false, :partial => 'contacts'
end
def companies
@companies = []
q = (params[:q] || params[:term]).to_s.strip
if q.present?
scope = Contact.joins(:projects).where({})
scope = scope.limit(params[:limit] || 10)
scope = scope.includes(:avatar)
scope = scope.by_project(@project) if @project
scope = scope.where('LOWER(first_name) LIKE LOWER(?)', "#{q}%") unless q.blank?
@companies = scope.visible.companies.order("#{Contact.table_name}.first_name")
end
render :layout => false, :partial => 'companies'
end
end
end
end
end
unless AutoCompletesController.included_modules.include?(RedmineContacts::Patches::AutoCompletesControllerPatch)
AutoCompletesController.send(:include, RedmineContacts::Patches::AutoCompletesControllerPatch)
end
@@ -0,0 +1,62 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module QueryPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
class << self
VISIBILITY_PRIVATE = 0
VISIBILITY_ROLES = 1
VISIBILITY_PUBLIC = 2
end
end
end
end
module InstanceMethods
VISIBILITY_PRIVATE = 0
VISIBILITY_ROLES = 1
VISIBILITY_PUBLIC = 2
def is_private?
visibility == VISIBILITY_PRIVATE
end
def is_public?
!is_private?
end
def visibility=(value)
self.is_public = value == VISIBILITY_PUBLIC
end
def visibility
self.is_public ? VISIBILITY_PUBLIC : VISIBILITY_PRIVATE
end
end
end
end
unless Query.included_modules.include?(RedmineContacts::Patches::QueryPatch)
Query.send(:include, RedmineContacts::Patches::QueryPatch)
end
@@ -0,0 +1,84 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ActiveRecordBasePatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :has_many_without_contacts, :has_many
alias_method :has_many, :has_many_with_contacts
end
end
module InstanceMethods
def has_many_with_contacts(name, param2 = nil, *param3, &extension)
return has_many_without_contacts(name, param2, *param3, &extension) if param3 && param3.is_a?(Array) && param3[0] && param3[0][:through]
if param2.nil?
options = {}
else
if param2.is_a?(Proc)
scope = param2
options = param3.empty? ? {} : param3[0]
else
options = param2
end
end
if ActiveRecord::VERSION::MAJOR >= 4
scope, options = build_scope_and_options(options) if scope.nil?
has_many_without_contacts(name, scope, options, &extension)
else
has_many_without_contacts(name, options, &extension)
end
end
def build_scope_and_options(options)
scope_opts, opts = parse_options(options)
unless scope_opts.empty?
scope = lambda do
scope_opts.inject(self) { |result, hash| result.send *hash }
end
end
[defined?(scope) ? scope : nil, opts]
end
def parse_options(opts)
scope_opts = {}
[:order, :having, :select, :group, :limit, :offset, :readonly].each do |o|
scope_opts[o] = opts.delete o if opts[o]
end
scope_opts[:where] = opts.delete :conditions if opts[:conditions]
scope_opts[:joins] = opts.delete :include if opts [:include]
scope_opts[:distinct] = opts.delete :uniq if opts[:uniq]
[scope_opts, opts]
end
end
end
end
end
if defined?(ActiveRecord::Base)
ActiveRecord::Base.extend RedmineContacts::Patches::ActiveRecordBasePatch::InstanceMethods
unless ActiveRecord::Associations::ClassMethods.included_modules.include?(RedmineContacts::Patches::ActiveRecordBasePatch)
ActiveRecord::Associations::ClassMethods.send(:include, RedmineContacts::Patches::ActiveRecordBasePatch)
end
end
@@ -0,0 +1,36 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ActiveRecordSanitizationPatch
def self.included(base)
base.class_eval do
def quote_value(value, column = nil)
connection.quote(value, column)
end
end
end
end
end
end
unless ActiveRecord::Sanitization::ClassMethods.included_modules.include?(RedmineContacts::Patches::ActiveRecordSanitizationPatch)
ActiveRecord::Sanitization::ClassMethods.send(:include, RedmineContacts::Patches::ActiveRecordSanitizationPatch)
end
@@ -0,0 +1,38 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ApplicationHelperPatch
def self.included(base) # :nodoc:
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
def stocked_reorder_link(object, name = nil, url = {}, method = :post)
Redmine::VERSION.to_s > '3.3' ? reorder_handle(object, :param => name) : reorder_links(name, url, method)
end
end
end
end
end
end
unless ApplicationHelper.included_modules.include?(RedmineContacts::Patches::ApplicationHelperPatch)
ApplicationHelper.send(:include, RedmineContacts::Patches::ApplicationHelperPatch)
end
@@ -0,0 +1,50 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module UserPatch
def self.included(base)
base.class_eval do
scope :having_mail, lambda {|arg|
addresses = Array.wrap(arg).map {|a| a.to_s.downcase}
if addresses.any?
joins(:email_addresses).where("LOWER(#{EmailAddress.table_name}.address) IN (?)", addresses).uniq
else
none
end
}
def self.find_by_mail(mail)
if ActiveRecord::VERSION::MAJOR >= 4
mail.is_a?(Array) ? mail : [mail]
having_mail(mail).first
else
where("LOWER(mail) = ?", mail.to_s.downcase).first
end
end
end
end
end
end
end
unless User.included_modules.include?(RedmineContacts::Patches::UserPatch)
User.send(:include, RedmineContacts::Patches::UserPatch)
end
@@ -0,0 +1,26 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
if Redmine::VERSION.to_s < '2.4'
Dir[File.dirname(__FILE__) + '/compatibility/2.3/*.rb'].each { |f| require f }
end
if ActiveRecord::VERSION::MAJOR > 3
Dir[File.dirname(__FILE__) + '/compatibility/rails/*.rb'].each { |f| require f }
end
@@ -0,0 +1,59 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'custom_fields_helper'
module RedmineContacts
module Patches
module CustomFieldsHelperPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
if Rails.version < '5.1'
alias_method_chain :custom_fields_tabs, :contacts_tab
else
alias_method :custom_fields_tabs_without_contacts, :custom_fields_tabs
alias_method :custom_fields_tabs, :custom_fields_tabs_with_contacts
end
end
end
module InstanceMethods
def custom_fields_tabs_with_contacts_tab
new_tabs = []
new_tabs << { :name => 'ContactCustomField', :partial => 'custom_fields/index', :label => :label_contact_plural }
new_tabs << { :name => 'DealCustomField', :partial => 'custom_fields/index', :label => :label_deal_plural }
new_tabs << { :name => 'NoteCustomField', :partial => 'custom_fields/index', :label => :label_crm_note_plural }
custom_fields_tabs_without_contacts_tab | new_tabs
end
end
end
end
end
if Redmine::VERSION.to_s > '2.5'
CustomFieldsHelper::CUSTOM_FIELDS_TABS << { :name => 'ContactCustomField', :partial => 'custom_fields/index', :label => :label_contact_plural }
CustomFieldsHelper::CUSTOM_FIELDS_TABS << { :name => 'DealCustomField', :partial => 'custom_fields/index', :label => :label_deal_plural }
CustomFieldsHelper::CUSTOM_FIELDS_TABS << { :name => 'NoteCustomField', :partial => 'custom_fields/index', :label => :label_crm_note_plural }
else
unless CustomFieldsHelper.included_modules.include?(RedmineContacts::Patches::CustomFieldsHelperPatch)
CustomFieldsHelper.send(:include, RedmineContacts::Patches::CustomFieldsHelperPatch)
end
end
@@ -0,0 +1,54 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'issue'
require_dependency 'contact'
module RedmineContacts
module Patches
module IssuePatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
has_and_belongs_to_many :contacts, :uniq => true
has_one :deals_issue
has_one :deal, :through => :deals_issue
accepts_nested_attributes_for :deals_issue, :reject_if => :reject_deal, :allow_destroy => true
safe_attributes 'deals_issue_attributes',
:if => lambda { |issue, user| user.allowed_to?(:edit_deals, issue.project) }
end
end
module InstanceMethods
def reject_deal(attributes)
exists = attributes['id'].present?
empty = attributes[:deal_id].blank?
attributes[:_destroy] = 1 if exists && empty
!exists && empty
end
end
end
end
end
unless Issue.included_modules.include?(RedmineContacts::Patches::IssuePatch)
Issue.send(:include, RedmineContacts::Patches::IssuePatch)
end
@@ -0,0 +1,138 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'query'
module RedmineContacts
module Patches
module IssueQueryPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.send(:include, RedmineContacts::Helper)
base.class_eval do
unloadable
alias_method :available_columns_without_contacts, :available_columns
alias_method :available_columns, :available_columns_with_contacts
alias_method :initialize_available_filters_without_contacts, :initialize_available_filters
alias_method :initialize_available_filters, :initialize_available_filters_with_contacts
end
end
module InstanceMethods
def sql_for_contacts_field(_field, operator, value)
case operator
when '=', '*'
compare = 'IN'
when '!', '!*'
compare = 'NOT IN'
end
contacts_select = "SELECT contacts_issues.issue_id FROM contacts_issues
WHERE contacts_issues.contact_id IN (#{value.join(',')})"
issues_with_contacts = 'SELECT DISTINCT(issue_id) FROM contacts_issues'
"(#{Issue.table_name}.id #{compare} (#{ %w(= !).include?(operator) ? contacts_select : issues_with_contacts }))"
end
def sql_for_companies_field(_field, operator, value)
compare = operator == '=' ? 'IN' : 'NOT IN'
employes_select = "SELECT contacts_issues.issue_id FROM contacts_issues
WHERE contacts_issues.contact_id IN
( SELECT c_1.id from #{Contact.table_name}
LEFT OUTER JOIN #{Contact.table_name} AS c_1 ON c_1.company = #{Contact.table_name}.first_name
WHERE #{Contact.table_name}.id IN (#{value.join(',')})
)"
companies_select = "SELECT contacts_issues.issue_id FROM contacts_issues
WHERE contacts_issues.contact_id IN (#{value.join(',')})"
"((#{Issue.table_name}.id #{compare} (#{employes_select}))
OR (#{Issue.table_name}.id #{compare} (#{companies_select})))"
end
def sql_for_deal_field(_field, operator, value)
if operator == '!*'
compare = 'NOT IN'
operator = '*'
else
compare = 'IN'
end
deals_select = "SELECT deals_issues.issue_id FROM deals_issues
WHERE #{sql_for_field('deal_id', operator, value, 'deals_issues', 'deal_id')}"
"(#{Issue.table_name}.id #{compare} (#{deals_select}))"
end
def available_columns_with_contacts
if @available_columns.blank?
@available_columns = available_columns_without_contacts
@available_columns << QueryColumn.new(:deal, :caption => :label_deal) if User.current.allowed_to?(:view_deals, project, :global => true)
@available_columns << QueryColumn.new(:contacts) if User.current.allowed_to?(:view_contacts, project, :global => true)
else
available_columns_without_contacts
end
@available_columns
end
def initialize_available_filters_with_contacts
initialize_available_filters_without_contacts
if !available_filters.key?('contacts') && User.current.allowed_to?(:view_contacts, project, :global => true)
selected_contacts = filters['contacts'].blank? ? [] : Contact.visible.where(:id => filters['contacts'][:values]).map { |c| [c.name, c.id.to_s] }
add_available_filter('contacts', :type => :list_optional, :field_format => 'contact', :name => l(:field_contacts), :values => selected_contacts)
end
if !available_filters.key?('companies') && User.current.allowed_to?(:view_contacts, project, :global => true)
selected_companies = filters['companies'].blank? ? [] : Contact.visible.where(:id => filters['companies'][:values]).map { |c| [c.name, c.id.to_s] }
add_available_filter('companies', :type => :list, :field_format => 'company', :name => l(:field_companies), :values => selected_companies)
end
if !available_filters.key?('deal') && User.current.allowed_to?(:view_deals, project, :global => true)
selected_deals = filters['deal'].blank? ? [] : Deal.visible.where(:id => filters['deal'][:values]).map { |deal| [deal.name, deal.id.to_s] }
add_available_filter('deal', :type => :list_optional, :field_format => 'deal', :name => l(:label_deal), :values => selected_deals)
end
end
def contact_query_values(options = {})
if options[:field] == 'deal'
deals_for_select(nil, :where => { :id => options[:values] }, :short_label => true)
else
contacts_for_select(nil, :where => { :id => options[:values] }, :short_label => true)
end
end
def default_contact_query_values(options = {})
records =
if options[:field] == 'deal'
Deal.visible.where(:id => options[:values])
else
Contact.joins(:projects).where(Contact.visible_condition(User.current)).where(:id => options[:values])
end
records.to_a.sort! { |x, y| x.name <=> y.name }.collect { |m| [m.name, m.id.to_s] }
end
end
end
end
end
unless IssueQuery.included_modules.include?(RedmineContacts::Patches::IssueQueryPatch)
IssueQuery.send(:include, RedmineContacts::Patches::IssueQueryPatch)
end
@@ -0,0 +1,47 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module IssuesControllerPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :build_new_issue_from_params_without_contacts, :build_new_issue_from_params
alias_method :build_new_issue_from_params, :build_new_issue_from_params_with_contacts
end
end
module InstanceMethods
def build_new_issue_from_params_with_contacts
build_new_issue_from_params_without_contacts
return if @issue.blank? || params[:deal_id].blank?
deal = Deal.visible.where(:id => params[:deal_id]).first
@issue.deals_issue = DealsIssue.new(:issue => @issue, :deal => deal) if deal
end
end
end
end
end
unless IssuesController.included_modules.include?(RedmineContacts::Patches::IssuesControllerPatch)
IssuesController.send(:include, RedmineContacts::Patches::IssuesControllerPatch)
end
@@ -0,0 +1,41 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module IssuesHelperPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
end
end
module InstanceMethods
def render_custom_fields_rows(issue)
render_half_width_custom_fields_rows(issue)
end
end
end
end
end
unless IssuesHelper.included_modules.include?(RedmineContacts::Patches::IssuesHelperPatch)
IssuesHelper.send(:include, RedmineContacts::Patches::IssuesHelperPatch)
end
@@ -0,0 +1,115 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module MailerPatch
module ClassMethods
end
module InstanceMethods
def crm_note_add(note)
redmine_headers 'Project' => note.source.project.identifier,
'X-Notable-Id' => note.source.id,
'X-Note-Id' => note.id
@author = note.author
message_id note
recipients = note.source.recipients
cc = (note.source.respond_to?(:all_watcher_recepients) ? note.source.all_watcher_recepients : note.source.watcher_recipients) - recipients
@note = note
@note_url = url_for(:controller => 'notes', :action => 'show', :id => note.id)
mail :to => recipients,
:cc => cc,
:subject => "[#{note.source.project.name}] - #{l(:label_crm_note_for)} #{note.source.name}"
end
def crm_contact_add(contact)
redmine_headers 'Project' => contact.project.identifier,
'X-Contact-Id' => contact.id
@author = contact.author
message_id contact
recipients = contact.recipients
cc = contact.watcher_recipients - recipients
@contact = contact
@contact_url = url_for(:controller => 'contacts', :action => 'show', :id => contact.id)
mail :to => recipients,
:cc => cc,
:subject => "[#{contact.project.name} - #{l(:label_contact)} ##{contact.id}] #{contact.name}"
end
def crm_deal_add(deal)
redmine_headers 'Project' => deal.project.identifier,
'X-Deal-Id' => deal.id
@author = deal.author
message_id deal
recipients = deal.recipients
cc = deal.watcher_recipients - recipients
@deal = deal
@deal_url = url_for(:controller => 'deals', :action => 'show', :id => deal.id)
mail :to => recipients,
:cc => cc,
:subject => "[#{deal.project.name} - #{l(:label_deal)} ##{deal.id}] #{deal.full_name}"
end
def crm_deal_updated(deal_process)
@deal = deal_process.deal
redmine_headers 'Project' => @deal.project.identifier,
'X-Deal-Id' => @deal.id
@author = deal_process.author
recipients = deal_process.recipients
cc = @deal.watcher_recipients - recipients
@status_was = deal_process.from
@status = deal_process.to
@deal_url = url_for(:controller => 'deals', :action => 'show', :id => @deal.id)
mail :to => recipients,
:cc => cc,
:subject => "[#{@deal.project.name} - #{l(:label_deal)} ##{@deal.id}] #{@deal.full_name}"
end
def crm_issue_connected(issue, contact)
redmine_headers 'X-Project' => contact.project.identifier,
'X-Issue-Id' => issue.id,
'X-Contact-Id' => contact.id
message_id contact
recipients contact.watcher_recipients
subject "[#{contact.projects.first.name}] - #{l(:label_issue_for)} #{contact.name}"
body :contact => contact,
:issue => issue,
:contact_url => url_for(:controller => contact.class.name.pluralize.downcase, :action => 'show', :project_id => contact.project, :id => contact.id),
:issue_url => url_for(:controller => "issues", :action => "show", :id => issue)
render_multipart('issue_connected', body)
end
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
receiver.class_eval do
unloadable
# TODO: Удалено из-за несовместимости, может быть косяк с шаблонами для майлера
# self.instance_variable_get("@inheritable_attributes")[:view_paths] << RAILS_ROOT + "/vendor/plugins/redmine_contacts/app/views"
end
end
end
end
end
unless Mailer.included_modules.include?(RedmineContacts::Patches::MailerPatch)
Mailer.send(:include, RedmineContacts::Patches::MailerPatch)
end
@@ -0,0 +1,52 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module NotifiablePatch
def self.included(base)
base.extend(ClassMethods)
base.class_eval do
unloadable
class << self
alias_method :all_without_contacts, :all
alias_method :all, :all_with_contacts
end
end
end
module ClassMethods
# include ContactsHelper
def all_with_contacts
notifications = all_without_contacts
notifications << Redmine::Notifiable.new('crm_contact_added')
notifications << Redmine::Notifiable.new('crm_deal_added')
notifications << Redmine::Notifiable.new('crm_deal_updated')
notifications << Redmine::Notifiable.new('crm_note_added')
notifications
end
end
end
end
end
unless Redmine::Notifiable.included_modules.include?(RedmineContacts::Patches::NotifiablePatch)
Redmine::Notifiable.send(:include, RedmineContacts::Patches::NotifiablePatch)
end
@@ -0,0 +1,47 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module ProjectPatch
def self.included(base) # :nodoc:
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
has_many :deals, :dependent => :delete_all
if ActiveRecord::VERSION::MAJOR >= 4
has_and_belongs_to_many :contacts, lambda { order("#{Contact.table_name}.last_name, #{Contact.table_name}.first_name") }
has_many :deal_categories, lambda { order("#{DealCategory.table_name}.name") }, :dependent => :delete_all
has_and_belongs_to_many :deal_statuses, lambda { order("#{DealStatus.table_name}.status_type, #{DealStatus.table_name}.position") }
else
has_and_belongs_to_many :contacts, :order => "#{Contact.table_name}.last_name, #{Contact.table_name}.first_name"
has_many :deal_categories, :order => "#{DealCategory.table_name}.name", :dependent => :delete_all
has_and_belongs_to_many :deal_statuses, :order => "#{DealStatus.table_name}.status_type, #{DealStatus.table_name}.position", :uniq => true
end
end
end
end
end
end
unless Project.included_modules.include?(RedmineContacts::Patches::ProjectPatch)
Project.send(:include, RedmineContacts::Patches::ProjectPatch)
end
@@ -0,0 +1,58 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'queries_helper'
module RedmineContacts
module Patches
module ProjectsHelperPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :project_settings_tabs_without_contacts, :project_settings_tabs
alias_method :project_settings_tabs, :project_settings_tabs_with_contacts
end
end
module InstanceMethods
# include ContactsHelper
def project_settings_tabs_with_contacts
tabs = project_settings_tabs_without_contacts
tabs.push(:name => 'contacts',
:action => :manage_contacts,
:partial => 'projects/contacts_settings',
:label => :label_contact_plural) if User.current.allowed_to?(:manage_contacts, @project)
tabs.push(:name => 'deals',
:action => :manage_deals,
:partial => 'projects/deals_settings',
:label => :label_deal_plural) if User.current.allowed_to?(:manage_deals, @project)
tabs
end
end
end
end
end
unless ProjectsHelper.included_modules.include?(RedmineContacts::Patches::ProjectsHelperPatch)
ProjectsHelper.send(:include, RedmineContacts::Patches::ProjectsHelperPatch)
end
@@ -0,0 +1,76 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'queries_helper'
module RedmineContacts
module Patches
module QueriesHelperPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :column_value_without_contacts, :column_value
alias_method :column_value, :column_value_with_contacts
end
end
module InstanceMethods
def column_value_with_contacts(column, list_object, value)
if column.name == :id && list_object.is_a?(Contact)
link_to(value, contact_path(value))
elsif column.name == :name && list_object.is_a?(Contact)
contact_tag(list_object)
elsif column.name == :name && list_object.is_a?(Deal)
link_to(list_object.name, deal_path(list_object))
elsif column.name == :price && list_object.is_a?(Deal)
list_object.price_to_s
elsif column.name == :expected_revenue && list_object.is_a?(Deal)
list_object.expected_revenue_to_s
elsif column.name == :probability && !value.blank? && list_object.is_a?(Deal)
"#{value.to_i}%"
elsif value.is_a?(Deal)
deal_tag(value, :no_contact => true, :plain => true)
elsif value.is_a?(Contact)
contact_tag(value)
elsif column.name == :contacts
contacts_span = []
[value].flatten.each do |contact|
contacts_span << contact_tag(contact)
end
contacts_span.join(', ').html_safe
elsif column.name == :tags && list_object.is_a?(Contact)
contact_tags = []
[value].flatten.each do |tag|
contact_tags << tag.name
end
contact_tags.join(', ')
else
column_value_without_contacts(column, list_object, value)
end
end
end
end
end
end
unless QueriesHelper.included_modules.include?(RedmineContacts::Patches::QueriesHelperPatch)
QueriesHelper.send(:include, RedmineContacts::Patches::QueriesHelperPatch)
end
@@ -0,0 +1,44 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'query'
module RedmineContacts
module Patches
module QueryFilterPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
end
end
module InstanceMethods
def []=(key, value)
return unless key == :values
@value = @options[:values] = value
end
end
end
end
end
unless QueryFilter.included_modules.include?(RedmineContacts::Patches::QueryFilterPatch)
QueryFilter.send(:include, RedmineContacts::Patches::QueryFilterPatch)
end
@@ -0,0 +1,68 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'query'
module RedmineContacts
module Patches
module QueryPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :add_filter_without_contacts, :add_filter
alias_method :add_filter, :add_filter_with_contacts
alias_method :available_filters_as_json_without_contacts, :available_filters_as_json
alias_method :available_filters_as_json, :available_filters_as_json_with_contacts
end
end
module InstanceMethods
def add_filter_with_contacts(field, operator, values = nil)
add_filter_without_contacts(field, operator, values)
if available_filters[field] && %w(company contact deal).include?(available_filters[field][:field_format])
filter_options = available_filters[field]
# Method :contact_query_values should be defined in query class for model
if respond_to?(:contact_query_values)
filter_options[:values] = contact_query_values(:field => field, :values => values)
end
return if filter_options[:values].present?
filter_options[:values] = default_contact_query_values(:field => field, :values => values)
end
true
end
def available_filters_as_json_with_contacts
json_data = available_filters_as_json_without_contacts
Hash[json_data.map do |f_name, f_data|
f_data['field_format'] = available_filters[f_name][:field_format]
[f_name, f_data]
end]
end
end
end
end
end
unless Query.included_modules.include?(RedmineContacts::Patches::QueryPatch)
Query.send(:include, RedmineContacts::Patches::QueryPatch)
end
@@ -0,0 +1,73 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module SettingPatch
def self.included(base)
base.extend(ClassMethods)
# base.send(:include, InstanceMethods)
base.class_eval do
unloadable
# Setting.available_settings["disable_taxes"] = {'default' => 0}
# @@available_settings["disable_taxes"] = {}
end
end
module ClassMethods
# Setting.available_settings["disable_taxes"] = {}
# def disable_taxes?
# self[:disable_taxes].to_i > 0
# end
# def disable_taxes=(value)
# self[:disable_taxes] = value
# end
%w(disable_taxes default_tax tax_type default_currency money_thousands_delimiter money_decimal_separator).each do |name|
src = <<-END_SRC
Setting.available_settings["#{name}"] = ""
def #{name}
self[:#{name}]
end
def #{name}?
self[:#{name}].to_i > 0
end
def #{name}=(value)
self[:#{name}] = value
end
END_SRC
class_eval src, __FILE__, __LINE__
end
end
end
end
end
unless Setting.included_modules.include?(RedmineContacts::Patches::SettingPatch)
Setting.send(:include, RedmineContacts::Patches::SettingPatch)
end
@@ -0,0 +1,51 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module SettingsHelperPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :administration_settings_tabs_without_contacts, :administration_settings_tabs
alias_method :administration_settings_tabs, :administration_settings_tabs_with_contacts
end
end
module InstanceMethods
# include ContactsHelper
def administration_settings_tabs_with_contacts
tabs = administration_settings_tabs_without_contacts
tabs.push(:name => 'money',
:partial => 'settings/contacts/money',
:label => :label_crm_money_settings)
end
end
end
end
end
unless SettingsHelper.included_modules.include?(RedmineContacts::Patches::SettingsHelperPatch)
SettingsHelper.send(:include, RedmineContacts::Patches::SettingsHelperPatch)
end
@@ -0,0 +1,45 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'query'
module RedmineContacts
module Patches
module TimeEntryQueryPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.send(:include, RedmineContacts::Helper)
base.class_eval do
unloadable
end
end
module InstanceMethods
def contact_query_values(options = {})
contacts_for_select(nil, :where => { :id => options[:values] }, :short_label => true)
end
end
end
end
end
unless TimeEntryQuery.included_modules.include?(RedmineContacts::Patches::TimeEntryQueryPatch)
TimeEntryQuery.send(:include, RedmineContacts::Patches::TimeEntryQueryPatch)
end
@@ -0,0 +1,54 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module TimeReportPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :load_available_criteria_without_contacts, :load_available_criteria
alias_method :load_available_criteria, :load_available_criteria_with_contacts
end
end
module InstanceMethods
def load_available_criteria_with_contacts
@available_criteria = load_available_criteria_without_contacts
@available_criteria['deal'] = { :sql => 'd_deals_issues.deal_id',
:kclass => Deal,
:joins => 'LEFT OUTER JOIN deals_issues d_deals_issues ON d_deals_issues.issue_id = issues.id',
:label => :label_deal } if User.current.allowed_to?(:view_deals, @project, :global => true)
@available_criteria['deal_contact'] = { :sql => 'd_deals.contact_id',
:kclass => Contact,
:joins => 'LEFT OUTER JOIN deals_issues c_deals_issues ON c_deals_issues.issue_id = issues.id
LEFT OUTER JOIN deals d_deals ON c_deals_issues.deal_id = d_deals.id',
:label => :label_crm_deal_contact } if User.current.allowed_to?(:view_deals, @project, :global => true)
@available_criteria
end
end
end
end
end
unless Redmine::Helpers::TimeReport.included_modules.include?(RedmineContacts::Patches::TimeReportPatch)
Redmine::Helpers::TimeReport.send(:include, RedmineContacts::Patches::TimeReportPatch)
end
@@ -0,0 +1,50 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module Patches
module TimelogHelperPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method :format_criteria_value_without_contacts, :format_criteria_value
alias_method :format_criteria_value, :format_criteria_value_with_contacts
end
end
module InstanceMethods
def format_criteria_value_with_contacts(criteria_options, value)
if !value.blank? && criteria_options[:kclass] == Contact && obj = Contact.find_by_id(value.to_i)
obj.visible? ? obj.name : "#{l(:label_contact)} - ##{obj.id}"
elsif !value.blank? && criteria_options[:kclass] == Deal && obj = Deal.find_by_id(value.to_i)
obj.visible? ? "#{obj.full_name} (#{obj.info})" : "#{l(:label_deal)} - ##{obj.id}"
else
format_criteria_value_without_contacts(criteria_options, value)
end
end
end
end
end
end
unless TimelogHelper.included_modules.include?(RedmineContacts::Patches::TimelogHelperPatch)
TimelogHelper.send(:include, RedmineContacts::Patches::TimelogHelperPatch)
end
@@ -0,0 +1,51 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require_dependency 'users_controller'
require_dependency 'user'
module RedmineContacts
module Patches
module UsersControllerPatch
def self.included(base) # :nodoc:
base.class_eval do
end
base.send(:include, InstanceMethods)
end
module InstanceMethods
def new_from_contact
contact = Contact.visible.find(params[:contact_id])
@user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
@user.firstname = contact.first_name
@user.lastname = contact.last_name
@user.mail = contact.emails.first
@auth_sources = AuthSource.all
respond_to do |format|
format.html { render :action => 'new' }
end
end
end
end
end
end
unless UsersController.included_modules.include?(RedmineContacts::Patches::UsersControllerPatch)
UsersController.send(:include, RedmineContacts::Patches::UsersControllerPatch)
end
@@ -0,0 +1,120 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require 'net/imap'
require 'net/pop'
require 'openssl'
require 'timeout'
module RedmineContacts
module Mailer
class << self
def check_imap(mailer, imap_options={}, options={})
host = imap_options[:host] || '127.0.0.1'
port = imap_options[:port] || '143'
ssl = !imap_options[:ssl].nil?
folder = imap_options[:folder] || 'INBOX'
Timeout::timeout(15) do
@imap = Net::IMAP.new(host, port, ssl)
@imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil?
end
@imap.select(folder)
msg_count = 0
@imap.uid_search(['NOT', 'SEEN']).each do |uid|
msg = @imap.uid_fetch(uid,'RFC822')[0].attr['RFC822']
logger.info "ContactsMailHandler: Receiving message #{uid}" if logger && logger.info?
msg_count += 1
if mailer.receive(msg, options)
logger.info "ContactsMailHandler: Message #{uid} successfully received" if logger && logger.info?
if imap_options[:move_on_success] && imap_options[:move_on_success] != folder
@imap.uid_copy(uid, imap_options[:move_on_success])
end
@imap.uid_store(uid, "+FLAGS", [:Seen, :Deleted])
else
logger.info "ContactsMailHandler: Message #{uid} can not be processed" if logger && logger.info?
@imap.uid_store(uid, "+FLAGS", [:Seen])
if imap_options[:move_on_failure]
@imap.uid_copy(uid, imap_options[:move_on_failure])
@imap.uid_store(uid, "+FLAGS", [:Deleted])
end
end
end
@imap.expunge
msg_count
ensure
if defined?(@imap) && @imap && !@imap.disconnected?
@imap.disconnect
end
end
def check_pop3(mailer, pop_options={}, options={})
host = pop_options[:host] || '127.0.0.1'
port = pop_options[:port] || '110'
apop = (pop_options[:apop].to_s == '1')
delete_unprocessed = (pop_options[:delete_unprocessed].to_s == '1')
pop = Net::POP3.APOP(apop).new(host,port)
pop.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if pop_options[:ssl]
logger.info "ContactsMailHandler: Connecting to #{host}..." if logger && logger.info?
msg_count = 0
pop.start(pop_options[:username], pop_options[:password]) do |pop_session|
if pop_session.mails.empty?
logger.info "ContactsMailHandler: No email to process" if logger && logger.info?
else
logger.info "ContactsMailHandler: #{pop_session.mails.size} email(s) to process..." if logger && logger.info?
pop_session.each_mail do |msg|
msg_count += 1
message = msg.pop(String.new)
uid = (message =~ /^Message-ID: (.*)/ ? $1 : '').strip
if mailer.receive(message, options)
msg.delete
logger.info "--> ContactsMailHandler: Message #{uid} processed and deleted from the server" if logger && logger.info?
else
if delete_unprocessed
msg.delete
logger.info "--> ContactsMailHandler: Message #{uid} NOT processed and deleted from the server" if logger && logger.info?
else
logger.info "--> ContactsMailHandler: Message #{uid} NOT processed and left on the server" if logger && logger.info?
end
end
end
end
end
msg_count
ensure
if defined?(pop) && pop && pop.started?
pop.finish
end
end
private
def logger
::Rails.logger
end
end
end
end
@@ -0,0 +1,49 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module CSVUtils
include Redmine::I18n
class << self
def csv_custom_value(custom_value)
return "" unless custom_value
value = custom_value.value
case custom_value.custom_field.field_format
when 'date'
begin; format_date(value.to_date); rescue; value end
when 'bool'
l(value == "1" ? :general_text_Yes : :general_text_No)
when 'float'
sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
else
if value.is_a?(Array)
value.map(&:to_s).join(', ')
else
value.to_s
end
end
rescue
return ""
end
end
end
end
@@ -0,0 +1,67 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module DateUtils
class << self
def retrieve_date_range(period)
from, to = nil, nil
case period
when 'today'
from = to = Date.today
when 'yesterday'
from = to = Date.today - 1
when 'current_week'
from = Date.today - (Date.today.cwday - 1)%7
to = from + 6
when 'last_week'
from = Date.today - 7 - (Date.today.cwday - 1)%7
to = from + 6
when 'last_2_weeks'
from = Date.today - 14 - (Date.today.cwday - 1)%7
to = from + 13
when '7_days'
from = Date.today - 7
to = Date.today
when 'last_7_days'
from = Date.today - 14
to = from + 7
when 'current_month'
from = Date.civil(Date.today.year, Date.today.month, 1)
to = (from >> 1) - 1
when 'last_month'
from = Date.civil(Date.today.year, Date.today.month, 1) << 1
to = (from >> 1) - 1
when '30_days'
from = Date.today - 30
to = Date.today
when 'current_year'
from = Date.civil(Date.today.year, 1, 1)
to = Date.civil(Date.today.year, 12, 31)
when 'last_year'
from = Date.civil(1.year.ago.year, 1, 1)
to = Date.civil(1.year.ago.year, 12, 31)
end
from, to = from, to + 1 if (from && to)
[from, to]
end
end
end
end
@@ -0,0 +1,51 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
require 'fileutils'
module RedmineContacts
module Thumbnail
extend Redmine::Utils::Shell
include Redmine::Thumbnail
CONVERT_BIN = (Redmine::Configuration['imagemagick_convert_command'] || 'convert').freeze
# Generates a thumbnail for the source image to target
def self.generate(source, target, size)
return nil unless Redmine::Thumbnail.convert_available?
unless File.exists?(target)
directory = File.dirname(target)
unless File.exists?(directory)
FileUtils.mkdir_p directory
end
size_option = "#{size}x#{size}^"
sharpen_option = "0.7x6"
crop_option = "#{size}x#{size}"
cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -resize #{shell_quote size_option} -sharpen #{shell_quote sharpen_option} -gravity center -extent #{shell_quote crop_option} #{shell_quote target}"
unless system(cmd)
Rails.logger.error("Creating thumbnail failed (#{$?}):\nCommand: #{cmd}")
return nil
end
end
target
end
end
end
@@ -0,0 +1,87 @@
# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
module RedmineContacts
module WikiMacros
Redmine::WikiFormatting::Macros.register do
desc "Contact Description Macro"
macro :contact_plain do |obj, args|
args, options = extract_macro_options(args, :parent)
raise 'No or bad arguments.' if args.size != 1
if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
first_name, last_name = args.first.split
conditions = {:first_name => first_name}
conditions[:last_name] = last_name if last_name
contact = Contact.visible.find(:first, :conditions => conditions)
else
contact = Contact.visible.find_by_id(args.first)
end
link_to_source(contact) if contact
end
desc "Contact avatar"
macro :contact_avatar do |obj, args|
args, options = extract_macro_options(args, :parent)
raise 'No or bad arguments.' if args.size != 1
if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
first_name, last_name = args.first.split
conditions = {:first_name => first_name}
conditions[:last_name] = last_name if last_name
contact = Contact.visible.find(:first, :conditions => conditions)
else
contact = Contact.visible.find_by_id(args.first)
end
link_to avatar_to(contact, :size => "32"), contact_path(contact), :id => "avatar", :title => contact.name if contact
end
desc "Contact with avatar"
macro :contact do |obj, args|
args, options = extract_macro_options(args, :parent)
raise 'No or bad arguments.' if args.size != 1
if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
first_name, last_name = args.first.split
conditions = {:first_name => first_name}
conditions[:last_name] = last_name if last_name
contact = Contact.visible.find(:first, :conditions => conditions)
else
contact = Contact.visible.find_by_id(args.first)
end
contact_tag(contact) if contact
end
desc "Contact/Deal note"
macro :contact_note do |obj, args|
args, options = extract_macro_options(args, :parent)
raise 'No or bad arguments.' if args.size != 1
note = Note.find_by_id(args.first)
textilizable(note, :content).html_safe if note && note.source.visible?
end
desc "Deal"
macro :deal do |obj, args|
args, options = extract_macro_options(args, :parent)
raise 'No or bad arguments.' if args.size != 1
deal = Deal.visible.find(args.first)
deal_tag(deal)
end
end
end
end
@@ -0,0 +1,16 @@
namespace :redmine do
namespace :contacts do
desc <<-END_DESC
Clear tags table.
rake redmine:contacts:clear_tags_table RAILS_ENV="production"
END_DESC
task :clear_tags_table => :environment do
ActiveRecord::Migration.remove_column(:tags, :color) if RedmineCrm::Tag.column_names.include?("color")
ActiveRecord::Migration.remove_column(:tags, :created_at) if RedmineCrm::Tag.column_names.include?("created_at")
ActiveRecord::Migration.remove_column(:tags, :updated_at) if RedmineCrm::Tag.column_names.include?("updated_at")
end
end
end
@@ -0,0 +1,69 @@
namespace :redmine do
namespace :contacts do
desc <<-END_DESC
Drop settings.
rake redmine:contacts:drop_settings RAILS_ENV="production" plugin="plugin_redmine_contacts"
Plugins:
plugin_redmine_contacts: Redmine CRM plugin
plugin_redmine_contacts_helpdesk: Redmine Helpdesk plugin
plugin_redmine_contacts_invoices: Redmine Invoices plugin
END_DESC
task :drop_settings => :environment do
plugin_name = ENV['plugin']
Setting[plugin_name.to_sym] = {} if plugin_name
end
desc <<-END_DESC
Set plugin settings.
rake redmine:contacts:settings RAILS_ENV="production" plugin="plugin_redmine_contacts" setting="list_partial_style" value="list"
rake redmine:contacts:settings RAILS_ENV="production" project="helpdesk" setting="contacts_show_deals_tab" value="1"
Plugins:
plugin_redmine_contacts: Redmine CRM plugin
plugin_redmine_contacts_helpdesk: Redmine Helpdesk plugin
plugin_redmine_contacts_invoices: Redmine Invoices plugin
END_DESC
task :settings => :environment do
plugin_name = ENV['plugin']
setting = ENV['setting']
value = ENV['value']
project = ENV['project']
if (plugin_name.blank? && project.blank?) || setting.blank? || value.blank?
puts "RedmineCRM: Params plugin, setting and value should be present"
return
end
if project
ContactsSetting[setting, Project.find(project).id] = value
else
plugin_settings = Setting[plugin_name.to_sym]
plugin_settings[setting] = value
Setting[plugin_name.to_sym] = plugin_settings
end
end
desc <<-END_DESC
Load CRM plugin default data.
END_DESC
task :load_default_data => :environment do
DealStatus.create(:name => l(:label_deal_status_pending), :status_type => DealStatus::OPEN_STATUS, :is_default => true, :color => "AAAAAA".hex)
DealStatus.create(:name => l(:label_deal_status_won), :status_type => DealStatus::WON_STATUS, :is_default => false, :color => "008000".hex)
DealStatus.create(:name => l(:label_deal_status_lost), :status_type => DealStatus::LOST_STATUS, :is_default => false, :color => "FF0000".hex)
end
end
end
@@ -0,0 +1,154 @@
namespace :redmine do
namespace :email do
namespace :contacts do
desc <<-END_DESC
Read an email from standard input.
General options:
unknown_user=ACTION how to handle emails from an unknown user
ACTION can be one of the following values:
ignore: email is ignored (default)
accept: accept as anonymous user
create: create a user account
no_permission_check=1 disable permission checking when receiving
the email
Issue attributes control options:
project=PROJECT identifier of the target project
status=STATUS name of the target status
tracker=TRACKER name of the target tracker
category=CATEGORY name of the target category
priority=PRIORITY name of the target priority
allow_override=ATTRS allow email content to override attributes
specified by previous options
ATTRS is a comma separated list of attributes
Examples:
# No project specified. Emails MUST contain the 'Project' keyword:
rake redmine:email:read RAILS_ENV="production" < raw_email
# Fixed project and default tracker specified, but emails can override
# both tracker and priority attributes:
rake redmine:email:contacts:read RAILS_ENV="production" \\
project=foo \\
tracker=bug \\
allow_override=tracker,priority < raw_email
END_DESC
task :read => :environment do
options = { :contact => {} }
# %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
# options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
# options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
# options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
ContactsMailer.receive(STDIN.read, options)
end
desc <<-END_DESC
Read emails from an IMAP server.
General options:
unknown_user=ACTION how to handle emails from an unknown user
ACTION can be one of the following values:
ignore: email is ignored (default)
accept: accept as anonymous user
create: create a user account
no_permission_check=1 disable permission checking when receiving
the email
Available IMAP options:
host=HOST IMAP server host (default: 127.0.0.1)
port=PORT IMAP server port (default: 143)
ssl=SSL Use SSL? (default: false)
username=USERNAME IMAP account
password=PASSWORD IMAP password
folder=FOLDER IMAP folder to read (default: INBOX)
Issue attributes control options:
project=PROJECT identifier of the target project
status=STATUS name of the target status
tracker=TRACKER name of the target tracker
category=CATEGORY name of the target category
priority=PRIORITY name of the target priority
allow_override=ATTRS allow email content to override attributes
specified by previous options
ATTRS is a comma separated list of attributes
Processed emails control options:
move_on_success=MAILBOX move emails that were successfully received
to MAILBOX instead of deleting them
move_on_failure=MAILBOX move emails that were ignored to MAILBOX
Examples:
# No project specified. Emails MUST contain the 'Project' keyword:
rake redmine:email:contacts:receive_imap RAILS_ENV="production" \\
host=imap.foo.bar username=redmine@example.net password=xxx
# Fixed project and default tracker specified, but emails can override
# both tracker and priority attributes:
rake redmine:email:receive_imap RAILS_ENV="production" \\
host=imap.foo.bar username=redmine@example.net password=xxx ssl=1 \\
project=foo \\
tracker=bug
END_DESC
task :receive_imap => :environment do
imap_options = {:host => ENV['host'],
:port => ENV['port'],
:ssl => ENV['ssl'],
:username => ENV['username'],
:password => ENV['password'],
:folder => ENV['folder'],
:move_on_success => ENV['move_on_success'],
:move_on_failure => ENV['move_on_failure']}
options = { :issue => {} }
%w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
RedmineContacts::Mailer.check_imap(ContactsMailer, imap_options, options)
end
desc <<-END_DESC
Read emails from an POP3 server.
Available POP3 options:
host=HOST POP3 server host (default: 127.0.0.1)
port=PORT POP3 server port (default: 110)
username=USERNAME POP3 account
password=PASSWORD POP3 password
apop=1 use APOP authentication (default: false)
delete_unprocessed=1 delete messages that could not be processed
successfully from the server (default
behaviour is to leave them on the server)
See redmine:email:contacts:receive_imap for more options and examples.
END_DESC
task :receive_pop3 => :environment do
pop_options = {:host => ENV['host'],
:port => ENV['port'],
:apop => ENV['apop'],
:username => ENV['username'],
:password => ENV['password'],
:delete_unprocessed => ENV['delete_unprocessed']}
options = { :issue => {} }
%w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
RedmineContacts::Mailer.check_pop3(ContactsMailer, pop_options, options)
end
end
end
end