This repository has been archived by the owner on Jul 25, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
drumbone.rb
executable file
·173 lines (131 loc) · 4.96 KB
/
drumbone.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
#!/usr/bin/env ruby
require 'config/environment'
# reload in development without starting server
configure(:development) do |config|
require 'sinatra/reloader'
config.also_reload "config/environment.rb"
config.also_reload "models/*.rb"
config.also_reload "sources/*.rb"
config.also_reload "report.rb"
end
not_found do
# If this is a JSONP request, and it did trigger one of the main routes, return an error response
# Otherwise, let it lapse into a normal content-less 404
# If we don't do this, in-browser clients using JSONP have no way of detecting a problem
if params[:captures] and params[:captures][0] and params[:callback]
json = {:error => {:code => 404, :message => "#{params[:captures][0].capitalize} not found"}}.to_json
jsonp = "#{params[:callback]}(#{json});";
halt 200, jsonp
end
end
get /^\/api\/(legislator)\.(json)$/ do
fields = fields_for Legislator, params[:sections]
conditions = conditions_for Legislator.unique_keys, params
unless conditions.any? and legislator = Legislator.first(:conditions => conditions, :fields => fields)
raise Sinatra::NotFound
end
json Legislator, attributes_for(legislator, fields), params[:callback]
end
get /^\/api\/(bill)\.(json)$/ do
fields = fields_for Bill, params[:sections]
conditions = conditions_for Bill.unique_keys, params
unless conditions.any? and bill = Bill.first(:conditions => conditions, :fields => fields)
raise Sinatra::NotFound
end
json Bill, attributes_for(bill, fields), params[:callback]
end
get /^\/api\/(roll)\.(json)$/ do
fields = fields_for Roll, params[:sections]
conditions = conditions_for Roll.unique_keys, params
unless conditions.any? and roll = Roll.first(:conditions => conditions, :fields => fields)
raise Sinatra::NotFound
end
json Roll, attributes_for(roll, fields), params[:callback]
end
get /^\/api\/(bills)\.(json)$/ do
fields = fields_for Bill, params[:sections]
conditions = search_conditions_for Bill, params
order = order_for Bill, params
bills = Bill.all({
:conditions => conditions,
:fields => fields,
:order => order,
}.merge(pagination_for(params)))
json Bill, bills.map {|bill| attributes_for bill, fields}, params[:callback]
end
get /^\/api\/(rolls)\.(json)$/ do
fields = fields_for Roll, params[:sections]
conditions = search_conditions_for Roll, params
order = order_for Roll, params
rolls = Roll.all({
:conditions => conditions,
:fields => fields,
:order => order,
}.merge(pagination_for(params)))
json Roll, rolls.map {|roll| attributes_for roll, fields}, params[:callback]
end
helpers do
def json(model, object, callback = nil)
response['Content-Type'] = 'application/json'
key = model.to_s.underscore
key = key.pluralize if object.is_a?(Array)
json = {key => object}.to_json
callback ? "#{callback}(#{json});" : json
end
def conditions_for(keys, params)
conditions = {}
keys.each do |key|
conditions[key] = params[key] if params[key]
end
conditions
end
def search_conditions_for(model, params)
conditions = {}
model.search_keys.keys.each do |key|
if params[key]
if model.search_keys[key] == Boolean
conditions[key] = (params[key] == "true") if ["true", "false"].include? params[key]
else
conditions[key] = params[key]
end
end
end
conditions
end
def order_for(model, params)
order_key = model.order_keys.detect {|key| params[:order].present? and params[:order].to_sym == key} || model.order_keys.first
order_sort = ['DESC', 'ASC'].detect {|sort| params[:sort].to_s.upcase == sort} || 'DESC'
secondary_sort = "#{model.unique_keys.first} DESC"
"#{order_key} #{order_sort}, #{secondary_sort}"
end
def pagination_for(params)
default_per_page = 20
max_per_page = 500
max_page = 200000000 # let's keep it realistic
# rein in per_page to somewhere between 1 and the max
per_page = (params[:per_page] || default_per_page).to_i
per_page = default_per_page if per_page <= 0
per_page = max_per_page if per_page > max_per_page
# valid page number, please
page = (params[:page] || 1).to_i
page = 1 if page <= 0 or page > max_page
{:limit => per_page, :offset => (page - 1 ) * per_page}
end
def fields_for(model, sections)
if sections.include?('basic')
sections.delete 'basic' # does nothing if not present
sections += model.basic_fields.map {|field| field.to_s}
end
sections.uniq
end
def attributes_for(document, fields)
attributes = document.attributes
# only match against field roots so that subobject requests can slip through
fields = fields.map {|field| field.split('.').first}
[:created_at, :updated_at, :_id, :id].each {|field| attributes.delete field.to_s}
if fields.any?
attributes.keys.each {|key| attributes.delete(key) unless fields.include?(key)}
end
attributes
end
end