Actualiza el plugin Additionals a 3.0.2-master
This commit is contained in:
parent
3b6a41320c
commit
cfa0d58b18
164 changed files with 2027 additions and 58190 deletions
|
@ -1,4 +1,5 @@
|
|||
class AdditionalsChart < ActiveRecord::Base
|
||||
class AdditionalsChart
|
||||
include ActiveRecord::Sanitization
|
||||
include Redmine::I18n
|
||||
|
||||
CHART_DEFAULT_HEIGHT = 350
|
||||
|
|
|
@ -6,7 +6,7 @@ class AdditionalsFontAwesome
|
|||
|
||||
class << self
|
||||
def load_icons(type)
|
||||
data = YAML.safe_load(ERB.new(IO.read(Rails.root.join('plugins/additionals/config/fontawesome_icons.yml'))).result) || {}
|
||||
data = YAML.safe_load(ERB.new(IO.read(File.join(Additionals.plugin_dir, '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))
|
||||
|
|
|
@ -31,7 +31,7 @@ class AdditionalsImport < Import
|
|||
next unless value
|
||||
|
||||
h[v.custom_field.id.to_s] =
|
||||
if value.is_a?(Array)
|
||||
if value.is_a? Array
|
||||
value.map { |val| v.custom_field.value_from_keyword(val.strip, object) }.flatten!&.compact
|
||||
else
|
||||
v.custom_field.value_from_keyword(value, object)
|
||||
|
|
73
plugins/additionals/app/models/additionals_info.rb
Normal file
73
plugins/additionals/app/models/additionals_info.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
class AdditionalsInfo
|
||||
include Redmine::I18n
|
||||
|
||||
class << self
|
||||
def system_infos
|
||||
{ system_info: { label: l(:label_system_info), value: system_info },
|
||||
system_uptime: { label: l(:label_uptime), value: system_uptime } }
|
||||
end
|
||||
|
||||
def system_info
|
||||
if windows_platform?
|
||||
win_info = `wmic os get Caption,CSDVersion,BuildNumber /value`
|
||||
return 'unknown' if win_info.blank?
|
||||
|
||||
windows_version = ''
|
||||
windows_build = ''
|
||||
build_names = %w[BuildNumber CSDVersion]
|
||||
win_info.split(/\n+/).each do |line|
|
||||
line_info = line.split '='
|
||||
if line_info[0] == 'Caption'
|
||||
windows_version = line_info[1]
|
||||
elsif build_names.include?(line_info[0]) && line_info[1]&.present?
|
||||
windows_build = line_info[1]
|
||||
end
|
||||
end
|
||||
"#{windows_version} build #{windows_build}"
|
||||
else
|
||||
`uname -a`
|
||||
end
|
||||
end
|
||||
|
||||
def system_uptime(format: :time_tag)
|
||||
if windows_platform?
|
||||
`net stats srv | find "Statist"`
|
||||
elsif File.exist? '/proc/uptime'
|
||||
secs = `cat /proc/uptime`.to_i
|
||||
min = 0
|
||||
hours = 0
|
||||
days = 0
|
||||
if secs.positive?
|
||||
min = (secs / 60).round
|
||||
hours = (secs / 3_600).round
|
||||
days = (secs / 86_400).round
|
||||
end
|
||||
if days >= 1
|
||||
"#{days} #{l(:days, count: days)}"
|
||||
elsif hours >= 1
|
||||
"#{hours} #{l(:hours, count: hours)}"
|
||||
else
|
||||
"#{min} #{l(:minutes, count: min)}"
|
||||
end
|
||||
else
|
||||
# this should be work on macOS
|
||||
seconds = `sysctl -n kern.boottime | awk '{print $4}'`.tr ',', ''
|
||||
so = DateTime.strptime seconds.strip, '%s'
|
||||
if so.present?
|
||||
if format == :datetime
|
||||
so
|
||||
else
|
||||
ApplicationController.helpers.time_tag so
|
||||
end
|
||||
else
|
||||
days = `uptime | awk '{print $3}'`.to_i.round
|
||||
"#{days} #{l(:days, count: days)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def windows_platform?
|
||||
/cygwin|mswin|mingw|bccwin|wince|emx/.match? RUBY_PLATFORM
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,6 +22,17 @@ module AdditionalsQuery
|
|||
sql.join(' AND ')
|
||||
end
|
||||
|
||||
def fix_sql_for_text_field(field, operator, value, table_name = nil, target_field = nil)
|
||||
table_name = queried_table_name if table_name.blank?
|
||||
target_field = field if target_field.blank?
|
||||
|
||||
sql = []
|
||||
sql << "(#{sql_for_field(field, operator, value, table_name, target_field)})"
|
||||
sql << "#{table_name}.#{target_field} != ''" if operator == '*'
|
||||
|
||||
sql.join(' AND ')
|
||||
end
|
||||
|
||||
def initialize_ids_filter(options = {})
|
||||
if options[:label]
|
||||
add_available_filter 'ids', type: :integer, label: options[:label]
|
||||
|
@ -44,30 +55,44 @@ module AdditionalsQuery
|
|||
end
|
||||
end
|
||||
|
||||
def sql_for_project_identifier_field(field, operator, values)
|
||||
value = values.first
|
||||
values = value.split(',').map(&:strip) if ['=', '!'].include?(operator) && value.include?(',')
|
||||
sql_for_field field, operator, values, Project.table_name, 'identifier'
|
||||
end
|
||||
|
||||
def sql_for_project_status_field(field, operator, value)
|
||||
sql_for_field field, operator, value, Project.table_name, 'status'
|
||||
end
|
||||
|
||||
def initialize_project_status_filter
|
||||
return if project&.leaf?
|
||||
def initialize_project_identifier_filter
|
||||
return if project
|
||||
|
||||
add_available_filter('project.status',
|
||||
add_available_filter 'project.identifier',
|
||||
type: :string,
|
||||
name: l(:label_attribute_of_project, name: l(:field_identifier))
|
||||
end
|
||||
|
||||
def initialize_project_status_filter
|
||||
return if project
|
||||
|
||||
add_available_filter 'project.status',
|
||||
type: :list,
|
||||
name: l(:label_attribute_of_project, name: l(:field_status)),
|
||||
values: -> { project_statuses_values })
|
||||
values: -> { project_statuses_values }
|
||||
end
|
||||
|
||||
def initialize_project_filter(options = {})
|
||||
if project.nil? || options[:always]
|
||||
add_available_filter('project_id', order: options[:position],
|
||||
add_available_filter 'project_id', order: options[:position],
|
||||
type: :list,
|
||||
values: -> { project_values })
|
||||
values: -> { project_values }
|
||||
end
|
||||
return if project.nil? || project.leaf? || subproject_values.empty?
|
||||
|
||||
add_available_filter('subproject_id', order: options[:position],
|
||||
add_available_filter 'subproject_id', order: options[:position],
|
||||
type: :list_subprojects,
|
||||
values: -> { subproject_values })
|
||||
values: -> { subproject_values }
|
||||
end
|
||||
|
||||
def initialize_created_filter(options = {})
|
||||
|
@ -83,16 +108,9 @@ module AdditionalsQuery
|
|||
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] }
|
||||
type: :list_optional,
|
||||
values: -> { tag_values(project) }
|
||||
end
|
||||
|
||||
def initialize_approved_filter
|
||||
|
@ -106,27 +124,35 @@ module AdditionalsQuery
|
|||
end
|
||||
|
||||
def initialize_author_filter(options = {})
|
||||
return if author_values.empty?
|
||||
|
||||
add_available_filter('author_id', order: options[:position],
|
||||
add_available_filter 'author_id', order: options[:position],
|
||||
type: :list_optional,
|
||||
values: options[:no_lambda].nil? ? author_values : -> { author_values })
|
||||
values: -> { author_values }
|
||||
end
|
||||
|
||||
def initialize_assignee_filter(options = {})
|
||||
return if author_values.empty?
|
||||
|
||||
add_available_filter('assigned_to_id', order: options[:position],
|
||||
add_available_filter 'assigned_to_id', order: options[:position],
|
||||
type: :list_optional,
|
||||
values: options[:no_lambda] ? assigned_to_all_values : -> { assigned_to_all_values })
|
||||
values: -> { assigned_to_all_values }
|
||||
end
|
||||
|
||||
def initialize_watcher_filter(options = {})
|
||||
return if watcher_values.empty? || !User.current.logged?
|
||||
return unless User.current.logged?
|
||||
|
||||
add_available_filter('watcher_id', order: options[:position],
|
||||
add_available_filter 'watcher_id', order: options[:position],
|
||||
type: :list,
|
||||
values: options[:no_lambda] ? watcher_values : -> { watcher_values })
|
||||
values: -> { watcher_values }
|
||||
end
|
||||
|
||||
def tag_values(project)
|
||||
values = if project
|
||||
queried_class.available_tags project: project.id
|
||||
else
|
||||
queried_class.available_tags
|
||||
end
|
||||
|
||||
return [] if values.blank?
|
||||
|
||||
values.collect { |t| [t.name, t.name] }
|
||||
end
|
||||
|
||||
# issue independend values. Use assigned_to_values from Redmine, if you want it only for issues
|
||||
|
@ -154,7 +180,7 @@ module AdditionalsQuery
|
|||
end
|
||||
|
||||
def sql_for_tags_field(field, _operator, value)
|
||||
AdditionalsTag.sql_for_tags_field(queried_class, operator_for(field), value)
|
||||
AdditionalTags.sql_for_tags_field queried_class, operator_for(field), value
|
||||
end
|
||||
|
||||
def sql_for_is_private_field(_field, operator, value)
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
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
|
||||
|
||||
class << self
|
||||
def all_type_tags(klass, options = {})
|
||||
RedmineCrm::Tag.where({})
|
||||
.joins(tag_joins(klass, options))
|
||||
.distinct
|
||||
.order("#{TAG_TABLE_NAME}.name")
|
||||
end
|
||||
|
||||
def 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.select("#{TAG_TABLE_NAME}.*, COUNT(DISTINCT #{TAGGING_TABLE_NAME}.taggable_id) AS count")
|
||||
.joins(tag_joins(klass, options))
|
||||
.group("#{TAG_TABLE_NAME}.id, #{TAG_TABLE_NAME}.name").having('COUNT(*) > 0')
|
||||
.order("#{TAG_TABLE_NAME}.name")
|
||||
end
|
||||
|
||||
def remove_unused_tags
|
||||
RedmineCrm::Tag.where.not(id: RedmineCrm::Tagging.select(:tag_id).distinct)
|
||||
.each(&:destroy)
|
||||
end
|
||||
|
||||
def 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
|
||||
|
||||
private
|
||||
|
||||
def tag_access(permission)
|
||||
projects_allowed = if permission.nil?
|
||||
Project.visible.ids
|
||||
else
|
||||
Project.where(Project.allowed_to_condition(User.current, permission)).ids
|
||||
end
|
||||
|
||||
if projects_allowed.present?
|
||||
"#{PROJECT_TABLE_NAME}.id IN (#{projects_allowed.join ','})" unless projects_allowed.empty?
|
||||
else
|
||||
'1=0'
|
||||
end
|
||||
end
|
||||
|
||||
def 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
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ class Dashboard < ActiveRecord::Base
|
|||
include Additionals::EntityMethods
|
||||
|
||||
class SystemDefaultChangeException < StandardError; end
|
||||
|
||||
class ProjectSystemDefaultChangeException < StandardError; end
|
||||
|
||||
belongs_to :project
|
||||
|
@ -302,7 +303,10 @@ class Dashboard < ActiveRecord::Base
|
|||
config = { dashboard_id: id,
|
||||
block: block }
|
||||
|
||||
settings[:user_id] = User.current.id if !options.key?(:skip_user_id) || !options[:skip_user_id]
|
||||
if !options.key?(:skip_user_id) || !options[:skip_user_id]
|
||||
settings[:user_id] = User.current.id
|
||||
settings[:user_is_admin] = User.current.admin?
|
||||
end
|
||||
|
||||
if settings.present?
|
||||
settings.each do |key, setting|
|
||||
|
@ -321,11 +325,11 @@ class Dashboard < ActiveRecord::Base
|
|||
unique_params = settings.flatten
|
||||
unique_params += options[:unique_params].reject(&:blank?) if options[:unique_params].present?
|
||||
|
||||
Rails.logger.debug "debug async_params for #{block}: unique_params=#{unique_params.inspect}"
|
||||
# Rails.logger.debug "debug async_params for #{block}: unique_params=#{unique_params.inspect}"
|
||||
config[:unique_key] = Digest::SHA256.hexdigest(unique_params.join('_'))
|
||||
end
|
||||
|
||||
Rails.logger.debug "debug async_params for #{block}: config=#{config.inspect}"
|
||||
# Rails.logger.debug "debug async_params for #{block}: config=#{config.inspect}"
|
||||
|
||||
config
|
||||
end
|
||||
|
@ -358,7 +362,10 @@ class Dashboard < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def validate_system_default
|
||||
return if new_record? || system_default_was == system_default || system_default?
|
||||
return if new_record? ||
|
||||
system_default_was == system_default ||
|
||||
system_default? ||
|
||||
project_id.present?
|
||||
|
||||
raise SystemDefaultChangeException
|
||||
end
|
||||
|
|
|
@ -41,9 +41,13 @@ class DashboardContent
|
|||
with_project: true
|
||||
},
|
||||
max_occurs: DashboardContent::MAX_MULTIPLE_OCCURS },
|
||||
'text' => { label: l(:label_text),
|
||||
'text' => { label: l(:label_text_sync),
|
||||
max_occurs: MAX_MULTIPLE_OCCURS,
|
||||
partial: 'dashboards/blocks/text' },
|
||||
'text_async' => { label: l(:label_text_async),
|
||||
max_occurs: MAX_MULTIPLE_OCCURS,
|
||||
async: { required_settings: %i[text],
|
||||
partial: 'dashboards/blocks/text_async' } },
|
||||
'news' => { label: l(:label_news_latest),
|
||||
permission: :view_news },
|
||||
'documents' => { label: l(:label_document_plural),
|
||||
|
|
|
@ -3,4 +3,7 @@ class DashboardRole < ActiveRecord::Base
|
|||
|
||||
belongs_to :dashboard
|
||||
belongs_to :role
|
||||
|
||||
validates :dashboard, :role,
|
||||
presence: true
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue