-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathapp.rb
More file actions
executable file
·294 lines (253 loc) · 8.09 KB
/
app.rb
File metadata and controls
executable file
·294 lines (253 loc) · 8.09 KB
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
require 'sinatra'
require './helpers/sinatra'
require './helpers/milieu'
require './model/mongodb'
require './model/analytics'
require 'haml'
require 'digest/md5'
require 'googlestaticmap'
require 'base64'
configure do
enable :sessions
end
# This runs prior to all requests.
# It passes along the logged in user's object (from the session)
before do
unless session[:user] == nil
@suser = session[:user]
end
end
get '/' do
haml :index
end
get '/login' do
haml :login
end
# The login post routine will take the provided params and run the auth routine.
# If the auth routine is successful it will return the user object, else nil
post '/login' do
if session[:user] = User.auth(params["email"], params["password"])
flash("Login successful")
if ! params[:callback_venue].nil?
redirect "/venue/" << params[:callback_venue]
else
redirect "/user/" << session[:user].email << "/dashboard"
end
else
flash("Login failed - Try again")
redirect '/login'
end
end
get '/logout' do
session[:user] = nil
flash("Logout successful")
redirect '/'
end
get '/register' do
haml :register
end
post '/register' do
if params[:admin] and !session[:user].admin
flash("Not an admin.")
redirect '/'
end
# Creating and populating a new user object from the DB
u = User.new
u.email = params[:email]
u.password = params[:password]
u.name = params[:name]
if params[:admin]
u.admin = true
else
u.admin = false
end
# Attempt to save the user to the DB
if u.save()
flash("User created")
# If user saved, authenticate from the database
session[:user] = User.auth( params["email"], params["password"])
redirect '/user/' << session[:user].email.to_s << "/dashboard"
else
# Else, display errors
tmp = []
u.errors.each do |e|
tmp << (e.join("<br/>"))
end
flash(tmp)
redirect '/create'
end
end
get '/user/:email/dashboard' do
# Get the user's details.
@user = USERS.find_one({:_id => session[:user]._id})
# Compute stats
@user['stats'] = {}
@user['stats']['num_locations'] = 0
@user['stats']['total_checkins'] = 0
if @user['checkins'] != nil
@user['stats']['num_locations'] = @user['checkins'].count.to_i
@user['checkins'].values.each do |v|
@user['stats']['total_checkins'] += v['count']
end
# Get the checkins for this user into a variable.
@venues = Array.new
@user['checkins'].keys.each do |k|
venue = VENUES.find_one({:_id => BSON::ObjectId(k)})
@venues.push(venue)
end
end
haml :user_dashboard
end
get '/user' do
if logged_in?
redirect '/user/' + session[:user].email + '/profile'
else
redirect '/'
end
end
get '/user/:email/profile' do
@user = User.new_from_email(params[:email])
if @user == nil
return haml :profile_missing
end
haml :user_profile
end
get '/list' do
@users = USERS.find
haml :list
end
# Listing the venues.
# As a warning, this approach to pagination isn't especially effective
# when dealing with very large result sets.
get '/venues/p/?:page?' do
@page = params.fetch('page', :page).to_i
num_per_page = 10
@venues = VENUES.find.skip(( @page - 1 ) * num_per_page).limit(num_per_page)
@total_pages = (VENUES.count.to_f / num_per_page).ceil
haml :venues
end
get '/venue/:_id' do
# Converting the string _id from the url into an ObjectId
object_id = BSON::ObjectId.from_string(params[:_id])
# Query for the venue from MongoDB based on the ObjectId
@venue = VENUES.find_one({ :_id => object_id })
# Grab the session user from the db to accurately provide stats
@user = User.new_from_email(@suser.email) if logged_in?
# Find 4 closest venues to this one
@nearby_venues = VENUES.find(
{ :'location.geo' =>
{ :$near => [ @venue['location']['geo'][0],
@venue['location']['geo'][1]]
}
}).limit(4).skip(1)
# Get the mayor user's name.
@mayor = USERS.find_one({:_id => @venue['mayor']})
# Render the template
haml :venue
end
get '/venue/:_id/checkin' do
# Converting the string _id from the url into an ObjectId
object_id = BSON::ObjectId.from_string(params[:_id])
# Query for the venue from MongoDB based on the ObjectId
@venue = VENUES.find_one({ :_id => object_id })
mayor = USERS.find_one({:_id => @venue['mayor']})
# Simultaneously add the users checkin to the venue & return it.
timestamp = Time.now
user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => {"checkins." << object_id.to_s << ".count" => 1},
:$set => {"checkins." << object_id.to_s << ".last_checkin_ts" => timestamp,
"last_checkin_ts" => timestamp,
"last_checkin_name" => @venue['name']}}, :new => 1)
# If it's the first time, increment both checkins and users counts
if user['checkins'][params[:_id]]['count'] == 1
VENUES.update({ :_id => @venue['_id']}, { :$inc => { :'stats.usersCount' => 1, :'stats.checkinsCount' => 1}})
# Else, just the increment the checkins
else
VENUES.update({ :_id => @venue['_id']}, { :$inc => { :'stats.checkinsCount' => 1}})
end
# Update the checkin collection
c = CHECKINS.find_one({:venue_id => object_id, :user_id => @suser._id})
if c
CHECKINS.update({:_id => c['_id']}, {:$push => {'timestamps' => timestamp}})
else
c = Checkin.new
c.venue_id = object_id
c.user_id = @suser._id
c.timestamps = Array.new
c.timestamps.push(timestamp)
if !c.save()
flash('Your checkin failed')
redirect('/venue/:_id')
end
end
if mayor
if mayor['checkins'][object_id.to_s]['count'] < user['checkins'][object_id.to_s]['count']
VENUES.update({:_id => @venue['_id']}, {:$set => {:'mayor' => @suser._id}})
end
else
VENUES.update({:_id => @venue['_id']}, {:$set => {:'mayor' => @suser._id}})
end
flash('Thanks for checking in')
redirect '/venue/' + params[:_id]
end
post '/venue/:_id/image' do
unless params['image'].nil?
# Converting the string _id from the url into an ObjectId
object_id = BSON::ObjectId.from_string(params[:_id])
# BSON is expecting a UTF-8 string, so serialize the image
image = Base64.encode64(params['image'][:tempfile].read())
venue_id = BSON::ObjectId.from_string(params[:_id])
VENUES.update({ :_id => venue_id}, { :$set => { :'image' => image}})
else
flash("Please upload an image")
end
redirect '/venue/' + params[:_id]
end
get '/venue/:_id/image' do
venue_id = BSON::ObjectId.from_string(params[:_id])
venue = VENUES.find_one({ :_id => venue_id});
content_type 'image/png'
# Convert the serialized image back to raw data
Base64.decode64(venue['image'])
end
get '/venues/create' do
if session[:user].admin
haml :venues_create
else
flash('Not an admin')
redirect '/'
end
end
post '/venues/create' do
if !session[:user].admin
flash('Not an admin')
redirect '/'
end
v = Venue.new
v.name = params[:name]
v.location = {
'address' => params[:address],
'cc' => params[:cc],
'city' => params[:city],
'country' => params[:country],
'geo' => [params[:longitude].to_f, params[:latitude].to_f],
'postalCode' => params[:postalCode],
'state' => params[:state],
}
v.stats = {
'checkinsCount' => 0,
'usersCount' => 0
}
# Attempt to save the venue to the DB
if v.save()
flash("Venue Created")
redirect '/venues/p/1'
else
# Else, display errors
tmp = []
u.errors.each do |e|
tmp << (e.join("<br/>"))
end
flash(tmp)
redirect 'venues/create'
end
end