skandragon/thing

View on GitHub
app/controllers/users/schedules_controller.rb

Summary

Maintainability
D
2 days
Test Coverage
class Users::SchedulesController < ApplicationController
  before_action :load_user

  def show
    # TODO: need to handle format here, and return an empty schedule for ICS requests
    # where the user does exist, 404 where it does not, and redirect for html requests.

    raise ActiveRecord::RecordNotFound.new('Not Found') unless @user

    render_options = { user: @user }

    uncached = params[:uncached_for_tests].present?

    respond_to do |format|
      format.html {
        if @user.schedule.nil? or @user.schedule.instructables.count == 0
          if current_user and current_user.id == @user.id
            redirect_to edit_user_schedule_path(@user) and return
          else
            redirect_to root_path, alert: 'No such schedule' and return
          end
        end
        @instances = Instance.where(instructable_id: @user.schedule.instructables).order('start_time, btrsort(location)').includes(instructable: [:user])
      }

      format.ics {
        if @user.schedule.nil? or @user.schedule.instructables.count == 0
          raise ActiveRecord::RecordNotFound.new('Not Found')
        end
        @instances = Instance.where(instructable_id: @user.schedule.instructables).order('start_time, btrsort(location)').includes(instructable: [:user])

        filename = "pennsic-#{Pennsic.year}-user#{@user.id}.ics"
        cache_filename = Rails.root.join('tmp', filename)

        if File.exist?(cache_filename)
          File.unlink(cache_filename)
        end

        render_options[:calendar_name] = "PennsicU #{Pennsic.year}"
        renderer = CalendarRenderer.new(@instances, @instructables)
        data = renderer.render_ics(render_options, filename, cache_filename)
        cache_in_file(cache_filename, data)
        send_file(cache_filename, type: Mime[:ics], disposition: "inline; filename=#{filename}", filename: filename)
#        File.unlink(cache_filename) if uncached
      }

      format.pdf {
        if @user.schedule.nil? or @user.schedule.instructables.count == 0
          raise ActiveRecord::RecordNotFound.new('Not Found')
        end

        @instances = Instance.where(instructable_id: @user.schedule.instructables).order('start_time, btrsort(location)').includes(instructable: [:user])
        omit_descriptions = params[:brief].present?

        @instructables = Instructable.where(id: @instances.map(&:instructable_id))

        filename = [
          "pennsic-#{Pennsic.year}-#{@user.id}",
          omit_descriptions ? 'brief' : nil,
        ].compact.join('-') + '.pdf'
        cache_filename = Rails.root.join('tmp', filename)

        if File.exist?(cache_filename)
          File.unlink(cache_filename)
        end

        render_options[:omit_descriptions] = omit_descriptions
        render_options[:no_long_descriptions] = true
        renderer = CalendarRenderer.new(@instances, @instructables)
        data = renderer.render_pdf(render_options, filename)
        cache_in_file(cache_filename, data)
        send_file(cache_filename, type: Mime[:pdf], disposition: "inline; filename=#{filename}", filename: filename)
#        File.unlink(cache_filename) if uncached
      }

      format.csv {
        if @user.schedule.nil? or @user.schedule.instructables.count == 0
          raise ActiveRecord::RecordNotFound.new('Not Found')
        end

        @instances = Instance.where(instructable_id: @user.schedule.instructables).order('start_time, btrsort(location)').includes(instructable: [:user])
        filename = "pennsic-#{Pennsic.year}-user#{@user.id}.csv"
        cache_filename = Rails.root.join('tmp', filename)

        if File.exist?(cache_filename)
          File.unlink(cache_filename)
        end

        renderer = CalendarRenderer.new(@instances, @instructables)
        data = renderer.render_csv(render_options, "pennsic-#{Pennsic.year}-user#{@user.id}.csv")
        cache_in_file(cache_filename, data)
        send_file(cache_filename, type: Mime[:csv], disposition: "filename=#{filename}", filename: filename)
      }

      format.xlsx {
        if @user.schedule.nil? or @user.schedule.instructables.count == 0
          raise ActiveRecord::RecordNotFound.new('Not Found')
        end

        @instances = Instance.where(instructable_id: @user.schedule.instructables).order('start_time, btrsort(location)').includes(instructable: [:user])
        filename = "pennsic-#{Pennsic.year}-#{@user.id}.xlsx"
        cache_filename = Rails.root.join('tmp', filename)

        if File.exist?(cache_filename)
          File.unlink(cache_filename)
        end

        renderer = CalendarRenderer.new(@instances, @instructables)
        data = renderer.render_xlsx(render_options, "pennsic-#{Pennsic.year}-user#{@user.id}.xlsx")
        cache_in_file(cache_filename, data)
        send_file(cache_filename, type: Mime[:xlsx], disposition: "filename=#{filename}", filename: filename)
#        File.unlink(cache_filename) if uncached
      }

    end
  end

  def edit
    @schedule = @user.schedule
    @schedule ||= @user.create_schedule

    instructable_search
  end

  def update
    respond_to do |format|
      format.json {
        if params.has_key?(:published)
          @user.schedule.published = params[:published]
        end
        if params.has_key?(:add_instructable)
          @user.schedule.instructables = (@user.schedule.instructables + [params[:add_instructable].to_i]).uniq.sort
        end
        if params.has_key?(:remove_instructable)
          @user.schedule.instructables = (@user.schedule.instructables - [params[:remove_instructable].to_i]).sort
        end
        if @user.schedule.save
          render json: {}
        else
          render json: {}, status: :unprocessable_entity
        end
      }
    end
  end

  private

  def instructable_search
    @topic = params[:topic]
    @culture = params[:culture]
    @search = params[:search]

    if params[:commit] == 'Clear'
      @search = nil
      @topic = nil
      @culture = nil
    end

    @instructables = Instructable.includes(:instances).order(:name).where(scheduled: true)

    if @search.present?
      @instructables = @instructables.where('name ILIKE ?', "%#{@search.strip}%")
    end

    if @topic.present?
      @instructables = @instructables.where(topic: @topic)
    end

    if @culture.present?
      @instructables = @instructables.where(culture: @culture)
    end

    @instructables = @instructables.paginate(page: params[:page], per_page: 20)
  end

  def load_user
    return @user if @user
    user_id = params[:user_id]
    if user_id =~ /^[a-zA-Z]+/
      @user = User.where(access_token: user_id).first
      if @user && @user.schedule
        @user.schedule.token_access = true
      end
    elsif current_user
      @user = User.where(id: current_user.id).first
    end
    @user
  end

  def cache_in_file(cache_filename, data)
    if cache_filename
      tmp_filename = [cache_filename, SecureRandom.hex(16)].join
      File.open(tmp_filename, 'wb') do |f|
        f.write data
      end
      File.rename(tmp_filename, cache_filename)
    end
  end

  def current_resource
    load_user
    if @user && @user.schedule
      @user.schedule
    else
      Schedule.new(published: true)
    end
  end

end