seeds.rb 4.46 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
require 'thwait'
require 'httparty'
require 'nokogiri'
require 'json'
10
require 'set'
Zac Wood's avatar
Zac Wood committed
11

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

15
16
17
18
19
20
21
  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
22

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

26
def load_courses(courses)
27
28
29
30
31
32
33
  insert_hashes = courses.map do |course|
    {
      subject: course[:subject],
      title: course[:title],
      course_number: course[:course_number],
      credits: course[:credits],
      description: course[:description],
34
      prereqs: course[:prereqs],
35
    }
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
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],
67
                                         course_number: section[:course_number])
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

      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,
84
85
                        instructor: instructor,
                        semester: semester)
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

  semesters = if ARGV.first == "update"
Zac Wood's avatar
Zac Wood committed
117
                [parser.parse_semesters[3]]
118
119
              else
                # expand to include however many semesters you want
Zac Wood's avatar
Zac Wood committed
120
                parser.parse_semesters[0..7]
121
122
              end

123
  puts "\tParsing subjects..."
124
125
126
127
128
  subjects = [].to_set
  subjects.merge(parser.parse_subjects(semesters.first[:value]))
  subjects.merge(parser.parse_subjects(semesters.second[:value])) if semesters.count > 1
  subjects.merge(parser.parse_subjects(semesters.third[:value])) if semesters.count > 2
  subjects = subjects.to_a
129
130
131
132
133
134

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

  puts "\tLoading courses..."
  load_courses(courses)
Zac Wood's avatar
Zac Wood committed
135

136
137
  semesters.each do |semester|
    puts "#{semester[:season]} #{semester[:year]}"
138
    db_semester = Semester.find_or_create_by!(season: semester[:season], year: semester[:year])
139

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

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

147
  load_closures
Zac Wood's avatar
Zac Wood committed
148
end
Zac Wood's avatar
Zac Wood committed
149

150
main