YaleSTC/shifts

View on GitHub
app/controllers/users_controller.rb

Summary

Maintainability
D
2 days
Test Coverage
class UsersController < ApplicationController
  before_filter :require_admin_or_superuser, except: 'autocomplete'

  def index
    if params[:show_inactive]
      @users = @department.users
    else
      @users = current_department.active_users.sort_by(&:reverse_name)
    end

    if params[:search]
      params[:search] = params[:search].downcase
      @search_result = []
      @users.each do |user|
        if user.login.downcase.include?(params[:search]) or user.name.downcase.include?(params[:search])
          @search_result << user
        end
      end
      @users = @search_result
    end

    @users = @users.sort_by(&:last_name)

    respond_to do |wants|
      wants.html
      wants.csv { render text: @users.to_csv_users }
    end
  end

  def show
    @user = User.find(params[:id])
    @user_profile = UserProfile.where(user_id: params[:id]).first
    unless @user_profile.user.departments.include?(@department)
      flash[:error] = "This user does not have a profile in this department."
    end
    @user_profile_entries = @user_profile.user_profile_entries.select{ |entry| entry.user_profile_field.department_id == @department.id && entry.user_profile_field.public }
  end

  def show_shifts
    @user = User.find(params[:id])
    @shifts = @user.shifts.sort_by{|s| s.start}.reverse
  end

  def ldap_search
    @results=[]
    return @results unless params[:user][:first_name] || params[:user][:last_name] || params[:user][:email]
    @results=User.search_ldap(params[:user][:first_name],params[:user][:last_name],params[:user][:email],5)
  end

  def new
    @user = User.new
    @results = []
  end

  def fill_form
    @user = User.new(params[:user])
  end

  def create
    if @user = User.where(login: params[:user][:login]).first
      if @user.departments.include? @department #if user is already in this department
        flash[:notice] = "This user already exists in this department."
      else
        @user.roles += (params[:user][:role_ids] ? params[:user][:role_ids].collect{|id| Role.find(id)} : [])
        @user.departments << @department unless @user.departments.include?(@department)
        flash[:notice] = "User successfully added to new department."
      end
      @user.set_payrate(params[:payrate], @department)
      redirect_to @user
    else
      @user = User.new(params[:user])
      @user.auth_type = @appconfig.login_options[0] if @appconfig.login_options.size == 1
      @user.set_random_password
      @user.departments << @department unless @user.departments.include?(@department)
      if @user.save
        UserMailer.delay.registration_confirmation(@user)
        @user.set_payrate(params[:payrate], @department)
        UserProfileField.all.each do |field|
          UserProfileEntry.create!(user_profile_id: @user.user_profile.id, user_profile_field_id: field.id)
        end
        if @user.auth_type == 'built-in' #What is going on here?
          @user.password_reset_instructions!(Proc.new {|n| UserMailer.delay.new_user_password_instructions(n, current_department)})
          flash[:notice] = "Successfully created user and emailed instructions for setting password."
        else
          flash[:notice] = "Successfully created user."
        end
        redirect_to @user
      else
        render action: 'new'
      end
    end
  end

  def edit
    @user = User.find(params[:id])
    @user_profile = UserProfile.where(user_id: @user.id).first
    @user_profile_entries = @user.user_profile.user_profile_entries.select{|entry| entry.user_profile_field.department_id == @department.id }
  end

  def update
    #TODO: prevent params hacking w/ regard to setting roles and login and payrate
    params[:user][:role_ids] ||= []
    @user = User.find(params[:id])
    #store role changes, or else they'll overwrite roles in other departments
    #remove all roles associated with this department
    department_roles = @user.roles.select{|role| role.department == current_department}
    updated_roles = @user.roles - department_roles
    #now add back all checked roles associated with this department (or empty if none were checked)
    updated_roles += (params[:user][:role_ids] ? params[:user][:role_ids].collect{|id| Role.find(id)} : [])
    #We can't save the roles association via update attributes, so we have to do it manually
    @user.roles = updated_roles
    @user.save!
    #Finally to prevent the @user.update_attribues from attempting to update the roles, we must remove them from params
    params[:user].delete(:role_ids)

    #So that the User Profile can be updated as well
      @user_profile = UserProfile.where(user_id: User.find(params[:id]).id).first
      @user_profile_entries = params[:user_profile_entries]

      if @user_profile_entries
        @user_profile_entries.each do |entry_id, entry_content|
          entry = UserProfileEntry.find(entry_id)
          @content = ""
            if entry.display_type == "check_box"
              UserProfileEntry.find(entry_id).values.split(", ").each do |value|
                c = entry_content[value]
                @content += value + ", " if c == "1"
              end
              @content.gsub!(/, \Z/, "")
              entry.content = @content
              entry.save
            elsif entry.display_type == "radio_button"
              entry.content = entry_content["1"]
              entry.save
            else
              entry.content = entry_content[entry_id]
              entry.save
            end
          end
      end

    @user_profile = UserProfile.where(user_id: @user.id).first
    @user_profile_entries = @user_profile.user_profile_entries.select{|entry| entry.user_profile_field.department_id == @department.id }

    @user.set_random_password if params[:reset_password]
    @user.password_reset_instructions!(Proc.new {|n| UserMailer.delay.change_auth_type_password_reset_instructions(n)}) if @user.auth_type=='CAS' && params[:user][:auth_type]=='built-in'
    if @user.update_attributes(params[:user])
      @user.set_payrate(params[:payrate].gsub(/\$/,""), @department) if params[:payrate]
      flash[:notice] = "Successfully updated user."
      @user.password_reset_instructions!(Proc.new {|n| UserMailer.delay.admin_password_reset_instructions(n)}) if params[:reset_password]
      redirect_to @user
    else
      render action: 'edit'
    end
  end

  def destroy #the preferred action. really only disables the user for that department.
  # DRAFT IMPROVEMENT -ben
  #    @user = User.find(params[:id])
  #    @user.destroy
  #    flash[:notice] = "Successfully destroyed user."
  #    redirect_to department_users_path(current_department)
  # END DRAFT
    @user = User.find(params[:id])
    if @user.toggle_active(@department) #new_entry.save
      flash[:notice] = "Successfully deactivated user."
      redirect_to @user
    else
      render action: 'edit'
    end
  end

  # I believe that neither of these two actions is in use anymore -ben
  # Replacement for destroy action
  #  def deactivate
  #    @user = User.find(params[:id])
  #    if @user.toggle_active(@department) #new_entry.save
  #      flash[:notice] = "Successfully deactivated user."
  #      redirect_to @user
  #    else
  #      render action: 'edit'
  #    end
  #  end

  # Reactivates the user
  #  def restore
  #    @user = User.find(params[:id])
  #    new_entry = DepartmentsUser.new();
  #    old_entry = DepartmentsUser.find(:first, conditions: { user_id: @user, department_id: @department})
  #    new_entry.attributes = old_entry.attributes
  #    new_entry.active = true
  #    DepartmentsUser.delete_all( user_id: @user, department_id: @department )
  #    if new_entry.save
  #      flash[:notice] = "Successfully restored user."
  #      redirect_to @user
  #    else
  #      render action: 'edit'
  #    end
  #  end

  # To be replaced with destroy
  def really_destroy #if we ever need an action that actually destroys users.
    @user = User.find(params[:id])
    @user.destroy
    flash[:notice] = "Successfully destroyed user."
    redirect_to department_users_path(current_department)
  end

  # Empty action, necessary for a view -ben
  # Used for importing from CSV
  def import
  end

  # Used for importing from CSV
  def verify_import
    file = params[:file]
    begin
      @results = User.import(file)
    rescue ActiveRecord::ActiveRecordError => e
      flash[:error] = "A database error was encountered: <br>#{e}.<br><br> Please try again. If you fail, contact your administrator."
    ensure
      render action: 'import'
    end
  end

  # Used for importing from CSV
  def save_import
    if params[:commit]=="Cancel"
      redirect_to import_department_users_path(@department) and return
    end
    @users=params[:users_to_import].collect{|i| params[:user][i]}
    failures = []
    @users.each do |u|
      if @user = User.where(login: u[:login]).first
        if @user.departments.include? @department #if user is already in this department
          #don't modify any data, as this is probably a mistake
          failures << {user:u, reason: "User already exists in this department!"}
        else
          @user.role = u[:role]
          #add user to new department
          @user.departments << @department unless @user.departments.include?(@department)
          @user.save
        end
      else
        @user = User.new(u)
        @user.auth_type = @appconfig.login_options[0] if @appconfig.login_options.size == 1
        @user.set_random_password
        @user.departments << @department unless @user.departments.include?(@department)
        if @user.save
          @user.password_reset_instructions!(Proc.new {|n| UserMailer.delay.new_user_password_instructions_csv(n, current_department)}) if @user.auth_type=='built-in'
        else
          failures << {user:u, reason: "Check all fields to make sure they\'re ok"}
        end
      end
    end
    if failures.empty?
      flash[:notice] = "All users successfully added."
      redirect_to department_users_path(@department)
    else
      @users=failures.collect{|e| User.new(e[:user])}
      flash[:notice] = "The users below failed for the following reasons:<br />"
      failures.each{|e| flash[:notice]+="#{e[:user][:login]}: #{e[:reason]}<br />"}
      render action: 'verify_import'
    end
  end

  def autocomplete
    @list = []
    classes = params[:classes] || ["User", "Department", "Role"]

    if classes.include?("User")
      users = Department.find(params[:department_id]).users.sort_by(&:first_name)
      users.each do |user|
        if user.login.downcase.include?(params[:q]) or user.name.downcase.include?(params[:q])
          @list << {id: "User||#{user.id}",name: "#{user.name} (#{user.login})"}
        end
      end
    end

    if classes.include?("Department")
      departments = current_user.departments.sort_by(&:name)
      departments.each do |department|
        if department.name.downcase.include?(params[:q])
          @list << {id: "Department||#{department.id}", name: "Department: #{department.name}"}
        end
      end
    end
    if classes.include?("Role")
      roles = Department.find(params[:department_id]).roles.sort_by(&:name)
      roles.each do |role|
        if role.name.downcase.include?(params[:q])
          @list << {id: "Role||#{role.id}", name: "Role: #{role.name}"}
        end
      end
    end

    render json: @list
  end

  def search
    @users = current_department.active_users

    #filter results if we are searching
    if params[:search]
      params[:search] = params[:search].downcase
      @search_result = []
      @users.each do |user|
        if user.login.downcase.include?(params[:search]) or user.name.downcase.include?(params[:search])
          @search_result << user
        end
      end
      @users = @search_result.sort_by(&:last_name)
    end
  end

  def toggle #for ajax deactivation/restore, POST action
    @user = User.find(params[:id])
    @user.toggle_active(@department)
    respond_to do |format|
      format.html {redirect_to user_path(@user)}
      format.js
    end
  end

  private

  def switch_department_path
    department_users_path(current_department)
  end

  def require_admin_or_superuser
    redirect_to(access_denied_path) unless current_user.is_admin_of?(current_department) || current_user.is_superuser?
  end
end