Index: /trunk/lib/Vote/Controller/Admin.pm
===================================================================
--- /trunk/lib/Vote/Controller/Admin.pm	(revision 20)
+++ /trunk/lib/Vote/Controller/Admin.pm	(revision 30)
@@ -30,10 +30,52 @@
     my ( $self, $c, undef, $id ) = @_;
     $c->stash->{voteid} = $id;
+    my $vote = $c->model('Vote');
 
-    # can't modify vote after date
-    if ($c->model('Vote')->vote_status($id) ne 'BEFORE') {
+    if ($vote->vote_status($id) eq 'BEFORE') {
+        if (my ($upload) = $c->req->upload('votinglist')) {
+            $vote->voting_from_file(
+                $id,
+                $upload->fh,
+                $c->req->param('delete'),
+            ) and $vote->db->commit;
+        } elsif ($c->req->param('addch')) {
+            $vote->vote_add_choice($id, $c->req->param('addch'))
+                and $vote->db->commit;
+        } elsif ($c->req->param('delch')) {
+            $vote->delete_choice($c->req->param('delch'))
+                and $vote->db->commit;
+        } elsif ($c->req->param('label')) {
+            $vote->vote_param(
+                $id,
+                map { $_ => ($c->req->param($_) || undef) }
+                qw(label description start end choice_count free_choice)
+            ) and $vote->db->commit;
+        } elsif($c->req->param('delvoting')) {
+            $vote->delete_voting($c->req->param('delvoting'))
+                and $vote->db->commit;
+        } elsif ($c->req->param('mail')) {
+            $vote->addupd_voting($id, $c->req->param('id'), $c->req->param('mail'))
+                and $vote->db->commit;
+        } elsif($c->req->param('mailpasswd')) {
+            $vote->mail_passwd_ifnul($id);
+        }
+    } elsif ($vote->vote_status($id) eq 'AFTER') {
+        foreach my $bid ($vote->list_vote_ballot_needvalid($id)) {
+            if (!$c->req->param($bid)) {
+                next;
+            } elsif($c->req->param($bid) eq 'invalid') {
+                $vote->mark_ballot_invalid($bid, 1);
+                $vote->db->commit;
+            } elsif($c->req->param($bid) eq 'valid') {
+                $vote->mark_ballot_invalid($bid, 0);
+                $vote->db->commit;
+            }
+        }
+    } else {
+        # can't modify vote after date
         $c->stash->{template} = 'admin/denied.tt';
         return;
     }
+
 }
 
Index: /trunk/lib/Vote/Controller/Ballot.pm
===================================================================
--- /trunk/lib/Vote/Controller/Ballot.pm	(revision 20)
+++ /trunk/lib/Vote/Controller/Ballot.pm	(revision 30)
@@ -60,5 +60,5 @@
     my %choices;
     foreach ($vote->vote_choices($id)) {
-        $choices{$_->{key}} = $_->{label};
+        $choices{$vote->choice_info($_)->{key}} = $vote->choice_info($_)->{label};
     }
     $c->stash->{choices} = { %choices };
@@ -98,12 +98,7 @@
             $c->req->address,
         ); # TODO trap error
-        $c->forward('done');
+        $c->stash->{template} = 'ballot/done.tt';
+        $c->delete_session('Vote terminÃ©');
     }
-}
-
-sub done : Private {
-    my ( $self, $c ) = @_;
-    $c->response->body('Vote rÃ©ussi.');
-    $c->delete_session('Vote terminÃ©');
 }
 
Index: /trunk/lib/Vote/Controller/Newpoll.pm
===================================================================
--- /trunk/lib/Vote/Controller/Newpoll.pm	(revision 30)
+++ /trunk/lib/Vote/Controller/Newpoll.pm	(revision 30)
@@ -0,0 +1,59 @@
+package Vote::Controller::Newpoll;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+=head1 NAME
+
+Vote::Controller::Newpoll - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 index 
+
+=cut
+
+sub index : Private {
+    my ( $self, $c ) = @_;
+
+    if ($c->req->param('mail')) {
+        $c->model('Vote')->create_poll_request(
+            mail => $c->req->param('mail'),
+            url => $c->uri_for('/newpoll'),
+            label => $c->req->param('label'),
+        );
+    }
+
+}
+
+sub default : LocalPath {
+    my ( $self, $c, undef, $id ) = @_;
+
+    $c->stash->{reqid} = $id;
+
+    if ($c->req->param('passwd')) {
+        my $pid = $c->model('Vote')->poll_from_request($id, $c->req->param('passwd'));
+        $c->res->redirect($c->uri_for('/admin', $pid));
+    }
+}
+
+=head1 AUTHOR
+
+Thauvin Olivier
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
Index: /trunk/lib/Vote/Model/Vote.pm
===================================================================
--- /trunk/lib/Vote/Model/Vote.pm	(revision 20)
+++ /trunk/lib/Vote/Model/Vote.pm	(revision 30)
@@ -6,4 +6,5 @@
 use Vote;
 use DBI;
+use Mail::Mailer;
 
 =head1 NAME
@@ -37,4 +38,17 @@
 sub db { $_[0]->{db} }
 
+sub random_string {
+    my $lenght = $_[-1] || 8;
+
+    return join('', map { ('a'..'z', 'A'..'Z', 0..9)[rand 62] } (1..$lenght));
+}
+
+sub gen_enc_passwd {
+    my ($self, $passwd) = @_;
+
+    $passwd ||= random_string(8);
+    return(crypt($passwd, '$1$' . random_string(8) . '$'));
+}
+
 sub list_comming_vote {
     my ($self) = @_;
@@ -95,4 +109,26 @@
 }
 
+sub vote_param {
+    my ($self, $voteid, %attr) = @_;
+
+    keys %attr or return;
+    my @online_f = qw(label start end owner password);
+
+    my $sth = $self->db->prepare_cached(
+        q{update poll set } .
+        join(',', map { qq("$_" = ?) } grep { exists $attr{$_} } @online_f) .
+        q{ where id = ?}
+    );
+    $sth->execute((map { $attr{$_} } grep { exists $attr{$_} } @online_f), $voteid)
+        or $self->db->rollback;
+
+    # vote settings in settings table
+    foreach my $var (keys %attr) {
+        grep { $var eq $_ } @online_f and next;
+        $self->vote_set_settings($voteid, $var, $attr{$var});
+    }
+    1
+}
+
 sub vote_status {
     my ($self, $id) = @_;
@@ -100,5 +136,5 @@
     my $sth = $self->db->prepare_cached(
         q{
-        select start > now() as before,
+        select (start > now() or start is null) as before,
                "end" < now() as after
         from poll
@@ -131,5 +167,30 @@
     my $res = $sth->fetchrow_hashref;
     $sth->finish;
+    if ($res) {
+        my $get = $self->db->prepare_cached(
+            q{select var, val from settings where poll = ?}
+        );
+        $get->execute($id);
+        while (my $set = $get->fetchrow_hashref) {
+            $res->{$set->{var}} = $set->{val};
+        }
+    }
     $res
+}
+
+sub vote_set_settings {
+    my ($self, $poll, $var, $val) = @_;
+
+    my $upd = $self->db->prepare_cached(
+        q{update settings set val = ? where poll = ? and var = ?}
+    );
+
+    if ($upd->execute($val, $poll, $var) == 0) {
+        my $add = $self->db->prepare_cached(
+            q{insert into settings (poll, var, val) values (?,?,?)}
+        );
+
+        $add->execute($poll, $var, $val);
+    }
 }
 
@@ -139,5 +200,5 @@
     my $sth = $self->db->prepare_cached(
         q{
-        select * from voting left join signing
+        select *, voting.key as vkey from voting left join signing
         on signing.key = voting.key
         where poll = ? order by voting.id
@@ -152,4 +213,38 @@
 }
 
+sub vote_voting {
+    my ($self, $id) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select key from voting
+        where poll = ? order by voting.id
+        }
+    );
+    $sth->execute($id);
+    my @people;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@people, $res->{key});
+    }
+    @people
+}
+
+sub voting_info {
+    my ($self, $id) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select *, voting.key as vkey from voting left join signing
+        on signing.key = voting.key
+        where voting.key = ?
+        }
+    );
+    $sth->execute($id);
+    
+    my $res = $sth->fetchrow_hashref;
+    $sth->finish;
+    $res
+}
+
 sub vote_signing_count {
     my ($self, $id) = @_;
@@ -172,5 +267,5 @@
     my $sth = $self->db->prepare_cached(
         q{
-        select * from choice where poll = ?
+        select key from choice where poll = ?
         order by label
         }
@@ -179,7 +274,52 @@
     my @ch;
     while (my $res = $sth->fetchrow_hashref) {
-        push(@ch, $res);
+        push(@ch, $res->{key});
     }
     @ch
+}
+
+sub choice_info {
+    my ($self, $chid) = @_;
+    my $sth = $self->db->prepare_cached(
+        q{select * from choice where key = ?}
+    );
+    $sth->execute($chid);
+    my $res = $sth->fetchrow_hashref;
+    $sth->finish;
+    $res
+}
+
+sub vote_add_choice {
+    my ($self, $voteid, $label) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{insert into choice (poll, label) values (?,?)}
+    );
+
+    $sth->execute($voteid, $label) or do {
+        $self->db->rollback;
+        return;
+    };
+
+    1
+}
+
+sub modify_choice {
+    my ($self, $chid, $label) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{update choice set label = ? where key = ?}
+    );
+    $sth->execute($label, $chid);
+}
+
+sub delete_choice {
+    my ($self, $chid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{delete from choice where key = ?}
+    );
+
+    $sth->execute($chid);
 }
 
@@ -307,5 +447,5 @@
         q{
         select count(*) from ballot where poll = ?
-        and id in (select id from ballot_item)
+        and id in (select id from ballot_item) and invalid = 'false'
         }
     );
@@ -387,4 +527,246 @@
 }
 
+sub list_vote_ballot {
+    my ($self, $voteid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select id from ballot where poll = ?
+        order by id
+        }
+    );
+    $sth->execute($voteid);
+    my @ids;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@ids, $res->{id});
+    }
+    @ids
+}
+
+sub list_vote_ballot_needvalid {
+    my ($self, $voteid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select id from ballot where poll = ?
+        and invalid is null order by id
+        }
+    );
+    $sth->execute($voteid);
+    my @ids;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@ids, $res->{id});
+    }
+    @ids
+}
+
+sub ballot_info {
+    my ($self, $ballotid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{ select * from ballot where id = ? }
+    );
+
+    $sth->execute($ballotid);
+    my $res = $sth->fetchrow_hashref;
+    $sth->finish;
+    $res
+}
+
+sub mark_ballot_invalid {
+    my ($self, $ballotid, $invalid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{update ballot set invalid = ? where id = ?}
+    );
+
+    $sth->execute($invalid ? 't' : 'f', $ballotid);
+}
+
+sub ballot_items {
+    my ($self, $ballotid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{select *, value as v from ballot_item where id = ?}
+    );
+    $sth->execute($ballotid);
+    my @ids;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@ids, $res);
+    }
+    @ids
+}
+
+sub addupd_voting {
+    my ($self, $voteid, $id, $mail) = @_;
+
+    my $upd = $self->db->prepare_cached(
+        q{
+        update voting set mail = ? where poll = ? and id = ?
+        }
+    );
+
+    if ($upd->execute($mail, $voteid, $id) == 0) {
+        my $add = $self->db->prepare_cached(q{
+            insert into voting (poll, id, mail) values (?,?,?)
+        });
+
+        $add->execute($voteid, $id, $mail);
+    }
+}
+
+sub delete_voting {
+    my ($self, $key) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{delete from voting where key = ?}
+    );
+
+    $sth->execute($key);
+}
+
+sub voting_from_file {
+    my ($self, $voteid, $fh, $delete) = @_;
+
+    if ($delete) {
+        my $sth = $self->db->prepare(q{delete from voting where poll = ?});
+        $sth->execute($voteid);
+    }
+
+    while (my $line = <$fh>) {
+        chomp($line);
+        warn $line;
+        my ($id, $mail) = split(';', $line);
+        $id && $mail or do {
+            $self->db->rollback;
+            return;
+        };
+        $self->addupd_voting($voteid, $id, $mail);
+    }
+    1;
+}
+
+sub mail_passwd_ifnul {
+    my ($self, $voteid, $mailinfo) = @_;
+
+    my $list_voting = $self->db->prepare_cached(
+        q{select key from voting where poll = ? and passwd is null or passwd = ''}
+    );
+
+    $list_voting->execute($voteid);
+    while (my $res = $list_voting->fetchrow_hashref) {
+        $self->mail_voting_passwd($res->{key}, $mailinfo);
+    }
+}
+
+sub mail_voting_passwd {
+    my ($self, $id, $mailinfo) = @_;
+    
+    my $vinfo = $self->voting_info($id) or return;
+    my $voteinfo = $self->vote_info($vinfo->{poll});
+
+    my $passwd = random_string(8);
+    my $encpasswd = $self->gen_enc_passwd($passwd);
+
+    my $upd_voting = $self->db->prepare_cached(
+        q{update voting set passwd = ? where key = ?}
+    );
+
+    $upd_voting->execute($encpasswd, $id);
+
+    # TODO complete this properly:
+    my $mailer = new Mail::Mailer 'smtp', Server => 'mailhost';
+    $mailer->open({
+        From => 'Voting system <nomail@nomail.com>',
+        To => $vinfo->{mail},
+        Subject => 'Vote passwd',
+    });
+    print $mailer <<EOF;
+Vous Ãªtes conviÃ© Ã  voter:
+$voteinfo->{label}
+
+Votre identifiant est: $vinfo->{id}
+Votre mot de passe est: $passwd
+
+Cordialement.
+EOF
+    $mailer->close;
+
+    $self->db->commit;
+}
+
+sub poll_request_info {
+    my ($self, $rid) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{select * from poll_request where id = ?}
+    );
+
+    $sth->execute($rid);
+    my $res = $sth->fetchrow_hashref;
+    $sth->finish;
+    $res
+}
+
+sub poll_from_request {
+    my ($self, $rid, $passwd) = @_;
+    my $rinfo = $self->poll_request_info($rid) or return;
+
+    my $encpasswd = $self->gen_enc_passwd($passwd);
+
+    my $getpollid = $self->db->prepare_cached(
+        q{select nextval('poll_id_seq')}
+    );
+    $getpollid->execute();
+    my $newpollid = $getpollid->fetchrow_hashref->{nextval};
+    
+    my $newpoll = $self->db->prepare_cached(
+        q{insert into poll (id, label, owner, password) values (?,?,?,?)}
+    );
+
+    $newpoll->execute($newpollid, $rinfo->{label}, $rinfo->{mail}, $encpasswd);
+
+    my $delreq = $self->db->prepare_cached(
+        q{delete from poll_request where id = ?}
+    );
+
+    $delreq->execute($rid);
+    $self->db->commit;
+
+    $newpollid
+}
+
+sub create_poll_request {
+    my ($self, %info) = @_;
+
+    $info{mail} or return;
+    my $addreq = $self->db->prepare_cached(
+        q{insert into poll_request (id, label, mail) values (?,?,?)}
+    );
+
+    my $reqid = gen_uid;
+
+    $addreq->execute($reqid, $info{label}, $info{mail});
+    my $mailer = new Mail::Mailer 'smtp', Server => 'mailhost';
+    $mailer->open({
+        From => 'Voting system <nomail@nomail.com>',
+        To => $info{mail},
+        Subject => 'Votre nouveau vote',
+    });
+    print $mailer <<EOF;
+
+Vous avez demandez la crÃ©ation d'un nouveau vote:
+$info{label}
+
+Pour valider votre demande, veuiller allez visitez la page:
+$info{url}/$reqid
+
+A bientot
+EOF
+    $mailer->close;
+    $self->db->commit;
+    1;
+}
+
 =head1 AUTHOR
 
Index: /trunk/root/templates/admin/default.tt
===================================================================
--- /trunk/root/templates/admin/default.tt	(revision 20)
+++ /trunk/root/templates/admin/default.tt	(revision 30)
@@ -1,4 +1,9 @@
 [% vote = c.model('Vote') %]
 
+[% IF vote.vote_status(voteid) == 'BEFORE' %]
+<table border="1">
+<tr><th>Vote</th><th>PossibilitÃ© de vote</th></tr>
+<tr>
+<td valign="TOP">
 <form action="[% c.uri_for(voteid) %]">
 
@@ -11,4 +16,5 @@
 Debut du vote:
 <input type="text" name="start" value="[% c.req.param('start') || thisvote.start | html %]">
+<br>
 Fin du vote:
 <input type="text" name="end" value="[% c.req.param('end') || thisvote.end | html %]">
@@ -20,6 +26,85 @@
 <input type="text" name="free_choice" value="[% c.req.param('free_choice') || thisvote.free_choice | html %]">
 <br>
-
-
 <input type="submit">
 </form>
+</td>
+<td valign="TOP">
+[% FOREACH choice = vote.vote_choices(voteid) %]
+<form action="[% c.uri_for(voteid) %]">
+[% loop.count %] - [% vote.choice_info(choice).label | html %]
+<input type="hidden" name="delch" value="[% vote.choice_info(choice).key %]">
+<input type="submit" name="del" value="Effacer">
+</form>
+<br>
+[% END %]
+<form action="[% c.uri_for(voteid) %]">
+Ajouter un choix:<br>
+<input type="text" name="addch">
+<input type="submit">
+</form>
+</td>
+</tr>
+</table>
+
+<hr>
+
+<table border="1">
+<tr>
+<td valign="TOP">
+[% signing = vote.vote_voting(voteid) %]
+[% FOREACH thisvoting = signing %]
+[% voting = vote.voting_info(thisvoting) %]
+<form action="[% c.uri_for(voteid) %]">
+<input type="hidden" name="delvoting" value="[% voting.vkey %]">
+[% voting.id | html %] [% voting.mail | html %]
+[% IF voting.passwd %]<i>(pass envoyÃ©)</i>[% END %]
+<input type="submit" name="delete" value="delete"><br>
+</form>
+[% END %]
+</td>
+<td valign="TOP">
+<form action="[% c.uri_for(voteid) %]">
+Login: <input type="text" name="id"><br>
+Mail: <input type="text" name="mail"><br>
+<input type="submit">
+</form>
+<hr>
+<form method="POST" ENCTYPE="multipart/form-data" action="[% c.uri_for(voteid) %]">
+<input type="file" name="votinglist"><br>
+<input type="checkbox" name="delete">Effacer la liste des votants<br>
+<input type="submit">
+</form>
+<hr>
+<form action="[% c.uri_for(voteid) %]">
+<input type="submit" name="mailpasswd" value="Envoyer les mot de passe">
+</form>
+</td>
+</tr>
+</table>
+
+[% ELSE %]
+
+[% FOREACH bid = vote.list_vote_ballot_needvalid(voteid) %]
+    [% IF loop.first %]
+    <form action="[% c.uri_for(voteid) %]">
+    <table border="1">
+    [% END %]
+<tr>
+<td>[% bid %]</td>
+<td>
+[% FOREACH item = [ vote.ballot_items(bid) ] %]
+[% item.v %]<br>
+[% END %]
+</td>
+<td>
+<input type="radio" name="[% bid %]" value="valid">est valide<br>
+<input type="radio" name="[% bid %]" value="invalid">n'est pas valide<br>
+</td>
+</tr>
+    [% IF loop.last %]
+    </table>
+    <input type="submit">
+    </form>
+    [% END %]
+[% END %]
+[% END %]
Index: /trunk/root/templates/ballot/default.tt
===================================================================
--- /trunk/root/templates/ballot/default.tt	(revision 20)
+++ /trunk/root/templates/ballot/default.tt	(revision 30)
@@ -27,7 +27,7 @@
 <form action="[% c.uri_for(voteid) %]">
 [% FOREACH choice = vote.vote_choices(voteid) %]
-[% key = choice.key %]
-<input type="checkbox" name="sbal" value="[% choice.key %]"[% " checked" IF sbal.$key %]>
-[% choice.label | html %]<br>
+[% key = vote.choice_info(choice).key %]
+<input type="checkbox" name="sbal" value="[% key %]"[% " checked" IF sbal.$key %]>
+[% vote.choice_info(choice).label | html %]<br>
 [% END %]
 
Index: /trunk/root/templates/ballot/done.tt
===================================================================
--- /trunk/root/templates/ballot/done.tt	(revision 20)
+++ /trunk/root/templates/ballot/done.tt	(revision 30)
@@ -1,1 +1,4 @@
 Vote rÃ©ussi.
+
+Les rÃ©sultats seront disponibles ici:
+<a href="[% c.uri_for('/vote', voteid) %]">Ici</a>.
Index: /trunk/root/templates/vote/default.tt
===================================================================
--- /trunk/root/templates/vote/default.tt	(revision 20)
+++ /trunk/root/templates/vote/default.tt	(revision 30)
@@ -11,5 +11,7 @@
 <p>Resultats:</p>
 Nombre de bulletin exprimÃ©s: [% vote.ballot_count_nonull(voteid) %]
+[% IF vote.ballot_count(voteid) %]
 ([% vote.ballot_count_nonull(voteid) * 100 / vote.ballot_count(voteid) %]%)
+[% END %]
 <br>
 
@@ -20,7 +22,23 @@
 <td>[% res.value | html %]</td>
 <td>[% res.count %]</td>
-<td>[% res.count * 100 / vote.ballot_count(voteid) %]</td>
+<td>[% res.count * 100 / vote.ballot_count_nonull(voteid) %]</td>
 <td><img src="[% c.uri_for('/static', 'images', 'green-h.png') %]" 
-height="10px" width="[% res.count * 300 / vote.ballot_count(voteid) %]px"></td>
+height="10px" width="[% res.count * 300 / vote.ballot_count_nonull(voteid) %]px"></td>
+</tr>
+[% END %]
+</table>
+
+Liste des bulletins:
+<table border="1">
+<tr><th>numÃ©ro</th><th>Id</th><th>contenu</th></tr>
+[% FOREACH id = vote.list_vote_ballot(voteid) %]
+<tr>
+<td>[% loop.count %]</td>
+<td>[% id | html %]</td>
+<td>
+[% FOREACH item = [ vote.ballot_items(id) ] %]
+[% item.v %]<br>
+[% END %]
+</td>
 </tr>
 [% END %]
Index: /trunk/t/controller_Newpoll.t
===================================================================
--- /trunk/t/controller_Newpoll.t	(revision 30)
+++ /trunk/t/controller_Newpoll.t	(revision 30)
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+BEGIN { use_ok 'Catalyst::Test', 'Vote' }
+BEGIN { use_ok 'Vote::Controller::Newpoll' }
+
+ok( request('/newpoll')->is_success, 'Request should succeed' );
+
+
