Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
SRCT
schedules
Commits
891b8a0a
Commit
891b8a0a
authored
Sep 26, 2018
by
Zac Wood
Browse files
Merge branch '29-semesters' into 'dev-v2'
Now handles multiple semesters correctly See merge request
!27
parents
3918e500
1f63be1c
Pipeline
#2989
passed with stage
in 2 minutes and 16 seconds
Changes
14
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
schedules/app/controllers/application_controller.rb
View file @
891b8a0a
# Configures the application.
class
ApplicationController
<
ActionController
::
Base
protect_from_forgery
with: :null_session
before_action
:set_cookies
,
:set_cart
before_action
:set_cookies
,
:set_cart
,
:set_semester
def
set_cart
@cart
=
cookies
[
:ids
].
split
(
','
).
map
do
|
crn
|
...
...
@@ -12,4 +12,12 @@ class ApplicationController < ActionController::Base
def
set_cookies
cookies
[
:ids
]
=
""
if
cookies
[
:ids
].
nil?
end
def
set_semester
@semester
=
if
params
.
key?
(
:semester_id
)
Semester
.
find_by
(
id:
params
[
:semester_id
])
else
Semester
.
find_by
(
season:
'Fall'
,
year:
'2018'
)
end
end
end
schedules/app/controllers/search_controller.rb
View file @
891b8a0a
class
SearchController
<
ApplicationController
def
index
@courses
=
Course
.
where
(
subject:
params
[
:q
]).
select
do
|
course
|
@courses
=
Course
.
where
(
subject:
params
[
:q
]
,
semester:
@semester
).
select
do
|
course
|
course
.
course_sections
.
count
.
positive?
end
end
def
update
cookies
[
:ids
]
=
params
[
:ids
]
head
:ok
end
end
schedules/app/models/course.rb
View file @
891b8a0a
...
...
@@ -10,10 +10,4 @@ class Course < ApplicationRecord
validates
:course_number
,
presence:
true
validates
:subject
,
presence:
true
validates
:semester_id
,
presence:
true
# Returns all +CourseSection+ objects that belong to this course.
# @return [Array]
def
course_sections
CourseSection
.
where
course_id:
id
end
end
schedules/app/models/course_section.rb
View file @
891b8a0a
# Contains logic belonging to the +CourseSection+ model.
#
# TODO: Add more docs
class
CourseSection
<
ApplicationRecord
# Each +CourseSection+ belongs to a +Course+ and an +Instructor+.
belongs_to
:course
...
...
schedules/app/models/schedule.rb
View file @
891b8a0a
require
'icalendar'
require
'time'
# Creates a iCal object given a list of CRNs
class
Schedule
def
initialize
(
crns
)
@cal
=
Icalendar
::
Calendar
.
new
...
...
schedules/app/models/semester.rb
View file @
891b8a0a
...
...
@@ -3,12 +3,9 @@
# A +Semester+ is a simple model that consists of a +year+ and a +season+, e.g. "Fall 2018".
class
Semester
<
ApplicationRecord
has_many
:courses
has_many
:closures
# Ensure necessary fields are present.
validates
:year
,
presence:
true
validates
:season
,
presence:
true
def
courses
Course
.
where
semester_id:
id
end
end
schedules/config/routes.rb
View file @
891b8a0a
# Registers all routes for the app.
Rails
.
application
.
routes
.
draw
do
get
'search'
,
to:
'search#index'
get
'search/update'
,
to:
'search#update'
get
'search/update'
,
to:
'search#update'
,
as:
'update_cookie'
resources
:instructors
,
only:
[
:index
,
:show
]
...
...
schedules/db/patriot_web_networker.rb
View file @
891b8a0a
...
...
@@ -16,9 +16,9 @@ module PatriotWeb
})
end
def
fetch_courses_in_subject
(
subject
)
def
fetch_courses_in_subject
(
semester_val
,
subject
)
HTTParty
.
post
(
'https://patriotweb.gmu.edu/pls/prod/bwckschd.p_get_crse_unsec'
,
body:
"term_in=
201870
&sel_subj=dummy&sel_day=dummy&sel_schd=dummy&sel_insm=dummy&sel_camp=dummy&sel_levl=dummy&sel_sess=dummy&sel_instr=dummy&sel_ptrm=dummy&sel_attr=dummy&sel_subj=
#{
subject
}
&sel_crse=&sel_title=&sel_schd=%25&sel_from_cred=&sel_to_cred=&sel_camp=%25&sel_levl=%25&sel_ptrm=%25&sel_instr=%25&begin_hh=0&begin_mi=0&begin_ap=x&end_hh=0&end_mi=0&end_ap=x"
,
body:
"term_in=
#{
semester_val
}
&sel_subj=dummy&sel_day=dummy&sel_schd=dummy&sel_insm=dummy&sel_camp=dummy&sel_levl=dummy&sel_sess=dummy&sel_instr=dummy&sel_ptrm=dummy&sel_attr=dummy&sel_subj=
#{
subject
}
&sel_crse=&sel_title=&sel_schd=%25&sel_from_cred=&sel_to_cred=&sel_camp=%25&sel_levl=%25&sel_ptrm=%25&sel_instr=%25&begin_hh=0&begin_mi=0&begin_ap=x&end_hh=0&end_mi=0&end_ap=x"
,
headers:
{
'Content-Type'
=>
'application/x-www-form-urlencoded'
,
'charset'
=>
'utf-8'
...
...
schedules/db/patriot_web_parser.rb
View file @
891b8a0a
...
...
@@ -19,7 +19,6 @@ module PatriotWeb
def
parse_semesters
response
=
@networker
.
fetch_page_containing_semester_data
document
=
Nokogiri
::
HTML
(
response
)
# parse the document from the HTTP response
get_semesters_from_option_values
(
document
).
compact
end
...
...
@@ -33,8 +32,8 @@ module PatriotWeb
# Parses all courses belonging to a given subject
# @param subject [String]
def
parse_courses_in_subject
(
subject
)
response
=
@networker
.
fetch_courses_in_subject
(
subject
)
def
parse_courses_in_subject
(
semester
,
subject
)
response
=
@networker
.
fetch_courses_in_subject
(
semester
,
subject
)
document
=
Nokogiri
::
HTML
(
response
)
get_courses
(
document
,
subject
)
end
...
...
@@ -46,9 +45,10 @@ module PatriotWeb
# @param document [Nokogiri::HTML::Document]
def
get_semesters_from_option_values
(
document
)
document
.
css
(
'option'
).
map
do
|
opt
|
# for each option value
if
opt
.
attr
(
'value'
).
start_with?
'20'
# ensure it is a semester value
opt
.
attr
(
'value'
)
# return the value
end
next
unless
opt
.
attr
(
'value'
).
start_with?
'20'
# ensure it is a semester value
text
=
opt
.
text
.
gsub
(
/ *\(.*\).*/
,
""
).
gsub
(
/ +/
,
" "
)
season
,
year
=
text
.
split
{
value:
opt
.
attr
(
'value'
),
season:
season
,
year:
year
}
end
end
...
...
@@ -57,9 +57,7 @@ module PatriotWeb
# @param document [Nokogiri::HTML::Document]
def
get_subject_codes_from_option_values
(
document
)
document
.
xpath
(
'//*[@id="subj_id"]/option'
).
map
do
|
opt
|
# for each option value under "subj_id"
if
opt
.
attr
(
'value'
).
strip
.
alpha?
# if the value is alphanumeric
opt
.
attr
(
'value'
)
# return the value
end
opt
.
attr
(
'value'
)
if
opt
.
attr
(
'value'
).
strip
.
alpha?
# return the value if the value is alphanumeric
end
end
...
...
@@ -69,10 +67,6 @@ module PatriotWeb
def
get_courses
(
document
,
_subject
)
table
=
document
.
css
(
'html body div.pagebodydiv table.datadisplaytable'
)
rows
=
table
.
css
(
'tr'
)
# rows[100..110].each_with_index do |row, i|
# puts i
# puts row
# end
data_from
rows
end
...
...
@@ -95,7 +89,7 @@ module PatriotWeb
data
[
:section
]
=
title_elements
[
3
].
strip
details
=
rows
[
i
+
2
].
css
(
'td table tr td'
)
unless
!
details
.
empty?
if
details
.
empty?
# puts "#{full_name.join(' ')} is fake news"
i
+=
1
next
...
...
schedules/db/seeds.rb
View file @
891b8a0a
...
...
@@ -23,23 +23,27 @@ def parse_courses(subjects)
end
def
load_courses
(
courses
,
semester
)
courses
.
each
do
|
course
|
Course
.
create!
(
subject:
course
[
:subject
],
title:
course
[
:title
],
course_number:
course
[
:course_number
],
credits:
course
[
:credits
],
description:
course
[
:description
],
semester:
semester
)
insert_hashes
=
courses
.
map
do
|
course
|
{
subject:
course
[
:subject
],
title:
course
[
:title
],
course_number:
course
[
:course_number
],
credits:
course
[
:credits
],
description:
course
[
:description
],
semester:
semester
}
end
Course
.
create!
(
insert_hashes
)
end
def
parse_sections
(
subjects
)
def
parse_sections
(
semester
,
subjects
)
parser
=
PatriotWeb
::
Parser
.
new
sections_in
=
{}
threads
=
subjects
.
map
do
|
subject
|
Thread
.
new
do
sections_in
[
subject
]
=
parser
.
parse_courses_in_subject
(
subject
)
sections_in
[
subject
]
=
parser
.
parse_courses_in_subject
(
semester
,
subject
)
end
end
...
...
@@ -91,39 +95,44 @@ def wipe_db
Semester
.
delete_all
end
def
load_closures
(
semester
)
def
load_closures
# create closures for the days there will be no classes
# see: https://registrar.gmu.edu/calendars/fall-2018/
Closure
.
create!
date:
Date
.
new
(
2018
,
9
,
3
),
semester:
semester
Closure
.
create!
date:
Date
.
new
(
2018
,
10
,
8
),
semester:
semester
(
21
..
25
).
each
{
|
n
|
Closure
.
create!
date:
Date
.
new
(
2018
,
11
,
n
),
semester:
semester
}
(
10
..
19
).
each
{
|
n
|
Closure
.
create!
date:
Date
.
new
(
2018
,
12
,
n
),
semester:
semester
}
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
}
end
def
main
wipe_db
parser
=
PatriotWeb
::
Parser
.
new
semesters
=
[
parser
.
parse_semesters
.
first
]
# expand to include however many semesters you want
courses
=
nil
puts
"Parsing subjects..."
semester
=
parser
.
parse_semesters
.
first
subjects
=
parser
.
parse_subjects
(
semester
)
semesters
.
each
do
|
semester
|
puts
"
#{
semester
[
:season
]
}
#{
semester
[
:year
]
}
"
db_semester
=
Semester
.
create!
(
season:
semester
[
:season
],
year:
semester
[
:year
]
)
puts
"Parsing
courses from catalog.gmu.edu
..."
course
s
=
parse
_cou
rse
s
(
subjects
)
puts
"
\t
Parsing
subjects
..."
subject
s
=
parse
r
.
pa
rse
_
subjects
(
semester
[
:value
]
)
db_semester
=
Semester
.
create!
season:
'Fall'
,
year:
2018
puts
"
\t
Parsing courses from catalog.gmu.edu..."
courses
=
parse_courses
(
subjects
)
if
courses
.
nil?
puts
"Loading courses..."
load_courses
(
courses
,
db_semester
)
puts
"
\t
Loading courses..."
load_courses
(
courses
,
db_semester
)
puts
"Parsing sections from Patriot Web..."
sections_in
=
parse_sections
(
subjects
)
puts
"
\t
Parsing sections from Patriot Web..."
sections_in
=
parse_sections
(
semester
[
:value
],
subjects
)
puts
"Loading sections..."
load_sections
(
sections_in
,
db_semester
)
puts
"
\t
Loading sections..."
load_sections
(
sections_in
,
db_semester
)
end
load_closures
(
db_semester
)
load_closures
end
main
schedules/test/controllers/search_controller_test.rb
View file @
891b8a0a
require
'test_helper'
class
SearchControllerTest
<
ActionDispatch
::
IntegrationTest
# test "should get index" do
# get search_index_url
# assert_response :success
# end
test
"should get index"
do
get
search_url
assert_response
:success
end
test
"should update cookie"
do
get
update_cookie_url
crns:
'71926,71924'
assert_response
:success
end
end
schedules/test/fixtures/course_sections.yml
View file @
891b8a0a
...
...
@@ -36,5 +36,31 @@ cs211001:
start_time
:
2:30 pm
end_time
:
3:00 pm
location
:
ENGR
200
course
:
cs211
course
:
cs211
spring
instructor
:
otten
cs112001spring
:
name
:
CS 112
001
crn
:
70192
title
:
Introduction to Computing
start_date
:
2018-05-21
end_date
:
2018-06-04
days
:
MWF
start_time
:
12:00 pm
end_time
:
1:00 pm
location
:
Innovation Hall
204
course
:
cs112spring
instructor
:
kinga
acct110001
:
name
:
ACCT 110
001
crn
:
71926
title
:
Business
start_date
:
2018-05-21
end_date
:
2018-06-04
days
:
MWF
start_time
:
12:00 pm
end_time
:
1:00 pm
location
:
Innovation Hall
204
course
:
acct110spring
instructor
:
business_man
schedules/test/fixtures/courses.yml
View file @
891b8a0a
...
...
@@ -10,12 +10,17 @@ cs211:
course_number
:
211
semester
:
fall2018
acct110
:
acct110
spring
:
subject
:
ACCT
course_number
:
110
semester
:
spring2018
cs110
:
cs110
spring
:
subject
:
CS
course_number
:
110
semester
:
spring2018
cs112spring
:
subject
:
CS
course_number
:
112
semester
:
spring2018
schedules/test/fixtures/instructors.yml
View file @
891b8a0a
...
...
@@ -8,3 +8,6 @@ otten:
kinga
:
name
:
Kinga
business_man
:
name
:
Bob
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment