3scale/porta

View on GitHub
app/models/cms/section.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true
 
Mass assignment is not restricted using attr_accessible
Class `Section` has 21 methods (exceeds 20 allowed). Consider refactoring.
CMS::Section has at least 17 methods
class CMS::Section < ApplicationRecord
include ThreeScale::Search::Scopes
include CMS::Filtering
extend System::Database::Scopes::IdOrSystemName
include NormalizePathAttribute
 
self.table_name = :cms_sections
 
self.background_deletion = %w[group_sections]
self.background_deletion_method = :delete
 
self.allowed_search_scopes = %i[parent_id]
 
scope :by_parent_id, ->(parent_id) { where(parent_id: parent_id) }
 
belongs_to :provider, :class_name => 'Account'
 
has_many :builtins, :class_name => 'CMS::Builtin'
 
has_many :pages, :class_name => 'CMS::Page'
has_many :files, :class_name => 'CMS::File'
 
has_many :children, :class_name => 'CMS::Section', :foreign_key => :parent_id
belongs_to :parent, :foreign_key => :parent_id, :class_name => 'CMS::Section'
 
alias sections children
alias section= parent=
 
validates :title, :system_name, :provider, presence: true
validates :parent_id, presence: { :unless => :root? }
 
validates :title, uniqueness: { scope: [:provider_id, :parent_id], case_sensitive: true }
validates :system_name, uniqueness: { scope: [:provider_id], case_sensitive: true }, length: { maximum: 255 }
validates :partial_path, :title, :type, length: { maximum: 255 }
 
before_validation :set_system_name , on: %i[create update]
before_validation :set_partial_path, :on => :create
verify_path_format :partial_path
before_validation :set_provider, :on => :create
 
before_destroy :avoid_destruction
 
validate :not_own_child
validate :parent_same_provider, { unless: :root? }
 
has_many :group_sections, :class_name => 'CMS::GroupSection', inverse_of: :section, :dependent => :destroy
has_many :groups, :class_name => 'CMS::Group', :through => :group_sections
 
before_save :strip_trailing_slashes
 
module ProviderAssociationExtension
def root
self.find_by_system_name('root')
end
 
def root!
self.find_by_system_name!('root')
end
 
def partial_paths
self.select('id, partial_path, tenant_id').map{ |section| [section.id, section.partial_path] }
end
 
def find_or_create!(name, path, options = {})
system_name = name.parameterize
 
if section = find_by_system_name(system_name)
section
else
with_defaults = options.reverse_merge!(partial_path: path, system_name: system_name, title: name, public: true, parent: root)
create!(with_defaults)
end
end
end
 
def full_path
path_from_root = parent ? parent.full_path : +"/"
path_from_root.gsub!(/([^\/])$/,"\\1/")
self.root? ? path_from_root : (path_from_root + partial_path).gsub(/\/+/,"/")
end
 
def search
super.merge string: "#{self.title} #{self.system_name}"
end
 
def protected?
not public?
end
 
# def partial_path=(value)
# @partial_path = value.gsub(/\A\/+/,'').gsub(/\/+$/,'')
# end
 
alias restricted_access? protected?
 
def accessible_by?(buyer)
return true if root? && public?
if public? # buyer can be nil (non logged users)
CMS::Section#accessible_by? calls 'parent.accessible_by?(buyer)' 2 times
parent.accessible_by?(buyer)
else # protected. buyer has to be an Account
buyer && buyer.accessible_sections.include?(self) && parent.accessible_by?(buyer)
end
end
 
def root?
system_name.to_s == "root"
end
 
# Adds or removes `model_type` elements from/to the section,
# that it only includes those from `inside_ids`.
#
# TODO : doc this
#
CMS::Section#add_remove_by_ids has approx 12 statements
Method `add_remove_by_ids` has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring.
def add_remove_by_ids( model_type, inside_ids)
CMS::Section#add_remove_by_ids calls 'model_type.to_s.pluralize' 2 times
CMS::Section#add_remove_by_ids calls 'model_type.to_s' 2 times
all = provider.send(model_type.to_s.pluralize)
inside = self.send(model_type.to_s.pluralize)
 
inside_ids = (inside_ids || []).uniq
 
CMS::Section#add_remove_by_ids has the variable name 'p'
to_keep, to_delete = inside.partition { |p| inside_ids.include?(p.id.to_s) }
CMS::Section#add_remove_by_ids has the variable name 'k'
to_add = inside_ids - to_keep.map{ |k| k.id.to_s}
 
to_add.each do |file_id|
CMS::Section#add_remove_by_ids calls 'all.find(file_id)' 2 times
if all.exists?(file_id) && all.find(file_id).valid?
inside << all.find(file_id)
end
end
 
CMS::Section#add_remove_by_ids has the variable name 'a'
to_delete.each{|a| a.section = provider.sections.root; a.save} unless self.root?
end
 
 
# TODO: optimize
def dirty?
CMS::Section#dirty? has the variable name 'c'
self.children.any? { |c| c.dirty? } ||
CMS::Section#dirty? has the variable name 'f'
self.files.any? { |f| f.dirty? } ||
CMS::Section#dirty? calls 'p.dirty?' 2 times
CMS::Section#dirty? has the variable name 'p'
self.pages.any? { |p| p.dirty? } ||
self.builtins.any? { |p| p.dirty? }
end
 
CMS::Section#destroy has approx 14 statements
def destroy
CMS::Section tests 'root?' at least 3 times
unless root?
CMS::Section.transaction do
CMS::Section#destroy calls 'p.section = parent' 2 times
CMS::Section#destroy calls 'p.save!' 2 times
CMS::Section#destroy has the variable name 'p'
builtins.each{|p| p.section = parent; p.save!}
pages.each {|p| p.section = parent; p.save!}
CMS::Section#destroy has the variable name 'f'
files.each {|f| f.section = parent; f.save!}
CMS::Section#destroy has the variable name 's'
children.each{|s| s.parent = parent; s.save!}
super
end
end
end
 
def child_of?(ancestor_id)
if parent.present?
return (parent_id == ancestor_id) || parent.child_of?(ancestor_id)
else
return false
end
end
 
protected
 
def set_system_name
self.system_name = title.parameterize if title.present? && system_name.blank?
end
 
def set_partial_path
if partial_path.blank?
self.partial_path = root? ? '/' : title.try!(:parameterize)
end
end
 
def set_provider
CMS::Section#set_provider performs a nil-check
self.provider = parent.provider if self.parent && self.provider.nil?
end
 
def avoid_destruction
throw :abort if root?
end
 
def label
title || system_name
end
 
private
 
def not_own_child
if child_of?(self.id)
errors.add(:base, "cannot be it's own ancestor")
end
end
 
def parent_same_provider
return if parent&.provider == provider
 
errors.add(:parent_id, "must belong to the same provider")
end
 
def strip_trailing_slashes
self.partial_path.to_s.gsub!(/^\/+/,"/")
end
end