Newer
Older
dmpopidor / app / controllers / api / v0 / statistics_controller.rb
# frozen_string_literal: true

class Api::V0::StatisticsController < Api::V0::BaseController

  before_action :authenticate

  # GET /api/v0/statistics/users_joined?start_date=&end_date=&org_id=
  #
  # Returns the number of users joined for the user's org.
  # If start_date is passed, only counts those with created_at is >= than start_date
  # If end_date is passed, only counts those with created_at is <= than end_date are
  # If org_id is passed and user has super_admin privileges that counter is performed
  # against org_id param instead of user's org
  def users_joined
    unless Api::V0::StatisticsPolicy.new(@user, :statistics).users_joined?
      raise Pundit::NotAuthorizedError
    end

    if @user.can_super_admin? && params[:org_id].present?
      scoped = User.unscoped.where(org_id: params[:org_id])
    else
      scoped = User.unscoped.where(org_id: @user.org_id)
    end

    if params[:range_dates].present?
      r = {}
      params[:range_dates].each_pair do |k, v|
        r[k] = scoped.where(created_at: dates_to_range(v)).count
      end

      # Reverse hash r, so dates in ascending order
      r = Hash[r.to_a.reverse]

      respond_to do |format|
        format.json { render(json: r.to_json) }
        format.csv {
          send_data(CSV.generate do |csv|
            csv << [_("Month"), _("No. Users joined")]
            total = 0
            r.each_pair { |k, v| csv << [k, v]; total += v }
            csv << [_("Total"), total]
          end, filename: "#{_('users_joined')}.csv") }
      end
    else
      if params["start_date"].present? || params["end_date"].present?
        scoped = scoped.where(created_at: dates_to_range(params))
      end
      @users_count = scoped.count
      respond_with @users_count
    end
  end
  # GET
  # Returns the number of completed plans within the user's org for the data
  # start_date and end_date specified
  def completed_plans
    unless Api::V0::StatisticsPolicy.new(@user, :statistics).completed_plans?
      raise Pundit::NotAuthorizedError
    end

    if @user.can_super_admin? && params[:org_id].present?
      scoped = Org.find(params[:org_id]).plans.where(complete: true)
    else
      scoped = @user.org.plans.where(complete: true)
    end

    if params[:range_dates].present?
      r = {}
      params[:range_dates].each_pair do |k, v|
        r[k] = scoped.where(created_at: dates_to_range(v)).count
      end

      # Reverse hash r, so dates in ascending order
      r = Hash[r.to_a.reverse]

      respond_to do |format|
        format.json { render(json: r.to_json) }
        format.csv {
          send_data(CSV.generate do |csv|
            csv << [_("Month"), _("No. Completed Plans")]
            total = 0
            r.each_pair { |k, v| csv << [k, v]; total += v }
            csv << [_("Total"), total]
          end, filename: "#{_('completed_plans')}.csv") }
      end
    else
      if params["start_date"].present? || params["end_date"].present?
        scoped = scoped.where(created_at: dates_to_range(params))
      end
      render(json: { completed_plans: scoped.count })
    end
  end

  # /api/v0/statistics/created_plans
  # Returns the number of created plans within the user's org for the data
  # start_date and end_date specified
  def created_plans
    unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans?
      raise Pundit::NotAuthorizedError
    end

    if @user.can_super_admin? && params[:org_id].present?
      scoped = Org.find(params[:org_id]).plans
    else
      scoped = @user.org.plans
    end

    if params[:range_dates].present?
      r = {}
      params[:range_dates].each_pair do |k, v|
        r[k] = scoped.where(created_at: dates_to_range(v)).count
      end

      # Reverse hash r, so dates in ascending order
      r = Hash[r.to_a.reverse]

      respond_to do |format|
        format.json { render(json: r.to_json) }
        format.csv {
          send_data(CSV.generate do |csv|
            csv << [_("Month"), _("No. Plans")]
            total = 0
            r.each_pair { |k, v| csv << [k, v]; total += v }
            csv << [_("Total"), total]
          end, filename: "#{_('plans')}.csv") }
      end
    else
      if params["start_date"].present? || params["end_date"].present?
        scoped = scoped.where(created_at: dates_to_range(params))
      end
      render(json: { completed_plans: scoped.count })
    end
  end

  ##
  # Displays the number of DMPs using templates owned/create by the caller's Org
  # between the optional specified dates
  def using_template
    org_templates = @user.org.templates.where(customization_of: nil)
    unless Api::V0::StatisticsPolicy.new(@user, org_templates.first).using_template?
      raise Pundit::NotAuthorizedError
    end
    @templates = {}
    org_templates.each do |template|
      if @templates[template.title].blank?
        @templates[template.title]          = {}
        @templates[template.title][:title]  = template.title
        @templates[template.title][:id]     = template.family_id
        @templates[template.title][:uses]   = 0
      end
      scoped = template.plans
      if params["start_date"].present? || params["end_date"].present?
        scoped = scoped.where(created_at: dates_to_range(params))
      end
      @templates[template.title][:uses] += scoped.length
    end
    respond_with @templates
  end

  ##
  # GET
  # Renders a list of templates with their titles, ids, and uses between the optional
  # specified dates the uses are restricted to DMPs created by users of the same
  # organisation as the user who ititiated the call.
  def plans_by_template
    unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans_by_template?
      raise Pundit::NotAuthorizedError
    end
    @templates = {}
    scoped = @user.org.plans
    if params["start_date"].present? || params["end_date"].present?
      scoped = scoped.where(created_at: dates_to_range(params))
    end
    scoped.each do |plan|
      # if hash exists
      if @templates[plan.template.title].blank?
        @templates[plan.template.title] = {}
        @templates[plan.template.title][:title] = plan.template.title
        @templates[plan.template.title][:id] = plan.template.family_id
        @templates[plan.template.title][:uses] = 1
      else
        @templates[plan.template.title][:uses] += 1
      end
    end
    respond_with @templates
  end

  # GET
  #
  # Renders a list of DMPs metadata, provided the DMPs were created between the
  # optional specified dates DMPs must be owned by a user who's organisation is the
  # same as the user who generates the call.
  def plans
    unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans?
      raise Pundit::NotAuthorizedError
    end
    @org_plans = @user.org.plans
    if params["remove_tests"].present? && params["remove_tests"].downcase == "true"
      @org_plans = @org_plans.where.not(visibility: Plan.visibilities[:is_test])
    end
    if params["start_date"].present? || params["end_date"].present?
      @org_plans = @org_plans.where(created_at: dates_to_range(params))
    end
    respond_with @org_plans
  end


  private

  # Convert start/end dates in hash to a range of Dates
  def dates_to_range(hash)
    today = Date.today
    start_date = Date.parse(hash.fetch("start_date", today.prev_month.to_date.to_s))
    end_date = Date.parse(hash.fetch("end_date", today.to_date.to_s)) + 1.day
    start_date..end_date
  end

end