datacite/volpino

View on GitHub
app/controllers/users_controller.rb

Summary

Maintainability
B
6 hrs
Test Coverage
F
50%
# frozen_string_literal: true

class UsersController < BaseController
  # include helper module for caching infrequently changing resources
  include Cacheable

  # include helper module for metadata lookup from ORCID
  include Metadatable

  # include helper module for information about associated DOIs
  include Countable

  prepend_before_action :load_user, only: %i[show destroy]
  before_action :set_include, :authenticate_user_from_token!
  load_and_authorize_resource only: [:destroy]

  def show
    options = {}

    meta = get_meta(user_id: params[:id])
    options[:meta] = {
      dois: meta.fetch("created", []),
      published: meta.fetch("published", []),
      "resourceTypes" => meta.fetch("resourceTypes", []),
      views: meta.fetch("views", []),
      downloads: meta.fetch("downloads", []),
      citations: meta.fetch("citations", []),
    }.compact
    options[:include] = @include
    options[:is_collection] = false
    options[:params] = { current_ability: current_ability }

    render json: UserSerializer.new(@user, options).serialized_json, status: :ok
  end

  def index
    sort = case params[:sort]
           when "relevance" then { "_score" => { order: "desc" } }
           when "name" then { "family_name.raw" => { order: "asc" } }
           when "-name" then { "family_name.raw" => { order: "desc" } }
           when "created" then { created_at: { order: "asc" } }
           when "-created" then { created_at: { order: "desc" } }
           else { "family_name.raw" => { order: "asc" } }
    end

    page = page_from_params(params)

    response = if params[:id].present?
      User.find_by(id: params[:id])
    elsif params[:ids].present?
      User.find_by_id(params[:ids], page: page, sort: sort)
    else
      User.query(params[:query], page: page, sort: sort)
    end

    begin
      total = response.results.total
      total_for_pages = page[:cursor].nil? ? [total.to_f, 10000].min : total.to_f
      total_pages = page[:size] > 0 ? (total_for_pages / page[:size]).ceil : 0

      options = {}
      options[:meta] = {
        total: total,
        "totalPages" => total_pages,
        page: page[:number],
      }.compact

      options[:links] = {
        self: request.original_url,
        next: response.results.blank? ? nil : request.base_url + "/users?" + {
          query: params[:query],
          "page[number]" => page[:number] + 1,
          "page[size]" => page[:size],
          sort: params[:sort],
        }.compact.to_query,
      }.compact
      options[:is_collection] = true

      fields = fields_from_params(params)
      if fields
        render json: UserSerializer.new(response.results, options.merge(fields: fields)).serialized_json, status: :ok
      else
        render json: UserSerializer.new(response.results, options).serialized_json, status: :ok
      end
    rescue Elasticsearch::Transport::Transport::Errors::BadRequest => e
      Raven.capture_exception(e)

      message = JSON.parse(e.message[6..-1]).to_h.dig("error", "root_cause", 0, "reason")

      render json: { "errors" => { "title" => message } }.to_json, status: :bad_request
    end
  end

  def create
    @user = User.new(safe_params)
    authorize! :create, @user

    if @user.save
      options = {}
      options[:is_collection] = false
      render json: UserSerializer.new(@user, options).serialized_json, status: :created
    else
      logger.error @user.errors.inspect
      render json: serialize_errors(@user.errors), status: :unprocessable_entity
    end
  end

  def update
    @user = User.where(uid: params[:id]).first
    exists = @user.present?

    if exists
      authorize! :update, @user
      @user.assign_attributes(safe_params)
      status = :ok
    else
      @user = User.new(safe_params.merge(uid: params[:id], provider: "globus"))
      authorize! :new, @user
      status = :created
    end

    if @user.save
      options = {}
      options[:is_collection] = false
      render json: UserSerializer.new(@user, options).serialized_json, status: status
    else
      logger.error @user.errors.inspect
      render json: serialize_errors(@user.errors), status: :unprocessable_entity
    end
  end

  def destroy; end

  protected
    def load_user
      @user = User.where(uid: params[:id]).first
      fail ActiveRecord::RecordNotFound if @user.blank?
    end

    def set_include
      if params[:include].present?
        @include = params[:include].split(",").map { |i| i.downcase.underscore }.join(",")
        @include = @include & [:claims]
      else
        @include = []
      end
    end

  private
    def safe_params
      fail JSON::ParserError, "You need to provide a payload following the JSONAPI spec" if params[:data].blank?

      ActiveModelSerializers::Deserialization.jsonapi_parse!(
        params,
        only: [
          :id, :uid, :name, "givenNames", "familyName", :email, :beta_tester, :role, :provider, :client
        ],
        keys: {
          id: :uid, "givenNames" => :given_names, "familyName" => :family_name
        },
      )
    end
end