unepwcmc/SAPI

View on GitHub
app/controllers/api/v1/documents_controller.rb

Summary

Maintainability
C
1 day
Test Coverage
class Api::V1::DocumentsController < ApplicationController

  def index
    if params[:taxon_concept_query].present?
      exact_match = MTaxonConcept.where("LOWER(full_name) = ?", params[:taxon_concept_query].downcase)
                                 .where(taxonomy_id: 1)
                                 .first
      @species_search = Species::Search.new({
        visibility: :elibrary,
        taxon_concept_query: params[:taxon_concept_query]
      })

      ids = @species_search.ids
      anc_ids = []
      children_ids = []
      anc_ids = MaterialDocIdsRetriever.ancestors_ids(exact_match.try(:id), params[:taxon_concept_query], exact_match) if exact_match
      children_ids = MTaxonConcept.descendants_ids(exact_match.try(:id)).map(&:to_i) if exact_match
      params[:taxon_concepts_ids] = anc_ids | children_ids | ids
    else
      if params[:taxon_concepts_ids].present?
        taxa = TaxonConcept.find(params[:taxon_concepts_ids])
        children_ids = taxa.map(&:children).map do
          |children| children.pluck(:id) if children.present?
        end.flatten.uniq.compact
        taxa_ids = taxa.map(&:id)
        ancestor_ids = MaterialDocIdsRetriever.ancestors_ids(taxa_ids.first)
        params[:taxon_concepts_ids] = taxa_ids | ancestor_ids | children_ids
      end
    end

    @search = DocumentSearch.new(
      params.merge(show_private: !access_denied?, per_page: 100), 'public'
    )

    #TODO move pagination and ordering to the document_search module after refactoring of SQL mviews
    page = params[:page] || 1
    per_page = (params[:per_page] || 100).to_i

    ordered_docs =
      if params[:taxon_concepts_ids].present? && params[:event_type] == 'IdMaterials'
        if params[:taxon_concept_query].present? && !exact_match
          @search.cached_results.sort_by{ |doc| [doc.taxon_names.first, doc.date_raw] }
        else
          @search.cached_results.sort_by do |doc|
            doc_tc_ids = doc.taxon_concept_ids
            params[:taxon_concepts_ids].index{ |id| doc_tc_ids.include?(id) } || 1_000_000
          end
        end
      else
        @search.cached_results.sort{ |a, b| [b.date_raw , a.taxon_names.first || ''] <=> [a.date_raw, b.taxon_names.first || ''] }
      end

    ordered_docs =
      Kaminari.paginate_array(ordered_docs).page(page).per(per_page) if ordered_docs.kind_of?(Array)

    render :json => ordered_docs,
      each_serializer: Species::DocumentSerializer,
      meta: {
        total: @search.cached_total_cnt,
        page: @search.page,
        per_page: per_page
      }
  end

  def show
    @document = Document.find(params[:id])
    path_to_file = @document.filename.path unless @document.is_link?
    if access_denied? && !@document.is_public
      render_403
    elsif @document.is_link?
      redirect_to @document.filename.model[:filename]
    elsif !File.exists?(path_to_file)
      render_404
    else
      response.headers['Content-Length'] = File.size(path_to_file).to_s
      send_file(
        path_to_file,
          :filename => File.basename(path_to_file),
          :type => @document.filename.content_type,
          :disposition => 'inline',
          :url_based_filename => true
      )
    end
  end

  def download_zip
    @documents = Document.find(params[:ids].split(','))

    t = Tempfile.new('tmp-zip-' + request.remote_ip)
    missing_files = []
    Zip::OutputStream.open(t.path) do |zos|
      @documents.each do |document|
        path_to_file = document.filename.path
        filename = path_to_file.split('/').last
        unless File.exists?(path_to_file)
          missing_files <<
            "{\n  title: #{document.title},\n  filename: #{filename}\n}"
        else
          zos.put_next_entry(filename)
          zos.print IO.read(path_to_file)
        end
      end
      if missing_files.present?
        if missing_files.length == @documents.count
          render_404 && return
        end
        zos.put_next_entry('missing_files.txt')
        zos.print missing_files.join("\n\n")
      end
    end

    send_file t.path,
      :type => "application/zip",
      :filename => "elibrary-documents.zip"

    t.close
  end

  private

  def access_denied?
    !current_user || current_user.is_api_user_or_secretariat?
  end

  def render_404
    head 404
  end

  def render_403
    head 403
  end

end