-
Notifications
You must be signed in to change notification settings - Fork 0
/
s.rb
executable file
·328 lines (288 loc) · 7.96 KB
/
s.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/ruby
require "sinatra"
require "sinatra/cookies"
require "date"
require_relative "int/parse.rb"
require_relative "int/logger.rb"
require_relative "int/gcal.rb"
enable :sessions
set :session_secret, "setme"
# Load the timetable from
f = Nokogiri::HTML(open("int/timetable"))
t = Timetable.new(f)
log = SWLogger.new("public/logs/")
callbackURI = nil
if ARGV[0] == 'production'
puts "Running in produciton mode!"
callbackURI = "http://plaintime.com/permCall"
end
# Needed to keep cookies around for more than a single session
set(:cookie_options) do
{ :expires => Time.now + 3600*24*7 }
end
get "/" do
# Show the index file
# found in /public/views/
erb :index
end
# User is sent here why the update their settings
get "/user/cols/*/*/*/*" do
parts = params["splat"]
name = parts[0]
parts[3].slice!("/")
cols = cookies[:"#{name}"]
cols = "rgb(#{parts[1]},#{parts[2]},#{parts[3]})"
cookies[:"#{name}"] = cols
redirect "/user/#{params['id']}/"
end
get "/user" do
id = session[:id]
if id == nil
redirect "/"
end
redirect "/user/#{id}/"
end
# JSON API
get "/user/:id/*/json" do
# Get the user id and the student with that ID
n = params["id"]
s = Student.fromNumber(n)
if s == nil
content_type :json
log.log("Unable to find user info for ID: #{n}\n#{params}")
{:status => "Invalid", :lectures => "none"}.to_json # Not found so tell them that
else
log.log("Found info for user with ID: #{n}")
tom = params["splat"][0] # The * between the ID and json in the url
day = tom == nil ? (Time.now.wday - 1) : tom.to_i # use 'tom' if it's not null else use the actual day
if tom == "tomorrow"
tday = Time.now.wday
t.getDay(tday)
day = tday
elsif tom == "0"
t.getDay(0)
elsif tom == "1"
t.getDay(1)
elsif tom == "2"
t.getDay(2)
elsif tom == "3"
t.getDay(3)
elsif tom == "4"
t.getDay(4)
else
t.getToday()
hour = Time.now.hour
end
content_type :json
{:status => "Valid", :day => t.getDayName(), :lectures => t.getLectures(s)}.to_json
end
end
# User is looking at either today or tomorrow's timetable
get "/user/:id/:tom?" do
n = params["id"]
s = Student.fromNumber(n)
colors = cookies[:colors]
if s == nil
log.log("Unable to find user info for ID: #{n}\n#{params}")
erb :index, :locals => {:err => "No data on that user"}
else
log.log("Found info for user with ID: #{n}")
tom = params["tom"]
hour = 8
day = tom == nil ? (Time.now.wday - 1) : tom.to_i
if tom == "tomorrow"
tday = Time.now.wday
t.getDay(tday)
day = tday
elsif tom == "0"
t.getDay(0)
elsif tom == "1"
t.getDay(1)
elsif tom == "2"
t.getDay(2)
elsif tom == "3"
t.getDay(3)
elsif tom == "4"
t.getDay(4)
else
day = Time.now.wday - 1
t.getToday()
hour = Time.now.hour
end
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
cols = cookies.select{|k| k.start_with? "CS"}
# Just to keep the cookies on the system
if cols != nil
cookies.each do |c|
cookies[c[0]] = c[1]
end
end
session[:id] = n
erb :user, :locals => {:id => n, :hour => hour, :lecs => t.getLectures(s), :colors => cols, :day => days[day]}
end
end
# We got some feedback data
post "/feedback" do
name = params["name"]
id = params["id"]
dets = params["dets"]
ti = Time.now
n = "#{ti.year}-#{ti.month}-#{ti.day}-#{ti.hour}:#{ti.min}:#{ti.sec}"
suc = false
begin
File.open("public/feedback/#{n}.txt", "w") do |f|
f.write("Name: #{name}\n")
f.write("ID: #{id}\n")
f.write("Details: #{dets}\n")
end
log.log("Feedback was posted")
suc = true
rescue # If it fails for what ever reason don't just crash
log.log("Error posting feedback")
end
erb :error, :locals => {:done => suc}
end
# User is giving us some feedback
get "/feedback" do
if session[:id] != nil
redirect "/feedback/#{session[:id]}"
else
redirect "/"
end
end
get "/feedback/:id?" do
erb :error, :locals => {:id => params["id"]}
end
# Caled by the Google calendar API
# Wouldn't recommend touching this
get "/permCall" do
client_secrets = Google::APIClient::ClientSecrets.load
auth_client = client_secrets.to_authorization
call = callbackURI || url("/permCall")
auth_client.update!(
:scope => 'https://www.googleapis.com/auth/calendar',
:redirect_uri => call)
if request['code'] == nil
auth_uri = auth_client.authorization_uri.to_s
redirect to(auth_uri)
else # The request is good so we can return to /gcal
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
session[:credentials] = auth_client.to_json
session[:exp] = Time.now + auth_client.expiry
id = session[:id]
log.log("Successfully got OAuth code")
redirect "/gcal"
end
end
# Add the events to the users Google calender
get "/gcal" do
id = session[:id] || -1 # id is equal to session[:id] or -1
if id == -1 # User hasn't done anything yet
redirect "/"
end
unless session.has_key?(:credentials)
redirect to('/permCall')
end
# Check if the token has expired
if session[:exp] != nil
if Time.now > session[:exp]
# if it has renew it
redirect "/permCall"
end
end
# Google OAuth2 junk
client_opts = JSON.parse(session[:credentials])
auth_client = Signet::OAuth2::Client.new(client_opts)
####
ecal = EasyCalendar.new(auth_client)
cal = ecal.getCalendarByName("Uni Timetable")
ecal.clearCalendar(cal)
s = Student.fromNumber(id)
t.getDay(Time.now.wday)
lecs = t.getLectures(s)
log.log("Going to add events to a google calendar for ID: #{id}")
if lecs.length == 0
puts "No events to add"
else
ti = Time.now + 60*60*24
date = "#{ti.year}-#{ti.month}-#{ti.day}"
tomLecs = ecal.getEventsForXDaysTime(cal, 1) #Get tomorrow's events (Lectures)
puts tomLecs[0]
if tomLecs.length == 0 # No events tomorrow just add them
puts "Nothing new"
lecs.each do |l|
s = l.getStart()
len = l.getLength()
event = ecal.createEvent(l.getName(), {:date => date, :hour => s, :length => len , :location => l.getLocation()})
ecal.addEvent(cal, event)
end
else # Some events tomorrow so we need to see if they are ours
if tomLecs.length == lecs.length
puts "We have the same ammount"
for i in 0..lecs.length-1
cl = lecs[i]
ctl = tomLecs[i]
puts cl.getName()
puts ctl.summary
puts ""
if cl.getName() == ctl.summary && cl.getDateTime() == ctl.start.date_time # Do they have the same name"
next # Skip this event
else
s = cl.getStart()
len = cl.getLength()
event = ecal.createEvent(cl.getName(), {:date => date, :hour => s, :length => len , :location => cl.getLocation()})
#ecal.addEvent(cal, event)
end
end
else
if tomLecs.length > lecs.length
puts "Tomorrow has more events than we do"
for i in 0..tomLecs.length - 1
ctl = tomLecs[i]
if ctl == nil
next
end
for j in 0..lecs.length - 1
cl = lecs[j]
if ctl.summary == cl.getName() && cl.getDateTime() == ctl.start.date_time # Same name and same time, don't add this one
next
end
end
end
elsif lecs.length > tomLecs.items.length
puts "We have more"
for i in 0..lecs.length - 1
needed = true
cl = lecs[i]
for j in 0..tomLecs.items.length - 1
ctl = tomLecs.items[j]
if cl.getName() == ctl.summary && cl.getDateTime() == ctl.start.date_time
needed = false
break
end
end
if needed
puts cl.getLength()
event = ecal.createEvent(cl.getName(), {:date => date, :hour => cl.getStart(), :length => cl.getLength() , :location => cl.getLocation()})
end
end
end
end
end
end
""
end
# A small function so that when the server gets the latest
# timetable we can load it without having to restart the server
get "/updateTime" do
f = Nokogiri::HTML(open("int/timetable"))
log.log("Updated the timetable")
""
end
# Simple error correction page
error 404 do
log.err("Something wasn't found @ #{request.url}\n#{params}")
redirect "/"
end