sv.rb 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. require "sequel"
  2. require "sinatra"
  3. require 'newrelic_rpm' if production?
  4. require "slim"
  5. require "pry" unless production?
  6. require "envyable"
  7. require "hashids"
  8. require "set"
  9. Envyable.load("config/env.yaml", ENV['RACK_ENV'])
  10. if ENV['RACK_ENV'] != "test"
  11. DB = Sequel.connect(:adapter=>'postgres', :host=>ENV['SV_HOST'], :database=>ENV['SV_DB'], :user=>ENV['SV_USER'], :password=>ENV['SV_PASSWORD'], :sslmode => "require")
  12. end
  13. class Schueler < Sequel::Model(:schueler)
  14. one_to_many :sprecher_stimmen, :class => :Sprecher
  15. one_to_many :schuko_stimmen, :class => :Schuko
  16. end
  17. class Lehrer < Sequel::Model(:lehrer)
  18. one_to_many :lehrer_stimmen, :class => :Verbindungslehrer
  19. end
  20. class Info < Sequel::Model(:infos);end
  21. class Sprecher < Sequel::Model(:sprecher)
  22. many_to_one :schueler, :class => :Schueler
  23. end
  24. class Schuko < Sequel::Model(:schuko)
  25. many_to_one :schueler, :class => :Schueler
  26. end
  27. class Verbindungslehrer < Sequel::Model(:verbindungslehrer)
  28. many_to_one :lehrer, :key => :lehrer_id, :class => :Lehrer
  29. end
  30. class SV < Sinatra::Application
  31. configure do
  32. STOP_ZEIT = 'Oct 3, 2017, 18:00'
  33. enable :sessions
  34. set :session_secret, (ENV['SV_SESSION_SECRET'] || 'your_secret')
  35. Slim::Engine.set_options pretty: true
  36. enable :static
  37. set :public_folder, File.dirname(__FILE__) + '/public'
  38. end
  39. configure :production do
  40. newrelic_ignore '/ping'
  41. end
  42. helpers do
  43. def ende
  44. Time.now > time_for(STOP_ZEIT)
  45. end
  46. def protected!
  47. return if authorized?
  48. headers['WWW-Authenticate'] = 'Basic realm="Bitte anmelden"'
  49. halt 401, "Not authorized\n"
  50. end
  51. def authorized?
  52. @auth ||= Rack::Auth::Basic::Request.new(request.env)
  53. @auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == [ENV['SV_BASIC_AUTH_USER'], ENV['SV_BASIC_AUTH_PASSWORD']]
  54. end
  55. def hashids
  56. hashids = Hashids.new(ENV['SV_SESSION_SECRET'], 5, "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789")
  57. end
  58. end
  59. error do
  60. 'Es ist ein Fehler aufgetreten. Sollte das nochmal passieren, schreiben Sie mir doch bitte eine eMail: bk@hmt.im'
  61. end
  62. before do
  63. if session[:flash] && session[:flash][0] == 0
  64. logger.info session[:flash][1]
  65. end
  66. end
  67. get '/' do
  68. if ende
  69. redirect to("/ergebnis")
  70. end
  71. infos = Info.all
  72. slim :home, :locals => {:infos => infos}
  73. end
  74. get '/ping' do
  75. [200]
  76. end
  77. post "/wahl" do
  78. if ende
  79. session[:flash] = [0, "Sie können sich nicht mehr aufstellen lassen, die Wahl hat bereits begonnen"]
  80. redirect back
  81. end
  82. schueler = Schueler.where(:hashid => params[:hashid]).first
  83. if schueler.update_fields params, [:info, :email, :schuko, :sprecher, :nachname]
  84. session[:flash] = [1, "Ihre Eingabe wurde gespeichert"]
  85. else
  86. session[:flash] = [0, "Es gab einen Fehler beim Speichern"]
  87. end
  88. redirect back
  89. end
  90. post '/info' do
  91. protected!
  92. if DB[:infos].insert(params)
  93. session[:flash] = [1, "Die Info wurde gespeichert"]
  94. else
  95. session[:flash] = [0, "Es gab einen Fehler beim Speichern der Info"]
  96. end
  97. redirect to("/")
  98. end
  99. get '/info_loeschen/:id' do |id|
  100. protected!
  101. Info.where(:id => id).first.delete
  102. redirect back
  103. end
  104. get '/info' do
  105. protected!
  106. infos = Info.all
  107. slim :info, :locals => {:infos => infos}
  108. end
  109. get '/ergebnis' do
  110. protected! if !ende
  111. sprecher, schuko, lehrer, waehler = [], [], [], 0
  112. DB.transaction do
  113. sprecher = Schueler.where(:sprecher => true).all
  114. schuko = Schueler.where(:schuko => true).all
  115. lehrer = Lehrer.all
  116. waehler = Schueler.where(:gewaehlt => true).count
  117. end
  118. slim :ergebnis, :locals => {:sprecher => sprecher, :schuko => schuko, :lehrer => lehrer, :waehler => waehler}
  119. end
  120. post "/hashcheck" do
  121. redirect back if params[:stimm_hash].nil?
  122. arrays = params[:stimm_hash].split("l").map{|a| hashids.decode a}
  123. sprecher = Sprecher.where(:id => arrays[0])
  124. schuko = Schuko.where(:id => arrays[1])
  125. lehrer = Verbindungslehrer.where(:id => arrays[2])
  126. slim :hashcheck, :locals => {:sprecher => sprecher, :schuko => schuko, :lehrer => lehrer}
  127. end
  128. post "/hashid" do
  129. redirect to("/#{params[:hashid]}")
  130. end
  131. get "/:hashid" do
  132. schueler = Schueler.where(:hashid => params[:hashid]).first
  133. if schueler.nil?
  134. halt 404, "Adresse richtig abgetippt? Eventuell geht es mit dem QR-Code am Telefon leichter?"
  135. end
  136. lehrer = Lehrer.all
  137. slim :hashid, :locals => {:schueler => schueler, :lehrer => lehrer}
  138. end
  139. post "/:hashid" do
  140. if ende
  141. session[:flash] = [0, "Der Wahlzeitraum ist seit 3. Oktober 18:00 Uhr abgelaufen."]
  142. redirect back
  143. else
  144. session[:flash] = [0, "Der Wahlzeitraum beginnt erst am 30. September um 18:00 Uhr."]
  145. redirect back
  146. end
  147. schueler = Schueler.where(:hashid => params[:hashid]).first
  148. if schueler.nil?
  149. halt 404, "Hier stimmt etwas nicht mit Ihrem persönlichen Code"
  150. end
  151. if schueler.gewaehlt
  152. session[:flash] = [0, "Sie haben schon gewählt"]
  153. redirect back
  154. end
  155. sprecher, schuko, lehrer = params[:sprecher], params[:schuko], params[:lehrer]
  156. if sprecher && sprecher.count > 2
  157. session[:flash] = [0, "Zu viele Sprecher gewählt (max. 2)"]
  158. redirect back
  159. elsif schuko && schuko.count > 8
  160. session[:flash] = [0, "Zu viele Vertreter für die Schulkonferenz gewählt (max. 8)"]
  161. redirect back
  162. elsif lehrer && lehrer.count > 2
  163. session[:flash] = [0, "Zu viele Vertrauenslehrer gewählt (max. 2)"]
  164. redirect back
  165. end
  166. stimm_ids = []
  167. sprecher_ids, schuko_ids, lehrer_ids =[], [], []
  168. stimmabgabe = DB.transaction do
  169. sprecher && sprecher.to_set.each do |s|
  170. if Schueler[s].sprecher
  171. sprecher_ids << DB[:sprecher].insert(:schueler_id => s)
  172. else
  173. raise Sequel::Rollback
  174. session[:flash] = [0, "Es wurde ein nichtaufgestellter Sprecher gewählt"]
  175. redirect back
  176. end
  177. end
  178. schuko && schuko.to_set.each do |s|
  179. if Schueler[s].schuko
  180. schuko_ids << DB[:schuko].insert(:schueler_id => s)
  181. else
  182. raise Sequel::Rollback
  183. session[:flash] = [0, "Es wurde ein nichtaufgestellter Vertreter zur Schulkonferenz gewählt"]
  184. redirect back
  185. end
  186. end
  187. lehrer && lehrer.to_set.each do |l|
  188. lehrer_ids << DB[:verbindungslehrer].insert(:lehrer_id => l)
  189. end
  190. schueler.update(:gewaehlt => true)
  191. end
  192. stimm_ids << sprecher_ids << schuko_ids << lehrer_ids
  193. stimm_hash = stimm_ids.map do |s_id|
  194. return "" if s_id.nil?
  195. hashids.encode s_id
  196. end
  197. if stimmabgabe
  198. session[:flash] = [1, "Ihre Wahl wurde gespeichert"]
  199. session[:stimm_hash] = stimm_hash.join("l")
  200. else
  201. session[:flash] = [0, "Es gab einen Fehler bei der Speicherung der Wahlergebnisse"]
  202. end
  203. redirect back
  204. end
  205. end