-
Notifications
You must be signed in to change notification settings - Fork 5
/
app.rb
210 lines (175 loc) · 6.5 KB
/
app.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
# frozen_string_literal: true
system 'roda-parse_routes', '-f', 'routes.json', __FILE__
require 'area'
require 'rack/host_redirect'
require 'roda'
require 'rollbar/middleware/rack'
require 'securerandom'
require 'tilt'
# require 'zbar'
require_relative 'lib/auth'
require_relative 'lib/bookmooch'
require_relative 'lib/cache'
require_relative 'lib/goodreads'
require_relative 'lib/overdrive'
class App < Roda
use Rollbar::Middleware::Rack
use Rack::HostRedirect, 'bookmooch.herokuapp.com' => 'yonderbook.com'
plugin :halt
plugin :head
plugin :assets, css: 'styles.css'
plugin :public, root: 'assets'
plugin :flash
plugin :sessions, secret: ENV.fetch('SESSION_SECRET')
plugin :slash_path_empty
plugin :render
plugin :default_headers, 'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains'
compile_assets
# TODO: figure out how to reroute 404s to /
route do |r|
r.public
r.assets
session['session_id'] ||= SecureRandom.uuid
# route: GET /
r.root do
request_token = Auth.fetch_request_token
Cache.set(session, request_token:)
@auth_url = request_token.authorize_url
view 'welcome'
end
r.is 'login' do
request_token = Cache.get session, :request_token
# TODO: this is blocking people who are already logged in but not a huge deal
unless request_token
flash[:error] = 'Please authenticate first'
r.redirect '/'
end
# route: GET /login
r.get do
goodreads_user_id, access_token, access_token_secret = Goodreads.fetch_user request_token
session['access_token'] = access_token
session['access_token_secret'] = access_token_secret
session['goodreads_user_id'] = goodreads_user_id
r.redirect '/auth/shelves'
rescue OAuth::Unauthorized
flash[:error] = 'Please authenticate first'
r.redirect '/'
end
end
r.is 'about' do
# route: GET /about
r.get do
view 'about'
end
end
r.on 'auth' do
@goodreads_user_id = session['goodreads_user_id']
r.redirect '/' unless @goodreads_user_id
# TODO: change this so I'm not passing stuff back and forth from cache unnecessarily
r.on 'shelves' do
# route: GET /auth/shelves
r.get true do
@shelves = Goodreads.fetch_shelves @goodreads_user_id
view 'shelves/index'
end
r.on String do |shelf_name|
@shelf_name = shelf_name
Cache.set session, shelf_name: @shelf_name
@book_info = Cache.get session, @shelf_name.to_sym
unless @book_info
access_token = Auth.rebuild_access_token(session['access_token'], session['access_token_secret'])
@book_info = Goodreads.get_books @shelf_name, @goodreads_user_id, access_token
Cache.set session, @shelf_name.to_sym => @book_info
end
# route: GET /auth/shelves/:id
r.get true do
@women, @men, @andy = Goodreads.get_gender @book_info
@histogram_dataset = Goodreads.plot_books_over_time @book_info
@ratings = Goodreads.rating_stats @book_info
view 'shelves/show'
end
r.on 'bookmooch' do
# route: GET /auth/shelves/:id/bookmooch
r.get true do
view 'shelves/bookmooch'
end
# route: POST /auth/shelves/:id/bookmooch?username=foo&password=baz
r.post do
r.halt(403) if r['username'] == 'susanb'
@books_added, @books_failed = Bookmooch.books_added_and_failed @book_info, r['username'], r['password']
Cache.set session, books_added: @books_added, books_failed: @books_failed
r.redirect 'bookmooch/results'
end
# route: GET /auth/shelves/:id/bookmooch/results
r.get 'results' do
@books_added = Cache.get session, :books_added
@books_failed = Cache.get session, :books_failed
view 'bookmooch'
end
end
r.is 'overdrive' do
# TODO: have browser get their location
# route: GET /auth/shelves/:id/overdrive
r.get true do
view 'shelves/overdrive'
end
# route: POST /auth/shelves/:id/overdrive?consortium=1047
r.post do
titles = Overdrive.new(@book_info, r['consortium']).fetch_titles_availability
Cache.set(session, titles:)
r.redirect '/auth/availability'
end
end
end
end
r.is 'availability' do
# route: GET /auth/availability
r.get do
# TODO: Sort titles by recently added to goodreads list
@titles = Cache.get session, :titles
unless @titles
flash[:error] = 'Please choose a shelf first'
r.redirect 'shelves'
end
@available_books = @titles.select { |a| a.copies_available.positive? }
@waitlist_books = @titles.select { |a| a.copies_available.zero? && a.copies_owned.positive? }
@unavailable_books = @titles.select { |a| a.copies_owned.zero? }
view 'availability'
end
end
# TODO: add library logos to the cards in the views
r.is 'library' do
# route: POST /auth/library?zipcode=90029
r.post do
@shelf_name = Cache.get session, :shelf_name
zip = r['zipcode']
if zip.empty?
flash[:error] = 'You need to enter a zip code'
r.redirect "shelves/#{@shelf_name}/overdrive"
end
unless zip.to_latlon
flash[:error] = 'please try a different zip code'
r.redirect "shelves/#{@shelf_name}/overdrive"
end
@local_libraries = Overdrive.local_libraries zip.delete ' '
Cache.set session, libraries: @local_libraries
r.redirect '/auth/library'
end
# route: GET /auth/library
r.get do
@shelf_name = Cache.get session, :shelf_name
@local_libraries = Cache.get session, :libraries
# TODO: see if we can bring the person back to the choose a library stage rather than all the way back to choose a shelf
unless @local_libraries
flash[:error] = 'Please choose a shelf first'
r.redirect 'shelves'
end
view 'library'
end
end
end
rescue OAuth::Unauthorized, StandardError, ScriptError => e
raise e unless ENV['RACK_ENV'] == 'production'
r.redirect '/'
end
end