YaleSTC/shifts

View on GitHub
app/controllers/application_controller.rb

Summary

Maintainability
D
2 days
Test Coverage
class ApplicationController < ActionController::Base
  # almost everything we do is restricted to a department so we always load_department
  # feel free to skip_before_filter when desired
  before_filter :load_app_config
  before_filter :department_chooser
  before_filter :load_user_session
  before_filter RubyCAS::Filter, if: Proc.new{|s| s.using_CAS?}, except: [ 'access_denied', 'grab' ] # calendar_feeds#grab; see issue #478
  before_filter :login_check, except: :access_denied
  before_filter :load_department
  before_filter :prepare_mail_url
  before_filter :prepare_for_mobile
  before_filter :load_user

  helper :layout
  helper :application

  #Replaced with similar prototype legacy helper plugin
  #helper :prototype #TODO including this helper is a stopgap for the shift to Rails 3; contained methods should be rewritten

  helper_method :current_user
  helper_method :current_department

  protect_from_forgery # See ActionController::RequestForgeryProtection for details

  def load_app_config
    @appconfig = AppConfig.all.first
  end

  def access_denied
    render "layouts/access_denied"
  end

  def using_CAS?
    User.all.first && (!current_user || current_user.auth_type=='CAS') && @appconfig && @appconfig.login_options.include?('CAS')
  end

  def user_for_paper_trail
    current_user.name if current_user
  end

  protected
  def current_user
    @current_user ||= (
    if @user_session
      @user_session.user
    elsif session[:cas_user]
      User.where(login: session[:cas_user]).first
    else
      nil
    end)
  end

  def current_department
    unless @current_department
      if current_user
        @current_department = Department.where(session[:department_id]).first
        unless @current_department
          @current_department = current_user.default_department
          session[:department_id] = @current_department.id
        end
      end
    end
    @current_department
  end

  def load_department
    if (params[:department_id])
      @department = Department.find(params[:department_id])
      if @department
        session[:department_id] = params[:department_id]
      end
    end
    @department ||= current_department
  end

  def load_user
    @current_user = (@user_session && @user_session.user) || User.where(login: session[:cas_user]).first
  end

  def load_user_session
    @user_session = UserSession.find
  end

  # These are the authorization before_filters to use under controllers
  # These all return nil
  def require_department_admin
    unless current_user.is_admin_of?(current_department)
      error_message = "That action is restricted to department administrators."
      flash[:error] = error_message
      respond_to do |format|
        format.html do
          redirect_to access_denied_path
        end
        format.js do
          @ajax_error_message = "<strong>Error:</strong>" + error_message
          render :update 
          return false
        end
      end
    end
    return true
  end

  def require_loc_group_admin(current_loc_group)
    unless current_user.is_admin_of?(current_loc_group)
      error_message = "That action is restricted to location group administrators."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  def require_any_loc_group_admin
    unless current_user.is_loc_group_admin?(current_department)
      error_message = "That action is restricted to location group administrators."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  def require_superuser
    unless current_user.is_superuser?
      error_message = "That action is only available to superusers."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  def require_proper_template_role
    unless current_user.has_proper_role_for?(Template.find(params[:template_id])) || current_user.is_admin_of?(Template.find(params[:template_id]).department)
      error_message = "This page is only availabe to the following roles: #{Template.find(params[:template_id]).roles.to_sentence}"
      flash[:error] = error_message
      redirect_to access_denied_path
    end
    return true
  end

  # These three methods all return true/false, so they can be tested to
  # trigger return statements

  # TODO: Ultimately, we should abstract all this away into a permissions
  # module, and include that into the application. Ideally, after that we'd
  # refactor to to have these methods share the redirect code

  # Takes a department, location, or loc_group
  def user_is_admin_of(thing)
    unless current_user.is_admin_of?(thing)
      error_message = "You are not authorized to administer this #{thing.class.name.decamelize}."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path and return false
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end


  # Takes any object that has a user method and checks against current_user
  #TODO: This is mixing model logic!!!
  def user_is_owner_of(thing)
    unless current_user.is_owner_of?(thing)
      error_message = "You are not the owner of this #{thing.class.name.decamelize}."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path and return false
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  # Takes any object that has a user method and its department
  #TODO: This is mixing model logic!!!
  def user_is_owner_or_admin_of(thing, dept)
    unless current_user.is_owner_of?(thing) || current_user.is_admin_of?(dept)
      error_message = "You are not the owner of this #{thing.class.name.decamelize}, nor are you the department administrator."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path and return false
        end
        format.js do
          render :update do |page|
            # display alert
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  # Takes a department; intended to be passed some_thing.department
  def require_department_membership(dept)
    unless current_user.departments.include?(dept)
      error_message = "You are not a member of the appropriate department."
      respond_to do |format|
        format.html do
          flash[:error] = error_message
          redirect_to access_denied_path and return false
        end
        format.js do
          render :update do |page|
            ajax_alert(page, "<strong>error:</strong> "+error_message);
          end
          return false
        end
      end
    end
    return true
  end

  def login_check
    if User.all.empty?
      redirect_to first_app_config_path
    elsif !current_user
      if @appconfig.login_options==['built-in'] #AppConfig.first.login_options_array.include?('built-in')
        redirect_to login_path
      else
        redirect_to access_denied_path
      end
    end
  end

#  def redirect_with_flash(msg = nil, options = {action: :index})
#    if msg
#      msg = msg.join("<br/>") if msg.is_a?(Array)
#      flash[:notice] = msg
#    end
#    redirect_to options
#  end

  def parse_date_and_time_output(form_output)
        time_attribute_names = ["start", "end", "mandatory_start", "mandatory_end"]
    time_attribute_names.each do |field_name|

      unless form_output["#{field_name}_time(5i)"].blank? || form_output["#{field_name}_time(4i)"].blank?
        hh=form_output["#{field_name}_time(4i)"]
        mm=form_output["#{field_name}_time(5i)"]
        form_output["#{field_name}_time"] = Time.parse("#{hh}:#{mm}:00" )
        form_output.delete("#{field_name}_time(4i)")
        form_output.delete("#{field_name}_time(3i)")
        form_output.delete("#{field_name}_time(2i)")
        form_output.delete("#{field_name}_time(1i)")

      end

      ## Date Input - Hidden Field
      unless form_output["#{field_name}_date"].blank?
        form_output["#{field_name}_date"] = Date.parse( form_output["#{field_name}_date"] )
      end

      ## Date Input - Select (Rails default)
      unless (form_output["#{field_name}_date(1i)"].blank? || form_output["#{field_name}_date(2i)"].blank? || form_output["#{field_name}_date(3i)"].blank?)
        join_date = [ form_output["#{field_name}_date(1i)"], form_output["#{field_name}_date(2i)"], form_output["#{field_name}_date(3i)"] ].join('-')
        form_output["#{field_name}_date"] = Date.parse( join_date )
      end
    end


    #when there is no end_date (such as shifts, time_slots, and sub_requests)
    form_output["end_date"] ||= form_output["start_date"] if form_output["start_date"]
    form_output["mandatory_end_date"] ||= form_output["mandatory_start_date"] if form_output["mandatory_start_date"]

    #Midnight?
    time_attribute_names.each do |field_name|
        unless form_output["#{field_name}_time(5i)"].nil?
          unless form_output["#{field_name}_time(5i)"].scan(/\+$/).empty?
            form_output["#{field_name}_date"] += 1.day
          end
        end
    end

    #cleanup
    time_attribute_names.each do |field_name|
        form_output.delete("#{field_name}_date(1i)")
        form_output.delete("#{field_name}_date(2i)")
        form_output.delete("#{field_name}_date(3i)")
        form_output.delete("#{field_name}_time(5i)") if form_output["#{field_name}_time(4i)"].blank?
    end

    form_output
  end

  def set_payform_item_hours(model_name)
    if params[:calculate_hours] == 'user_input'
      params[model_name.to_sym][:hours] = params[:other][:hours].to_f + params[:other][:minutes].to_f/60
    else
      start_params = []
      end_params = []
      for num in (1..7)
        unless num == 6 #we skip seconds; meridian is stored in 7
          start_params << params[:time_input]["start(#{num}i)"].to_i
          end_params << params[:time_input]["end(#{num}i)"].to_i
        end
      end
      start_time = convert_to_time(start_params)
      end_time = convert_to_time(end_params)
      params[model_name.to_sym][:hours] = (end_time-start_time) / 3600.0
    end
  end

  def convert_to_time(date_array)
    # 0 = year, 1 = month, 2 = day, 3 = hour, 4 = minute, 5 = meridiem(am/pm)
    if date_array[3] == 12 #if noon or midnight
      date_array[3] -= 12
    end
    if date_array[5] == -2 #if pm
      date_array[3] += 12
    end
    Time.utc(date_array[0], nil, nil, date_array[3], date_array[4])
  end


  def join_date_and_time(form_output)
  #join date and time
    %w{start end mandatory_start mandatory_end}.each do |field_name|
      if form_output["#{field_name}_date"] && form_output["#{field_name}_time"]
        date = form_output["#{field_name}_date"]
        time = form_output["#{field_name}_time"]
        zone = date.end_of_day.zone
        form_output["#{field_name}"] ||= DateTime.new( date.year, date.month,
                                                       date.day, time.hour,
                                                       time.min, time.sec, zone)
        form_output.delete("#{field_name}_date")
        form_output.delete("#{field_name}_time")
      end
      form_output["start"] ||= Time.now
      form_output
    end
  end


  def parse_users_autocomplete(token_output)
    result = []
    list = token_output.split(',').map{|l| l.split("||")}
    list.each do |tokens|
      result += tokens[0].safe_constantize.find(tokens[1]).users
    end
    return result.uniq    
  end

  def department_day_start_time
    DateTime.now.in_time_zone(Time.zone).beginning_of_day + current_department.department_config.schedule_start.minutes
  end

  def department_day_end_time
    DateTime.now.in_time_zone(Time.zone).beginning_of_day + current_department.department_config.schedule_end.minutes - 1.second
  end

  private


  def department_chooser
    if (params[:su_mode] && current_user.superuser?)
      current_user.update_attribute(:supermode, params[:su_mode]=='ON')
      flash[:notice] = "Supermode is now #{current_user.supermode? ? 'ON' : 'OFF'}"
      redirect_to :back
    elsif (params["chooser"] && params["chooser"]["dept_id"])
      session[:department_id] = params["chooser"]["dept_id"]
      redirect_to switch_department_path
    end
  end

  #checks to see if the action should be rendered without a layout. optionally pass it another action/controller
  def layout_check(action = action_name, controller = controller_name)
    if params[:layout] == "false"
      render controller: controller, action: action, layout: false
    end
  end

  # overwrite this method in other controller if you wanna go to a different url after chooser submit
  # it tries to find the index path of the current resource;
  # for example if you're in shifts_controller then it goes to shifts_path
  # however it won't work for some nested routes (and defaults to root_path instead) so please overwrite this method in such controller
  def switch_department_path
    send("#{controller_name}_path") rescue root_path
  end

  def prepare_mail_url
    ActionMailer::Base.default_url_options[:host] = request.host_with_port
  end

  def mobile_device?
    if session[:mobile_param]
      session[:mobile_param] == "1"
    else
      request.user_agent =~ /Mobile|webOS/
    end
  end
  helper_method :mobile_device?

  def prepare_for_mobile
    session[:mobile_param] = params[:mobile] if params[:mobile]
  end

end