Class: Ubcbooker::Scraper::Cs

Inherits:
BaseScraper show all
Defined in:
lib/ubcbooker/scrapers/cs.rb

Constant Summary collapse

CS_ROOM_BASE_URL =
"https://my.cs.ubc.ca/space/"
CS_BOOK_URL =
"https://my.cs.ubc.ca/node/add/pr-booking"
CS_ROOMS =

1st Floor

["X139", "X141", "X151", "X153", # 1st Floor
"X237", "X239", "X241",         # 2nd Floor
"X337", "X339", "X341"]

Instance Method Summary collapse

Methods inherited from BaseScraper

#initialize, #is_logged_in, #login_ubc_cwl, #populate_account_info

Constructor Details

This class inherits a constructor from Ubcbooker::Scraper::BaseScraper

Instance Method Details

#ampm_to_time(str) ⇒ Object

05:00pm -> 17:99



170
171
172
173
# File 'lib/ubcbooker/scrapers/cs.rb', line 170

def ampm_to_time(str)
  time = Time.parse(str)
  return time.strftime("%H:%M")
end

#batch_request(room_list, book_date) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ubcbooker/scrapers/cs.rb', line 73

def batch_request(room_list, book_date)
  cookie = @agent.cookies.join("; ")
  spinner = get_spinner("Checking room availabilities")

  hydra = Typhoeus::Hydra.new
  requests = room_list.map do |room_id|
    room_url = get_room_cal_url(book_date, room_id)
    request = Typhoeus::Request.new(room_url, headers: { Cookie: cookie })
    hydra.queue(request)
    request
  end
  hydra.run # Start requests
  spinner.success("Done!")
  return typhoeus_to_mechanize(requests)
end

#book(options) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ubcbooker/scrapers/cs.rb', line 10

def book(options)
  
  title = options[:name]
  book_date = Date.parse(options[:date])
  book_slot = get_time_slot(options[:time])

  room_pages = batch_request(CS_ROOMS, book_date)
  room_pages.select! { |r| is_available(r, book_date, book_slot) }

  if room_pages.any?
    # TODO: If -c CHOOSE option then run CLI-UI here
    room = room_pages.first  # Choose the first available room
    submit_booking(room, title, book_date, book_slot)
    return get_room_page_id(room)
  else
    raise Ubcbooker::Error::NoAvailableRoom.new(options[:time])
  end
end

#get_date_div_id(date) ⇒ Object



148
149
150
151
152
# File 'lib/ubcbooker/scrapers/cs.rb', line 148

def get_date_div_id(date)
  date_div_base = "calendar_space_entity_project_room-"
  date_div_base += "#{date.year}-#{date.strftime("%m")}-#{date.strftime("%d")}-0"
  return date_div_base
end

#get_room_cal_url(book_date, room_id) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ubcbooker/scrapers/cs.rb', line 89

def get_room_cal_url(book_date, room_id)
  if CS_ROOMS.include?(room_id)
    room_url = CS_ROOM_BASE_URL + "ICCS" + room_id
    if is_next_month(book_date)
      today = Date.today
      month_query = "?month=" + today.year + "-" + (today.month + 1)
      return room_url + month_query
    else
      return room_url
    end
  end
end

#get_room_page_id(page) ⇒ Object



69
70
71
# File 'lib/ubcbooker/scrapers/cs.rb', line 69

def get_room_page_id(page)
  return page.form.action.split("/").last
end

#get_slot_booked(room_page, book_date) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/ubcbooker/scrapers/cs.rb', line 132

def get_slot_booked(room_page, book_date)
  day_div_id = get_date_div_id(book_date)
  day_div = room_page.search("td##{day_div_id}").first
  slot_num = day_div.search("div.item").size
  start_times = day_div.search("span.date-display-start")
  end_times = day_div.search("span.date-display-end")

  slot_booked = []
  (0..slot_num-1).each do |i|
    slot_start = ampm_to_time(start_times[i].text) # 01:00
    slot_end = ampm_to_time(end_times[i].text) # 05:00
    slot_booked.push((slot_start..slot_end))
  end
  return slot_booked
end

#get_spinner(text) ⇒ Object



154
155
156
157
158
# File 'lib/ubcbooker/scrapers/cs.rb', line 154

def get_spinner(text)
  spinner = ::TTY::Spinner.new("[:spinner] #{text} ... ", format: :dots)
  spinner.auto_spin # Automatic animation with default interval
  return spinner
end

#get_time_slot(time_str) ⇒ Object

Expect HH:MM-HH:MM



164
165
166
167
# File 'lib/ubcbooker/scrapers/cs.rb', line 164

def get_time_slot(time_str)
  times = time_str.split("-")
  return (times[0]..times[1])
end

#is_available(room_page, book_date, book_slot) ⇒ Object



115
116
117
118
# File 'lib/ubcbooker/scrapers/cs.rb', line 115

def is_available(room_page, book_date, book_slot)
  slot_booked = get_slot_booked(room_page, book_date)
  return !is_slot_booked(slot_booked, book_slot)
end

#is_next_month(date) ⇒ Object



111
112
113
# File 'lib/ubcbooker/scrapers/cs.rb', line 111

def is_next_month(date)
  return date.month != Date.today.month
end

#is_slot_booked(slot_booked, book_slot) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ubcbooker/scrapers/cs.rb', line 120

def is_slot_booked(slot_booked, book_slot)
  booked = false
  slot_booked.each do |s|
    if (s.include?(book_slot.min) ||
        s.include?(book_slot.max) ||
        book_slot.include?(s))
      booked = true
    end
  end
  return booked
end

#loginObject



29
30
31
32
33
34
35
36
37
# File 'lib/ubcbooker/scrapers/cs.rb', line 29

def 
  spinner = get_spinner("Logging into CWL")
  booking_url = BOOKING_URL[:cs]
  @agent.get(booking_url) do |page|
     = page.link_with(text: "CWL Login Redirect").click
    ()
  end
  spinner.success("Done!") # Stop animation
end

#select_room_option(booking_form, page) ⇒ Object

Select the form otpion with right room id



59
60
61
62
63
64
65
66
67
# File 'lib/ubcbooker/scrapers/cs.rb', line 59

def select_room_option(booking_form, page)
  room_id = get_room_page_id(page)
  select_options = booking_form.field_with(name: "field_space_project_room[und]").options
  select_options.each do |o|
    if o.text.include?(room_id)
      o.click
    end
  end
end

#submit_booking(room, title, book_date, book_slot) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ubcbooker/scrapers/cs.rb', line 39

def submit_booking(room, title, book_date, book_slot)
  spinner = get_spinner("Submitting booking request")
  booking_form = @agent.get(CS_BOOK_URL).forms[1]
  booking_form["title"] = title
  book_date_str = book_date.strftime("%Y/%m/%d")  # ex 2018/03/08
  select_room_option(booking_form, room)
  booking_form["field_date[und][0][value][date]"] = book_date_str
  booking_form["field_date[und][0][value][time]"] = time_to_ampm(book_slot.min)
  booking_form["field_date[und][0][value2][date]"] = book_date_str
  booking_form["field_date[und][0][value2][time]"] = time_to_ampm(book_slot.max)
  confirmation_page = booking_form.submit
  if confirmation_page.search("div.alert-error").empty?
    spinner.success("Done!")
  else
    spinner.fail("Booking rejected")
    raise Ubcbooker::Error::BookingFailed.new
  end
end

#time_to_ampm(str) ⇒ Object

17:00 -> 05:00pm



176
177
178
179
# File 'lib/ubcbooker/scrapers/cs.rb', line 176

def time_to_ampm(str)
  time = Time.parse(str)
  return time.strftime("%I:%M%P")
end

#typhoeus_to_mechanize(requests) ⇒ Object

Turn typhoneus obj to mechanize page obj



103
104
105
106
107
108
109
# File 'lib/ubcbooker/scrapers/cs.rb', line 103

def typhoeus_to_mechanize(requests)
  pages = requests.map do |request|
    html = request.response.body
    Mechanize::Page.new(nil, {"ontent-type" => "text/html"}, html, nil, @agent)
  end
  return pages
end