seeds.rb 4.3 KB
Newer Older
Zac Wood's avatar
Zac Wood committed
1 2
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
3

Zac Wood's avatar
Zac Wood committed
4
require_relative 'patriot_web_parser'
5
require_relative 'courses_loader'
Zac Wood's avatar
Zac Wood committed
6 7 8 9 10
require 'thwait'
require 'httparty'
require 'nokogiri'
require 'json'

11 12
def parse_courses(subjects)
  courses = []
Zac Wood's avatar
Zac Wood committed
13

14 15 16 17 18 19 20
  threads = subjects.map do |subject|
    Thread.new do
      courses.push(*get_courses(subject.downcase))
    end
  end

  ThreadsWait.all_waits(*threads)
Zac Wood's avatar
Zac Wood committed
21

22 23
  courses
end
Zac Wood's avatar
Zac Wood committed
24

25
def load_courses(courses, semester)
26 27 28 29 30 31 32
  insert_hashes = courses.map do |course|
    {
      subject: course[:subject],
      title: course[:title],
      course_number: course[:course_number],
      credits: course[:credits],
      description: course[:description],
33
      prereqs: course[:prereqs],
34 35
      semester: semester
    }
36
  end
37

38
  insert_hashes.each { |c| Course.find_or_create_by!(c) }
Zac Wood's avatar
Zac Wood committed
39 40
end

41
def parse_sections(semester, subjects)
42 43 44 45 46
  parser = PatriotWeb::Parser.new
  sections_in = {}

  threads = subjects.map do |subject|
    Thread.new do
47
      sections_in[subject] = parser.parse_courses_in_subject(semester, subject)
48 49 50
    end
  end

51
  ThreadsWait.all_waits(*threads)
52

53 54
  sections_in
end
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
def load_sections(sections_in, semester)
  sections_in.each do |subject, sections|
    all_sections = []

    sections.each do |section|
      if section.nil? || !section.key?(:subj) || !section.key?(:course_number)
        puts "#{subject} failed section: #{section.class}"
        next
      end

      course = Course.find_or_create_by!(subject: section[:subj],
                                         course_number: section[:course_number],
                                         semester: semester)

      instructor = Instructor.find_or_create_by!(name: section[:instructor])

      section_name = "#{section[:subj]} #{section[:course_number]} #{section[:section]}"

      all_sections.push(name: section_name,
                        crn: section[:crn],
                        section_type: section[:type],
                        title: section[:title],
                        start_date: section[:start_date],
                        end_date: section[:end_date],
                        days: section[:days],
                        start_time: section[:start_time],
                        end_time: section[:end_time],
                        location: section[:location],
                        course: course,
                        instructor: instructor)
86
    end
Zac Wood's avatar
Zac Wood committed
87

88
    all_sections.each { |s| CourseSection.find_or_create_by! s }
Zac Wood's avatar
Zac Wood committed
89
  end
90 91 92 93 94 95 96 97 98
end

def wipe_db
  Closure.delete_all
  CourseSection.delete_all
  Course.delete_all
  Semester.delete_all
end

99
def load_closures
100 101
  # create closures for the days there will be no classes
  # see: https://registrar.gmu.edu/calendars/fall-2018/
102 103 104 105 106 107 108
  # fall2018 = Semester.find_by(season: 'Fall', year: '2018')
  # Closure.create! date: Date.new(2018, 9, 3), semester: fall2018
  # Closure.create! date: Date.new(2018, 10, 8), semester: fall2018
  # (21..25).each { |n| Closure.create! date: Date.new(2018, 11, n), semester: fall2018 }
  # (10..19).each { |n| Closure.create! date: Date.new(2018, 12, n), semester: fall2018 }
  spring2019 = Semester.find_by(season: 'Spring', year: '2019')
  (11..17).each { |day| Closure.find_or_create_by! date: Date.new(2019, 3, day), semester: spring2019 }
109 110 111
end

def main
112
  # wipe_db
113 114

  parser = PatriotWeb::Parser.new
115 116 117 118 119 120 121 122

  semesters = if ARGV.first == "update"
                [parser.parse_semesters.first]
              else
                # expand to include however many semesters you want
                parser.parse_semesters[0..6]
              end

123
  courses = nil
Zac Wood's avatar
oops  
Zac Wood committed
124

125 126
  semesters.each do |semester|
    puts "#{semester[:season]} #{semester[:year]}"
127
    db_semester = Semester.find_or_create_by!(season: semester[:season], year: semester[:year])
128

129 130
    puts "\tParsing subjects..."
    subjects = parser.parse_subjects(semester[:value])
131

132 133
    puts "\tParsing courses from catalog.gmu.edu..."
    courses = parse_courses(subjects) if courses.nil?
134

135 136
    puts "\tLoading courses..."
    load_courses(courses, db_semester)
137

138 139
    puts "\tParsing sections from Patriot Web..."
    sections_in = parse_sections(semester[:value], subjects)
140

141 142 143
    puts "\tLoading sections..."
    load_sections(sections_in, db_semester)
  end
Zac Wood's avatar
Zac Wood committed
144

145
  load_closures
Zac Wood's avatar
Zac Wood committed
146
end
Zac Wood's avatar
Zac Wood committed
147

148
main