module Katello module Concerns module Api::V2::RepositoryContentController extend ActiveSupport::Concern included do include Katello::Concerns::FilteredAutoCompleteSearch before_action :find_repository before_action :find_optional_organization, :only => [:index, :show, :auto_complete_search] before_action :find_environment, :only => [:index, :auto_complete_search] before_action :find_content_view_version, :only => [:index, :auto_complete_search] before_action :find_filter, :find_filter_rule, :only => [:index, :auto_complete_search] before_action :find_content_resource, :only => [:show] before_action :check_show_all_and_available_params, only: [:index] end extend ::Apipie::DSL::Concern api :GET, "/:resource_id", N_("List :resource_id") api :GET, "/content_views/:content_view_id/filters/:filter_id/:resource_id", N_("List :resource_id") api :GET, "/content_view_filters/:content_view_filter_id/:resource_id", N_("List :resource_id") api :GET, "/repositories/:repository_id/:resource_id", N_("List :resource_id") param :organization_id, :number, :desc => N_("organization identifier") param :content_view_version_id, :number, :desc => N_("content view version identifier") param :content_view_filter_id, :number, :desc => N_("content view filter identifier") param :content_view_filter_rule_id, :number, :desc => N_("content view filter rule identifier") param :repository_id, :number, :desc => N_("repository identifier") param :environment_id, :number, :desc => N_("environment identifier") param :ids, Array, :desc => N_("ids to filter content by") param :include_filter_ids, :bool, desc: N_("Includes associated content view filter ids in response") param_group :search, ::Katello::Api::V2::ApiController def index sort_by, sort_order, options = sort_options respond(:collection => scoped_search(index_relation, sort_by, sort_order, options)) end api :GET, "/:resource_id/:id", N_("Show :a_resource") api :GET, "/repositories/:repository_id/:resource_id/:id", N_("Show :a_resource") param :repository_id, :number, :desc => N_("repository identifier") param :organization_id, :number, :desc => N_("organization identifier") param :id, String, :desc => N_(":a_resource identifier"), :required => true def show respond :resource => @resource end api :GET, "/:resource_id/compare/", N_("List :resource") param :content_view_version_ids, Array, :desc => N_("content view versions to compare") param :repository_id, :number, :desc => N_("Library repository id to restrict comparisons to") param :restrict_comparison, String, :desc => N_("Return same, different or all results") def compare fail _("No content_view_version_ids provided") if params[:content_view_version_ids].empty? @versions = ContentViewVersion.readable.where(:id => params[:content_view_version_ids]) if @versions.count != params[:content_view_version_ids].uniq.length missing = params[:content_view_version_ids] - @versions.pluck(:id) fail HttpErrors::NotFound, _("Couldn't find content view versions '%s'") % missing.join(',') end sort_by, sort_order, options = sort_options if respond_to?(:custom_collection_by_content_view_version) collection = custom_collection_by_content_view_version(@versions) else repos = Katello::Repository.where(:content_view_version_id => @versions.pluck(:id)) repos = repos.where(:root_id => @repo.root_id) if @repo collection = filter_by_repos(repos, resource_class.all, @versions, params[:restrict_comparison]) end collection = scoped_search(collection.distinct, sort_by, sort_order, options) collection[:results] = collection[:results].map { |item| ContentViewVersionComparePresenter.new(item, @versions, @repo) } respond_for_index(:collection => collection) end param :available_for, :string, :desc => N_("Return content that can be added to the specified object. The values 'content_view_version' and 'content_view_filter are supported.") param :show_all_for, :bool, :desc => N_("Returns content that can be both added and is currently added to the object. The value 'content_view_filter' is supported") param :filterId, :integer, :desc => N_("Content View Filter id"), deprecated: true def index_relation if @version && params[:available_for] == "content_view_version" && self.respond_to?(:available_for_content_view_version) collection = self.available_for_content_view_version(@version) else collection = resource_class.all collection = filter_by_content_view_version(@version, collection) if @version end collection = filter_by_repos(repos, collection) collection = filter_by_ids(params[:ids], collection) if params[:ids] collection = handle_cv_filter(collection, @filter, @filter_rule, params) if @filter || @filter_rule collection = self.custom_index_relation(collection) if self.respond_to?(:custom_index_relation) collection end private def default_sort %w(id desc) end def sort_options case default_sort when Array return [default_sort[0], default_sort[1], {}] when Proc return [nil, nil, { :custom_sort => default_sort }] else fail "Unsupported default_sort type" end end def filter_by_content_view_filter(_filter, _collection) fail NotImplementedError, "Unsupported content type for content view filter parameter" end def filter_by_content_view_filter_rule(_filter, _collection) fail NotImplementedError, "Unsupported content type for content view filter rule parameter" end def repos repos = Repository.readable repos = repos.where(:id => @repo) if @repo repos = repos.where(:id => Repository.readable.in_organization(@organization)) if @organization if @environment&.library? repos = repos.where(:id => @environment.repositories) end repos end def filter_by_repos(repos, collection, content_view_versions = nil, compare = 'all') collection = collection.in_repositories(repos) case compare when 'same' compare_same(collection, content_view_versions) when 'different' collection_all_ids = collection&.pluck(:id) collection_same_ids = compare_same(collection, content_view_versions)&.pluck(:id) collection.where(id: collection_all_ids - collection_same_ids) else collection end end def compare_same(collection, content_view_versions = nil) cv_version_first = content_view_versions[0] collection_ids = collection.in_repositories(Katello::Repository.where(:content_view_version_id => cv_version_first&.id))&.pluck(:id) content_view_versions[1..].each do |version| collection_version_ids = collection.in_repositories(Katello::Repository.where(:content_view_version_id => version&.id))&.pluck(:id) collection_ids = collection_ids.intersection collection_version_ids end return collection.where(id: collection_ids) end def filter_by_content_view_version(version, collection) if params[:content_type] return collection.where(:id => version.send(controller_name, params[:content_type])) end collection.where(:id => version.send(controller_name)) end def find_content_resource @resource = resource_class.with_identifiers(params[:id]).first if resource_class == Katello::Erratum && @resource.blank? @resource = Erratum.find_by_errata_id(params[:id]) end if @resource.blank? fail HttpErrors::NotFound, _("Failed to find %{content} with id '%{id}'.") % { content: resource_name, id: params[:id] } end if params[:repository_id] && !@resource.repositories.include?(@repo) fail HttpErrors::NotFound, _("Could not find %{content} with id '%{id}' in repository.") % { content: resource_name, id: params[:id] } end if params[:organization_id] && !@resource.repositories.any? { |repo| repo.organization_id == params[:organization_id].to_i } fail HttpErrors::BadRequest, _("The requested resource does not belong to the specified organization") end end def filter_by_ids(ids, collection) collection.with_identifiers(ids) end def find_repository if params[:repository_id] @repo = Repository.readable.find_by(:id => params[:repository_id]) fail HttpErrors::NotFound, _("Couldn't find repository '%s'") % params[:repository_id] if @repo.nil? end end def find_environment if params[:environment_id] @environment = KTEnvironment.readable.find_by(:id => params[:environment_id]) if @environment.nil? fail HttpErrors::NotFound, _("Could not find Lifecycle Environment with id '%{id}'.") % { id: params[:environment_id] } end end end def find_content_view_version if params[:content_view_version_id] @version = ContentViewVersion.readable.find_by(:id => params[:content_view_version_id]) fail HttpErrors::NotFound, _("Couldn't find content view version '%s'") % params[:content_view_version_id] if @version.nil? end end def find_filter # TODO: in v2.rb some routes use "filters", others use "content_view_filters" filter_id = params[:content_view_filter_id] || params[:filter_id] || params[:filterId] if filter_id scoped = ContentViewFilter.all @filter = scoped.where(:type => filter_class_name).find_by(:id => filter_id) unless @filter fail HttpErrors::NotFound, _("Couldn't find %{type} Filter with id %{id}") % { :type => resource_name, :id => params[:filter_id] } end end end def find_filter_rule filter_rule_id = params[:content_view_filter_rule_id] if filter_rule_id @filter_rule = filter_rule_class_name.constantize.find_by(:id => filter_rule_id) unless @filter_rule fail HttpErrors::NotFound, _("Couldn't find %{type} Filter with id %{id}") % { :type => resource_name, :id => filter_rule_id } end end end def check_show_all_and_available_params if params[:show_all_for] && params[:available_for] fail HttpErrors::BadRequest, _("params 'show_all_for' and 'available_for' must be used independently") end end def resource_class "Katello::#{controller_name.classify}".constantize end def singular_resource_name controller_name.singularize end def filter_class_name "Katello::ContentView#{controller_name.classify}Filter" end def filter_rule_class_name "Katello::ContentView#{controller_name.classify}FilterRule" end def resource_name(_i18n = true) case resource_class.to_s when "Katello::Erratum" _("Erratum") when "Katello::Deb" _("Deb Package") when "Katello::Rpm" _("Package") when "Katello::Srpm" _("Source RPM") when "Katello::PackageGroup" _("Package Group") when "Katello::DockerManifest" _("Container Image Manifest") when "Katello::DockerMetaTag" _("Container Image Tag") when "Katello::OstreeBranch" _("OSTree Branch") when "Katello::FileUnit" _("File") when "Katello::ModuleStream" _("Module Stream") when "Katello::AnsibleCollection" _("Ansible Collection") else fail "Can't find resource class: #{resource_class}" end end def repo_association :repoids end def check_repo_for_content_resource if params[:repository_id] && !@resource.send(repo_association).include?(@repo.pulp_id) fail HttpErrors::NotFound, _("Could not find %{content} with id '%{id}' in repository.") % { content: resource_name, id: params[:id] } end end def handle_cv_filter(collection, filter, filter_rule, params) if params[:show_all_for] == "content_view_filter" && self.respond_to?(:all_for_content_view_filter) collection = self.all_for_content_view_filter(filter, collection) elsif params[:available_for] == "content_view_filter" && self.respond_to?(:available_for_content_view_filter) collection = self.available_for_content_view_filter(filter, collection) else # Filtering by the CV filter rule makes filtering by the CV filter redundant, keeping these # exclusive to keep the queries simple. if filter_rule collection = filter_by_content_view_filter_rule(filter_rule, collection) elsif filter collection = filter_by_content_view_filter(filter, collection) end end collection end end end end