openSUSE/open-build-service

View on GitHub
src/api/app/controllers/webui/patchinfo_controller.rb

Summary

Maintainability
B
5 hrs
Test Coverage
require 'builder'

class Webui::PatchinfoController < Webui::WebuiController
  include Webui::PackageHelper
  before_action :set_project
  before_action :get_binaries, except: [:show, :destroy, :new_tracker]
  before_action :require_exists, except: [:create, :new_tracker]
  before_action :require_login, except: [:show]
  before_action :set_patchinfo, only: [:show, :edit]

  def create
    authorize @project, :update?, policy_class: ProjectPolicy

    unless @project.exists_package?('patchinfo')
      unless Patchinfo.new.create_patchinfo(@project.name, nil)
        flash[:error] = 'Error creating patchinfo'
        redirect_to(controller: 'project', action: 'show', project: @project) && return
      end
    end
    @package = @project.packages.find_by_name('patchinfo')
    unless @package.patchinfo
      flash[:error] = "Patchinfo not found for #{params[:project]}"
      redirect_to(controller: 'package', action: 'show', project: @project, package: @package) && return
    end
    redirect_to edit_patchinfo_path(project: @project, package: @package)
  end

  def edit
    # TODO: check that @tracker has sense if it's coming from create (new_patchinfo) action
    @tracker = ::Configuration.default_tracker
    @patchinfo.binaries.each { |bin| @binarylist.delete(bin) }

    switch_to_webui2
  end

  def show
    @pkg_names = @project.packages.pluck(:name)
    @pkg_names.delete('patchinfo')
    @packager = User.where(login: @patchinfo.packager).first

    switch_to_webui2
  end

  def update
    switch_to_webui2

    authorize @package, :update?
    @patchinfo = Patchinfo.new(patchinfo_params)
    if @patchinfo.valid?
      xml = @patchinfo.to_xml(@project, @package)
      begin
        Package.verify_file!(@package, '_patchinfo', xml)
        Backend::Api::Sources::Package.write_patchinfo(@package.project.name, @package.name, User.session!.login, xml)
        @package.sources_changed(wait_for_update: true) # wait for indexing for special files
      rescue APIError, Timeout::Error => e
        flash[:error] = "patchinfo is invalid: #{e.message}"
        flash[:error] = 'Timeout when saving file. Please try again.' if e.is_a?(Timeout::Error)
        render action: :edit, project: @project, package: @package
        return
      end

      flash[:success] = "Successfully edited #{@package}"
      redirect_to controller: 'patchinfo', action: 'show', project: @project.name, package: @package
    else
      flash[:error] = @patchinfo.errors.full_messages.to_sentence
      @patchinfo.binaries.to_a.each { |bin| @binarylist.delete(bin) }
      render action: :edit, project: @project, package: @package
    end
  rescue Backend::Error
    flash[:error] = 'No permission to edit the patchinfo-file.'
    redirect_to action: 'show', project: @project.name, package: @package.name
  end

  def destroy
    authorize @package, :destroy?

    if @package.check_weak_dependencies? && @package.destroy
      redirect_to(project_show_path(@project), success: 'Patchinfo was successfully removed.')
    else
      redirect_to(patchinfo_show_path(package: @package, project: @project),
                  notice: "Patchinfo can't be removed: #{@package.errors.full_messages.to_sentence}")
    end
  end

  def delete_dialog
    render_dialog
  end

  def update_issues
    authorize @project, :update?

    Patchinfo.new.cmd_update_patchinfo(params[:project], params[:package], 'updated via update_issues call')
    redirect_to edit_patchinfo_path(project: @project, package: @package)
  end

  def new_tracker
    # collection with all informations of the new issues
    issue_collection = []
    error = ''
    invalid_format = ''
    # params[:issues] = list of new issues to add
    params[:issues].each do |new_issue|
      issue = IssueTracker::IssueTrackerHelper.new(new_issue)
      if issue.valid?
        begin
          issue_tracker = IssueTracker.find_by_name(issue.tracker)
          if issue_tracker
            issue.url = issue_tracker.show_url_for(issue.issue_id)
            summary = IssueTracker::IssueSummary.new(issue.tracker, issue.issue_id)
            unless summary.belongs_bug_to_tracker?
              invalid_format += "#{issue.tracker} "
              next
            end
            issue.summary = summary.issue_summary
            issue_collection << issue.to_a
          else
            error << "#{issue.tracker} is not a valid tracker.\n"
          end
        rescue Backend::NotFoundError
          invalid_format += "#{issue.tracker} "
        end
      else
        invalid_format += "#{issue.tracker} "
      end
    end

    error += print_invalid_format(invalid_format) unless invalid_format.empty?

    render json: { error: error, issues: issue_collection }
  end

  private

  def print_invalid_format(invalid_format)
    "#{invalid_format.strip} has no valid format. (Correct formats are e.g. " \
             'boo#123456, CVE-1234-5678 and the string has to be a comma-separated list)'
  end

  def get_binaries
    @binarylist = []
    binary_list = Xmlhash.parse(Backend::Api::Build::Project.binarylist(params[:project]))
    binary_list.elements('result') do |result|
      result.elements('binarylist') do |list|
        list.elements('binary') do |bin|
          next if ['rpmlint.log', 'updateinfo.xml'].include?(bin['filename'])
          @binarylist << bin['filename'].sub(/-[^-]*-[^-]*.rpm$/, '')
        end
      end
    end
    @binarylist.uniq!
  end

  def require_exists
    if params[:package].present?
      begin
        @package = Package.get_by_project_and_name(params[:project], params[:package], use_source: false)
      rescue Package::UnknownObjectError
        flash[:error] = "Patchinfo '#{params[:package]}' not found in project '#{params[:project]}'"
        redirect_to project_show_path(project: params[:project])
        return
      end
    end

    return if @package && @package.patchinfo

    # FIXME: should work for remote packages
    flash[:error] = "Patchinfo not found for #{params[:project]}"
    redirect_to(controller: 'package', action: 'show', project: @project, package: @package)
  end

  def set_patchinfo
    patchinfo_xml = Xmlhash.parse(@package.patchinfo.document.to_xml)
    @patchinfo = Patchinfo.new.load_from_xml(patchinfo_xml)
  end

  def patchinfo_params
    params.require(:patchinfo).permit(:summary, :description, :packager, :category, :rating, :name, :version, :message,
                                      :relogin_needed, :reboot_needed, :zypp_restart_needed, :block, :block_reason,
                                      binaries: [], issueid: [], issueurl: [], issuetracker: [], issuesum: [])
  end
end