Index: openacs-4/packages/oct-election/oct-election.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/oct-election.info,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/oct-election.info	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- Generated by the OpenACS Package Manager -->
+
+<package key="oct-election" url="http://openacs.org/repository/apm/packages/oct-election" type="apm_application">
+    <package-name>OCT Election</package-name>
+    <pretty-plural>OCT Elections</pretty-plural>
+    <initial-install-p>f</initial-install-p>
+    <singleton-p>f</singleton-p>
+    <auto-mount>oct-election</auto-mount>
+
+    <version name="0.1d" url="http://openacs.org/repository/download/apm/oct-election-0.1d.apm">
+        <owner url="mailto:joel@aufrecht.org">Joel Aufrecht</owner>
+        <summary>Web app for voting in OCT elections.</summary>
+
+        <!-- No dependency information -->
+
+        <callbacks>
+        </callbacks>
+        <parameters>
+        <!-- No version parameters -->
+        </parameters>
+
+    </version>
+</package>
Index: openacs-4/packages/oct-election/sql/postgresql/oct-election-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/sql/postgresql/oct-election-create.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/sql/postgresql/oct-election-create.sql	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,34 @@
+create table oct_election (
+    election_id          serial 
+                         primary key,
+    start_time           timestamptz,
+    end_time             timestamptz,
+    vote_forum_cutoff    timestamptz,
+    number_of_candidates integer,
+    label                varchar(100)
+);
+
+create table oct_candidate (
+    candidate_id         serial 
+                         primary key,
+    election             integer
+                         references oct_election,
+    label                varchar(50)
+);
+
+create table oct_vote (
+    candidate_id         integer
+                         references oct_candidate
+);
+
+create table oct_ballot (
+    user_id              integer
+                         references users,
+    election_id          integer
+                         references oct_election,
+    primary key (user_id, election_id)
+);
+
+
+   
+    
\ No newline at end of file
Index: openacs-4/packages/oct-election/sql/postgresql/oct-election-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/sql/postgresql/oct-election-drop.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/sql/postgresql/oct-election-drop.sql	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,10 @@
+drop table oct_ballot;
+drop table oct_vote;
+drop table oct_candidate;
+drop table oct_election;
+
+
+
+
+   
+    
\ No newline at end of file
Index: openacs-4/packages/oct-election/tcl/oct-election-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/tcl/oct-election-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/tcl/oct-election-procs.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,61 @@
+ad_library {
+    Procs for election
+}
+
+namespace eval oct-election {}
+
+ad_proc -private oct-election::valid_voter_p {
+    -election_id
+    -user_id 
+} {
+    @author Joel Aufrecht
+} {
+    set status 1
+    # Has the user already voted in this election?
+    set ballot_p [db_string get_ballot {
+	select count(*) 
+	from oct_ballot
+	where user_id = :user_id
+	and election_id = :election_id
+    }]
+
+    if {$ballot_p} {
+	set status 0
+	set text "You have already voted in this election."
+	return [list $status $text]
+    }
+     
+    set num_days 90
+    set valid_voter_p 0
+    db_1row get_election {
+	select start_time,
+	end_time,
+	vote_forum_cutoff,
+	label
+	from oct_election
+	where election_id = :election_id
+    }
+
+    set before_sql "to_date(:vote_forum_cutoff, 'YYYY-MM-DD')"
+    
+    #TODO: enable and test this on openacs
+    set num_posts 2
+    # set num_posts [db_string get_count "
+    #     select count(message_id) as num_posts
+    #     from   cc_users, forums_messages
+    #     where  cc_users.user_id = forums_messages.user_id
+    #     and    posting_date between $before_sql - interval '$num_days days' and $before_sql
+    #     and    cc_users.user_id = $user_id
+    #     group  by cc_users.user_id
+    #"]
+    
+    if {$num_posts < 2} {
+	set status 0
+	set text "You are not a valid voter for this election.  See <a href=\"http://openacs.org/governance/\">OpenACS Governance</a>"
+	return [list $status $text]
+    }
+
+    set status 1
+    set text "You have already voted in this election."
+    return [list $status $text]
+}
Index: openacs-4/packages/oct-election/www/candidate-add.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/candidate-add.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/candidate-add.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,19 @@
+ad_page_contract {
+    @cvs-id $Id: candidate-add.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    election_id:integer
+    candidate
+} 
+
+auth::require_login
+permission::require_permission -object_id [ad_conn package_id] -privilege create
+
+db_dml candidate_add {
+    insert into oct_candidate 
+    (election, label)
+    values (:election_id, :candidate)
+}
+
+ad_returnredirect [export_vars -base "election" {election_id}]
+
+
Index: openacs-4/packages/oct-election/www/candidate-delete.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/candidate-delete.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/candidate-delete.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,18 @@
+ad_page_contract {
+    @cvs-id $Id: candidate-delete.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    candidate_id:integer
+    election_id:integer
+} 
+
+auth::require_login
+permission::require_permission -object_id [ad_conn package_id] -privilege create
+
+db_dml candidate_delete {
+    delete from oct_candidate 
+    where candidate_id = :candidate_id
+}
+
+ad_returnredirect [export_vars -base "election" {election_id}]
+
+
Index: openacs-4/packages/oct-election/www/election-edit.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/election-edit.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/election-edit.adp	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,5 @@
+<master>
+  <property name="title">@page_title;noquote@</property>
+  <property name="context">@context;noquote@</property>
+  
+<formtemplate id="election"></formtemplate>
\ No newline at end of file
Index: openacs-4/packages/oct-election/www/election-edit.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/election-edit.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/election-edit.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,53 @@
+ad_page_contract {
+    @cvs-id $Id: election-edit.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    election_id:integer,optional
+} 
+
+set page_title "Editing Election"
+set context [list $page_title]
+
+ad_form -name election -form {
+    {election_id:key}
+    {label:text {label Election}}
+    {start_time:text {label "Start Time (2005-04-01 10:00PST)"}}
+    {end_time:text {label "End Time"}}
+    {vote_forum_cutoff:text {label "Forum Posting cutoff date (2005-04-01 10:00PST)"}}
+    {number_of_candidates:integer {label "Number of Candidates"}}
+} -new_request {
+    auth::require_login
+    permission::require_permission -object_id [ad_conn package_id] -privilege create
+    set page_title "Add an election"
+    set context [list $page_title]
+} -edit_request {
+    auth::require_login
+    permission::require_write_permission -object_id $election_id
+
+    db_1row get_election {
+	select start_time,
+	end_time,
+	label,
+	vote_forum_cutoff,
+        number_of_candidates
+	from oct_election
+	where election_id = :election_id;
+    }
+    set page_title "Edit $label"
+    set context [list $page_title]
+} -new_data {
+    db_dml create_election {
+	insert into oct_election
+	(start_time, end_time, number_of_candidates, label)
+	values (:start_time, :end_time, :number_of_candidates, :label);
+    }
+} -edit_data {
+    db_dml update_election {
+	update oct_election
+	set start_time = :start_time,
+	end_time = :end_time,
+	vote_forum_cutoff = :vote_forum_cutoff,
+        number_of_candidates = :number_of_candidates,
+        label = :label
+	where election_id = :election_id}
+    ad_returnredirect [export_vars -base election {election_id}]
+}
Index: openacs-4/packages/oct-election/www/election.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/election.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/election.adp	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,30 @@
+<master>
+  <property name="title">@page_title;noquote@</property>
+  <property name="context">@context;noquote@</property>
+
+<p>Election: @label@
+<p>Start time: @start_time@
+<p>End time: @end_time@
+<p>Label: @label@
+<h2>Candidates</h2>
+<listtemplate name="candidates"></listtemplate>
+<if @admin_p@>
+<p>
+  <form action="candidate-add">
+    <input type="hidden" name="election_id" value="@election_id@"/>
+    <input type="text" name="candidate"/>
+    <input type="submit" value="add candidate"/>
+  </form>
+</p>
+</if>
+
+<if @valid_voter_p@>
+  <form action="vote">
+    <input type="hidden" name="election_id" value="@election_id@"/>
+    <input type="submit" value="Vote"/>
+  </form>
+</if>
+<else>
+  @valid_voter_text@
+</else>
+
Index: openacs-4/packages/oct-election/www/election.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/election.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/election.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,59 @@
+ad_page_contract {
+    @cvs-id $Id: election.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    election_id:integer
+} 
+
+set user_id [auth::require_login]
+set admin_p [acs_user::site_wide_admin_p]
+set valid_voter [oct-election::valid_voter_p -election_id $election_id -user_id $user_id]
+set valid_voter_p [lindex $valid_voter 0]
+set valid_voter_text [lindex $valid_voter 1]
+
+db_1row get_election {
+    select start_time,
+           end_time,
+           vote_forum_cutoff,
+           label
+      from oct_election
+     where election_id = :election_id
+}
+
+set page_title $label
+set context $page_title
+
+template::list::create \
+    -name candidates \
+    -multirow candidates \
+    -elements {
+	candidate_label {
+	    label "Candidate"
+	}
+	delete {
+	    link_url_col delete_url 
+	    display_template {
+  		  <img src="/resources/acs-subsite/Delete16.gif" width="16" height="16" border="0">
+	    }
+	    sub_class narrow
+	}
+    }
+
+db_multirow \
+    -extend { 
+	delete_url
+    } candidates candidates_select {
+	select candidate_id,
+               label as candidate_label
+          from oct_candidate
+         where election = :election_id
+    } {
+	set delete_url [export_vars -base "candidate-delete" {candidate_id  election_id}]
+    }
+ 
+#TODO: show vote total if election is over
+#TODO: hide delete button if not admin
+#TODO: sort candidates by vote total if election is over, or alpha if not
+
+
+
+
Index: openacs-4/packages/oct-election/www/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/index.adp	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,8 @@
+<master>
+  <property name="title">@page_title;noquote@</property>
+  <property name="context">@context;noquote@</property>
+
+<listtemplate name="elections"></listtemplate>
+<if @admin_p@>
+<p><a href="election-edit">Add an Election</a></p>
+</if>
\ No newline at end of file
Index: openacs-4/packages/oct-election/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/index.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,33 @@
+ad_page_contract {
+    @cvs-id $Id: index.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+}
+
+set page_title "OCT Elections"
+set context $page_title
+set admin_p [acs_user::site_wide_admin_p]
+
+template::list::create \
+    -name elections \
+    -multirow elections \
+    -elements {
+	label {
+	    link_url_col election_url
+	    label "Election"
+	}
+    }
+
+db_multirow \
+    -extend { 
+	election_url
+    } elections elections_select {
+	select election_id,
+               label,
+               start_time,
+               end_time
+          from oct_election
+    } {
+	set election_url [export_vars -base "election" {election_id}]
+    }
+ 
+
Index: openacs-4/packages/oct-election/www/vote-process.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/vote-process.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/vote-process.adp	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,2 @@
+<master>
+  Your vote has been tallied.
Index: openacs-4/packages/oct-election/www/vote-process.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/vote-process.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/vote-process.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,49 @@
+ad_page_contract {
+    @cvs-id $Id: vote-process.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    election_id:integer
+    q:integer,array,optional
+} 
+
+set user_id [auth::require_login]
+set valid_voter [oct-election::valid_voter_p -election_id $election_id -user_id $user_id]
+set valid_voter_p [lindex $valid_voter 0]
+set valid_voter_text [lindex $valid_voter 1]
+
+if {!$valid_voter_p} {
+    ad_return_complaint 1 "$valid_voter_text"
+    ad_script_abort
+}
+
+set votes 0
+set max_votes [db_string get_max_votes {
+    select number_of_candidates
+      from oct_election
+    where election_id = :election_id}]
+
+# TODO: this should all be in a transaction, and would if I knew/trusted how to do that
+
+# process the ballot one candidate at a time, keeping an eye on the total vote limit
+set searchId [array startsearch q]
+while {[array anymore q $searchId]} {
+    if {$votes  > $max_votes} {
+	#don't process this vote or any others
+	# this may be early by 1 - should it go after set candidate?
+	break
+    }
+
+    set candidate_id [array nextelement q $searchId]
+    set votes [expr $votes + 1]
+
+    # TODO: verify that the candidate is actually in the election
+    db_dml tally_vote {
+	insert into oct_vote values (:candidate_id);
+    }
+
+
+}
+
+db_dml mark_user_ballot {
+    insert into oct_ballot values (:user_id, :election_id);
+}
+
Index: openacs-4/packages/oct-election/www/vote.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/vote.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/vote.adp	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,14 @@
+<master>
+  <property name="title">@page_title;noquote@</property>
+  <property name="context">@context;noquote@</property>
+
+<p>Vote for up to @number_of_candidates@ candidates.  (Extra votes will be ignored.)  Ballots are anonymous and cannot be revoked or altered.</p>
+<form action="vote-process">
+  <input type="hidden" name="election_id" value="@election_id@">
+
+<multiple name="candidates">
+<p><input type="checkbox" name="q.@candidates.candidate_id@" value="@candidates.candidate_id@"/> <b>@candidates.candidate_label@</b></p>
+</multiple>
+
+<p>  <input type="submit" value="Submit Ballot"></p>
+</form>
\ No newline at end of file
Index: openacs-4/packages/oct-election/www/vote.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/oct-election/www/vote.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/oct-election/www/vote.tcl	14 May 2005 19:49:49 -0000	1.1
@@ -0,0 +1,36 @@
+ad_page_contract {
+    @cvs-id $Id: vote.tcl,v 1.1 2005/05/14 19:49:49 joel Exp $
+} {
+    election_id:integer
+} 
+
+#TODO: add javascript to prevent people from voting too many times
+
+db_1row get_election {
+    select start_time,
+           end_time,
+           vote_forum_cutoff,
+           number_of_candidates,
+           label
+      from oct_election
+     where election_id = :election_id
+}
+
+set user_id [auth::require_login]
+set page_title "Vote for $label"
+set context [list $page_title]
+set valid_voter [oct-election::valid_voter_p -election_id $election_id -user_id $user_id]
+set valid_voter_p [lindex $valid_voter 0]
+set valid_voter_text [lindex $valid_voter 1]
+
+if {!$valid_voter_p} {
+    ad_return_complaint 1 "$valid_voter_text"
+    ad_script_abort
+}
+
+db_multirow candidates candidates_select {
+	select candidate_id,
+	label as candidate_label
+	from oct_candidate
+	where election = :election_id
+    }