Nuevo plugin Additionals 2.0.20
This commit is contained in:
parent
a2a901b71b
commit
93e1e28683
354 changed files with 40514 additions and 0 deletions
118
plugins/additionals/app/models/additionals_font_awesome.rb
Executable file
118
plugins/additionals/app/models/additionals_font_awesome.rb
Executable file
|
@ -0,0 +1,118 @@
|
|||
class AdditionalsFontAwesome
|
||||
include Redmine::I18n
|
||||
|
||||
class << self
|
||||
def load_icons(type)
|
||||
data = YAML.safe_load(ERB.new(IO.read(Rails.root.join('plugins',
|
||||
'additionals',
|
||||
'config',
|
||||
'fontawesome_icons.yml'))).result) || {}
|
||||
icons = {}
|
||||
data.each do |key, values|
|
||||
icons[key] = { unicode: values['unicode'], label: values['label'] } if values['styles'].include?(convert_type2style(type))
|
||||
end
|
||||
icons
|
||||
end
|
||||
|
||||
def convert_type2style(type)
|
||||
case type
|
||||
when :fab
|
||||
'brands'
|
||||
when :far
|
||||
'regular'
|
||||
else
|
||||
'solid'
|
||||
end
|
||||
end
|
||||
|
||||
def font_weight(key)
|
||||
case key
|
||||
when :fas
|
||||
900
|
||||
else
|
||||
'normal'
|
||||
end
|
||||
end
|
||||
|
||||
def font_family(key)
|
||||
case key
|
||||
when :fab
|
||||
'Font Awesome\ 5 Brands'
|
||||
else
|
||||
'Font Awesome\ 5 Free'
|
||||
end
|
||||
end
|
||||
|
||||
def key2value(key, type)
|
||||
"fa#{type}_" + key
|
||||
end
|
||||
|
||||
def classes(value)
|
||||
info = value_info(value)
|
||||
return '' if info.blank?
|
||||
|
||||
info[:classes]
|
||||
end
|
||||
|
||||
def json_values(type)
|
||||
FONTAWESOME_ICONS[type].collect { |fa_symbol, values| { id: key2value(fa_symbol, type[-1]), text: values[:label] } }
|
||||
end
|
||||
|
||||
def select_values(type)
|
||||
FONTAWESOME_ICONS[type].collect { |fa_symbol, values| [values[:label], key2value(fa_symbol, type[-1])] }
|
||||
end
|
||||
|
||||
def json_for_select
|
||||
[{ text: l(:label_fontawesome_regular), children: json_values(:far) },
|
||||
{ text: l(:label_fontawesome_solid), children: json_values(:fas) },
|
||||
{ text: l(:label_fontawesome_brands), children: json_values(:fab) }].to_json
|
||||
end
|
||||
|
||||
# show only one value as current selected
|
||||
# (all other options are retrieved by select2
|
||||
def active_option_for_select(selected)
|
||||
info = value_info(selected, with_details: true)
|
||||
return [] if info.blank?
|
||||
|
||||
[[info[:label], selected]]
|
||||
end
|
||||
|
||||
def options_for_select
|
||||
[[l(:label_fontawesome_regular), select_values(:far)],
|
||||
[l(:label_fontawesome_solid), select_values(:fas)],
|
||||
[l(:label_fontawesome_brands), select_values(:fab)]]
|
||||
end
|
||||
|
||||
def value_info(value, options = {})
|
||||
return {} if value.blank?
|
||||
|
||||
values = value.split('_')
|
||||
return {} unless values.count == 2
|
||||
|
||||
info = { type: values[0].to_sym,
|
||||
name: "fa-#{values[1]}" }
|
||||
|
||||
info[:classes] = "#{info[:type]} #{info[:name]}"
|
||||
info[:font_weight] = font_weight(info[:type])
|
||||
info[:font_family] = font_family(info[:type])
|
||||
|
||||
if options[:with_details]
|
||||
info.merge!(load_details(info[:type], values[1]))
|
||||
return {} if info[:unicode].blank?
|
||||
end
|
||||
|
||||
info
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_details(type, name)
|
||||
return {} unless FONTAWESOME_ICONS.key?(type)
|
||||
|
||||
values = FONTAWESOME_ICONS[type][name]
|
||||
return {} if values.blank?
|
||||
|
||||
{ unicode: "&#x#{values[:unicode]};".html_safe, label: values[:label] } # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
end
|
43
plugins/additionals/app/models/additionals_import.rb
Executable file
43
plugins/additionals/app/models/additionals_import.rb
Executable file
|
@ -0,0 +1,43 @@
|
|||
class AdditionalsImport < Import
|
||||
class_attribute :import_class
|
||||
|
||||
# Returns the objects that were imported
|
||||
def saved_objects
|
||||
object_ids = saved_items.pluck(:obj_id)
|
||||
import_class.where(id: object_ids).order(:id)
|
||||
end
|
||||
|
||||
def project=(project)
|
||||
settings['project'] = project
|
||||
end
|
||||
|
||||
def project
|
||||
settings['project']
|
||||
end
|
||||
|
||||
def mappable_custom_fields
|
||||
object = import_class.new
|
||||
@custom_fields = object.custom_field_values.map(&:custom_field)
|
||||
end
|
||||
|
||||
def build_custom_field_attributes(object, row)
|
||||
object.custom_field_values.each_with_object({}) do |v, h|
|
||||
value = case v.custom_field.field_format
|
||||
when 'date'
|
||||
row_date(row, "cf_#{v.custom_field.id}")
|
||||
when 'list'
|
||||
row_value(row, "cf_#{v.custom_field.id}").try(:split, ',')
|
||||
else
|
||||
row_value(row, "cf_#{v.custom_field.id}")
|
||||
end
|
||||
next unless value
|
||||
|
||||
h[v.custom_field.id.to_s] =
|
||||
if value.is_a?(Array)
|
||||
value.map { |val| v.custom_field.value_from_keyword(val.strip, object) }.compact.flatten
|
||||
else
|
||||
v.custom_field.value_from_keyword(value, object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
75
plugins/additionals/app/models/additionals_macro.rb
Executable file
75
plugins/additionals/app/models/additionals_macro.rb
Executable file
|
@ -0,0 +1,75 @@
|
|||
class AdditionalsMacro
|
||||
def self.all(options = {})
|
||||
all = Redmine::WikiFormatting::Macros.available_macros
|
||||
macros = {}
|
||||
macro_list = []
|
||||
|
||||
# needs to run every request (for each user once)
|
||||
permissions = build_permissions(options)
|
||||
|
||||
if options[:filtered].present?
|
||||
options[:filtered] << 'hello_world'
|
||||
else
|
||||
options[:filtered] = ['hello_world']
|
||||
end
|
||||
|
||||
all.each do |macro, macro_options|
|
||||
next if options[:filtered].include?(macro.to_s)
|
||||
next unless macro_allowed(macro, permissions)
|
||||
|
||||
macro_list << macro.to_s
|
||||
macros[macro] = macro_options
|
||||
end
|
||||
|
||||
if options[:only_names]
|
||||
macro_list.sort
|
||||
else
|
||||
macros.sort
|
||||
end
|
||||
end
|
||||
|
||||
def self.macro_allowed(macro, permissions)
|
||||
permissions.each do |permission|
|
||||
next if permission[:list].exclude?(macro)
|
||||
return false unless permission[:access]
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def self.build_permissions(options)
|
||||
gpermission = []
|
||||
macro_permissions.each do |permission|
|
||||
permission[:access] = if options[:controller_only] &&
|
||||
permission[:controller].present? &&
|
||||
options[:controller_only].to_sym != permission[:controller]
|
||||
false
|
||||
else
|
||||
User.current.allowed_to?(permission[:permission], nil, global: true)
|
||||
end
|
||||
gpermission << permission
|
||||
end
|
||||
|
||||
gpermission
|
||||
end
|
||||
|
||||
def self.macro_permissions
|
||||
[{ list: %i[issue issue_name_link],
|
||||
permission: :view_issues },
|
||||
{ list: %i[password password_query password_tag password_tag_count],
|
||||
permission: :view_passwords },
|
||||
{ list: %i[contact deal contact_avatar contact_note contact_plain],
|
||||
permission: :view_contacts },
|
||||
{ list: %i[db db_query db_tag db_tag_count],
|
||||
permission: :view_db_entries },
|
||||
{ list: %i[child_pages calendar last_updated_at last_updated_by lastupdated_at lastupdated_by
|
||||
new_page recently_updated recent comments comment_form tags taggedpages tagcloud
|
||||
show_count count vote show_vote terms_accept terms_reject],
|
||||
permission: :view_wiki_pages,
|
||||
controller: :wiki },
|
||||
{ list: %i[mail send_file],
|
||||
permission: :view_helpdesk_tickets },
|
||||
{ list: %i[kb article_id article category],
|
||||
permission: :view_kb_articles }]
|
||||
end
|
||||
end
|
150
plugins/additionals/app/models/additionals_query.rb
Executable file
150
plugins/additionals/app/models/additionals_query.rb
Executable file
|
@ -0,0 +1,150 @@
|
|||
module AdditionalsQuery
|
||||
def self.included(base)
|
||||
base.send :include, InstanceMethods
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def initialize_ids_filter(options = {})
|
||||
if options[:label]
|
||||
add_available_filter 'ids', type: :integer, label: options[:label]
|
||||
else
|
||||
add_available_filter 'ids', type: :integer, name: '#'
|
||||
end
|
||||
end
|
||||
|
||||
def sql_for_ids_field(_field, operator, value)
|
||||
if operator == '='
|
||||
# accepts a comma separated list of ids
|
||||
ids = value.first.to_s.scan(/\d+/).map(&:to_i)
|
||||
if ids.present?
|
||||
"#{queried_table_name}.id IN (#{ids.join(',')})"
|
||||
else
|
||||
'1=0'
|
||||
end
|
||||
else
|
||||
sql_for_field('id', operator, value, queried_table_name, 'id')
|
||||
end
|
||||
end
|
||||
|
||||
def initialize_project_filter(options = {})
|
||||
if project.nil?
|
||||
add_available_filter('project_id', order: options[:position],
|
||||
type: :list,
|
||||
values: -> { project_values })
|
||||
end
|
||||
return if project.nil? || project.leaf? || subproject_values.empty?
|
||||
|
||||
add_available_filter('subproject_id', order: options[:position],
|
||||
type: :list_subprojects,
|
||||
values: -> { subproject_values })
|
||||
end
|
||||
|
||||
def initialize_created_filter(options = {})
|
||||
add_available_filter 'created_on', order: options[:position],
|
||||
type: :date_past,
|
||||
label: options[:label].presence
|
||||
end
|
||||
|
||||
def initialize_updated_filter(options = {})
|
||||
add_available_filter 'updated_on', order: options[:position],
|
||||
type: :date_past,
|
||||
label: options[:label].presence
|
||||
end
|
||||
|
||||
def initialize_tags_filter(options = {})
|
||||
values = if project
|
||||
queried_class.available_tags(project: project.id)
|
||||
else
|
||||
queried_class.available_tags
|
||||
end
|
||||
return if values.blank?
|
||||
|
||||
add_available_filter 'tags', order: options[:position],
|
||||
type: :list,
|
||||
values: values.collect { |t| [t.name, t.name] }
|
||||
end
|
||||
|
||||
def initialize_author_filter(options = {})
|
||||
return if author_values.empty?
|
||||
|
||||
add_available_filter('author_id', order: options[:position],
|
||||
type: :list_optional,
|
||||
values: options[:no_lambda].nil? ? author_values : -> { author_values })
|
||||
end
|
||||
|
||||
def initialize_assignee_filter(options = {})
|
||||
return if author_values.empty?
|
||||
|
||||
add_available_filter('assigned_to_id', order: options[:position],
|
||||
type: :list_optional,
|
||||
values: options[:no_lambda] ? author_values : -> { author_values })
|
||||
end
|
||||
|
||||
def initialize_watcher_filter(options = {})
|
||||
return if watcher_values.empty? || !User.current.logged?
|
||||
|
||||
add_available_filter('watcher_id', order: options[:position],
|
||||
type: :list,
|
||||
values: options[:no_lambda] ? watcher_values : -> { watcher_values })
|
||||
end
|
||||
|
||||
def watcher_values
|
||||
watcher_values = [["<< #{l(:label_me)} >>", 'me']]
|
||||
watcher_values += users.collect { |s| [s.name, s.id.to_s] } if User.current.allowed_to?(:manage_public_queries, project, global: true)
|
||||
watcher_values
|
||||
end
|
||||
|
||||
def sql_for_watcher_id_field(field, operator, value)
|
||||
watchable_type = queried_class == User ? 'Principal' : queried_class.to_s
|
||||
|
||||
db_table = Watcher.table_name
|
||||
"#{queried_table_name}.id #{operator == '=' ? 'IN' : 'NOT IN'}
|
||||
(SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='#{watchable_type}' AND " +
|
||||
sql_for_field(field, '=', value, db_table, 'user_id') + ')'
|
||||
end
|
||||
|
||||
def sql_for_tags_field(field, _operator, value)
|
||||
AdditionalsTag.sql_for_tags_field(queried_class, operator_for(field), value)
|
||||
end
|
||||
|
||||
def sql_for_is_private_field(_field, operator, value)
|
||||
if bool_operator(operator, value)
|
||||
return '1=1' if value.count > 1
|
||||
|
||||
"#{queried_table_name}.is_private = #{self.class.connection.quoted_true}"
|
||||
else
|
||||
return '1=0' if value.count > 1
|
||||
|
||||
"#{queried_table_name}.is_private = #{self.class.connection.quoted_false}"
|
||||
end
|
||||
end
|
||||
|
||||
# use for list fields with to values 1 (true) and 0 (false)
|
||||
def bool_operator(operator, values)
|
||||
operator == '=' && values.first == '1' || operator != '=' && values.first != '1'
|
||||
end
|
||||
|
||||
# use for list
|
||||
def bool_values
|
||||
[[l(:general_text_yes), '1'], [l(:general_text_no), '0']]
|
||||
end
|
||||
|
||||
def query_count
|
||||
objects_scope.count
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid, e.message
|
||||
end
|
||||
|
||||
def results_scope(options = {})
|
||||
order_option = [group_by_sort_order, (options[:order] || sort_clause)].flatten.reject(&:blank?)
|
||||
|
||||
objects_scope(options)
|
||||
.order(order_option)
|
||||
.joins(joins_for_order_statement(order_option.join(',')))
|
||||
.limit(options[:limit])
|
||||
.offset(options[:offset])
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid, e.message
|
||||
end
|
||||
end
|
||||
end
|
70
plugins/additionals/app/models/additionals_tag.rb
Executable file
70
plugins/additionals/app/models/additionals_tag.rb
Executable file
|
@ -0,0 +1,70 @@
|
|||
class AdditionalsTag
|
||||
TAG_TABLE_NAME = RedmineCrm::Tag.table_name if defined? RedmineCrm
|
||||
TAGGING_TABLE_NAME = RedmineCrm::Tagging.table_name if defined? RedmineCrm
|
||||
PROJECT_TABLE_NAME = Project.table_name
|
||||
|
||||
def self.get_available_tags(klass, options = {})
|
||||
scope = RedmineCrm::Tag.where({})
|
||||
scope = scope.where("#{PROJECT_TABLE_NAME}.id = ?", options[:project]) if options[:project]
|
||||
if options[:permission]
|
||||
scope = scope.where(tag_access(options[:permission]))
|
||||
elsif options[:visible_condition]
|
||||
scope = scope.where(klass.visible_condition(User.current))
|
||||
end
|
||||
scope = scope.where("LOWER(#{TAG_TABLE_NAME}.name) LIKE ?", "%#{options[:name_like].downcase}%") if options[:name_like]
|
||||
scope = scope.where("#{TAG_TABLE_NAME}.name=?", options[:name]) if options[:name]
|
||||
scope = scope.where("#{TAGGING_TABLE_NAME}.taggable_id!=?", options[:exclude_id]) if options[:exclude_id]
|
||||
scope = scope.where(options[:where_field] => options[:where_value]) if options[:where_field].present? && options[:where_value]
|
||||
|
||||
scope = scope.select("#{TAG_TABLE_NAME}.*, COUNT(DISTINCT #{TAGGING_TABLE_NAME}.taggable_id) AS count")
|
||||
scope = scope.joins(tag_joins(klass, options))
|
||||
scope = scope.group("#{TAG_TABLE_NAME}.id, #{TAG_TABLE_NAME}.name").having('COUNT(*) > 0')
|
||||
scope = scope.order("#{TAG_TABLE_NAME}.name")
|
||||
scope
|
||||
end
|
||||
|
||||
def self.tag_joins(klass, options = {})
|
||||
table_name = klass.table_name
|
||||
|
||||
joins = ["JOIN #{TAGGING_TABLE_NAME} ON #{TAGGING_TABLE_NAME}.tag_id = #{TAG_TABLE_NAME}.id"]
|
||||
joins << "JOIN #{table_name} " \
|
||||
"ON #{table_name}.id = #{TAGGING_TABLE_NAME}.taggable_id AND #{TAGGING_TABLE_NAME}.taggable_type = '#{klass}'"
|
||||
|
||||
if options[:project_join]
|
||||
joins << options[:project_join]
|
||||
elsif options[:project] || !options[:without_projects]
|
||||
joins << "JOIN #{PROJECT_TABLE_NAME} ON #{table_name}.project_id = #{PROJECT_TABLE_NAME}.id"
|
||||
end
|
||||
|
||||
joins
|
||||
end
|
||||
|
||||
def self.tag_access(permission)
|
||||
projects_allowed = if permission.nil?
|
||||
Project.visible.pluck(:id)
|
||||
else
|
||||
Project.where(Project.allowed_to_condition(User.current, permission)).pluck(:id)
|
||||
end
|
||||
|
||||
if projects_allowed.present?
|
||||
"#{PROJECT_TABLE_NAME}.id IN (#{projects_allowed.join(',')})" unless projects_allowed.empty?
|
||||
else
|
||||
'1=0'
|
||||
end
|
||||
end
|
||||
|
||||
def self.remove_unused_tags
|
||||
unused = RedmineCrm::Tag.find_by_sql(<<-SQL)
|
||||
SELECT * FROM tags WHERE id NOT IN (
|
||||
SELECT DISTINCT tag_id FROM taggings
|
||||
)
|
||||
SQL
|
||||
unused.each(&:destroy)
|
||||
end
|
||||
|
||||
def self.sql_for_tags_field(klass, operator, value)
|
||||
compare = operator.eql?('=') ? 'IN' : 'NOT IN'
|
||||
ids_list = klass.tagged_with(value).collect(&:id).push(0).join(',')
|
||||
"( #{klass.table_name}.id #{compare} (#{ids_list}) ) "
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue