Election results in the London Borough of Sutton.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

299 lignes
6.8 KiB

  1. require 'rubygems'
  2. require 'sinatra'
  3. require 'haml'
  4. require './models'
  5. require 'rack-flash'
  6. set :root, File.dirname(__FILE__)
  7. enable :sessions
  8. use Rack::Flash
  9. class String
  10. def pluralize(num)
  11. if num == 1
  12. return self
  13. end
  14. case self[-1]
  15. when 'y'
  16. self[0..-2] + 'ies'
  17. when 's'
  18. self + "es"
  19. else
  20. self + "s"
  21. end
  22. end
  23. end
  24. helpers do
  25. # Format a number with commas for every ^3
  26. def commify(num)
  27. num.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,'\1,').reverse
  28. end
  29. # From http://snippets.dzone.com/posts/show/593
  30. def to_ordinal(num)
  31. num = num.to_i
  32. if (10...20) === num
  33. "#{num}th"
  34. else
  35. g = %w{ th st nd rd th th th th th th }
  36. a = num.to_s
  37. c = a[-1..-1].to_i
  38. a + g[c]
  39. end
  40. end
  41. def format_percent(num)
  42. sprintf("%.0f%%", num)
  43. end
  44. def short_date(d)
  45. d.strftime("%e %b %Y")
  46. end
  47. def long_date(d)
  48. d.strftime("%e %B %Y")
  49. end
  50. # Exception for Labour/Co-operative candidacies
  51. def party_name(labcoop, party_name)
  52. labcoop ? "Labour and Co-operative Party" : party_name
  53. end
  54. end
  55. get '/' do
  56. if params[:postcode]
  57. @postcode = params[:postcode].strip.upcase
  58. if @p = Postcode.get(@postcode)
  59. # Postcode is valid and in LB Sutton
  60. @ward = Ward.get(@p.ward_id)
  61. flash[:notice] = "Postcode <strong>#{@postcode}</strong> is in #{@ward.name} ward"
  62. redirect "/bodies/sutton-council/wards/#{@ward.slug}"
  63. else
  64. flash.now[:error] = "<strong>#{@postcode}</strong> is not a postcode in Sutton"
  65. end
  66. end
  67. # Display a random postcode as default search term
  68. @random_pc = repository(:default).adapter.select("
  69. SELECT postcode
  70. FROM postcodes
  71. ORDER BY RANDOM()
  72. LIMIT 1
  73. ")
  74. @default_pc = @random_pc[0]
  75. @future_elections = Election.future
  76. @past_elections = Election.past
  77. haml :index
  78. end
  79. get '/bodies/:body/elections/:date' do
  80. @body = Body.first(:slug => params[:body])
  81. @election = Election.first(:body => @body, :d => params[:date])
  82. @elections_for_this_body = Election.all(:body => @body, :order => [:d])
  83. @total_seats = Candidacy.sum(:seats, :election => @election)
  84. @total_votes = Candidacy.sum(:votes, :election => @election)
  85. # There's got to be a better way to do this, either with SQL or Datamapper
  86. @total_districts = repository(:default).adapter.select("
  87. SELECT district_id
  88. FROM candidacies
  89. WHERE election_id = ?
  90. GROUP BY district_id
  91. ORDER BY district_id
  92. ", @election.id).count
  93. @results_by_party = repository(:default).adapter.select("
  94. SELECT
  95. p.colour,
  96. p.name,
  97. SUM(c.votes) AS votez,
  98. SUM(c.seats) AS seatz,
  99. COUNT(*) AS cands
  100. FROM candidacies c
  101. LEFT JOIN parties p ON p.id = c.party_id
  102. WHERE c.election_id = ?
  103. GROUP BY c.party_id, p.colour, p.name
  104. ORDER BY seatz DESC, votez DESC
  105. ", @election.id)
  106. @results_by_district = repository(:default).adapter.select("
  107. SELECT
  108. d.name,
  109. d.slug AS district_slug,
  110. SUM(c.seats) AS seats,
  111. SUM(c.votes) AS votez,
  112. COUNT(c.id) AS num_candidates
  113. FROM districts d, candidacies c
  114. WHERE
  115. c.district_id = d.id
  116. AND c.election_id = ?
  117. GROUP BY c.district_id, d.name, d.slug
  118. ORDER BY d.name
  119. ", @election.id)
  120. # For elections that haven't yet been held
  121. @districts_in_this_election = repository(:default).adapter.select("
  122. SELECT DISTINCT d.name, d.slug
  123. FROM candidacies c
  124. LEFT JOIN districts d
  125. ON c.district_id = d.id
  126. WHERE c.election_id = ?
  127. ORDER BY d.name
  128. ", @election.id)
  129. haml :electionsummary
  130. end
  131. # get '/bodies/:body/elections/:date/parties/:party' do
  132. # Not written yet. Show how this party did at this election.
  133. # end
  134. get '/bodies/?' do
  135. @bodies = Body.all
  136. haml :bodies
  137. end
  138. get '/bodies/:body/?' do
  139. @body = Body.first(:slug => params[:body])
  140. @elections = Election.all(:body => @body, :order => [:d.desc])
  141. @districts = District.all(:body => @body, :order => [:name])
  142. haml :body
  143. end
  144. # get '/wards/:slug/postcode/:postcode/?' do
  145. # @ward = Ward.first(:slug => params[:slug])
  146. # @postcode = params[:postcode]
  147. # haml :wards
  148. # end
  149. get '/candidates/:id/?' do
  150. if @candidate = Candidate.get(params[:id])
  151. @candidacies = repository(:default).adapter.select("
  152. SELECT
  153. e.d,
  154. c.*,
  155. p.name AS party_name,
  156. p.colour AS party_colour,
  157. b.name AS body_name,
  158. b.slug AS body_slug,
  159. b.districts_name AS districts_name,
  160. d.name AS district_name,
  161. d.slug AS district_slug
  162. FROM candidacies c
  163. INNER JOIN elections e
  164. ON c.election_id = e.id
  165. INNER JOIN parties p
  166. ON c.party_id = p.id
  167. INNER JOIN bodies b
  168. ON e.body_id = b.id
  169. INNER JOIN districts d
  170. ON c.district_id = d.id
  171. WHERE c.candidate_id = ?
  172. ORDER BY d
  173. ", @candidate.id)
  174. haml :candidate
  175. else
  176. 404
  177. end
  178. end
  179. get '/candidates/?' do
  180. @candidates = Candidate.all(:order => [ :surname, :forenames ])
  181. haml :candidates
  182. end
  183. get '/bodies/:body/elections/:date/:districts_name/:district' do
  184. @district = District.first(:slug => params[:district])
  185. @body = Body.first(:slug => params[:body])
  186. @election = Election.first(:body => @body, :d => params[:date])
  187. @candidacies = Candidacy.all(:district => @district, :election => @election, :order => [:votes.desc])
  188. @total_votes = Candidacy.sum(:votes, :district => @district, :election => @election)
  189. @total_candidates = Candidacy.count(:district => @district, :election => @election)
  190. @total_seats = Candidacy.sum(:seats, :district => @district, :election => @election)
  191. @districts_in_this_election = @election.candidacies.districts
  192. # Postgres: All the columns selected when using GROUP BY must either be aggregate functions or appear in the GROUP BY clause
  193. @results_by_party = repository(:default).adapter.select("
  194. SELECT
  195. p.name AS party_name,
  196. p.colour AS party_colour,
  197. COUNT(c.id) AS num_candidates,
  198. SUM(c.seats) AS num_seats,
  199. SUM(c.votes) AS total_votes
  200. FROM candidacies c
  201. LEFT JOIN parties p
  202. ON c.party_id = p.id
  203. WHERE c.district_id = ?
  204. AND c.election_id = ?
  205. GROUP BY p.name, p.colour
  206. ORDER BY total_votes DESC
  207. ", @district.id, @election.id)
  208. haml :resultsdistrict
  209. end
  210. get '/bodies/:body/:districts_name/:district' do
  211. @district = District.first(:slug => params[:district])
  212. @body = Body.first(:slug => params[:body])
  213. haml :district
  214. end
  215. get '/how-the-council-election-works' do
  216. haml :election
  217. end
  218. get '/how-the-parliament-election-works' do
  219. haml :parliament
  220. end
  221. # get '/voting' do
  222. # haml :voting
  223. # end
  224. get '/error' do
  225. haml :error
  226. end
  227. get '/about' do
  228. haml :about
  229. end
  230. # get '/aliens' do
  231. # haml :aliens
  232. # end
  233. not_found do
  234. haml :not_found
  235. end