This commit is contained in:
parent
e579c809e0
commit
444e48e377
27 changed files with 647 additions and 0 deletions
|
@ -0,0 +1,9 @@
|
|||
# Copyright (C) 2018 Zammad Foundation, http://zammad-foundation.org/
|
||||
module HasObjectManagerAttributesValidation
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
include ActiveModel::Validations
|
||||
validates_with ObjectManager::Attribute::Validation, on: %i[create update]
|
||||
end
|
||||
end
|
|
@ -6,6 +6,7 @@ class Group < ApplicationModel
|
|||
include ChecksClientNotification
|
||||
include ChecksLatestChangeObserved
|
||||
include HasHistory
|
||||
include HasObjectManagerAttributesValidation
|
||||
|
||||
belongs_to :email_address
|
||||
belongs_to :signature
|
||||
|
|
66
app/models/object_manager/attribute/validation.rb
Normal file
66
app/models/object_manager/attribute/validation.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
class ObjectManager::Attribute::Validation < ActiveModel::Validator
|
||||
include ::Mixin::HasBackends
|
||||
|
||||
def validate(record)
|
||||
return if validation_unneeded?
|
||||
|
||||
@record = record
|
||||
sanitize_memory_cache
|
||||
|
||||
return if attributes_unchanged?
|
||||
|
||||
model_attributes.select(&:editable).each do |attribute|
|
||||
perform_validation(attribute)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :record
|
||||
|
||||
def validation_unneeded?
|
||||
return true if Setting.get('import_mode')
|
||||
|
||||
ApplicationHandleInfo.current != 'application_server'
|
||||
end
|
||||
|
||||
def attributes_unchanged?
|
||||
model_attributes.none? do |attribute|
|
||||
record.will_save_change_to_attribute?(attribute.name)
|
||||
end
|
||||
end
|
||||
|
||||
def model_attributes
|
||||
@model_attributes ||= begin
|
||||
object_lookup_id = ObjectLookup.by_name(record.class.name)
|
||||
@active_attributes.select { |attribute| attribute.object_lookup_id == object_lookup_id }
|
||||
end
|
||||
end
|
||||
|
||||
def perform_validation(attribute)
|
||||
backends.each do |backend|
|
||||
backend.validate(
|
||||
record: record,
|
||||
attribute: attribute
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def validations
|
||||
@validations ||= backend.map { backend.new }
|
||||
end
|
||||
|
||||
def sanitize_memory_cache
|
||||
@model_attributes = nil
|
||||
|
||||
latest_cache_key = active_attributes_in_db.cache_key
|
||||
return if @previous_cache_key == latest_cache_key
|
||||
|
||||
@previous_cache_key = latest_cache_key
|
||||
@active_attributes = active_attributes_in_db.to_a
|
||||
end
|
||||
|
||||
def active_attributes_in_db
|
||||
ObjectManager::Attribute.where(active: true)
|
||||
end
|
||||
end
|
26
app/models/object_manager/attribute/validation/backend.rb
Normal file
26
app/models/object_manager/attribute/validation/backend.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class ObjectManager::Attribute::Validation::Backend
|
||||
include Mixin::IsBackend
|
||||
|
||||
def self.inherited(subclass)
|
||||
subclass.is_backend_of(::ObjectManager::Attribute::Validation)
|
||||
end
|
||||
|
||||
def self.validate(*args)
|
||||
new(*args).validate
|
||||
end
|
||||
|
||||
attr_reader :record, :attribute, :value, :previous_value
|
||||
|
||||
def initialize(record:, attribute:)
|
||||
@record = record
|
||||
@attribute = attribute
|
||||
@value = record[attribute.name]
|
||||
@previous_value = record.attribute_in_database(attribute.name)
|
||||
end
|
||||
|
||||
def invalid_because_attribute(message)
|
||||
record.errors.add attribute.name.to_sym, message
|
||||
end
|
||||
end
|
||||
|
||||
Mixin::RequiredSubPaths.eager_load_recursive(__dir__)
|
30
app/models/object_manager/attribute/validation/date.rb
Normal file
30
app/models/object_manager/attribute/validation/date.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
class ObjectManager::Attribute::Validation::Date < ObjectManager::Attribute::Validation::Backend
|
||||
|
||||
def validate
|
||||
return if value.blank?
|
||||
return if irrelevant_attribute?
|
||||
|
||||
validate_past
|
||||
validate_future
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def irrelevant_attribute?
|
||||
%w[date datetime].exclude?(attribute.data_type)
|
||||
end
|
||||
|
||||
def validate_past
|
||||
return if attribute.data_option[:past]
|
||||
return if !value.past?
|
||||
|
||||
invalid_because_attribute('does not allow past dates.')
|
||||
end
|
||||
|
||||
def validate_future
|
||||
return if attribute.data_option[:future]
|
||||
return if !value.future?
|
||||
|
||||
invalid_because_attribute('does not allow future dates.')
|
||||
end
|
||||
end
|
45
app/models/object_manager/attribute/validation/required.rb
Normal file
45
app/models/object_manager/attribute/validation/required.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
class ObjectManager::Attribute::Validation::Required < ObjectManager::Attribute::Validation::Backend
|
||||
|
||||
def validate
|
||||
return if value.present?
|
||||
return if optional_for_user?
|
||||
|
||||
invalid_because_attribute('is required but missing.')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def optional_for_user?
|
||||
return true if system_user?
|
||||
return true if required_for_permissions.blank?
|
||||
return false if required_for_permissions.include?('-all-')
|
||||
|
||||
!user.permissions?(required_for_permissions)
|
||||
end
|
||||
|
||||
def system_user?
|
||||
user_id.blank? || user_id == 1
|
||||
end
|
||||
|
||||
def user_id
|
||||
user_id ||= UserInfo.current_user_id
|
||||
end
|
||||
|
||||
def user
|
||||
@user ||= User.lookup(id: user_id)
|
||||
end
|
||||
|
||||
def required_for_permissions
|
||||
@required_for_permissions ||= begin
|
||||
attribute.screens[action]&.each_with_object([]) do |(permission, config), result|
|
||||
result.push(permission) if config[:required].present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def action
|
||||
return :edit if record.persisted?
|
||||
|
||||
attribute.screens.keys.find { |e| e.start_with?('create') }
|
||||
end
|
||||
end
|
|
@ -8,6 +8,7 @@ class Organization < ApplicationModel
|
|||
include HasSearchIndexBackend
|
||||
include CanCsvImport
|
||||
include ChecksHtmlSanitized
|
||||
include HasObjectManagerAttributesValidation
|
||||
|
||||
include Organization::ChecksAccess
|
||||
include Organization::Assets
|
||||
|
|
|
@ -14,6 +14,7 @@ class Ticket < ApplicationModel
|
|||
include HasKarmaActivityLog
|
||||
include HasLinks
|
||||
include Ticket::ChecksAccess
|
||||
include HasObjectManagerAttributesValidation
|
||||
|
||||
include Ticket::Escalation
|
||||
include Ticket::Subject
|
||||
|
|
|
@ -6,6 +6,7 @@ class Ticket::Article < ApplicationModel
|
|||
include HasHistory
|
||||
include ChecksHtmlSanitized
|
||||
include CanCsvImport
|
||||
include HasObjectManagerAttributesValidation
|
||||
|
||||
include Ticket::Article::ChecksAccess
|
||||
include Ticket::Article::Assets
|
||||
|
|
|
@ -9,6 +9,7 @@ class User < ApplicationModel
|
|||
include ChecksHtmlSanitized
|
||||
include HasGroups
|
||||
include HasRoles
|
||||
include HasObjectManagerAttributesValidation
|
||||
|
||||
include User::ChecksAccess
|
||||
include User::Assets
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class ObjectManagerAttributeIndexes < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
|
||||
add_index :object_manager_attributes, :active
|
||||
add_index :object_manager_attributes, :updated_at
|
||||
end
|
||||
end
|
13
lib/mixin/has_backends.rb
Normal file
13
lib/mixin/has_backends.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
module Mixin
|
||||
module HasBackends
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
cattr_accessor :backends do
|
||||
Set.new
|
||||
end
|
||||
|
||||
require_dependency "#{name}::Backend".underscore
|
||||
end
|
||||
end
|
||||
end
|
12
lib/mixin/is_backend.rb
Normal file
12
lib/mixin/is_backend.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
module Mixin
|
||||
module IsBackend
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
|
||||
def is_backend_of(klass) # rubocop:disable Naming/PredicateName
|
||||
klass.backends.add(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
12
spec/lib/mixin/has_backends_examples.rb
Normal file
12
spec/lib/mixin/has_backends_examples.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
RSpec.shared_examples 'Mixin::HasBackends' do
|
||||
|
||||
describe '.backends' do
|
||||
it 'is a Set' do
|
||||
expect(described_class.backends).to be_a(Set)
|
||||
end
|
||||
end
|
||||
|
||||
it "auto requires #{described_class}::Backend" do
|
||||
expect(described_class).to be_const_defined(:Backend)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
RSpec.shared_examples 'HasObjectManagerAttributesValidation' do
|
||||
it 'validates ObjectManager::Attributes' do
|
||||
expect(described_class.validators.map(&:class)).to include(ObjectManager::Attribute::Validation)
|
||||
end
|
||||
end
|
|
@ -1,8 +1,10 @@
|
|||
require 'rails_helper'
|
||||
require 'models/application_model_examples'
|
||||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
|
||||
RSpec.describe Group, type: :model do
|
||||
it_behaves_like 'ApplicationModel'
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
end
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.shared_examples 'a validation without errors' do
|
||||
it 'validatates without errors' do
|
||||
subject.validate
|
||||
expect(record.errors).to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'a validation with errors' do
|
||||
it 'validates with errors' do
|
||||
subject.validate
|
||||
expect(record.errors).to be_present
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ObjectManager::Attribute::Validation::Backend do
|
||||
|
||||
it 'registers inheriting classes as ObjectManager::Attribute::Validation backends' do
|
||||
backends = spy
|
||||
expect(ObjectManager::Attribute::Validation).to receive(:backends).and_return(backends)
|
||||
backend = Class.new(described_class)
|
||||
expect(backends).to have_received(:add).with(backend)
|
||||
end
|
||||
|
||||
describe 'backend interface' do
|
||||
|
||||
let(:record) { build(:user) }
|
||||
let(:attribute) { ::ObjectManager::Attribute.find_by(name: 'firstname') }
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
record: record,
|
||||
attribute: attribute
|
||||
)
|
||||
end
|
||||
|
||||
it 'has attr_accessor for record' do
|
||||
expect(subject.record).to eq(record)
|
||||
end
|
||||
|
||||
it 'has attr_accessor for attribute' do
|
||||
expect(subject.attribute).to eq(attribute)
|
||||
end
|
||||
|
||||
it 'has attr_accessor for value' do
|
||||
expect(subject.value).to eq(record[attribute.name])
|
||||
end
|
||||
|
||||
it 'has attr_accessor for previous_value' do
|
||||
record.save!
|
||||
previous_value = record[attribute.name]
|
||||
record[attribute.name] = 'changed'
|
||||
expect(subject.previous_value).to eq(previous_value)
|
||||
end
|
||||
|
||||
describe '.invalid_because_attribute' do
|
||||
|
||||
before do
|
||||
subject.invalid_because_attribute('has value that is ... .')
|
||||
end
|
||||
|
||||
it 'adds Rails validation error' do
|
||||
expect(record.errors.count).to be(1)
|
||||
end
|
||||
|
||||
it 'uses ObjectManager::Attribute#name as ActiveModel::Errors identifier' do
|
||||
expect(record.errors.to_h).to have_key(attribute.name.to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
61
spec/models/object_manager/attribute/validation/date_spec.rb
Normal file
61
spec/models/object_manager/attribute/validation/date_spec.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
require 'rails_helper'
|
||||
require 'models/object_manager/attribute/validation/backend_examples'
|
||||
|
||||
RSpec.describe ::ObjectManager::Attribute::Validation::Date do
|
||||
|
||||
let(:record) { build(:user) }
|
||||
let(:attribute) { build(:object_manager_attribute_date) }
|
||||
subject do
|
||||
described_class.new(
|
||||
record: record,
|
||||
attribute: attribute
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:value).and_return(value)
|
||||
end
|
||||
|
||||
shared_examples 'data_option validator' do |data_option:, value:|
|
||||
context "for data_option '#{data_option}'" do
|
||||
|
||||
let(:value) { value }
|
||||
|
||||
context 'when data_option is set to true' do
|
||||
|
||||
before { attribute.data_option[data_option] = true }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'when data_option is set to false' do
|
||||
|
||||
before { attribute.data_option[data_option] = false }
|
||||
|
||||
it_behaves_like 'a validation with errors'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'data_option validator', data_option: :future, value: Time.current.tomorrow.midnight
|
||||
it_behaves_like 'data_option validator', data_option: :past, value: Time.current.yesterday.midnight
|
||||
|
||||
context 'when validation should not be performed' do
|
||||
|
||||
context 'for blank value' do
|
||||
|
||||
let(:value) { nil }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'for irrelevant attribute data_type' do
|
||||
|
||||
let(:value) { 'some_value' }
|
||||
|
||||
before { attribute.data_type = 'select' }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
end
|
||||
end
|
155
spec/models/object_manager/attribute/validation/required_spec.rb
Normal file
155
spec/models/object_manager/attribute/validation/required_spec.rb
Normal file
|
@ -0,0 +1,155 @@
|
|||
require 'rails_helper'
|
||||
require 'models/object_manager/attribute/validation/backend_examples'
|
||||
|
||||
RSpec.describe ::ObjectManager::Attribute::Validation::Required do
|
||||
|
||||
let(:record) { build(:user) }
|
||||
let(:attribute) { build(:object_manager_attribute_date) }
|
||||
subject do
|
||||
described_class.new(
|
||||
record: record,
|
||||
attribute: attribute
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:value).and_return(value)
|
||||
end
|
||||
|
||||
context 'when validation should be performed' do
|
||||
|
||||
let(:value) { nil }
|
||||
|
||||
shared_examples 'a permission based validator' do |permission:|
|
||||
|
||||
let(:performing_user) { create(:agent_user) }
|
||||
|
||||
before { UserInfo.current_user_id = performing_user.id }
|
||||
|
||||
context "for applying permission (#{permission})" do
|
||||
|
||||
let(:permission) { permission }
|
||||
|
||||
before do
|
||||
attribute.screens = {
|
||||
action => {
|
||||
permission => {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when action is edit' do
|
||||
|
||||
let(:action) { 'edit' }
|
||||
let(:record) { create(:user) }
|
||||
|
||||
it_behaves_like 'a validation with errors'
|
||||
end
|
||||
|
||||
context 'when action is create_...' do
|
||||
|
||||
let(:action) { 'create_middle' }
|
||||
|
||||
it_behaves_like 'a validation with errors'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'a permission based validator', permission: 'ticket.agent'
|
||||
it_behaves_like 'a permission based validator', permission: '-all-'
|
||||
end
|
||||
|
||||
context 'when validation should not be performed' do
|
||||
|
||||
context 'for present value' do
|
||||
|
||||
let(:value) { 'some_value' }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'when value is actually blank' do
|
||||
|
||||
let(:value) { nil }
|
||||
|
||||
context "when action wasn't performed by a user" do
|
||||
context 'for blank UserInfo.current_user_id', current_user_id: nil do
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'for system UserInfo.current_user_id', current_user_id: 1 do
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for required => false' do
|
||||
|
||||
let(:performing_user) { create(:agent_user) }
|
||||
|
||||
before { UserInfo.current_user_id = performing_user.id }
|
||||
|
||||
context 'for applying permission' do
|
||||
|
||||
let(:permission) { 'ticket.agent' }
|
||||
|
||||
before do
|
||||
attribute.screens = {
|
||||
action => {
|
||||
permission => {
|
||||
required: false
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when action is edit' do
|
||||
|
||||
let(:action) { 'edit' }
|
||||
let(:record) { create(:user) }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'when action is create_...' do
|
||||
|
||||
let(:action) { 'create_middle' }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for not applying permission' do
|
||||
|
||||
let(:permission) { 'ticket.customer' }
|
||||
|
||||
before do
|
||||
attribute.screens = {
|
||||
action => {
|
||||
permission => {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when action is edit' do
|
||||
|
||||
let(:action) { 'edit' }
|
||||
let(:record) { create(:user) }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
|
||||
context 'when action is create_...' do
|
||||
|
||||
let(:action) { 'create_middle' }
|
||||
|
||||
it_behaves_like 'a validation without errors'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
98
spec/models/object_manager/attribute/validation_spec.rb
Normal file
98
spec/models/object_manager/attribute/validation_spec.rb
Normal file
|
@ -0,0 +1,98 @@
|
|||
require 'rails_helper'
|
||||
require 'lib/mixin/has_backends_examples'
|
||||
|
||||
RSpec.describe ObjectManager::Attribute::Validation, application_handle: 'application_server' do
|
||||
it_behaves_like 'Mixin::HasBackends'
|
||||
|
||||
it 'is a ActiveModel::Validator' do
|
||||
expect(described_class).to be < ActiveModel::Validator
|
||||
end
|
||||
|
||||
describe '#validate' do
|
||||
|
||||
subject { described_class.new }
|
||||
let(:record) { build(:user) }
|
||||
let(:backend) { spy }
|
||||
|
||||
around do |example|
|
||||
original_backends = described_class.backends.dup
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
described_class.backends = original_backends
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
described_class.backends = Set[backend]
|
||||
end
|
||||
|
||||
it 'sends .validate to backends' do
|
||||
subject.validate(record)
|
||||
expect(backend).to have_received(:validate).with(record: record, attribute: instance_of(::ObjectManager::Attribute)).at_least(:once)
|
||||
end
|
||||
|
||||
context 'for cached ObjectManager::Attribute records' do
|
||||
|
||||
it 'fetches current records when in memory Cache is blank' do
|
||||
allow(::ObjectManager::Attribute).to receive(:where).and_call_original
|
||||
subject.validate(record)
|
||||
expect(::ObjectManager::Attribute).to have_received(:where).twice
|
||||
end
|
||||
|
||||
it "doesn't fetch current records when in memory Cache is valid" do
|
||||
subject.validate(record)
|
||||
|
||||
allow(::ObjectManager::Attribute).to receive(:where).and_call_original
|
||||
subject.validate(record)
|
||||
expect(::ObjectManager::Attribute).to have_received(:where).once
|
||||
end
|
||||
|
||||
it 'fetches current records when in memory Cache is outdated' do
|
||||
subject.validate(record)
|
||||
|
||||
::ObjectManager::Attribute.last.touch
|
||||
|
||||
allow(::ObjectManager::Attribute).to receive(:where).and_call_original
|
||||
subject.validate(record)
|
||||
expect(::ObjectManager::Attribute).to have_received(:where).twice
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no validation is performed' do
|
||||
|
||||
it 'is skipped because of irrelevant ApplicationHandleInfo', application_handle: 'non_application_server' do
|
||||
subject.validate(record)
|
||||
expect(backend).to_not have_received(:validate)
|
||||
end
|
||||
|
||||
it 'is skipped because of import_mode is active' do
|
||||
expect(Setting).to receive(:get).with('import_mode').and_return(true)
|
||||
subject.validate(record)
|
||||
expect(backend).to_not have_received(:validate)
|
||||
end
|
||||
|
||||
it 'is skipped because of unchanged attributes' do
|
||||
record.save!
|
||||
RSpec::Mocks.space.proxy_for(backend).reset
|
||||
subject.validate(record)
|
||||
expect(backend).not_to have_received(:validate)
|
||||
end
|
||||
|
||||
context 'when caused by ObjectManager::Attribute records' do
|
||||
|
||||
it 'is skipped because no custom attributes are present' do
|
||||
::ObjectManager::Attribute.update(editable: false)
|
||||
subject.validate(record)
|
||||
expect(backend).not_to have_received(:validate)
|
||||
end
|
||||
|
||||
it 'is skipped because no active attributes are present' do
|
||||
::ObjectManager::Attribute.update(active: false)
|
||||
subject.validate(record)
|
||||
expect(backend).not_to have_received(:validate)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,14 @@ require 'models/application_model_examples'
|
|||
require 'models/concerns/can_lookup_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'
|
||||
|
||||
RSpec.describe Organization, type: :model do
|
||||
it_behaves_like 'ApplicationModel', can_assets: { associations: :members }
|
||||
it_behaves_like 'CanLookup'
|
||||
it_behaves_like 'HasSearchIndexBackend', indexed_factory: :organization
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :organization
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
|
||||
describe '.where_or_cis' do
|
||||
it 'finds instance by querying multiple attributes case insensitive' do
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
require 'rails_helper'
|
||||
require 'models/application_model_examples'
|
||||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
|
||||
RSpec.describe Ticket::Article, type: :model do
|
||||
it_behaves_like 'ApplicationModel'
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
|
||||
describe 'Callbacks, Observers, & Async Transactions' do
|
||||
describe 'NULL byte handling (via ChecksAttributeValuesAndLength concern):' do
|
||||
|
|
|
@ -3,12 +3,14 @@ require 'models/application_model_examples'
|
|||
require 'models/concerns/can_be_imported_examples'
|
||||
require 'models/concerns/can_lookup_examples'
|
||||
require 'models/concerns/has_xss_sanitized_note_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
|
||||
RSpec.describe Ticket, type: :model do
|
||||
it_behaves_like 'ApplicationModel'
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'CanLookup'
|
||||
it_behaves_like 'HasXssSanitizedNote', model_factory: :ticket
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
|
||||
subject(:ticket) { create(:ticket) }
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ 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/can_lookup_examples'
|
||||
require 'models/concerns/has_object_manager_attributes_validation_examples'
|
||||
|
||||
RSpec.describe User, type: :model do
|
||||
it_behaves_like 'ApplicationModel', can_assets: { associations: :organization }
|
||||
|
@ -15,6 +16,7 @@ RSpec.describe User, type: :model do
|
|||
it_behaves_like 'HasGroups and Permissions', group_access_no_permission_factory: :user
|
||||
it_behaves_like 'CanBeImported'
|
||||
it_behaves_like 'CanLookup'
|
||||
it_behaves_like 'HasObjectManagerAttributesValidation'
|
||||
|
||||
subject(:user) { create(:user) }
|
||||
let(:admin) { create(:admin_user) }
|
||||
|
|
11
spec/support/application_handle_info.rb
Normal file
11
spec/support/application_handle_info.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
RSpec.configure do |config|
|
||||
|
||||
config.around(:each, :application_handle) do |example|
|
||||
ApplicationHandleInfo.current = example.metadata[:application_handle]
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
ApplicationHandleInfo.current = nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,4 +25,13 @@ end
|
|||
|
||||
RSpec.configure do |config|
|
||||
config.include ZammadSpecSupportUserInfo
|
||||
|
||||
config.around(:each, :current_user_id) do |example|
|
||||
UserInfo.current_user_id = example.metadata[:current_user_id]
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
UserInfo.current_user_id = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue