redmine_extensions 0.1.27 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/easy_settings_controller.rb +24 -19
- data/app/models/easy_setting.rb +144 -35
- data/app/presenters/redmine_extensions/easy_setting_presenter.rb +18 -1
- data/app/views/easy_settings/edit.html.erb +2 -2
- data/lib/redmine_extensions/easy_settings.rb +8 -0
- data/lib/redmine_extensions/easy_settings/form_model.rb +39 -0
- data/lib/redmine_extensions/easy_settings/key.rb +113 -0
- data/lib/redmine_extensions/easy_settings/key_dsl.rb +44 -0
- data/lib/redmine_extensions/easy_settings/mapper.rb +87 -0
- data/lib/redmine_extensions/easy_settings/params_wrapper.rb +82 -0
- data/lib/redmine_extensions/redmine_patches/controllers/application_controller_patch.rb +10 -0
- data/lib/redmine_extensions/version.rb +1 -1
- metadata +14 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8cb8428973f6c3353ad74154a7e78037c8e368e
|
4
|
+
data.tar.gz: 83333323c82696c521141ba162396926da14e9d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab40411071438c646db1a43352981b6c0761fc00d9836d8de6d68f6155143df67b7b48a25b8a464f561c8e6feef997d211c77abb7f2ae5dddb2c664806d2fa09
|
7
|
+
data.tar.gz: 9f6334ced28ff923275659a8ce4ca113cf0d911580441f8e9f198acbdde69f4f095738610b929d57aaeda809a17369926771ab267cab5e637c3020bb072d7284
|
@@ -1,10 +1,10 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
#
|
2
|
+
# For now edit and update actions are for a plugin settings
|
3
|
+
#
|
3
4
|
class EasySettingsController < ApplicationController
|
4
5
|
|
5
6
|
before_filter :require_admin, only: [:edit, :update]
|
6
7
|
before_filter :find_optional_project
|
7
|
-
before_filter :prepare_presenter
|
8
8
|
before_filter :find_plugin, only: [:edit, :update]
|
9
9
|
|
10
10
|
def new
|
@@ -19,36 +19,41 @@ class EasySettingsController < ApplicationController
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def edit
|
22
|
-
@settings = Setting.send
|
22
|
+
@settings = Setting.send("plugin_#{@plugin.id}")
|
23
|
+
@easy_settings = EasySettings::FormModel.new(prefix: @plugin.id, project: @project)
|
23
24
|
end
|
24
25
|
|
25
26
|
def update
|
26
|
-
|
27
|
-
|
28
|
-
flash[:notice] = l(:notice_successful_update)
|
29
|
-
redirect_back_or_default edit_easy_setting_path(@easy_settings)
|
30
|
-
else
|
31
|
-
render :edit
|
27
|
+
if params[:settings]
|
28
|
+
Setting.send("plugin_#{@plugin.id}=", params[:settings])
|
32
29
|
end
|
30
|
+
|
31
|
+
if params[:easy_setting]
|
32
|
+
@easy_settings = EasySettings::ParamsWrapper.from_params(params[:easy_setting], project: @project, prefix: @plugin.id)
|
33
|
+
|
34
|
+
if @easy_settings.save
|
35
|
+
# All good
|
36
|
+
else
|
37
|
+
render :edit
|
38
|
+
return
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
flash[:notice] = l(:notice_successful_update)
|
43
|
+
redirect_back_or_default edit_easy_setting_path(@plugin.id)
|
33
44
|
end
|
34
45
|
|
35
46
|
private
|
36
|
-
def find_optional_project
|
37
|
-
@project = Project.find(params[:project_id]) unless params[:project_id].blank?
|
38
|
-
end
|
39
47
|
|
40
|
-
def
|
41
|
-
@
|
48
|
+
def find_optional_project
|
49
|
+
@project = Project.find_by(id: params[:project_id]) if params[:project_id].present?
|
42
50
|
end
|
43
51
|
|
44
52
|
def find_plugin
|
45
53
|
@plugin = Redmine::Plugin.find(params[:id])
|
46
|
-
|
47
54
|
return render_404 unless @plugin.settings.is_a?(Hash)
|
48
|
-
|
49
|
-
@easy_settings.plugin = @plugin
|
50
|
-
|
51
55
|
rescue Redmine::PluginNotFound
|
52
56
|
render_404
|
53
57
|
end
|
58
|
+
|
54
59
|
end
|
data/app/models/easy_setting.rb
CHANGED
@@ -1,15 +1,120 @@
|
|
1
|
+
require 'redmine_extensions/easy_settings'
|
2
|
+
|
3
|
+
##
|
4
|
+
# EasySetting
|
5
|
+
#
|
6
|
+
# == Mapping
|
7
|
+
# type::
|
8
|
+
# boolean, integer, float
|
9
|
+
# (default: none)
|
10
|
+
#
|
11
|
+
# default::
|
12
|
+
# (default: nil)
|
13
|
+
#
|
14
|
+
# disabled_from_params::
|
15
|
+
# (default: false)
|
16
|
+
#
|
17
|
+
# skip_blank_params::
|
18
|
+
# (default: false)
|
19
|
+
#
|
20
|
+
# from_params::
|
21
|
+
# Accept block or lambda with one argument for raw_value. Evaluated in EasySetting instance.
|
22
|
+
# (default: none)
|
23
|
+
#
|
24
|
+
# validate::
|
25
|
+
# Accept block or lambda. Evaluated in EasySetting instance.
|
26
|
+
# (default: none)
|
27
|
+
#
|
28
|
+
# after_save::
|
29
|
+
# Accept block or lambda. Evaluated in EasySetting instance.
|
30
|
+
# (default: none)
|
31
|
+
#
|
32
|
+
# == Mapping examples
|
33
|
+
#
|
34
|
+
# EasySetting.map do
|
35
|
+
#
|
36
|
+
# # Integer key
|
37
|
+
# key :integer_key do
|
38
|
+
# type 'integer'
|
39
|
+
# default 42
|
40
|
+
#
|
41
|
+
# validate { errors.add(:value, 'Bad range') if value < 0 || value > 500 }
|
42
|
+
# after_save { Mailer.integer_key_changed }
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # Custom definition
|
46
|
+
# key :custom_key do
|
47
|
+
# default 'Ondra'
|
48
|
+
# from_params lambda {|v| v.to_s }
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# # Cannot be changed via params
|
52
|
+
# key :not_from_params do
|
53
|
+
# default 'Ondra'
|
54
|
+
# disabled_from_params
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# # Boolean key definition
|
60
|
+
# EasySetting.map.key(:boolean_key, type: 'boolean')
|
61
|
+
#
|
62
|
+
# # Multiple defintions
|
63
|
+
# EasySetting.map.keys(:key1, :key2, :key3, disabled_from_params: true)
|
64
|
+
#
|
1
65
|
class EasySetting < ActiveRecord::Base
|
2
66
|
|
3
67
|
belongs_to :project
|
4
68
|
|
5
|
-
|
6
|
-
|
7
|
-
validates :name, :presence => true
|
8
|
-
attr_protected :id
|
69
|
+
validates :name, presence: true
|
70
|
+
validate :mapper_validate
|
9
71
|
|
10
72
|
after_save :update_cache
|
73
|
+
after_save :mapper_after_save
|
11
74
|
after_destroy :invalidate_cache
|
12
75
|
|
76
|
+
attr_protected :id
|
77
|
+
serialize :value
|
78
|
+
|
79
|
+
@@mapper = EasySettings::Mapper.new
|
80
|
+
|
81
|
+
def self.map(&block)
|
82
|
+
if block_given?
|
83
|
+
@@mapper.instance_eval(&block)
|
84
|
+
else
|
85
|
+
@@mapper
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.mapper_defaults
|
90
|
+
@mapper_defaults ||= @@mapper.default_values
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.mapper_clear_caches
|
94
|
+
@mapper_defaults = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def mapper_after_save
|
98
|
+
@@mapper.after_save(self)
|
99
|
+
end
|
100
|
+
|
101
|
+
def mapper_validate
|
102
|
+
@@mapper.validate(self)
|
103
|
+
end
|
104
|
+
|
105
|
+
def from_params(raw_value)
|
106
|
+
return if disabled_from_params?
|
107
|
+
self.value = @@mapper.from_params(self, raw_value)
|
108
|
+
end
|
109
|
+
|
110
|
+
def disabled_from_params?
|
111
|
+
@@mapper.disabled_from_params?(self)
|
112
|
+
end
|
113
|
+
|
114
|
+
def skip_blank_params?
|
115
|
+
@@mapper.skip_blank_params?(self)
|
116
|
+
end
|
117
|
+
|
13
118
|
def self.boolean_keys
|
14
119
|
[]
|
15
120
|
end
|
@@ -18,8 +123,8 @@ class EasySetting < ActiveRecord::Base
|
|
18
123
|
source_project = source_project.id if source_project.is_a?(Project)
|
19
124
|
target_project = target_project.id if target_project.is_a?(Project)
|
20
125
|
|
21
|
-
options = {:
|
22
|
-
Redmine::Hook.call_hook(:copy_all_project_settings_exceceptions, :
|
126
|
+
options = { scope: EasySetting.where(project_id: source_project) }
|
127
|
+
Redmine::Hook.call_hook(:copy_all_project_settings_exceceptions, options: options)
|
23
128
|
source_project_names = options[:scope].pluck(:name)
|
24
129
|
|
25
130
|
source_project_names.each do |name|
|
@@ -28,13 +133,13 @@ class EasySetting < ActiveRecord::Base
|
|
28
133
|
end
|
29
134
|
|
30
135
|
def self.copy_project_settings(setting_name, source_project_id, target_project_id)
|
31
|
-
source = EasySetting.where(:
|
32
|
-
target = EasySetting.where(:
|
136
|
+
source = EasySetting.where(name: setting_name, project_id: source_project_id).first
|
137
|
+
target = EasySetting.where(name: setting_name, project_id: target_project_id).first
|
33
138
|
|
34
139
|
if source.nil? && !target.nil?
|
35
140
|
target.destroy
|
36
141
|
elsif !source.nil? && target.nil?
|
37
|
-
EasySetting.create(:
|
142
|
+
EasySetting.create(name: setting_name, project_id: target_project_id, value: source.value)
|
38
143
|
elsif !source.nil? && !target.nil? && target.value != source.value
|
39
144
|
target.value = source.value
|
40
145
|
target.save
|
@@ -52,45 +157,47 @@ class EasySetting < ActiveRecord::Base
|
|
52
157
|
end
|
53
158
|
end
|
54
159
|
|
55
|
-
def self.value(key,
|
56
|
-
if
|
57
|
-
project_id =
|
58
|
-
elsif
|
59
|
-
project_id =
|
160
|
+
def self.value(key, project = nil, use_fallback = true)
|
161
|
+
if project.is_a?(Project)
|
162
|
+
project_id = project.id
|
163
|
+
elsif project.present?
|
164
|
+
project_id = project.to_i
|
60
165
|
else
|
61
166
|
project_id = nil
|
62
167
|
end
|
63
168
|
|
64
|
-
cache_key =
|
169
|
+
cache_key = "EasySetting/#{key}/#{project_id}"
|
65
170
|
fallback_cache_key = "EasySetting/#{key}/"
|
66
171
|
|
67
|
-
|
68
|
-
EasySetting.where(name: key, project_id: project_id).pluck(:value).first
|
172
|
+
result = Rails.cache.fetch(cache_key) do
|
173
|
+
EasySetting.where(name: key, project_id: project_id).limit(1).pluck(:value).first
|
69
174
|
end
|
70
175
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
else
|
76
|
-
cached_value
|
176
|
+
if use_fallback && result.blank?
|
177
|
+
result = Rails.cache.fetch(fallback_cache_key) do
|
178
|
+
EasySetting.where(name: key, project_id: nil).limit(1).pluck(:value).first
|
77
179
|
end
|
180
|
+
end
|
181
|
+
|
78
182
|
result = plugin_defaults[key.to_s] if result.nil?
|
183
|
+
result = mapper_defaults[key.to_s] if result.nil?
|
79
184
|
result
|
80
185
|
end
|
81
186
|
|
82
|
-
def self.delete_key(key,
|
83
|
-
if
|
84
|
-
project_id =
|
85
|
-
elsif
|
86
|
-
project_id =
|
187
|
+
def self.delete_key(key, project)
|
188
|
+
if project.is_a?(Project)
|
189
|
+
project_id = project.id
|
190
|
+
elsif project.present?
|
191
|
+
project_id = project.to_i
|
87
192
|
else
|
88
193
|
project_id = nil
|
89
194
|
end
|
195
|
+
|
90
196
|
return if project_id.nil?
|
91
|
-
EasySetting.where(:
|
197
|
+
EasySetting.where(name: key, project_id: project_id).destroy_all
|
92
198
|
end
|
93
199
|
|
200
|
+
# TODO: Move away
|
94
201
|
def self.get_beginning_of_fiscal_for_year(year = nil)
|
95
202
|
f_y = year || Date.today.year
|
96
203
|
f_m = (EasySetting.value('fiscal_month') || 1).to_i
|
@@ -103,6 +210,7 @@ class EasySetting < ActiveRecord::Base
|
|
103
210
|
end
|
104
211
|
end
|
105
212
|
|
213
|
+
# TODO: Move away
|
106
214
|
def self.beginning_of_fiscal_year(date = nil)
|
107
215
|
today = date || Date.today
|
108
216
|
fy = get_beginning_of_fiscal_for_year(today.year)
|
@@ -114,18 +222,19 @@ class EasySetting < ActiveRecord::Base
|
|
114
222
|
end
|
115
223
|
end
|
116
224
|
|
225
|
+
# TODO: Move away
|
117
226
|
def self.end_of_fiscal_year(date = nil)
|
118
227
|
beginning_of_fiscal_year(date) + 1.year - 1.day
|
119
228
|
end
|
120
229
|
|
121
230
|
private
|
122
231
|
|
123
|
-
|
124
|
-
|
125
|
-
|
232
|
+
def invalidate_cache
|
233
|
+
Rails.cache.delete("EasySetting/#{name}/#{project_id}")
|
234
|
+
end
|
126
235
|
|
127
|
-
|
128
|
-
|
129
|
-
|
236
|
+
def update_cache
|
237
|
+
Rails.cache.write("EasySetting/#{name}/#{project_id}", value)
|
238
|
+
end
|
130
239
|
|
131
240
|
end
|
@@ -4,10 +4,12 @@ module RedmineExtensions
|
|
4
4
|
attr_accessor :project_id, :plugin
|
5
5
|
|
6
6
|
def self.boolean_keys
|
7
|
-
@boolean_keys ||=
|
7
|
+
@boolean_keys ||= BooleanKeysAlsoToMapperKey.new
|
8
8
|
end
|
9
9
|
|
10
10
|
def initialize(settings_params={}, project = nil)
|
11
|
+
ActiveSupport::Deprecation.warn('RedmineExtensions::EasySettingPresenter is deprecated in favor of EasySettings::ParamsWrapper.')
|
12
|
+
|
11
13
|
@settings = settings_params || {}
|
12
14
|
@settings = @settings.dup.symbolize_keys
|
13
15
|
self.project = project
|
@@ -124,5 +126,20 @@ module RedmineExtensions
|
|
124
126
|
end
|
125
127
|
end
|
126
128
|
|
129
|
+
# To keep backward compatibility with old presenter
|
130
|
+
class BooleanKeysAlsoToMapperKey < Array
|
131
|
+
|
132
|
+
def <<(key)
|
133
|
+
EasySetting.map.key(key, type: 'boolean')
|
134
|
+
super
|
135
|
+
end
|
136
|
+
|
137
|
+
def concat(keys)
|
138
|
+
EasySetting.map.keys(*keys, type: 'boolean')
|
139
|
+
super
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
127
144
|
end
|
128
145
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
<%= form_for(@easy_settings, html: { class: 'form-box easy-setting-plugin-form' }) do |f| %>
|
1
|
+
<%= form_for(@easy_settings, url: easy_setting_path(@plugin.id), html: { class: 'form-box easy-setting-plugin-form' }) do |f| %>
|
2
2
|
<%= hidden_field_tag :back_url, params[:back_url] %>
|
3
3
|
|
4
|
-
<%= render "easy_settings/#{@
|
4
|
+
<%= render "easy_settings/#{@plugin.id}", easy_settings: @easy_settings, settings: @settings, form: f %>
|
5
5
|
|
6
6
|
<div class="form-actions">
|
7
7
|
<%= f.submit l(:button_update_easy_settings), class: 'button-1' %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module EasySettings
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'redmine_extensions/easy_settings/key'
|
5
|
+
require 'redmine_extensions/easy_settings/key_dsl'
|
6
|
+
require 'redmine_extensions/easy_settings/mapper'
|
7
|
+
require 'redmine_extensions/easy_settings/form_model'
|
8
|
+
require 'redmine_extensions/easy_settings/params_wrapper'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module EasySettings
|
2
|
+
##
|
3
|
+
# EasySettings::FormModel
|
4
|
+
#
|
5
|
+
# Fake models/proxy for easy seettings. Usable in rails form.
|
6
|
+
#
|
7
|
+
# settings = EasySettings::FormModel.new(prefix: 'easy_gantt')
|
8
|
+
# settings.show_holidays == EasySetting.value(:easy_gantt_show_holidays)
|
9
|
+
#
|
10
|
+
class FormModel
|
11
|
+
|
12
|
+
def initialize(prefix: nil, project: nil)
|
13
|
+
@prefix = "#{prefix}_" if prefix.present?
|
14
|
+
@project_id = project.is_a?(Project) ? project.id : project
|
15
|
+
end
|
16
|
+
|
17
|
+
def model_name
|
18
|
+
EasySetting.model_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def persisted?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_model
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Called for missing :id parameter
|
30
|
+
#
|
31
|
+
# def to_param
|
32
|
+
# end
|
33
|
+
|
34
|
+
def method_missing(name, *args)
|
35
|
+
EasySetting.value("#{@prefix}#{name}", @project_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module EasySettings
|
2
|
+
##
|
3
|
+
# EasySettings::Key
|
4
|
+
#
|
5
|
+
# Definition of easy setting key
|
6
|
+
#
|
7
|
+
class Key
|
8
|
+
|
9
|
+
attr_reader :name, :options
|
10
|
+
|
11
|
+
def self.init(name, **options)
|
12
|
+
key_class =
|
13
|
+
case options[:type].to_s
|
14
|
+
when 'boolean', 'bool'
|
15
|
+
BooleanKey
|
16
|
+
when 'integer', 'int'
|
17
|
+
IntegerKey
|
18
|
+
when 'float'
|
19
|
+
FloatKey
|
20
|
+
else
|
21
|
+
Key
|
22
|
+
end
|
23
|
+
|
24
|
+
key_class.new(name, options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(name, **options)
|
28
|
+
@name = name
|
29
|
+
@options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
def default
|
33
|
+
@options[:default]
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate(easy_setting)
|
37
|
+
if options[:validate].is_a?(Proc)
|
38
|
+
easy_setting.instance_eval(&options[:validate])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def after_save(easy_setting)
|
43
|
+
if options[:after_save].is_a?(Proc)
|
44
|
+
easy_setting.instance_eval(&options[:after_save])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def from_params(easy_setting, value)
|
49
|
+
if options[:from_params].is_a?(Proc)
|
50
|
+
easy_setting.instance_exec(value, &options[:from_params])
|
51
|
+
else
|
52
|
+
value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def disabled_from_params?
|
57
|
+
!!options[:disabled_from_params]
|
58
|
+
end
|
59
|
+
|
60
|
+
def skip_blank_params?
|
61
|
+
!!options[:skip_blank_params]
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class BooleanKey < Key
|
67
|
+
|
68
|
+
def from_params(easy_setting, value)
|
69
|
+
value.to_s.to_boolean
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate(easy_setting)
|
73
|
+
easy_setting.instance_eval do
|
74
|
+
if ![nil, true, false].include?(value)
|
75
|
+
errors.add(:base, "#{name} must be boolean")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
class IntegerKey < Key
|
83
|
+
|
84
|
+
def from_params(easy_setting, value)
|
85
|
+
value.try(:to_i)
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate(easy_setting)
|
89
|
+
easy_setting.instance_eval do
|
90
|
+
if !value.nil? && !value.is_a?(Integer)
|
91
|
+
errors.add(:base, "#{name} must be inetger")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class FloatKey < Key
|
99
|
+
|
100
|
+
def from_params(easy_setting, value)
|
101
|
+
value.try(:to_f)
|
102
|
+
end
|
103
|
+
|
104
|
+
def validate(easy_setting)
|
105
|
+
easy_setting.instance_eval do
|
106
|
+
if !value.nil? && !value.is_a?(Float)
|
107
|
+
errors.add(:base, "#{name} must be float")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module EasySettings
|
2
|
+
##
|
3
|
+
# EasySettings::KeyDSL
|
4
|
+
#
|
5
|
+
# For a comfortable way how to set new key via DSL
|
6
|
+
#
|
7
|
+
class KeyDSL
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def type(new_type)
|
16
|
+
@options[:type] = new_type
|
17
|
+
end
|
18
|
+
|
19
|
+
def default(new_default)
|
20
|
+
@options[:default] = new_default
|
21
|
+
end
|
22
|
+
|
23
|
+
def disabled_from_params
|
24
|
+
@options[:disabled_from_params] = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def skip_blank_params
|
28
|
+
@options[:skip_blank_params] = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_params(func=nil, &block)
|
32
|
+
@options[:from_params] = func || block
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate(func=nil, &block)
|
36
|
+
@options[:validate] = func || block
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_save(func=nil, &block)
|
40
|
+
@options[:after_save] = func || block
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module EasySettings
|
2
|
+
class Mapper
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@all_keys = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
# Be careful for double definition of the same key
|
9
|
+
# Last definition wins
|
10
|
+
def key(name, **options, &block)
|
11
|
+
name = name.to_s
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
key_dsl = EasySettings::KeyDSL.new
|
15
|
+
key_dsl.instance_eval(&block)
|
16
|
+
options = options.merge(key_dsl.options)
|
17
|
+
end
|
18
|
+
|
19
|
+
EasySetting.mapper_clear_caches
|
20
|
+
@all_keys[name] = EasySettings::Key.init(name, options)
|
21
|
+
end
|
22
|
+
alias_method :add_key, :key
|
23
|
+
|
24
|
+
def keys(*names, **options, &block)
|
25
|
+
names.each do |name|
|
26
|
+
key(name, options, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method :add_keys, :keys
|
30
|
+
|
31
|
+
# Shortcust due to frequent usage
|
32
|
+
def boolean_keys(*names)
|
33
|
+
names.each do |name|
|
34
|
+
key(name, type: 'boolean')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def default_values
|
39
|
+
values = {}
|
40
|
+
@all_keys.each do |name, key|
|
41
|
+
values[name] = key.default
|
42
|
+
end
|
43
|
+
values
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate(easy_setting)
|
47
|
+
if @all_keys.has_key?(easy_setting.name)
|
48
|
+
@all_keys[easy_setting.name].validate(easy_setting)
|
49
|
+
else
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def after_save(easy_setting)
|
55
|
+
if @all_keys.has_key?(easy_setting.name)
|
56
|
+
@all_keys[easy_setting.name].after_save(easy_setting)
|
57
|
+
else
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def from_params(easy_setting, value)
|
63
|
+
if @all_keys.has_key?(easy_setting.name)
|
64
|
+
@all_keys[easy_setting.name].from_params(easy_setting, value)
|
65
|
+
else
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def disabled_from_params?(easy_setting)
|
71
|
+
if @all_keys.has_key?(easy_setting.name)
|
72
|
+
@all_keys[easy_setting.name].disabled_from_params?
|
73
|
+
else
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def skip_blank_params?(easy_setting)
|
79
|
+
if @all_keys.has_key?(easy_setting.name)
|
80
|
+
@all_keys[easy_setting.name].skip_blank_params?
|
81
|
+
else
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module EasySettings
|
2
|
+
class ParamsWrapper
|
3
|
+
|
4
|
+
attr_reader :errors
|
5
|
+
|
6
|
+
def self.from_params(raw_params, project: nil, prefix: nil)
|
7
|
+
if !raw_params.is_a?(Hash) && !raw_params.is_a?(ActionController::Parameters)
|
8
|
+
raw_params = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
new(raw_params, project, prefix)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(raw_params, project, prefix)
|
15
|
+
@raw_params = raw_params
|
16
|
+
@project_id = project.is_a?(Project) ? project.id : project
|
17
|
+
@prefix = "#{prefix}_" if prefix.present?
|
18
|
+
@errors = []
|
19
|
+
|
20
|
+
prepare_params
|
21
|
+
prepare_easy_settings
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid?
|
25
|
+
validate
|
26
|
+
@errors.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def save
|
30
|
+
@errors.clear
|
31
|
+
|
32
|
+
@easy_settings.each do |setting|
|
33
|
+
# TO CONSIDER: Should this line exist?
|
34
|
+
# This skip callbacks after saving
|
35
|
+
# setting but is it desirable?
|
36
|
+
next if !setting.changed?
|
37
|
+
|
38
|
+
if setting.save
|
39
|
+
# All good
|
40
|
+
else
|
41
|
+
@errors << [setting, setting.errors]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
@errors.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def prepare_params
|
51
|
+
@params = {}
|
52
|
+
@raw_params.each do |name, value|
|
53
|
+
@params["#{@prefix}#{name}"] = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_easy_settings
|
58
|
+
saved_settings = EasySetting.where(name: @params.keys, project_id: @project_id).map{|e| [e.name, e] }.to_h
|
59
|
+
|
60
|
+
@easy_settings = []
|
61
|
+
@params.each do |name, value|
|
62
|
+
setting = saved_settings[name]
|
63
|
+
setting ||= EasySetting.new(name: name, project_id: @project_id)
|
64
|
+
next if setting.disabled_from_params?
|
65
|
+
next if value.blank? && setting.skip_blank_params?
|
66
|
+
|
67
|
+
setting.from_params(value)
|
68
|
+
@easy_settings << setting
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate
|
73
|
+
@errors.clear
|
74
|
+
@easy_settings.each do |setting|
|
75
|
+
if !setting.valid?
|
76
|
+
@errors << [setting, setting.errors]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -27,6 +27,16 @@ module RedmineExtensions
|
|
27
27
|
self.class.easy_extensions?
|
28
28
|
end
|
29
29
|
|
30
|
+
private
|
31
|
+
|
32
|
+
def save_easy_settings(project = nil)
|
33
|
+
if params[:easy_setting].is_a?(Hash) || params[:easy_setting].is_a?(ActionController::Parameters)
|
34
|
+
wrapper = EasySettings::ParamsWrapper.from_params(params.delete(:easy_setting), project: project)
|
35
|
+
wrapper.save
|
36
|
+
wrapper
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
30
40
|
end
|
31
41
|
|
32
42
|
module ClassMethods
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redmine_extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Easy Software Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -218,6 +218,12 @@ files:
|
|
218
218
|
- lib/redmine_extensions/easy_form_builder.rb
|
219
219
|
- lib/redmine_extensions/easy_query_adapter.rb
|
220
220
|
- lib/redmine_extensions/easy_query_helpers/outputs.rb
|
221
|
+
- lib/redmine_extensions/easy_settings.rb
|
222
|
+
- lib/redmine_extensions/easy_settings/form_model.rb
|
223
|
+
- lib/redmine_extensions/easy_settings/key.rb
|
224
|
+
- lib/redmine_extensions/easy_settings/key_dsl.rb
|
225
|
+
- lib/redmine_extensions/easy_settings/mapper.rb
|
226
|
+
- lib/redmine_extensions/easy_settings/params_wrapper.rb
|
221
227
|
- lib/redmine_extensions/engine.rb
|
222
228
|
- lib/redmine_extensions/export/easy_other_formats_builder.rb
|
223
229
|
- lib/redmine_extensions/hooks.rb
|
@@ -276,16 +282,16 @@ specification_version: 4
|
|
276
282
|
summary: Redmine Extensions is set of usefull features for Redmine. Main focus is
|
277
283
|
on development helpers, but many users can find it helpfull
|
278
284
|
test_files:
|
279
|
-
- spec/presenters/redmine_extensions/easy_setting_presenter_spec.rb
|
280
285
|
- spec/rails_helper.rb
|
281
|
-
- spec/features/autocomplete_spec.rb
|
282
|
-
- spec/models/easy_setting_spec.rb
|
283
|
-
- spec/factories/issues.rb
|
284
286
|
- spec/factories/time_entries.rb
|
287
|
+
- spec/factories/easy_settings.rb
|
288
|
+
- spec/factories/issues.rb
|
289
|
+
- spec/factories/projects.rb
|
285
290
|
- spec/factories/trackers.rb
|
286
291
|
- spec/factories/easy_queries.rb
|
287
|
-
- spec/factories/projects.rb
|
288
292
|
- spec/factories/users.rb
|
289
|
-
- spec/
|
293
|
+
- spec/presenters/redmine_extensions/easy_setting_presenter_spec.rb
|
290
294
|
- spec/support/plugin_generator.rb
|
291
295
|
- spec/spec_helper.rb
|
296
|
+
- spec/models/easy_setting_spec.rb
|
297
|
+
- spec/features/autocomplete_spec.rb
|