Election results in the London Borough of Sutton.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

13 роки тому
14 роки тому
13 роки тому
11 роки тому
11 роки тому
13 роки тому
13 роки тому
13 роки тому
14 роки тому
13 роки тому
14 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
14 роки тому
13 роки тому
13 роки тому
11 роки тому
13 роки тому
11 роки тому
13 роки тому
11 роки тому
13 роки тому
13 роки тому
11 роки тому
13 роки тому
13 роки тому
11 роки тому
13 роки тому
13 роки тому
11 роки тому
13 роки тому
13 роки тому
13 роки тому
14 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
11 роки тому
11 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
13 роки тому
12 роки тому
12 роки тому
11 роки тому
12 роки тому
12 роки тому
11 роки тому
12 роки тому
13 роки тому
14 роки тому
13 роки тому
14 роки тому
14 роки тому
13 роки тому
14 роки тому
10 роки тому
14 роки тому
13 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. if @p.polling_station
  63. @ps_postcode = Postcode.get(@p.polling_station.postcode)
  64. flash[:polling_station] = "Your polling station is \
  65. <a href=\"http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=16\">%s, %s, %s</a>" \
  66. % [ @ps_postcode.lat, @ps_postcode.lng, @p.polling_station.name, \
  67. @p.polling_station.address, @p.polling_station.postcode]
  68. end
  69. redirect "/bodies/sutton-council/elections/2014-05-22/wards/#{@ward.slug}"
  70. else
  71. flash.now[:error] = "<strong>#{@postcode}</strong> is not a postcode in Sutton"
  72. end
  73. end
  74. # Display a random postcode as default search term
  75. @random_pc = repository(:default).adapter.select("
  76. SELECT postcode
  77. FROM postcodes
  78. ORDER BY RANDOM()
  79. LIMIT 1
  80. ")
  81. @default_pc = @random_pc[0]
  82. @future_elections = Election.future
  83. @past_elections = Election.past
  84. haml :index
  85. end
  86. get '/bodies/:body/elections/:date' do
  87. @body = Body.first(:slug => params[:body])
  88. @election = Election.first(:body => @body, :d => params[:date])
  89. @elections_for_this_body = Election.all(:body => @body, :order => [:d])
  90. @total_seats = Candidacy.sum(:seats, :election => @election)
  91. @total_votes = Candidacy.sum(:votes, :election => @election)
  92. # There's got to be a better way to do this, either with SQL or Datamapper
  93. @total_districts = repository(:default).adapter.select("
  94. SELECT district_id
  95. FROM candidacies
  96. WHERE election_id = ?
  97. GROUP BY district_id
  98. ORDER BY district_id
  99. ", @election.id).count
  100. @results_by_party = repository(:default).adapter.select("
  101. SELECT
  102. p.colour,
  103. p.name,
  104. SUM(c.votes) AS votez,
  105. SUM(c.seats) AS seatz,
  106. COUNT(*) AS cands
  107. FROM candidacies c
  108. LEFT JOIN parties p ON p.id = c.party_id
  109. WHERE c.election_id = ?
  110. GROUP BY c.party_id, p.colour, p.name
  111. ORDER BY seatz DESC, votez DESC
  112. ", @election.id)
  113. @results_by_district = repository(:default).adapter.select("
  114. SELECT
  115. d.name,
  116. d.slug AS district_slug,
  117. SUM(c.seats) AS seats,
  118. SUM(c.votes) AS votez,
  119. COUNT(c.id) AS num_candidates
  120. FROM districts d, candidacies c
  121. WHERE
  122. c.district_id = d.id
  123. AND c.election_id = ?
  124. GROUP BY c.district_id, d.name, d.slug
  125. ORDER BY d.name
  126. ", @election.id)
  127. # For elections that haven't yet been held
  128. @districts_in_this_election = repository(:default).adapter.select("
  129. SELECT DISTINCT d.name, d.slug
  130. FROM candidacies c
  131. LEFT JOIN districts d
  132. ON c.district_id = d.id
  133. WHERE c.election_id = ?
  134. ORDER BY d.name
  135. ", @election.id)
  136. haml :electionsummary
  137. end
  138. # get '/bodies/:body/elections/:date/parties/:party' do
  139. # Not written yet. Show how this party did at this election.
  140. # end
  141. get '/bodies/?' do
  142. @bodies = Body.all
  143. haml :bodies
  144. end
  145. get '/bodies/:body/?' do
  146. @body = Body.first(:slug => params[:body])
  147. @elections = Election.all(:body => @body, :order => [:d.desc])
  148. @districts = District.all(:body => @body, :order => [:name])
  149. haml :body
  150. end
  151. # get '/wards/:slug/postcode/:postcode/?' do
  152. # @ward = Ward.first(:slug => params[:slug])
  153. # @postcode = params[:postcode]
  154. # haml :wards
  155. # end
  156. get '/candidates/:id/?' do
  157. if @deleted_candidate = DeletedCandidate.get(params[:id])
  158. redirect "/candidates/#{@deleted_candidate.candidate_id}", 301 # HTTP 301 Moved Permanently
  159. end
  160. if @candidate = Candidate.get(params[:id])
  161. @candidacies = repository(:default).adapter.select("
  162. SELECT
  163. e.d,
  164. c.*,
  165. p.name AS party_name,
  166. p.colour AS party_colour,
  167. b.name AS body_name,
  168. b.slug AS body_slug,
  169. b.districts_name AS districts_name,
  170. d.name AS district_name,
  171. d.slug AS district_slug
  172. FROM candidacies c
  173. INNER JOIN elections e
  174. ON c.election_id = e.id
  175. INNER JOIN parties p
  176. ON c.party_id = p.id
  177. INNER JOIN bodies b
  178. ON e.body_id = b.id
  179. INNER JOIN districts d
  180. ON c.district_id = d.id
  181. WHERE c.candidate_id = ?
  182. ORDER BY d
  183. ", @candidate.id)
  184. haml :candidate
  185. else
  186. 404
  187. end
  188. end
  189. get '/candidates/?' do
  190. @candidates = Candidate.all(:order => [ :surname, :forenames ])
  191. haml :candidates
  192. end
  193. get '/bodies/:body/elections/:date/:districts_name/:district' do
  194. @district = District.first(:slug => params[:district])
  195. @body = Body.first(:slug => params[:body])
  196. @election = Election.first(:body => @body, :d => params[:date])
  197. @candidacies = Candidacy.all(:district => @district, :election => @election, :order => [:votes.desc])
  198. @total_votes = Candidacy.sum(:votes, :district => @district, :election => @election)
  199. @total_candidates = Candidacy.count(:district => @district, :election => @election)
  200. @total_seats = Candidacy.sum(:seats, :district => @district, :election => @election)
  201. @districts_in_this_election = @election.candidacies.districts
  202. @poll = Poll.get(@district.id, @election.id)
  203. # Postgres: All the columns selected when using GROUP BY must either be aggregate functions or appear in the GROUP BY clause
  204. @results_by_party = repository(:default).adapter.select("
  205. SELECT
  206. p.name AS party_name,
  207. p.colour AS party_colour,
  208. COUNT(c.id) AS num_candidates,
  209. SUM(c.seats) AS num_seats,
  210. SUM(c.votes) AS total_votes
  211. FROM candidacies c
  212. LEFT JOIN parties p
  213. ON c.party_id = p.id
  214. WHERE c.district_id = ?
  215. AND c.election_id = ?
  216. GROUP BY p.name, p.colour
  217. ORDER BY total_votes DESC
  218. ", @district.id, @election.id)
  219. haml :resultsdistrict
  220. end
  221. get '/bodies/:body/:districts_name/:district' do
  222. @district = District.first(:slug => params[:district])
  223. @body = Body.first(:slug => params[:body])
  224. haml :district
  225. end
  226. get '/how-the-council-election-works' do
  227. haml :election
  228. end
  229. get '/how-the-parliament-election-works' do
  230. haml :parliament
  231. end
  232. # get '/voting' do
  233. # haml :voting
  234. # end
  235. get '/error' do
  236. haml :error
  237. end
  238. get '/about' do
  239. haml :about
  240. end
  241. # get '/aliens' do
  242. # haml :aliens
  243. # end
  244. get '/polling-stations' do
  245. @stations = PollingStation.all
  246. haml :pollingstations
  247. end
  248. not_found do
  249. haml :not_found
  250. end