An open source, stand-alone, customisable public spending data web app.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

app.rb 5.2 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. require 'rubygems'
  2. require 'sinatra'
  3. require 'sinatra-helpers/haml/partials'
  4. require 'haml'
  5. require 'lib/models'
  6. SETTING = Setting.first # Could also do this with Sinatra filters before/do
  7. PAYMENTS_FILTER_MIN = 1000
  8. helpers do
  9. def commify(amount)
  10. amount.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,'\1,').reverse
  11. end
  12. def yesno(boolean)
  13. boolean == true ? 'Yes' : 'No'
  14. end
  15. def nicedate(d)
  16. d.strftime("%d %b %Y")
  17. end
  18. end
  19. get '/' do
  20. @directorates = Directorate.all( :order => ['name'] )
  21. @payments_count = Payment.count
  22. @suppliers_count = Supplier.count
  23. @services_count = Service.count
  24. haml :home
  25. end
  26. get '/directorates/:slug' do
  27. @directorate = Directorate.first(:slug => params[:slug])
  28. haml :directorate
  29. end
  30. get '/suppliers/:slug.csv' do
  31. @supplier = Supplier.first(:slug => params[:slug])
  32. headers "Content-Disposition" => "attachment;filename=supplier-#{@supplier.slug}.csv",
  33. "Content-Type" => "application/octet-stream"
  34. result = "Date,Ref.,URL,Directorate,Service,Amount ex. VAT\n"
  35. for payment in @supplier.payments
  36. result += "#{payment.d.strftime("%d %b %Y")},#{payment.id},#{payment.url},\"#{payment.service.directorate.name}\",#{payment.service.name},#{sprintf("%0.2f", payment.amount)}\n"
  37. end
  38. result
  39. end
  40. get '/suppliers/:slug' do
  41. @supplier = Supplier.first(:slug => params[:slug])
  42. @total = @supplier.payments.sum(:amount)
  43. @count = @supplier.payments.size # Payment.count(:supplier_id => @supplier.id) ?
  44. @avg = @supplier.payments.avg(:amount)
  45. @max = @supplier.payments.max(:amount)
  46. @min = @supplier.payments.min(:amount)
  47. @d_start = @supplier.payments.min(:d)
  48. @d_end = @supplier.payments.max(:d)
  49. haml :supplier
  50. end
  51. get '/suppliers/?' do
  52. @suppliers = Supplier.all( :order => ['name'] )
  53. haml :suppliers
  54. end
  55. get '/services/:slug/payments.csv' do
  56. @service = Service.first(:slug => params[:slug])
  57. headers "Content-Disposition" => "attachment;filename=service-#{@service.slug}.csv",
  58. "Content-Type" => "application/octet-stream"
  59. result = "Date,Ref.,URL,Directorate,Supplier,Amount ex. VAT\n"
  60. for payment in @service.payments
  61. result += "#{payment.d.strftime("%d %b %Y")},#{payment.id},#{payment.url},\"#{payment.service.directorate.name}\",#{payment.supplier.name},#{sprintf("%0.2f", payment.amount)}\n"
  62. end
  63. result
  64. end
  65. get '/services/:slug.json' do
  66. @service = Service.first(:slug => params[:slug])
  67. headers "Content-Type" => "application/json"
  68. @service.to_json(:relationships => { :payments => { :include => :all }, :directorate => { :include => :all } })
  69. end
  70. get '/services/:slug' do
  71. @service = Service.first(:slug => params[:slug])
  72. @total = @service.payments.sum(:amount)
  73. @count = @service.payments.size
  74. @avg = @service.payments.avg(:amount)
  75. @max = @service.payments.max(:amount)
  76. @min = @service.payments.min(:amount)
  77. @d_start = @service.payments.min(:d)
  78. @d_end = @service.payments.max(:d)
  79. @results = repository(:default).adapter.query("
  80. SELECT s.name AS supplier_name, s.slug AS supplier_slug, SUM(p.amount) AS total
  81. FROM payments p, suppliers s
  82. WHERE p.supplier_id = s.id
  83. AND p.service_id = #{@service.id}
  84. GROUP BY s.name, s.slug
  85. ORDER BY total DESC")
  86. haml :service
  87. end
  88. get '/services/:slug/payments' do
  89. @FILTER_VALUES = %w[ 500 1000 2500 5000 10000 20000 ]
  90. @service = Service.first(:slug => params[:slug])
  91. # payments_filter_min cookie persists user selection of filter value
  92. unless @min = request.cookies["payments_filter_min"]
  93. @min = PAYMENTS_FILTER_MIN
  94. response.set_cookie(
  95. "payments_filter_min",
  96. { :value => @min, :expires => Time.now + (60 * 24 * 60 * 60) }
  97. ) # 60 days
  98. end
  99. @payments = Payment.all(:service_id => @service.id, :amount.gte => @min, :order => [ 'd' ])
  100. @total = @payments.sum(:amount)
  101. haml :servicepayments
  102. end
  103. get '/services/:slug/paymentsdetail' do
  104. @service = Service.first(:slug => params[:slug])
  105. min = PAYMENTS_FILTER_MIN
  106. if params[:min].to_i > 0
  107. min = params[:min].to_i
  108. end
  109. @payments = Payment.all(:service_id => @service.id, :amount.gte => min, :order => [ 'd' ])
  110. @total = @payments.sum(:amount)
  111. haml :servicepaymentsdetail, :layout => false
  112. end
  113. get '/services/?' do
  114. @services = Service.all( :order => ['name'] )
  115. haml :services
  116. end
  117. get '/payments/:id' do
  118. @payment = Payment.get(params[:id])
  119. haml :payment
  120. end
  121. get '/error' do
  122. haml :error
  123. end
  124. get '/about' do
  125. haml :about
  126. end
  127. get '/scoreboard.csv' do
  128. halt 404
  129. @councils = Council.all( :order => ['name'] )
  130. labels = %w[
  131. id
  132. created_at
  133. updated_at
  134. name
  135. slug
  136. url
  137. data_url
  138. open_licence
  139. machine_readable
  140. start_d
  141. end_d
  142. ]
  143. headers "Content-Disposition" => "attachment;filename=armchair-auditor-scoreboard.csv",
  144. "Content-Type" => "text/csv"
  145. output = ""
  146. for council in @councils
  147. output += "#{council.id},#{council.created_at.strftime("%d %b %Y")},#{council.updated_at.strftime("%d %b %Y")},#{council.name},#{council.slug},#{council.url},#{council.data_url},#{council.open_licence},#{council.machine_readable},#{council.start_d.strftime("%d %b %Y")},#{council.end_d.strftime("%d %b %Y")}\n"
  148. end
  149. labels.join(',') + "\n" + output
  150. end
  151. get '/scoreboard' do
  152. halt 404
  153. @councils = Council.all( :order => ['name'] )
  154. haml :scoreboard
  155. end
  156. not_found do
  157. haml :not_found
  158. end