require 'sinatra' require 'sinatra/activerecord' require 'bcrypt' require 'gettext' require 'securerandom' require_relative 'mj' class Vote < ActiveRecord::Base has_many :candidates, dependent: :destroy has_many :ratings, dependent: :destroy has_many :organizers, dependent: :destroy has_many :users, through: :organizers validates :state, inclusion: { in: ["draft", "open", "closed"] } end class Candidate < ActiveRecord::Base belongs_to :vote has_many :ratings, dependent: :destroy def mj return MajorityJudgment.new(self.ratings.collect {|r| r.value }) end end class User < ActiveRecord::Base has_many :ratings has_many :organizers has_many :votes, through: :organizers end class Organizer < ActiveRecord::Base belongs_to :vote belongs_to :user validates :vote_id, uniqueness: { scope: :user_id } validates :user_id, uniqueness: { scope: :vote_id } end class Rating < ActiveRecord::Base belongs_to :vote belongs_to :user belongs_to :candidate end def hash_password(password) BCrypt::Password.create(password).to_s end def verify_password(password, hash) BCrypt::Password.new(hash) == password end enable :sessions set :values, [ { :id => 1, :label => "Awful" }, { :id => 2, :label => "Very bad" }, { :id => 3, :label => "Bad" }, { :id => 4, :label => "Mediocre" }, { :id => 5, :label => "Good" }, { :id => 6, :label => "Very good" }, { :id => 7, :label => "Excellent" } ] MajorityJudgment.values = settings.values include GetText set_output_charset('UTF-8') bindtextdomain('vote', 'locale') set_locale('ca') get '/' do redirect '/login' unless current_user @votes = Vote.all erb :home end get '/signup' do erb :signup end post '/signup' do @user = User.create(email: params[:email], password: hash_password(params[:password])) redirect '/' end get '/login' do erb :login end post '/login' do user = User.find_by(email: params[:email]) if user && verify_password(params[:password], user.password) session.clear session[:user_id] = user.id redirect '/' else @error = 'Username or password was incorrect' erb :login end end get '/logout' do session.clear redirect '/login' end post '/logout' do session.clear redirect '/login' end get '/votes/new' do redirect '/login' unless current_user erb :votes_new end post '/votes' do redirect '/login' unless current_user @vote = Vote.create(secure_id: SecureRandom.hex(8), title: params[:title], description: params[:description], state: "draft") @vote.users << current_user redirect '/votes/' + @vote.secure_id end get '/votes/:id' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) case @vote.state when "draft" if @vote.users.exists?(current_user.id) erb :votes_edit else erb :votes_show_draft end when "open" erb :votes_show_open when "closed" erb :votes_show_closed else @vote.state = "draft" @vote.save erb :votes_edit end end post '/votes/:id/edit' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "draft" and @vote.users.exists?(current_user.id) @vote.title = params[:title] @vote.description = params[:description] @vote.save erb :votes_edit end post '/votes/:id/candidates' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "draft" and @vote.users.exists?(current_user.id) @candidate = Candidate.new(name: params[:name], description: params[:description]) @candidate.vote = @vote @candidate.save redirect '/votes/' + @vote.secure_id end post '/votes/:id/candidates/:cid/delete' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "draft" and @vote.users.exists?(current_user.id) @candidate = Candidate.find(params[:cid]) @candidate.destroy redirect '/votes/' + @vote.secure_id end post '/votes/:id/open' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "draft" and @vote.users.exists?(current_user.id) @vote.state = "open" @vote.save redirect '/votes/' + @vote.secure_id end post '/votes/:id/draft' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "open" and @vote.users.exists?(current_user.id) @vote.ratings.each {|r| r.destroy} @vote.state = "draft" @vote.save redirect '/votes/' + @vote.secure_id end post '/votes/:id/close' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "open" and @vote.users.exists?(current_user.id) @vote.state = "closed" @vote.save redirect '/votes/' + @vote.secure_id end post '/votes/:id/reopen' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.state == "closed" and @vote.users.exists?(current_user.id) @vote.state = "open" @vote.save redirect '/votes/' + @vote.secure_id end post '/votes/:id/ratings' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) @vote.candidates.each do |candidate| rating = Rating.find_or_initialize_by(vote: @vote, user: current_user, candidate: candidate) rating.value = params[candidate.id.to_s] rating.save end redirect '/votes/' + @vote.secure_id end post '/votes/:id/organizers' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.users.exists?(current_user.id) user = User.find_by(email: params[:email]) @vote.users << user redirect '/votes/' + @vote.secure_id end post '/votes/:id/delete' do redirect '/login' unless current_user @vote = Vote.find_by(secure_id: params[:id]) redirect '/votes/' + @vote.secure_id unless @vote.users.exists?(current_user.id) @vote.destroy redirect '/' end helpers do def current_user if session[:user_id] User.find(session[:user_id]) else nil end end end