Commit b31f4f94 authored by Zac Wood's avatar Zac Wood

Merge branch 'course-review' of git.gmu.edu:srct/schedules into course-review

parents 4d7d8564 18661541
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
// Place all the styles related to the course_sections controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
class CourseSectionsController < ApplicationController
def show
@section = CourseSection.find_by_id(params[:id])
end
end
......@@ -7,14 +7,11 @@ class InstructorsController < ApplicationController
@instructor = Instructor.find_by_id(params[:id])
# find the courses being taught this semester
sections = CourseSection.where(instructor: @instructor, semester: @semester)
@courses = Course.build_set(sections)
# build the list of courses the instructor has taught in the past
@past = []
@instructor.course_sections.map(&:course).each do |c|
@past << c unless @past.select { |past| past.full_name == c.full_name }.count.positive?
sections = CourseSection.where(instructor: @instructor)
@semesters = sections.group_by do |s|
s.semester.to_s
end
@past.sort_by!(&:full_name)
@rating = { teaching: @instructor.rating, respect: @instructor.rating(6) }
end
end
......@@ -2,6 +2,11 @@ class SearchController < ApplicationController
def index
redirect_to(home_url) unless params[:query].length > 1
if params[:query].casecmp('god').zero?
bell = Instructor.find_by_name('Jonathan Bell')
redirect_to(instructor_url(bell))
end
results = SearchHelper::GenericItem.fetchall(String.new(params[:query]), semester: @semester).group_by(&:type)
@instructors = results[:instructor]&.map(&:data)
@courses = results[:course]&.map(&:data)
......
......@@ -49,13 +49,4 @@ class Course < ApplicationRecord
query
end
# build_set builds
def self.build_set(sections)
courses = [].to_set
sections.each do |s|
courses.add s.course
end
courses
end
end
......@@ -14,6 +14,24 @@ class CourseSection < ApplicationRecord
validates :course_id, presence: true
validates :semester_id, presence: true
serialize :rating_questions, Array
def teaching_rating
if rating_questions.empty?
nil
else
"#{rating_questions[0]['instr_mean']} / #{rating_questions[0]['resp']} responses"
end
end
def course_rating
if rating_questions.empty?
nil
else
"#{rating_questions[1]['instr_mean']} / #{rating_questions[1]['resp']} responses"
end
end
def overlaps?(other)
t1_start, t1_end = Time.parse(start_time), Time.parse(end_time)
t2_start, t2_end = Time.parse(other.start_time), Time.parse(other.end_time)
......
......@@ -4,4 +4,16 @@ class Instructor < ApplicationRecord
def self.from_name(base_query, name)
base_query.where("upper(instructors.name) LIKE ?", "%#{name.upcase}%")
end
def rating(question = 0, sections = CourseSection.where(instructor_id: id))
total = 0
resp = 0
sections.each do |s|
next if s.rating_questions.empty?
resp += s.rating_questions[question]["resp"].to_i
total += s.rating_questions[question]["instr_mean"].to_f * s.rating_questions[0]["resp"].to_i
end
[(total / resp).round(2), resp] unless resp.zero?
end
end
<h1><%= @section.name %> - <%= @section.semester.to_s %> - <%= @section.instructor.name %></h1>
<ol>
<% @section.rating_questions.each do |q| %>
<b>
<li><%= q["q"] %></li>
</b>
Instructor mean: <%= q["instr_mean"] %>, Responses: <%= q["resp"] %>
<% end %>
</ol>
<div class="row">
<div class="col-lg-4 col-12">
<h1><%= @instructor.name %></h1>
<% if @past.count.positive? %>
<strong>Previously taught: </strong>
<ul>
<% @past.each do |c| %>
<li><%= link_to(c.full_name, course_path(c)) %></li>
<% end %>
</ul>
<% unless @rating[:teaching].nil? %>
Average rating: <%= @rating[:teaching][0] %> / <%= @rating[:teaching][1] %> responses
<% end %>
</div>
<div class ="col-lg-8 col-12">
<h3><%= @semester.to_s %></h3>
<% if @courses.any? %>
<%= render(partial: 'shared/course', collection: @courses, locals: { expanded: true }) %>
<% else %>
<p><%= @instructor.name %> is not teaching any courses this semester...</p>
<div class="col-lg-8 col-12">
<% @semesters.each do |semester, sections| %>
<h2><%= semester %></h2>
<%= render(partial: 'shared/section', collection: sections) %>
<br/>
<% end %>
</div>
</div>
......
......@@ -40,7 +40,7 @@
<% prereqs, note = rest.split('.') %>
<p><strong><%= first %>:</strong> <%= prereqs %> <sub><%= note %></sub></p>
<% end %>
<% if expanded %>
<div class="d-block" style="text-align: center">
<p id="chevron-label" style="margin-bottom:-4px; font-size: 10px;">Minimize</p>
......@@ -52,6 +52,8 @@
<i id="course-chevron" class="fas fa-chevron-down"></i>
</div>
<% end %>
<!-- List of Course Sections -->
<div class="list-group list-group-flush sections" style="display: <%= expanded ? "flex" : "none" %>">
......
......@@ -23,8 +23,19 @@
<% if section.instructor.name == "TBA" %>
TBA
<% else %>
<%= link_to section.instructor.name, section.instructor %><% end %> <br/>
<%= link_to section.instructor.name, section.instructor %>
<% end %>
<br/>
<i class="fas fa-map-marker-alt"></i> <%= section.location %> <br/>
<i class="fas fa-clock"></i> <%= "#{section.days}, #{section.start_time}-#{section.end_time}" %> <br/>
<% unless section.rating_questions.empty? %>
<br/>
<b>Rating Info</b> (<%= link_to("See all ratings", course_section_url(section))%>)
<ul>
<li>Instructor rating: <%= section.teaching_rating %></li>
<li>Course rating: <%= section.course_rating %></li>
</ul>
<% end %>
</li>
# Registers all routes for the app.
Rails.application.routes.draw do
get '/', to: 'home#index', as: 'home'
get 'search', to: 'search#index'
get 'search', to: 'search#index', as: 'search'
get 'sessions/update', as: 'update_session'
get 'sessions/cart'
get 'sessions/add_bulk'
resources :courses, only: [:show]
resources :course_sections, only: [:show]
resources :instructors, only: [:index, :show]
get 'schedule', to: 'schedules#show', as: 'schedule'
get 'schedule/view', to: 'schedules#view', as: 'view_schedule'
......
require 'httparty'
require 'nokogiri'
sem = ARGV.first
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://crserating.gmu.edu/ReportPaper/',
'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'keep-alive',
'Cookie': 'ga=GA1.2.1878572417.1543773996; __unam=74bec77-167701a5090-6fe3a784-10; __insp_slim=1549744302281; CFID=1938650; CFTOKEN=b1990d0cd24bb3f4-19FA09EB-5056-9470-35EEF241BAFA23D5; CFGLOBALS=urltoken%3DCFID%23%3D1938650%26CFTOKEN%23%3Db1990d0cd24bb3f4%2D19FA09EB%2D5056%2D9470%2D35EEF241BAFA23D5%23lastvisit%3D%7Bts%20%272019%2D01%2D29%2019%3A40%3A10%27%7D%23timecreated%3D%7Bts%20%272019%2D01%2D29%2019%3A39%3A51%27%7D%23hitcount%3D7%23cftoken%3Db1990d0cd24bb3f4%2D19FA09EB%2D5056%2D9470%2D35EEF241BAFA23D5%23cfid%3D1938650%23; __insp_wid=1435896333; __insp_nv=true; __insp_ref=aHR0cHM6Ly9pcnIyLmdtdS5lZHUvTmV3L05fRW5yb2xsT2ZmL0VucmxTdHMuY2Zt; __insp_targlpu=https%3A%2F%2Firr2.gmu.edu%2FNew%2FN_EnrollOff%2FEnrlSts.cfm; __insp_targlpt=Office%20of%20Institutional%20Research%20and%20Effectiveness; BIGipServer~web.gmu.edu~goose.gmu.edu_p80=1242087434.20480.0000',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
}
resp = HTTParty.post('https://crserating.gmu.edu/ReportPaper/InstructorList.cfm',
body: "SearchType=instructor&semester=#{sem}&ctitle=&iname=&divsname=&deptname=&disc=&ckey=&orig=off&SearchTypeHid=instructor",
headers: headers).body
document = Nokogiri::HTML(resp)
values = document.css('select option').map { |e| e['value'] }
i = values.index('--Select an Instructor--')
values = values[i + 1..-1]
all = {}
c = values.count
counter = 1
values.each do |v|
puts "#{counter}/#{c} getting data for #{v}..."
counter += 1
resp = HTTParty.post('https://crserating.gmu.edu/ReportPaper/InstructorList.cfm',
body: "SearchType=instructor&semester=#{sem}&ctitle=&iname=#{v}&divsname=&deptname=&disc=&ckey=&orig=off&SearchTypeHid=instructor",
headers: headers)
document = Nokogiri::HTML(resp)
rows = document.css('tr')
i = rows.index { |r| r.css('td').first&.text == 'Course' }
next if i.nil?
rows[i + 1..-3].each do |s_tr|
tds = s_tr.css('td')
id = tds.first.css('font a').first['href'].match(/[0-9]+/)[0]
section, instr = tds.first&.text, tds[2]&.text
resp = HTTParty.post("https://crserating.gmu.edu/ReportPaper/MeansSummary16.cfm?rat_num=#{id}&caller=InstructorList",
body: "semester=#{sem}&formseq=62&orig=off&iname=#{instr}",
headers: headers)
document = Nokogiri::HTML(resp)
rows = document.css('tr')
qs = [9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39].map do |n|
datas = rows[n].css('td')
{ q: datas[0].text.match(/[A-Z].*/)[0], resp: datas[1].text.strip, instr_mean: datas[2].text.strip, dept_mean: datas[3].text.strip }
end
all[section] = qs
end
puts '------------------------------'
end
File.write("#{sem}.json", all.to_json)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
require 'json'
[['f18', 'Fall', '2018'], ['sp18', 'Spring', '2018'],
['f17', 'Fall', '2017'], ['sp17', 'Spring', '2017']].each do |arr|
puts arr
ratings = JSON.parse(File.read("db/data/#{arr[0]}.json"))
semester = Semester.find_by!(season: arr[1], year: arr[2])
ratings.each do |section, qs|
section = section.split(',').first
subj = section.match(/[A-Z]+/)[0]
course = section.match(/[0-9]{3} /)[0].strip
sect_num = section.match(/ [A-Z0-9]+/)[0].strip
name = "#{subj} #{course} #{sect_num}"
s = CourseSection.find_by(name: name, semester: semester)
next if s.nil?
s.rating_questions = qs
s.save!
end
end
class AddRatingsToCourseSection < ActiveRecord::Migration[5.1]
def change
add_column :course_sections, :rating_questions, :string
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20190210152552) do
ActiveRecord::Schema.define(version: 20190307042304) do
create_table "closures", force: :cascade do |t|
t.date "date"
......@@ -40,6 +40,7 @@ ActiveRecord::Schema.define(version: 20190210152552) do
t.datetime "updated_at", null: false
t.integer "instructor_id"
t.integer "semester_id"
t.string "rating_questions"
t.index ["course_id"], name: "index_course_sections_on_course_id"
t.index ["instructor_id"], name: "index_course_sections_on_instructor_id"
t.index ["semester_id"], name: "index_course_sections_on_semester_id"
......
......@@ -114,7 +114,7 @@ def main
parser = PatriotWeb::Parser.new
semesters = if ARGV.first == "update"
[parser.parse_semesters.first]
[parser.parse_semesters[3]]
else
# expand to include however many semesters you want
parser.parse_semesters[0..7]
......
require 'test_helper'
class CourseSectionsControllerTest < ActionDispatch::IntegrationTest
test "should get show" do
s = CourseSection.first
get course_section_url(s)
assert_response :success
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment