redmine_extensions 0.1.27 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|