Files
Jan Sandbrink d385b0437f Allow to configure authentication method through UI
This includes a refactoring to our storage contracts,
which so far required to perform all validations of a storage at
once, even though the storage is assembled step by step.

It's now possible to validate only one step of the storage creation,
while still having a contract that validates the storage as a whole.

By default the Create/Update contract will validate the whole storage,
as before, but they can now be instructed to validate using one
of the partial contracts.
2025-02-19 14:28:48 +01:00

95 lines
3.0 KiB
Ruby

# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
##
# A contract that allows to compose itself from other contracts like:
#
# class MyContract < ComposedContract
# include_contract MyOtherContractA
# include_contract MyOtherContractB
# end
#
# This allows to run the smaller contracts separately, but also to have one contract
# that validates the model as a whole. The composed contract will make sure that all attributes
# defined as writable in one contract are also considered writable in other contracts.
#
# It's not possible to add validations to the composed contract directly. If you need additional validations,
# extract them into a separate contract that you include in the composed contract.
class ComposedContract
class << self
def included_contract_classes
@included_contract_classes ||= []
end
def include_contract(contract_class)
included_contract_classes << contract_class
end
end
attr_reader :errors, :model, :writable_attributes
def initialize(model, user, options: {})
@model = model
@user = user
@options = options
@errors = ActiveModel::Errors.new(model)
@writable_attributes = []
end
def validate
errors.clear
included_contracts.each do |subcontract|
subcontract.validate
errors.merge!(subcontract.errors)
end
errors.empty?
end
def valid?
validate
end
private
def included_contracts
@included_contracts ||= begin
contracts = self.class.included_contract_classes.map { |klass| klass.new(model, @user, options: @options) }
all_writable_attributes = (writable_attributes + contracts.flat_map(&:writable_attributes)).uniq
contracts.each do |subcontract|
subcontract.writable_attributes.append(*all_writable_attributes)
end
contracts
end
end
end