Skip to content

Commit

Permalink
Migrate home page and CSV parsing logic (#32)
Browse files Browse the repository at this point in the history
* Migrate homepage to schedule index

* Fixed RSpec failures

* Migrate CSV logic to separate service

* Update Cucumber scenarios

* Change class name to satisfy autoloader

* Remove unused require
  • Loading branch information
colbyendres authored Oct 23, 2024
1 parent c0c0c98 commit 0e047d2
Show file tree
Hide file tree
Showing 19 changed files with 225 additions and 252 deletions.
41 changes: 0 additions & 41 deletions app/controllers/csv_controller.rb

This file was deleted.

98 changes: 14 additions & 84 deletions app/controllers/schedules_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require 'csv'

# app/controllers/schedules_controller.rb
class SchedulesController < ApplicationController
before_action :set_schedule, only: %i[show destroy upload_rooms upload_instructors]
Expand Down Expand Up @@ -46,96 +44,28 @@ def destroy

def upload_rooms
if params[:room_file].present?
begin
ActiveRecord::Base.transaction do
room_data = CSV.read(params[:room_file].path, headers: true)

@schedule.rooms.destroy_all

room_data.each do |row|
Room.create!(
schedule_id: @schedule.id,
campus: row['campus'],
building_code: row['building_code'],
room_number: row['room_number'],
capacity: row['capacity'],
is_lecture_hall: row['is_lecture_hall'] == 'True',
is_learning_studio: row['is_learning_studio'] == 'True',
is_lab: row['is_lab'] == 'True',
is_active: row['is_active'] == 'True',
comments: row['comments']
)
end
end
flash[:notice] = 'Rooms successfully uploaded.'
rescue StandardError => e
flash[:alert] = "There was an error uploading the CSV file: #{e.message}"
raise e
end
# FIXME: What if the input file is malformed?
# We've erased our past data with no way to restore it
# We probably need to create a back up and restore if parsing gives an alert
@schedule.rooms.destroy_all
csv_handler = CsvHandler.new
csv_handler.upload(params[:room_file])
flash_result = csv_handler.parse_room_csv(@schedule.id)
flash[flash_result.keys.first] = flash_result.values.first
else
flash[:alert] = 'Please upload a CSV file.'
end

redirect_to schedule_path(@schedule)
end

def upload_instructors
if params[:instructor_file].present?
begin
ActiveRecord::Base.transaction do
instructor_data = CSV.read(params[:instructor_file].path)

@schedule.instructors.destroy_all
actual_headers = instructor_data[1]

required_headers = [
'anonimized ID',
'First Name',
'Last Name',
'Email',
'Teaching before 9:00 am.',
'Teaching after 3:00 pm.',
'Middle Name',
'Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)' # Optional: Include if needed
]

missing_headers = required_headers - actual_headers
unless missing_headers.empty?
flash[:alert] = "Missing required headers: #{missing_headers.join(', ')}"
redirect_to schedule_path(@schedule) and return
end

instructor_data[2..].each do |row|
# Extracting values and checking for nulls
id_number = row[actual_headers.index('anonimized ID')]
first_name = row[actual_headers.index('First Name')]
last_name = row[actual_headers.index('Last Name')]
middle_name = row[actual_headers.index('Middle Name')]
email = row[actual_headers.index('Email')]
before_9 = row[actual_headers.index('Teaching before 9:00 am.')]
after_3 = row[actual_headers.index('Teaching after 3:00 pm.')]
beaware_of = row[actual_headers.index('Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)')]

instructor_data = {
schedule_id: @schedule.id,
id_number: id_number,
first_name: first_name,
last_name: last_name,
middle_name: middle_name,
email: email,
before_9: before_9,
after_3: after_3,
beaware_of: beaware_of
}

Instructor.create(instructor_data)
end
end
flash[:notice] = 'Instructors successfully uploaded.'
rescue StandardError => e
flash[:alert] = "There was an error uploading the CSV file: #{e.message}"
raise e
end
# FIXME: See concern in upload_rooms
@schedule.instructors.destroy_all
csv_handler = CsvHandler.new
csv_handler.upload(params[:instructor_file])
flash_result = csv_handler.parse_instructor_csv(@schedule.id)
flash[flash_result.keys.first] = flash_result.values.first
else
flash[:alert] = 'Please upload a CSV file.'
end
Expand Down
4 changes: 1 addition & 3 deletions app/controllers/welcome_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ class WelcomeController < ApplicationController

def index
return unless logged_in?

flash[:notice] = "Welcome back, #{@current_user.first_name}!" unless flash[:notice] || flash[:error]
redirect_to user_path(@current_user)
redirect_to schedules_path
end
end
89 changes: 89 additions & 0 deletions app/services/csv_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# frozen_string_literal: true

class CsvHandler
require 'csv'

def upload(file)
@file = file
end

def parse_room_csv(schedule_id)
begin
ActiveRecord::Base.transaction do
room_data = CSV.parse(@file.read, headers: true)
room_data.each do |row|
Room.create!(
schedule_id: schedule_id,
campus: row['campus'],
building_code: row['building_code'],
room_number: row['room_number'],
capacity: row['capacity'].to_i,
is_lecture_hall: row['is_lecture_hall'] == 'True',
is_learning_studio: row['is_learning_studio'] == 'True',
is_lab: row['is_lab'] == 'True',
is_active: row['is_active'] == 'True',
comments: row['comments']
)
end
end
# Flash data to be received by controller
return { notice: 'Rooms successfully uploaded.' }
rescue StandardError => e
return { alert: "There was an error uploading the CSV file: #{e.message}" }
end
end

def parse_instructor_csv(schedule_id)
begin
ActiveRecord::Base.transaction do
instructor_data = CSV.parse(@file.read)
actual_headers = instructor_data[1]
required_headers = [
'anonimized ID',
'First Name',
'Last Name',
'Email',
'Teaching before 9:00 am.',
'Teaching after 3:00 pm.',
'Middle Name',
'Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)' # Optional: Include if needed
]

missing_headers = required_headers - actual_headers
unless missing_headers.empty?
return {alert: "Missing required headers: #{missing_headers.join(', ')}"}
end

instructor_data[2..].each do |row|
# Extracting values and checking for nulls
id_number = row[actual_headers.index('anonimized ID')]
first_name = row[actual_headers.index('First Name')]
last_name = row[actual_headers.index('Last Name')]
middle_name = row[actual_headers.index('Middle Name')]
email = row[actual_headers.index('Email')]
before_9 = row[actual_headers.index('Teaching before 9:00 am.')]
after_3 = row[actual_headers.index('Teaching after 3:00 pm.')]
beaware_of = row[actual_headers.index('Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)')]

instructor_data = {
schedule_id: schedule_id,
id_number: id_number,
first_name: first_name,
last_name: last_name,
middle_name: middle_name,
email: email,
before_9: before_9,
after_3: after_3,
beaware_of: beaware_of
}

Instructor.create(instructor_data)
end
end
return {notice: 'Instructors successfully uploaded.'}
rescue StandardError => e
return {alert: "There was an error uploading the CSV file: #{e.message}"}
end
end

end
2 changes: 1 addition & 1 deletion app/views/schedules/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Semester:<%= @schedule.semester_name %></h5>
<%= form_with url: upload_instructors_schedule_path(@schedule), multipart: true, method: :post, local: true do |f| %>
<div class='col-4'>
<%= f.label :instructor_file, "Select Instructors Data (CSV)", class: "form-label fw-bold" %>
<%= f.label :instructor_file, "Select Instructor Data (CSV)", class: "form-label fw-bold" %>
<%= f.file_field :instructor_file, class: "form-control" %>
</div>
<div>
Expand Down
23 changes: 0 additions & 23 deletions app/views/users/show.html.erb

This file was deleted.

5 changes: 1 addition & 4 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@
get 'manifest' => 'rails/pwa#manifest', as: :pwa_manifest

# Defines the root path route ("/")
root 'welcome#index'
get 'welcome/index', to: 'welcome#index', as: 'welcome'

# Show user
get '/users/:id', to: 'users#show', as: 'user'
root 'welcome#index'

# Login/logout
get '/logout', to: 'sessions#logout', as: 'logout'
Expand Down
26 changes: 0 additions & 26 deletions features/csv_upload.feature

This file was deleted.

20 changes: 19 additions & 1 deletion features/schedules.feature
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,22 @@ Feature: Schedules page
When I visit the schedules index page
When I search for "ABCD"
Then I should not see "Test Schedule 1"
And I should not see "Another Schedule"
And I should not see "Another Schedule"

Scenario: User can upload room CSV
Given I am logged in as a user with first name "Test"
When I visit the schedules index page
And I click on the card for "Test Schedule 1"
Then I should see "Select Room Data (CSV)"
When I upload a valid room file
And I click the "Upload Room Data" button
Then I should see "Rooms successfully uploaded"

Scenario: User can upload instructor CSV
Given I am logged in as a user with first name "Test"
When I visit the schedules index page
And I click on the card for "Test Schedule 1"
Then I should see "Select Instructor Data (CSV)"
When I upload a valid instructor file
And I click the "Upload Instructor Data" button
Then I should see "Instructors successfully uploaded"
19 changes: 0 additions & 19 deletions features/step_definitions/csv_upload_steps.rb

This file was deleted.

Loading

0 comments on commit 0e047d2

Please sign in to comment.