Fixes #1653 - Default value not set for attributes of type input, select,...
This commit is contained in:
parent
86d65a571b
commit
0668e17d18
19 changed files with 203 additions and 27 deletions
|
@ -53,7 +53,7 @@ class App extends Spine.Controller
|
|||
@viewPrintItem: (item, attributeConfig = {}, valueRef, table, object) ->
|
||||
return '-' if item is undefined
|
||||
return '-' if item is ''
|
||||
return item if item is null
|
||||
return '-' if item is null
|
||||
result = ''
|
||||
items = [item]
|
||||
if _.isArray(item)
|
||||
|
|
|
@ -70,7 +70,7 @@ returns
|
|||
attributes[ attribute_ref_name ] = value
|
||||
end
|
||||
|
||||
if self.class.include?(HasObjectManagerAttributesValidation)
|
||||
if is_a? HasObjectManagerAttributes
|
||||
RequestCache.integer_fields(self.class.to_s).each do |field|
|
||||
next if attributes[field].blank?
|
||||
|
||||
|
|
14
app/models/concerns/has_object_manager_attributes.rb
Normal file
14
app/models/concerns/has_object_manager_attributes.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
module HasObjectManagerAttributes
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
# Disable table inheritance to allow columns with the name 'type'.
|
||||
self.inheritance_column = nil
|
||||
|
||||
validates_with ObjectManager::Attribute::Validation, on: %i[create update]
|
||||
|
||||
after_initialize ObjectManager::Attribute::SetDefaults.new
|
||||
end
|
||||
end
|
|
@ -5,9 +5,8 @@ module HasObjectManagerAttributesValidation
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
# Disable table inheritance to allow columns with the name 'type'.
|
||||
self.inheritance_column = nil
|
||||
ActiveSupport::Deprecation.warn("Concern 'HasObjectManagerAttributesValidation' is deprecated. Use 'HasObjectManagerValidation' instead.")
|
||||
|
||||
validates_with ObjectManager::Attribute::Validation, on: %i[create update]
|
||||
include HasObjectManagerAttributes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ class Group < ApplicationModel
|
|||
include ChecksHtmlSanitized
|
||||
include ChecksLatestChangeObserved
|
||||
include HasHistory
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasObjectManagerAttributes
|
||||
include HasCollectionUpdate
|
||||
include HasTicketCreateScreenImpact
|
||||
include HasSearchIndexBackend
|
||||
|
|
|
@ -38,6 +38,13 @@ class ObjectManager::Attribute < ApplicationModel
|
|||
|
||||
before_validation :set_base_options
|
||||
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :editable, -> { where(editable: true) }
|
||||
scope :for_object, lambda { |name_or_klass|
|
||||
id = ObjectLookup.lookup(name: name_or_klass.to_s)
|
||||
where(object_lookup_id: id)
|
||||
}
|
||||
|
||||
=begin
|
||||
|
||||
list of all attributes
|
||||
|
|
62
app/models/object_manager/attribute/set_defaults.rb
Normal file
62
app/models/object_manager/attribute/set_defaults.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class ObjectManager
|
||||
class Attribute
|
||||
class SetDefaults
|
||||
def after_initialize(record)
|
||||
return if !record.new_record?
|
||||
|
||||
attributes_for(record).each { |attr, config| set_value(record, attr, config) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_value(record, attr, config)
|
||||
method_name = "#{attr}="
|
||||
|
||||
return if !record.respond_to? method_name
|
||||
return if record.send(attr).present?
|
||||
|
||||
record.send method_name, build_value(config)
|
||||
end
|
||||
|
||||
def build_value(config)
|
||||
case config[:data_type]
|
||||
when 'date'
|
||||
config[:diff].days.from_now
|
||||
when 'datetime'
|
||||
config[:diff].hours.from_now
|
||||
else
|
||||
config[:default]
|
||||
end
|
||||
end
|
||||
|
||||
def attributes_for(record)
|
||||
query = ObjectManager::Attribute.active.editable.for_object(record.class)
|
||||
cache_key = "#{query.cache_key}/attribute_defaults"
|
||||
|
||||
Rails.cache.fetch cache_key do
|
||||
query
|
||||
.map { |attr| { attr.name => config_of(attr) } }
|
||||
.reduce({}, :merge)
|
||||
.compact
|
||||
end
|
||||
end
|
||||
|
||||
def config_of(attr)
|
||||
case attr.data_type
|
||||
when 'date', 'datetime'
|
||||
{
|
||||
data_type: attr.data_type,
|
||||
diff: attr.data_option&.dig(:diff)
|
||||
}
|
||||
else
|
||||
{
|
||||
data_type: attr.data_type,
|
||||
default: attr.data_option&.dig(:default)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,7 +8,7 @@ class Organization < ApplicationModel
|
|||
include HasSearchIndexBackend
|
||||
include CanCsvImport
|
||||
include ChecksHtmlSanitized
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasObjectManagerAttributes
|
||||
include HasTaskbars
|
||||
|
||||
include Organization::Assets
|
||||
|
|
|
@ -13,7 +13,7 @@ class Ticket < ApplicationModel
|
|||
include HasOnlineNotifications
|
||||
include HasKarmaActivityLog
|
||||
include HasLinks
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasObjectManagerAttributes
|
||||
include HasTaskbars
|
||||
include Ticket::CallsStatsTicketReopenLog
|
||||
include Ticket::EnqueuesUserTicketCounterJob
|
||||
|
|
|
@ -8,7 +8,7 @@ class Ticket::Article < ApplicationModel
|
|||
include ChecksHtmlSanitized
|
||||
include CanCsvImport
|
||||
include CanCloneAttachments
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasObjectManagerAttributes
|
||||
|
||||
include Ticket::Article::Assets
|
||||
include Ticket::Article::EnqueueCommunicateEmailJob
|
||||
|
|
|
@ -11,7 +11,7 @@ class User < ApplicationModel
|
|||
include ChecksHtmlSanitized
|
||||
include HasGroups
|
||||
include HasRoles
|
||||
include HasObjectManagerAttributesValidation
|
||||
include HasObjectManagerAttributes
|
||||
include ::HasTicketCreateScreenImpact
|
||||
include HasTaskbars
|
||||
include User::HasTicketCreateScreenImpact
|
||||
|
|
|
@ -5,6 +5,7 @@ FactoryBot.define do
|
|||
transient do
|
||||
object_name { 'Ticket' }
|
||||
additional_data_options { nil }
|
||||
default { nil }
|
||||
end
|
||||
|
||||
object_lookup_id { ObjectLookup.by_name(object_name) }
|
||||
|
@ -47,7 +48,7 @@ FactoryBot.define do
|
|||
'maxlength' => 200,
|
||||
'null' => true,
|
||||
'translate' => false,
|
||||
'default' => '',
|
||||
'default' => default || '',
|
||||
'options' => {},
|
||||
'relation' => '',
|
||||
}
|
||||
|
@ -58,7 +59,7 @@ FactoryBot.define do
|
|||
data_type { 'integer' }
|
||||
data_option do
|
||||
{
|
||||
'default' => 0,
|
||||
'default' => default || 0,
|
||||
'min' => 0,
|
||||
'max' => 9999,
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ FactoryBot.define do
|
|||
data_type { 'boolean' }
|
||||
data_option do
|
||||
{
|
||||
default: false,
|
||||
default: default || false,
|
||||
options: {
|
||||
true => 'yes',
|
||||
false => 'no',
|
||||
|
@ -83,7 +84,7 @@ FactoryBot.define do
|
|||
data_type { 'date' }
|
||||
data_option do
|
||||
{
|
||||
'diff' => 24,
|
||||
'diff' => default || 24,
|
||||
'null' => true,
|
||||
}
|
||||
end
|
||||
|
@ -96,7 +97,7 @@ FactoryBot.define do
|
|||
{
|
||||
'future' => true,
|
||||
'past' => true,
|
||||
'diff' => 24,
|
||||
'diff' => default || 24,
|
||||
'null' => true,
|
||||
}
|
||||
end
|
||||
|
@ -106,7 +107,7 @@ FactoryBot.define do
|
|||
data_type { 'select' }
|
||||
data_option do
|
||||
{
|
||||
'default' => '',
|
||||
'default' => default || '',
|
||||
'options' => {
|
||||
'key_1' => 'value_1',
|
||||
'key_2' => 'value_2',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
RSpec.shared_examples 'HasObjectManagerAttributesValidation' do
|
||||
RSpec.shared_examples 'HasObjectManagerAttributes' do
|
||||
it 'validates ObjectManager::Attributes' do
|
||||
expect(described_class.validators.map(&:class)).to include(ObjectManager::Attribute::Validation)
|
||||
end
|
|
@ -3,7 +3,7 @@
|
|||
require 'rails_helper'
|
||||
require 'models/application_model_examples'
|
||||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_examples'
|
||||
require 'models/concerns/has_collection_update_examples'
|
||||
require 'models/concerns/has_ticket_create_screen_impact_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
|
@ -13,7 +13,7 @@ RSpec.describe Group, type: :model do
|
|||
|
||||
it_behaves_like 'ApplicationModel'
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'HasObjectManagerAttributes'
|
||||
it_behaves_like 'HasCollectionUpdate', collection_factory: :group
|
||||
it_behaves_like 'HasTicketCreateScreenImpact', create_screen_factory: :group
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :group
|
||||
|
|
93
spec/models/object_manager/attribute/set_defaults_spec.rb
Normal file
93
spec/models/object_manager/attribute/set_defaults_spec.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ObjectManager::Attribute::SetDefaults, type: :model do
|
||||
describe 'setting default', db_strategy: :reset_all do
|
||||
before :all do # rubocop:disable RSpec/BeforeAfterAll
|
||||
{
|
||||
text: 'rspec',
|
||||
boolean: true,
|
||||
date: 1,
|
||||
datetime: 12,
|
||||
integer: 123,
|
||||
select: 'key_1'
|
||||
}.each do |key, value|
|
||||
create("object_manager_attribute_#{key}", name: "rspec_#{key}", default: value)
|
||||
end
|
||||
|
||||
create('object_manager_attribute_text', name: 'rspec_empty', default: '')
|
||||
|
||||
ObjectManager::Attribute.migration_execute
|
||||
end
|
||||
|
||||
after :all do # rubocop:disable RSpec/BeforeAfterAll
|
||||
ObjectManager::Attribute.where('name LIKE ?', 'rspec_%').destroy_all
|
||||
end
|
||||
|
||||
context 'with text type' do # on text
|
||||
it 'default value is set' do
|
||||
ticket = create :ticket
|
||||
expect(ticket.rspec_text).to eq 'rspec'
|
||||
end
|
||||
|
||||
it 'empty string as default value gets saved' do
|
||||
ticket = create :ticket
|
||||
expect(ticket.rspec_empty).to eq ''
|
||||
end
|
||||
|
||||
it 'given value overrides default value' do
|
||||
ticket = create :ticket, rspec_text: 'another'
|
||||
expect(ticket.rspec_text).to eq 'another'
|
||||
end
|
||||
|
||||
# actual create works slightly differently than FactoryGirl!
|
||||
it 'given value overrides default value when using native #create' do
|
||||
ticket_attrs = attributes_for :ticket, rspec_text: 'another', group: Group.first
|
||||
ticket_attrs[:group] = Group.first
|
||||
ticket_attrs[:customer] = User.first
|
||||
|
||||
ticket_created = Ticket.create! ticket_attrs
|
||||
|
||||
expect(ticket_created.rspec_text).to eq 'another'
|
||||
end
|
||||
|
||||
it 'given nil overrides default value' do
|
||||
ticket = create :ticket, rspec_text: nil
|
||||
expect(ticket.rspec_text).to be_nil
|
||||
end
|
||||
|
||||
it 'updating attribute to nil does not instantiate default' do
|
||||
ticket = create :ticket
|
||||
ticket.update! rspec_text: nil
|
||||
expect(ticket.rspec_text).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when using other types' do
|
||||
subject(:example) { create :ticket }
|
||||
|
||||
it 'boolean is set' do
|
||||
expect(example.rspec_boolean).to eq true
|
||||
end
|
||||
|
||||
it 'date is set' do
|
||||
freeze_time
|
||||
expect(example.rspec_date).to eq 1.day.from_now.to_date
|
||||
end
|
||||
|
||||
it 'datetime is set' do
|
||||
freeze_time
|
||||
expect(example.rspec_datetime).to eq 12.hours.from_now
|
||||
end
|
||||
|
||||
it 'integer is set' do
|
||||
expect(example.rspec_integer).to eq 123
|
||||
end
|
||||
|
||||
it 'select value is set' do
|
||||
expect(example.rspec_select).to eq 'key_1'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@ require 'models/concerns/can_csv_import_examples'
|
|||
require 'models/concerns/has_history_examples'
|
||||
require 'models/concerns/has_search_index_backend_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_examples'
|
||||
require 'models/concerns/has_taskbars_examples'
|
||||
|
||||
RSpec.describe Organization, type: :model do
|
||||
|
@ -17,7 +17,7 @@ RSpec.describe Organization, type: :model do
|
|||
it_behaves_like 'HasHistory'
|
||||
it_behaves_like 'HasSearchIndexBackend', indexed_factory: :organization
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :organization
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'HasObjectManagerAttributes'
|
||||
it_behaves_like 'HasTaskbars'
|
||||
|
||||
describe 'Class methods:' do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'models/application_model_examples'
|
|||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/can_csv_import_examples'
|
||||
require 'models/concerns/has_history_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_examples'
|
||||
require 'models/ticket/article/has_ticket_contact_attributes_impact_examples'
|
||||
|
||||
RSpec.describe Ticket::Article, type: :model do
|
||||
|
@ -15,7 +15,7 @@ RSpec.describe Ticket::Article, type: :model do
|
|||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'CanCsvImport'
|
||||
it_behaves_like 'HasHistory'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'HasObjectManagerAttributes'
|
||||
|
||||
it_behaves_like 'Ticket::Article::HasTicketContactAttributesImpact'
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'models/concerns/has_history_examples'
|
|||
require 'models/concerns/has_tags_examples'
|
||||
require 'models/concerns/has_taskbars_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_examples'
|
||||
require 'models/tag/writes_to_ticket_history_examples'
|
||||
require 'models/ticket/calls_stats_ticket_reopen_log_examples'
|
||||
require 'models/ticket/enqueues_user_ticket_counter_job_examples'
|
||||
|
@ -28,7 +28,7 @@ RSpec.describe Ticket, type: :model do
|
|||
it_behaves_like 'TagWritesToTicketHistory'
|
||||
it_behaves_like 'HasTaskbars'
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :ticket
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'HasObjectManagerAttributes'
|
||||
it_behaves_like 'Ticket::Escalation'
|
||||
it_behaves_like 'TicketCallsStatsTicketReopenLog'
|
||||
it_behaves_like 'TicketEnqueuesTicketUserTicketCounterJob'
|
||||
|
|
|
@ -8,7 +8,7 @@ require 'models/concerns/has_roles_examples'
|
|||
require 'models/concerns/has_groups_permissions_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_examples'
|
||||
require 'models/user/can_lookup_search_index_attributes_examples'
|
||||
require 'models/user/has_ticket_create_screen_impact_examples'
|
||||
require 'models/user/performs_geo_lookup_examples'
|
||||
|
@ -28,7 +28,7 @@ RSpec.describe User, type: :model do
|
|||
it_behaves_like 'HasXssSanitizedNote', model_factory: :user
|
||||
it_behaves_like 'HasGroups and Permissions', group_access_no_permission_factory: :user
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
it_behaves_like 'HasObjectManagerAttributes'
|
||||
it_behaves_like 'User::HasTicketCreateScreenImpact'
|
||||
it_behaves_like 'CanLookupSearchIndexAttributes'
|
||||
it_behaves_like 'HasTaskbars'
|
||||
|
|
Loading…
Reference in a new issue