A few major changes:
author<mako@atdot.cc> <>
Sun, 10 Sep 2006 19:39:06 +0000 (15:39 -0400)
committer<mako@atdot.cc> <>
Sun, 10 Sep 2006 19:39:06 +0000 (15:39 -0400)
 * Contiue with upgrade to Rails 1.1
 * Large variety of fixes to various bits and pieces.
 * Rudimentary (and broken) support for email in two different areas.

19 files changed:
app/controllers/election_controller.rb
app/controllers/site_controller.rb
app/controllers/user_controller.rb
app/models/candidate.rb
app/models/election.rb
app/models/user.rb
app/models/voter.rb
app/models/voter_notify.rb [new file with mode: 0644]
app/views/election/_candidate_form.rhtml
app/views/election/_candidates_form.rhtml [deleted file]
app/views/election/_voter_list.rhtml
app/views/election/_voters_form.rhtml
app/views/election/edit_candidate.rhtml
app/views/election/edit_candidates.rhtml
app/views/election/show.rhtml
app/views/voter_notify/votestart.rhtml [new file with mode: 0644]
config/environment.rb
public/stylesheets/vb.css
test/unit/voter_notify_test.rb [new file with mode: 0644]

index a0549d40d510fabb9abd71e223a528a29879be48..46da56ef784379d7fa87d0e7e59327e73f45ed01 100644 (file)
@@ -48,9 +48,17 @@ class ElectionController < ApplicationController
     end
   end
 
-  def destroy
-    election = Election.find(params[:id]).destroy
-    redirect_to :action => 'list'
+  def start_election
+    @election = Election.find(params[:id])
+    
+    @election.voters.each do |voter|
+      email = VoterNotify.create_votestart(voter)
+      render(:text => "<pre>" + email.encoded + "</pre>")
+      breakpoint
+      break
+    end
+
+    #@election.activate!
   end
 
   # methods fod display, adding, deleting, and manipulating candidate
@@ -97,12 +105,12 @@ class ElectionController < ApplicationController
 
   def update_candidate
     @candidate = Candidate.find(params[:id])
+    @election = @candidate.election
 
     if @candidate.update_attributes(params[:candidate])
-      flash[:notice] = 'Candidate information was successfully updated.'
-      redirect_to :action => 'edit_candidates', :id => @candidate.election
+      redirect_to :action => 'edit_candidates', :id => @candidate.election.id
     else
-      render :action => 'edit_candidates'
+      render :action => 'edit_candidate'
     end
   end
 
index 8d2f8b2a63c46a719efac7da711c7ad646f7e458..f2eb15343aa35cae5f29e85fde40e016b805f491 100644 (file)
@@ -3,10 +3,11 @@ class SiteController < ApplicationController
   model :user, :election
 
   def index
-    @current_elections = session[:user].elections.sort do |a,b|
-      b.enddate <=> a.enddate
+    if session[:user]
+      session[:user] = User.find(session[:user].id)
+      @current_elections = session[:user].elections.sort do |a,b|
+        b.enddate <=> a.enddate
+      end
     end
-
-    
   end
 end
index f88f7d54776d98f4fe09502385fbef92602a40a5..25f827c07072c051c3635622451ea7ac0a4316bf 100644 (file)
@@ -1,3 +1,8 @@
 class UserController < ApplicationController
   layout 'vb'
+
+  def home
+    redirect_to :controller => 'site', :action => 'index'
+  end
+
 end
index 7af978afb3f95e422d035b780f4e4519f7fb8021..7b6e8024a52bb30bfa1dbb57f80167426cf51502 100644 (file)
@@ -1,6 +1,7 @@
 class Candidate < ActiveRecord::Base
   belongs_to :election
   validates_uniqueness_of :name
+  validates_presence_of :name
 
   def <=>(other)
     self.name <=> other.name 
index 69038e473946ceddd9a2a23e5fe7dae7571ba31f..ba466b4b55928dac2f5291e0513d77b684a8c08d 100644 (file)
@@ -21,5 +21,23 @@ class Election < ActiveRecord::Base
     end
     super
   end
-  
+
+  def start_blockers
+    reasons = []
+    
+    if self.candidates.length <= 1
+      reasons << "You must have at least two candidates."
+    end
+    
+    if self.voters.length <= 1
+      reasons << "You must have at least two voters."
+    end
+
+    reasons
+  end
+
+  def activate!
+    self.active = 1
+  end
+
 end
index 62c5d1d0ebde12f2cfaafa5f6e0fb311be792f86..4f25e06983a24065464f2a320e7d820f04f95ea9 100644 (file)
@@ -1,5 +1,6 @@
 class User < ActiveRecord::Base
   include LoginEngine::AuthenticatedUser
+
   has_many :elections
 
   def name
index e9b3e9e2cfe4901a91df669815d6d8a0b944890f..c4700cbbef75d0a82fe8a598c8d454ce5ead4f42 100644 (file)
@@ -2,11 +2,12 @@ class Voter < ActiveRecord::Base
   belongs_to :election
   has_one :vote
 
-  def initialize(args)
-    super(args)
-    
+  before_create :create_password
+
+  def create_password
     token_generator = UniqueTokenGenerator.new( 16 )
-    until password and Voter.find_all( [ "password = ?", password ]).empty?
+    until password and not password.empty? \
+          and Voter.find_all( [ "password = ?", password ]).empty?
       self.password = token_generator.token
     end
   end
diff --git a/app/models/voter_notify.rb b/app/models/voter_notify.rb
new file mode 100644 (file)
index 0000000..09f7899
--- /dev/null
@@ -0,0 +1,14 @@
+class VoterNotify < ActionMailer::Base
+
+  def votestart(voter)
+    @subject = "[%s] Election In Progress!" % voter.election.name
+    @recipients = voter.email
+    @from = MAIL_CONFIG[:from]
+    @sent_on = Time.now
+    @body = { :voter => voter }
+  end
+
+  def reminder(voter)
+  end
+
+end
index e9770b8b6cc706bb012f34c15cda0432a4aad00e..6e0fb1fe59d79edb92bfb17a3beb6a8505afe8bc 100644 (file)
@@ -1,3 +1,5 @@
+<% %>
+
 <p>New candidate name:<br />
 <%= text_field :candidate, :name %></p>
  
@@ -6,3 +8,4 @@
 
 <p>Candidate picture (optional and < 100x100 pixels):<br />
 <%= file_field :candidate, :picture %></p>
+
diff --git a/app/views/election/_candidates_form.rhtml b/app/views/election/_candidates_form.rhtml
deleted file mode 100644 (file)
index 4528923..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<% %>
-
-<%= form_tag( { :action => :add_candidate, :id => @election.id },
-              :multipart => true ) %>
-
-<%= render_partial 'candidate_form' %>
-
-<%= submit_tag "Add Candidate" %>
-<%= end_form_tag %>
index 2a39b8cf4f3199a2568cd26e5e682e08979c9b9f..c55afdb63e62ebc10768bfc1fb3c65c67d76c09f 100644 (file)
@@ -1,6 +1,8 @@
-<%
-# basic election information template
--%>
+<% %>
+
+<% if @election.voters.length == 0 %>
+<p>There are currently no voters registered for this election.</p>
+<% else %>
 <p>The following voters are currently registered for this election:</p>
 
 <ul>
@@ -16,4 +18,4 @@
   </div>  
   <% end %>
 </ul>
-
+<% end %>
index 620b508be4841444c215b4abc65ec05863b72d2c..3b01c007c39843cd41eb1fce4d50fb9a96bb15d5 100644 (file)
@@ -1,10 +1,13 @@
-<p>Please enter a list of new email addresses of potential voters.</p>
+<p>Please enter a list of new email addresses of voters (one email
+address per line).</p>
 
 <%= text_area :raw_voter_list, :input_addresses %>
 
+<!-- 
 <p>Email voters:
 <%= select :raw_voter_list, :email, [ [ 'Never', 0 ],
                               [ 'Now', 1 ],
                               [ 'Vote Start', 2 ] ]  %>
+-->
 </p>
-<%= submit_tag "Add" %>
+<%= submit_tag "Add Voters" %>
index 9bc99544b8cb78c022f31773346cbfdac4e56ba3..e465ae961714ff6e227fdd8ad707ad967394ff1a 100644 (file)
@@ -1,9 +1,9 @@
 <h1>Editing <%= @candidate.name %></h1>
 
-<%= error_messages_on :candidate %>
-
-<%= form_tag :action => 'update_candidate', :id => @candidate.id %>
-  <%= render :partial => 'candidate_form' %>
-  <%= submit_tag "Done!" %>
+<%= error_messages_for :candidate %>
+<%= form_tag( { :action => :update_candidate, :id => @candidate.id },
+              :multipart => true ) %>
+<%= render :partial => 'candidate_form' %>
+<%= submit_tag "Save" %>
 <%= end_form_tag %>
 
index b5f06ff31856dd1e0822ed12cf5388f353a7509f..dbcc3f8bad3b49a550c4c5159195bdf3542c17e8 100644 (file)
@@ -1,4 +1,6 @@
-<h1><strong><%= @election.name %>:</strong> Edit Candidates</h1>
+<h1><strong><%= @election.name %>:</strong> Edit/Add Candidates</h1>
+
+<%= error_messages_for :candidate %>
 
 <% unless @election.candidates.empty? %>
   <p>The following are valid options or candidates in this election:</p>
 <% else %>
   <p>There are no candidates registered for this election.</p>
 <% end %>
+
 <p>Please enter new candidates below.</p>
-<%= render :partial => 'candidates_form' %>
+
+<%= form_tag( { :action => :add_candidate, :id => @election.id },
+              :multipart => true ) %>
+<%= render :partial => 'candidate_form' %>
+<%= submit_tag "Add Candidate" %>
+<%= end_form_tag %>
+
 <%= button_to "Done!", :action => 'show', :id => @election %>
index f389059d72436e9539c391860d6e6f18b8674bfb..90c93eacad2082a19f0a50280667f31eb4e54083 100644 (file)
 
 <% unless @election.voters.empty? %>
   <%= render :partial => 'voter_list' %>
+  <%= link_to "Add or remove voters.", :action => 'edit_voters', :id => @election.id %></em></p>
 <% else %>
   <p><em>There are currently no voters registered for this election.
   <%= link_to "Add some!", :action => 'edit_voters', :id => @election.id %></em></p>
 <% end %>
+
+<h2>Start Election</h2>
+
+<% if @election.start_blockers.length > 0 %>
+  <p>Your election cannot be started for the following reasons:</p>
+  <ul>
+  <% for reason in @election.start_blockers %>
+  <li><%= reason %></li>
+  <% end %>
+  </ul>
+<% else %>
+<p>Please check eveything carefully on this page before starting this
+election. Once you begin the election, you will <em>not</em> be able to
+add or change candidates, modify the voting lists, or change the
+election end time.</p>
+
+<p>When you begin the election, the following will happen:</p>
+
+<ul>
+  <li>The election will be "frozen" so that further edits to the
+      candidate list and voting list cannot occur.</li>
+  <li>All voters will be emailed notifying them that the election has
+      begun and of their unique login token.</li>
+</ul>
+
+<%= button_to 'Start Election!', :action => 'start_election', :id => @election.id %>
+
+<% end %>
diff --git a/app/views/voter_notify/votestart.rhtml b/app/views/voter_notify/votestart.rhtml
new file mode 100644 (file)
index 0000000..c2730bf
--- /dev/null
@@ -0,0 +1,29 @@
+Voter!
+
+This is an automated message sent by votingbooth.mako.cc.
+
+You have been listed as a voter in an upcoming election.
+
+The election title: <%= @voter.election.name %>
+
+To read more about the election, the candidates, and to vote, you will
+need to use the following token to log in to votingboth.mako.cc:
+  <%= @voter.password %>
+
+Alternatively, you can just click this URL:
+
+If you have any questions or if you feel you have recieved this message
+in error, you should contact:
+
+  <%= @voter.election.user.name %> <<%= @voter.election.user.email %>>
+  (The initiator of this election)
+
+Alternatively, if you feel there is a technical error, please contact:
+
+  help@votingbooth.mako.cc
+  (VotingBooth Tech Support)
+
+Thanks and happy voting!
+VotingBooth Staff
+  
+  
index 22cfe503ceb88f58cbdeb1c71e32a8c143ea0b7d..dcc9fad3b4ee5a7d2a514c3533ba74394ad85b31 100644 (file)
@@ -50,6 +50,8 @@ end
 #   inflect.uncountable %w( fish sheep )
 # end
 
+MAIL_CONFIG = { :from => 'VotingBooth <info@votingbooth.mako.cc>'} 
+
 # Include your application configuration below
 require 'uniq_token'
 require 'randarray'
@@ -57,6 +59,11 @@ require 'rubyvote'
 
 module LoginEngine
   config :salt, "voothingboat"
+  config :email_from, MAIL_CONFIG[:from]
 end
 
 Engines.start :login
+
+# action mailer configuration
+ActionMailer::Base.delivery_method = :sendmail
+ActionMailer::Base.default_charset = "utf-8"
index 176fd28efd98a09f592b0ac78ec0c6d38b77240e..9f0d7c82d6548ce3500a6bb30f91276ec23ff4dd 100644 (file)
@@ -101,3 +101,9 @@ a:active { color: #FFFFFF; text-decoration: none; background: #0259C4; }
        font-size: 12px;
        font-weight: bold; }
 
+.fieldWithErrors {
+    display: inline;
+}
+.fieldWithErrors input, .fieldWithErrors select {
+    background-color: #ffdfdf;
+}
diff --git a/test/unit/voter_notify_test.rb b/test/unit/voter_notify_test.rb
new file mode 100644 (file)
index 0000000..6e5f802
--- /dev/null
@@ -0,0 +1,27 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'voter_notify'
+
+class VoterNotifyTest < Test::Unit::TestCase
+  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
+  CHARSET = "utf-8"
+
+  include ActionMailer::Quoting
+
+  def setup
+    ActionMailer::Base.delivery_method = :test
+    ActionMailer::Base.perform_deliveries = true
+    ActionMailer::Base.deliveries = []
+
+    @expected = TMail::Mail.new
+    @expected.set_content_type "text", "plain", { "charset" => CHARSET }
+  end
+
+  private
+    def read_fixture(action)
+      IO.readlines("#{FIXTURES_PATH}/voter_notify/#{action}")
+    end
+
+    def encode(subject)
+      quoted_printable(subject, CHARSET)
+    end
+end

Benjamin Mako Hill || Want to submit a patch?