thecore_settings 1.1.15 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +20 -0
  3. data/.devcontainer/devcontainer.json +33 -0
  4. data/.github/workflows/gempush.yml +34 -0
  5. data/.gitignore +542 -0
  6. data/.rakeTasks +7 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.travis.yml +31 -0
  10. data/CHANGELOG.md +81 -0
  11. data/Gemfile +4 -0
  12. data/Gemfile.lock +275 -0
  13. data/LICENSE.txt +22 -0
  14. data/README.md +169 -0
  15. data/README.rdoc +68 -0
  16. data/Rakefile +6 -34
  17. data/app/assets/images/thecore_settings/.keep +0 -0
  18. data/app/assets/javascripts/thecore_settings/.keep +0 -0
  19. data/app/assets/stylesheets/thecore_settings/.keep +0 -0
  20. data/app/controllers/.keep +0 -0
  21. data/app/helpers/.keep +0 -0
  22. data/app/mailers/.keep +0 -0
  23. data/app/models/.keep +0 -0
  24. data/app/models/rails_admin_settings/setting.rb +77 -0
  25. data/app/views/.keep +0 -0
  26. data/app/views/rails_admin/main/_setting_value.html.haml +41 -0
  27. data/assets/javascripts/rails_admin/custom/thecore_settings.rb +2 -0
  28. data/bin/rails +13 -0
  29. data/config/locales/en.yml +29 -0
  30. data/config/locales/pt-BR.yml +28 -0
  31. data/config/locales/ru.yml +29 -0
  32. data/gemfiles/mongoid-6.0.gemfile +5 -0
  33. data/gemfiles/mongoid-6.3.gemfile +5 -0
  34. data/lib/generators/rails_admin_settings/migration_generator.rb +15 -0
  35. data/lib/generators/rails_admin_settings/templates/db/migrate/20161227101954_create_thecore_settings.rb +29 -0
  36. data/lib/generators/rails_admin_settings/templates/migration.rb +29 -0
  37. data/lib/thecore_settings/determine_mime_type.rb +193 -0
  38. data/lib/thecore_settings/dumper.rb +12 -0
  39. data/lib/thecore_settings/engine.rb +17 -3
  40. data/lib/thecore_settings/fallback.rb +21 -0
  41. data/lib/thecore_settings/hex_color_validator.rb +11 -0
  42. data/lib/thecore_settings/kinds.rb +34 -0
  43. data/lib/thecore_settings/mongoid.rb +19 -0
  44. data/lib/thecore_settings/namespaced.rb +210 -0
  45. data/lib/thecore_settings/processing.rb +217 -0
  46. data/lib/thecore_settings/rails_admin_config.rb +71 -0
  47. data/lib/thecore_settings/require_helpers.rb +86 -0
  48. data/lib/thecore_settings/settings.rb +95 -0
  49. data/lib/thecore_settings/storage/carrier_wave_uploader.rb +9 -0
  50. data/lib/thecore_settings/storage/shrine_uploader.rb +14 -0
  51. data/lib/thecore_settings/tasks.rb +35 -0
  52. data/lib/thecore_settings/uploads.rb +57 -0
  53. data/lib/thecore_settings/validation.rb +126 -0
  54. data/lib/thecore_settings/version.rb +1 -1
  55. data/lib/thecore_settings.rb +115 -123
  56. data/log/development.log +0 -0
  57. data/spec/advanced_usage_spec.rb +11 -0
  58. data/spec/carrierwave_spec.rb +41 -0
  59. data/spec/database_trickery_spec.rb +48 -0
  60. data/spec/defaults_spec.rb +87 -0
  61. data/spec/enabling_spec.rb +29 -0
  62. data/spec/factories/setting.rb +8 -0
  63. data/spec/label_spec.rb +16 -0
  64. data/spec/migration_spec.rb +20 -0
  65. data/spec/model_spec.rb +105 -0
  66. data/spec/namespaced_spec.rb +67 -0
  67. data/spec/paperclip_spec.rb +38 -0
  68. data/spec/settings_spec.rb +75 -0
  69. data/spec/shrine_spec.rb +34 -0
  70. data/spec/spec_helper.rb +85 -0
  71. data/spec/support/1024x768.gif +0 -0
  72. data/spec/support/database_cleaner.rb +10 -0
  73. data/spec/support/defaults.yml +23 -0
  74. data/spec/support/defaults_w_file.yml +19 -0
  75. data/spec/support/mongoid.rb +6 -0
  76. data/spec/support/mongoid.yml +6 -0
  77. data/spec/types_spec.rb +101 -0
  78. data/test/dummy/Rakefile +6 -0
  79. data/test/dummy/app/assets/config/manifest.js +4 -0
  80. data/test/dummy/app/assets/images/.keep +0 -0
  81. data/test/dummy/app/assets/javascripts/application.js +13 -0
  82. data/test/dummy/app/assets/javascripts/cable.js +13 -0
  83. data/test/dummy/app/assets/javascripts/channels/.keep +0 -0
  84. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  85. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  86. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  87. data/test/dummy/app/controllers/application_controller.rb +3 -0
  88. data/test/dummy/app/controllers/concerns/.keep +0 -0
  89. data/test/dummy/app/helpers/application_helper.rb +2 -0
  90. data/test/dummy/app/jobs/application_job.rb +2 -0
  91. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  92. data/test/dummy/app/models/application_record.rb +3 -0
  93. data/test/dummy/app/models/concerns/.keep +0 -0
  94. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  95. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  96. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  97. data/test/dummy/bin/bundle +3 -0
  98. data/test/dummy/bin/rails +4 -0
  99. data/test/dummy/bin/rake +4 -0
  100. data/test/dummy/bin/setup +34 -0
  101. data/test/dummy/bin/update +29 -0
  102. data/test/dummy/config/application.rb +15 -0
  103. data/test/dummy/config/boot.rb +5 -0
  104. data/test/dummy/config/cable.yml +9 -0
  105. data/test/dummy/config/database.yml +25 -0
  106. data/test/dummy/config/environment.rb +5 -0
  107. data/test/dummy/config/environments/development.rb +54 -0
  108. data/test/dummy/config/environments/production.rb +86 -0
  109. data/test/dummy/config/environments/test.rb +42 -0
  110. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  111. data/test/dummy/config/initializers/assets.rb +11 -0
  112. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  113. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  114. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  115. data/test/dummy/config/initializers/inflections.rb +16 -0
  116. data/test/dummy/config/initializers/mime_types.rb +4 -0
  117. data/test/dummy/config/initializers/new_framework_defaults.rb +24 -0
  118. data/test/dummy/config/initializers/session_store.rb +3 -0
  119. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  120. data/test/dummy/config/locales/en.yml +23 -0
  121. data/test/dummy/config/puma.rb +47 -0
  122. data/test/dummy/config/routes.rb +3 -0
  123. data/test/dummy/config/secrets.yml +22 -0
  124. data/test/dummy/config/spring.rb +6 -0
  125. data/test/dummy/config.ru +5 -0
  126. data/test/dummy/db/development.sqlite3 +0 -0
  127. data/test/dummy/lib/assets/.keep +0 -0
  128. data/test/dummy/log/.keep +0 -0
  129. data/test/dummy/log/development.log +16 -0
  130. data/test/dummy/public/404.html +67 -0
  131. data/test/dummy/public/422.html +67 -0
  132. data/test/dummy/public/500.html +66 -0
  133. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  134. data/test/dummy/public/apple-touch-icon.png +0 -0
  135. data/test/dummy/public/favicon.ico +0 -0
  136. data/test/dummy/tmp/.keep +0 -0
  137. data/test/integration/navigation_test.rb +8 -0
  138. data/test/test_helper.rb +19 -0
  139. data/test/thecore_settings_test.rb +7 -0
  140. data/thecore_settings.gemspec +44 -0
  141. metadata +457 -54
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Shrine
4
+ module Plugins
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/determine_mime_type
6
+ module DetermineMimeType
7
+ LOG_SUBSCRIBER = -> (event) do
8
+ Shrine.logger.info "MIME Type (#{event.duration}ms) – #{{
9
+ io: event[:io].class,
10
+ uploader: event[:uploader],
11
+ }.inspect}"
12
+ end
13
+
14
+ def self.configure(uploader, log_subscriber: LOG_SUBSCRIBER, **opts)
15
+ uploader.opts[:determine_mime_type] ||= { analyzer: :file, analyzer_options: {} }
16
+ uploader.opts[:determine_mime_type].merge!(opts)
17
+
18
+ # instrumentation plugin integration
19
+ uploader.subscribe(:mime_type, &log_subscriber) if uploader.respond_to?(:subscribe)
20
+ end
21
+
22
+ module ClassMethods
23
+ # Determines the MIME type of the IO object by calling the specified
24
+ # analyzer.
25
+ def determine_mime_type(io)
26
+ analyzer = opts[:determine_mime_type][:analyzer]
27
+
28
+ analyzer = mime_type_analyzer(analyzer) if analyzer.is_a?(Symbol)
29
+ args = if analyzer.is_a?(Proc)
30
+ [io, mime_type_analyzers].take(analyzer.arity.abs)
31
+ else
32
+ [io, opts[:determine_mime_type][:analyzer_options]]
33
+ end
34
+
35
+ mime_type = instrument_mime_type(io) { analyzer.call(*args) }
36
+ io.rewind
37
+
38
+ mime_type
39
+ end
40
+ alias mime_type determine_mime_type
41
+
42
+ # Returns a hash of built-in MIME type analyzers, where keys are
43
+ # analyzer names and values are `#call`-able objects which accepts the
44
+ # IO object.
45
+ def mime_type_analyzers
46
+ @mime_type_analyzers ||= MimeTypeAnalyzer::SUPPORTED_TOOLS.inject({}) do |hash, tool|
47
+ hash.merge!(tool => mime_type_analyzer(tool))
48
+ end
49
+ end
50
+
51
+ # Returns callable mime type analyzer object.
52
+ def mime_type_analyzer(name)
53
+ MimeTypeAnalyzer.new(name)
54
+ end
55
+
56
+ private
57
+
58
+ # Sends a `mime_type.shrine` event for instrumentation plugin.
59
+ def instrument_mime_type(io, &block)
60
+ return yield unless respond_to?(:instrument)
61
+
62
+ instrument(:mime_type, io: io, &block)
63
+ end
64
+ end
65
+
66
+ module InstanceMethods
67
+ private
68
+
69
+ # Calls the configured MIME type analyzer.
70
+ def extract_mime_type(io)
71
+ self.class.determine_mime_type(io)
72
+ end
73
+ end
74
+
75
+ class MimeTypeAnalyzer
76
+ SUPPORTED_TOOLS = [:fastimage, :file, :filemagic, :mimemagic, :marcel, :mime_types, :mini_mime, :content_type]
77
+ MAGIC_NUMBER = 256 * 1024
78
+
79
+ def initialize(tool)
80
+ raise Error, "unknown mime type analyzer #{tool.inspect}, supported analyzers are: #{SUPPORTED_TOOLS.join(",")}" unless SUPPORTED_TOOLS.include?(tool)
81
+
82
+ @tool = tool
83
+ end
84
+
85
+ def call(io, options = {})
86
+ mime_type = send(:"extract_with_#{@tool}", io, options)
87
+ io.rewind
88
+
89
+ mime_type
90
+ end
91
+
92
+ private
93
+
94
+ def extract_with_file(io, options)
95
+ require "open3"
96
+
97
+ return nil if io.eof? # file command returns "application/x-empty" for empty files
98
+
99
+ Open3.popen3(*%W[file --mime-type --brief -]) do |stdin, stdout, stderr, thread|
100
+ begin
101
+ IO.copy_stream(io, stdin.binmode)
102
+ rescue Errno::EPIPE
103
+ end
104
+ stdin.close
105
+
106
+ status = thread.value
107
+
108
+ raise Error, "file command failed to spawn: #{stderr.read}" if status.nil?
109
+ raise Error, "file command failed: #{stderr.read}" unless status.success?
110
+
111
+ $stderr.print(stderr.read)
112
+
113
+ output = stdout.read.strip
114
+
115
+ raise Error, "file command failed: #{output}" if output.include?("cannot open")
116
+
117
+ output
118
+ end
119
+ rescue Errno::ENOENT
120
+ raise Error, "file command-line tool is not installed"
121
+ end
122
+
123
+ def extract_with_fastimage(io, options)
124
+ require "fastimage"
125
+
126
+ type = FastImage.type(io)
127
+ "image/#{type}" if type
128
+ end
129
+
130
+ def extract_with_filemagic(io, options)
131
+ require "filemagic"
132
+
133
+ return nil if io.eof? # FileMagic returns "application/x-empty" for empty files
134
+
135
+ FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
136
+ filemagic.buffer(io.read(MAGIC_NUMBER))
137
+ end
138
+ end
139
+
140
+ def extract_with_mimemagic(io, options)
141
+ require "mimemagic"
142
+
143
+ mime = MimeMagic.by_magic(io)
144
+ mime&.type
145
+ end
146
+
147
+ def extract_with_marcel(io, options)
148
+ require "marcel"
149
+
150
+ return nil if io.eof? # marcel returns "application/octet-stream" for empty files
151
+
152
+ filename = (options[:filename_fallback] ? extract_filename(io) : nil)
153
+ Marcel::MimeType.for(io, name: filename)
154
+ end
155
+
156
+ def extract_with_mime_types(io, options)
157
+ require "mime/types"
158
+
159
+ if filename = extract_filename(io)
160
+ mime_type = MIME::Types.of(filename).first
161
+ mime_type&.content_type
162
+ end
163
+ end
164
+
165
+ def extract_with_mini_mime(io, options)
166
+ require "mini_mime"
167
+
168
+ if filename = extract_filename(io)
169
+ info = MiniMime.lookup_by_filename(filename)
170
+ info&.content_type
171
+ end
172
+ end
173
+
174
+ def extract_with_content_type(io, options)
175
+ if io.respond_to?(:content_type) && io.content_type
176
+ io.content_type.split(";").first
177
+ end
178
+ end
179
+
180
+ def extract_filename(io)
181
+ if io.respond_to?(:original_filename)
182
+ io.original_filename
183
+ elsif io.respond_to?(:path)
184
+ File.basename(io.path)
185
+ end
186
+ end
187
+ end
188
+
189
+ end
190
+
191
+ register_plugin(:determine_mime_type, DetermineMimeType)
192
+ end
193
+ end
@@ -0,0 +1,12 @@
1
+ module ThecoreSettings
2
+ module Dumper
3
+ def self.dump(path)
4
+ ns = {}
5
+ ThecoreSettings::Setting.each do |s|
6
+ ns[s.ns] = {} if ns[s.ns].nil?
7
+ ns[s.ns][s.key] = s.as_yaml
8
+ end
9
+ File.write(path, ns.to_yaml)
10
+ end
11
+ end
12
+ end
@@ -1,10 +1,24 @@
1
1
  module ThecoreSettings
2
2
  class Engine < ::Rails::Engine
3
- initializer "thecore_settings.add_to_migrations" do |app|
3
+ rake_tasks do
4
+ require File.expand_path('../tasks', __FILE__)
5
+ end
6
+
7
+ initializer 'ThecoreSettings.install_after_action' do |app|
8
+ require File.dirname(__FILE__) + '/../../app/models/thecore_settings/setting.rb'
9
+
10
+ if defined?(ActionController) and defined?(ActionController::Base)
11
+ ActionController::Base.class_eval do
12
+ after_action { Settings.unload! }
13
+ end
14
+ end
15
+ end
16
+
17
+ initializer 'ThecoreSettings.add_to_migrations' do |app|
4
18
  unless app.root.to_s.match root.to_s
5
19
  # APPEND TO MAIN APP MIGRATIONS FROM THIS GEM
6
- config.paths["db/migrate"].expanded.each do |expanded_path|
7
- app.config.paths["db/migrate"] << expanded_path
20
+ config.paths['db/migrate'].expanded.each do |expanded_path|
21
+ app.config.paths['db/migrate'] << expanded_path
8
22
  end
9
23
  end
10
24
  end
@@ -0,0 +1,21 @@
1
+ module ThecoreSettings
2
+ # we are inheriting from BasicObject so we don't get a bunch of methods from
3
+ # Kernel or Object
4
+ class Fallback < BasicObject
5
+ def initialize(ns, fb)
6
+ @ns = ns
7
+ @fb = fb
8
+ end
9
+
10
+ def inspect
11
+ "#<ThecoreSettings::Fallback ns: #{@ns.inspect}, fb: #{@fb.inspect}>"
12
+ end
13
+
14
+ def method_missing(*args)
15
+ @ns.ns_mutex.synchronize do
16
+ @ns.fallback = @fb
17
+ @ns.__send__(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module ThecoreSettings
2
+ class HexColorValidator < ActiveModel::EachValidator
3
+ def validate_each(record, attribute, value)
4
+ record.errors[attribute] << (options[:message] || I18n.t('admin.settings.color_invalid')) unless value.blank? || self.class.matches?(value)
5
+ end
6
+ def self.matches?(value)
7
+ return false unless value
8
+ /^(?:[0-9a-f]{3})(?:[0-9a-f]{3})?$/i.match(value).nil? ? false : true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module ThecoreSettings
2
+ def self.kinds
3
+ [
4
+ 'string',
5
+ 'text',
6
+ 'integer',
7
+ 'float',
8
+ 'boolean',
9
+ 'html',
10
+ 'code',
11
+ 'sanitized',
12
+ 'yaml',
13
+ 'phone',
14
+ 'phones',
15
+ 'email',
16
+ 'address',
17
+ 'file',
18
+ 'image',
19
+ 'url',
20
+ 'domain',
21
+ 'color',
22
+ 'strip_tags',
23
+ 'sanitize',
24
+ 'sanitize_code',
25
+ 'simple_format',
26
+ 'simple_format_raw',
27
+ 'json',
28
+ ]
29
+ end
30
+
31
+ def self.types
32
+ self.kinds
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module ThecoreSettings
2
+ module Mongoid
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ include ::Mongoid::Document
6
+ include ::Mongoid::Timestamps::Short
7
+
8
+ store_in collection: "thecore_settings"
9
+ field :enabled, type: ::Mongoid::VERSION.to_i < 4 ? Boolean : ::Mongoid::Boolean, default: true
10
+ field :kind, type: String, default: ThecoreSettings.types.first
11
+ field :ns, type: String, default: 'main'
12
+ field :key, type: String
13
+ field :raw, type: String
14
+ field :label, type: String
15
+ index({ns: 1, key: 1}, {unique: true, sparse: true})
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,210 @@
1
+ module ThecoreSettings
2
+ # we are inheriting from BasicObject so we don't get a bunch of methods from
3
+ # Kernel or Object
4
+ class Namespaced < BasicObject
5
+ attr_accessor :settings, :fallback
6
+ attr_reader :loaded, :mutex, :ns_mutex, :name
7
+
8
+ def initialize(name)
9
+ self.settings = {}
10
+ @mutex = ::Mutex.new
11
+ @ns_mutex = ::Mutex.new
12
+ @loaded = false
13
+ @locked = false
14
+ @name = name
15
+ end
16
+
17
+ def nil?
18
+ false
19
+ end
20
+ def inspect
21
+ "#<ThecoreSettings::Namespaced name: #{@name.inspect}, fallback: #{@fallback.inspect}, loaded: #{@loaded}>"
22
+ end
23
+ def pretty_inspect
24
+ inspect
25
+ end
26
+
27
+ def load!
28
+ mutex.synchronize do
29
+ return if loaded
30
+ @loaded = true
31
+ @settings = {}
32
+ ::ThecoreSettings::Setting.ns(@name).each do |setting|
33
+ @settings[setting.key] = setting
34
+ end
35
+ end
36
+ end
37
+
38
+ def unload!
39
+ mutex.synchronize do
40
+ @loaded = false
41
+ @settings = {}
42
+ end
43
+ end
44
+
45
+ # returns setting object
46
+ def get(key, options = {})
47
+ load!
48
+ key = key.to_s
49
+ mutex.synchronize do
50
+ @locked = true
51
+ v = @settings[key]
52
+ if v.nil?
53
+ unless @fallback.nil? || @fallback == @name
54
+ v = ::Settings.ns(@fallback).getnc(key)
55
+ end
56
+ if v.nil?
57
+ v = set(key, options[:default], options)
58
+ end
59
+ end
60
+ @locked = false
61
+ v
62
+ end
63
+ end
64
+
65
+ # returns setting object
66
+ def getnc(key)
67
+ load!
68
+ mutex.synchronize do
69
+ self.settings[key]
70
+ end
71
+ end
72
+
73
+ def set(key, value = nil, options = {})
74
+ load! unless @locked
75
+ key = key.to_s
76
+ options.symbolize_keys!
77
+
78
+ if !options[:type].nil? && options[:type] == 'yaml' && !value.nil?
79
+ if value.class.name != 'String'
80
+ value = value.to_yaml
81
+ end
82
+ end
83
+
84
+ options.merge!(value: value)
85
+ if @locked
86
+ write_to_database(key, options)
87
+ else
88
+ mutex.synchronize do
89
+ write_to_database(key, options)
90
+ end
91
+ end
92
+ end
93
+
94
+ def enabled?(key, options = {})
95
+ get(key, options).enabled?
96
+ end
97
+
98
+ def []=(key, value)
99
+ set(key, value)
100
+ end
101
+ def [](key)
102
+ get(key)
103
+ end
104
+
105
+ def destroy!(key)
106
+ load!
107
+ key = key.to_s
108
+ mutex.synchronize do
109
+ ::ThecoreSettings::Setting.where(ns: @name, key: key).destroy_all
110
+ @settings.delete(key)
111
+ end
112
+ end
113
+
114
+ def destroy_all!
115
+ mutex.synchronize do
116
+ ::ThecoreSettings::Setting.where(ns: @name).destroy_all
117
+ @loaded = false
118
+ @settings = {}
119
+ end
120
+ end
121
+
122
+ # returns processed setting value
123
+ def method_missing(key, *args)
124
+ key = key.to_s
125
+ if key.end_with?('_enabled?')
126
+ key = key[0..-10]
127
+ v = get(key)
128
+ if v.nil?
129
+ set(key, '').enabled
130
+ else
131
+ v.enabled
132
+ end
133
+ elsif key.end_with?('_enabled=')
134
+ key = key[0..-10]
135
+ v = get(key)
136
+ if ::ThecoreSettings.mongoid?
137
+ if ::Mongoid::VERSION >= "4.0.0"
138
+ v.set(enabled: args.first)
139
+ else
140
+ v.set("enabled", args.first)
141
+ end
142
+ else
143
+ v.enabled = args.first
144
+ v.save!
145
+ end
146
+ v.enabled
147
+ elsif key.end_with?('=')
148
+ key = key[0..-2]
149
+ options = args[1] || {}
150
+ value = args.first
151
+ set(key, value, options).val
152
+ else
153
+ v = get(key, args.first || {})
154
+ if v.nil?
155
+ ''
156
+ else
157
+ v.val
158
+ end
159
+ end
160
+ end
161
+
162
+ def write_to_database(key, options)
163
+ is_file = !options[:kind].nil? && (options[:kind] == 'image' || options[:kind] == 'file')
164
+ if is_file
165
+ options[:raw] = ''
166
+ file = options[:value]
167
+ else
168
+ options[:raw] = options[:value]
169
+ end
170
+
171
+ options.delete(:value)
172
+ options.delete(:default)
173
+ options[:ns] = @name
174
+
175
+ if @settings[key].nil?
176
+ options.delete(:overwrite)
177
+ v = ::ThecoreSettings::Setting.create(options.merge(key: key))
178
+ if !v.persisted?
179
+ if v.errors[:key].any?
180
+ v = ::ThecoreSettings::Setting.where(key: key).first
181
+ if v.nil?
182
+ ::Kernel.raise ::ThecoreSettings::PersistenceException, 'Fatal: error in key and not in DB'
183
+ end
184
+ else
185
+ ::Kernel.raise ::ThecoreSettings::PersistenceException, v.errors.full_messages.join(',')
186
+ end
187
+ end
188
+ @settings[key] = v
189
+ else
190
+ opts = options.dup
191
+ if options[:overwrite] == false && !@settings[key].value.blank?
192
+ opts.delete(:raw)
193
+ opts.delete(:value)
194
+ opts.delete(:enabled)
195
+ end
196
+ opts.delete(:overwrite)
197
+ # Pre Rails 6.1 vs Post Rails 6.1
198
+ # In Rails 6.1 update_attributes has been deprecated
199
+ @settings[key].respond_to?('update_attributes!') ? @settings[key].update_attributes!(opts) : @settings[key].update!(opts)
200
+ end
201
+ if is_file
202
+ if options[:overwrite] != false || !@settings[key].file?
203
+ @settings[key].file = file
204
+ @settings[key].save!
205
+ end
206
+ end
207
+ @settings[key]
208
+ end
209
+ end
210
+ end