- Timestamp:
- 05/23/10 19:51:07 (14 years ago)
- Location:
- trunk
- Files:
-
- 9 added
- 9 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/Epoll/Controller/Admin.pm
r301 r315 100 100 }; 101 101 102 /^(BEFORE|RUNNING)$/ and do {103 if (my ($upload) = $c->req->upload('votinglist')) {104 $poll->voting_from_file(105 $upload->fh,106 $c->req->param('delete'),107 ) and $poll->commit;108 } elsif($c->req->param('delvoting')) {109 $poll->delete_voting($c->req->param('delvoting'))110 and $poll->commit;111 } elsif ($c->req->param('mail')) {112 $poll->addupd_voting($c->req->param('mail'), $c->req->param('id'))113 and $poll->commit;114 } elsif($c->req->param('mailpasswd')) {115 # TODO116 foreach my $vkey ($poll->list_voting_no_passwd) {117 my $voting = $poll->voting($vkey);118 my $pass = $voting->gen_passwd;119 $c->forward(120 q'Epoll::View::Mail', 'render',121 [ 'voting_passwd.tt', {122 From => $poll->info->{owner},123 To => $voting->info->{mail},124 Subject => "Invitation à voter",125 mail => {126 voteid => $id,127 mail => $voting->info->{mail},128 passwd => $pass,129 }130 } ]131 );132 }133 }134 };135 136 102 /^AFTER$/ and do { 137 103 if ($c->req->param('mapfrom')) { … … 224 190 my ($self, $c) = @_; 225 191 ($c->stash->{voteid}) = @{ $c->req->snippets || [] }; 226 my $poll = $c->model('Vote')->poll($c->stash->{voteid}); 227 228 $poll->info or do { 229 $c->res->redirect($c->uri_for('/')); 230 return; 231 }; 232 233 $c->forward('auth') or return; 234 $c->forward('modify_poll'); 192 my $id = $c->stash->{voteid}; 193 my $poll = $c->model('Vote')->poll($c->stash->{voteid}); 194 195 $poll->info or do { 196 $c->res->redirect($c->uri_for('/')); 197 return; 198 }; 199 200 $c->forward('auth') or return; 201 202 for ($poll->status || '') { 203 /^(BEFORE|RUNNING)$/ and do { 204 if($c->req->param('delvoting')) { 205 $poll->delete_voting($c->req->param('delvoting')) 206 and $poll->commit; 207 } elsif ($c->req->param('mail')) { 208 $poll->addupd_voting($c->req->param('mail'), $c->req->param('id')) 209 and $poll->commit; 210 } elsif($c->req->param('mailpasswd')) { 211 # TODO 212 foreach my $vkey ($poll->list_voting_no_passwd) { 213 my $voting = $poll->voting($vkey); 214 my $pass = $voting->gen_passwd; 215 $c->forward( 216 q'Epoll::View::Mail', 'render', 217 [ 'voting_passwd.tt', { 218 From => $poll->info->{owner}, 219 To => $voting->info->{mail}, 220 Subject => "Invitation à voter", 221 mail => { 222 voteid => $id, 223 mail => $voting->info->{mail}, 224 passwd => $pass, 225 } 226 } ] 227 ); 228 } 229 } 230 }; 231 } 232 235 233 $c->stash->{page}{title} = $poll->info('label') . ': Administration, liste des electeurs'; 234 } 235 236 sub votersimport: LocalRegex('^(\w+)/voters/import$') { 237 my ($self, $c) = @_; 238 ($c->stash->{voteid}) = @{ $c->req->snippets || [] }; 239 my $poll = $c->model('Vote')->poll($c->stash->{voteid}); 240 241 if ($c->req->param('importtype')) { 242 if (my $handle = $poll->import_handle($c->req->param('importtype'))) { 243 $c->stash->{import_handle} = $handle; 244 if ($c->req->param('add_import')) { 245 warn $c->session->{import_param}; 246 $handle->load_xml_params($c->session->{import_param}); 247 if ($poll->voting_from_import($handle, 248 ext_auth => $c->req->param('ext_auth') || undef, 249 desc => $c->req->param('desc') || undef, 250 )) { 251 $poll->commit; 252 $c->res->redirect($c->uri_for($c->stash->{voteid}, 253 'voters')); 254 return; 255 } 256 } else { 257 $handle->load_web_params($c); 258 } 259 $c->stash->{voters} = [ $handle->fetch_voters() ]; 260 $c->{stash}->{importtt} = 'importv/' . 261 lc($c->req->param('importtype')) . '.tt'; 262 warn $handle->xml_params; 263 $c->session->{import_param} = $handle->xml_params; 264 } else { 265 warn "Fail to load input handle"; 266 } 267 } 268 236 269 } 237 270 -
trunk/lib/Epoll/DB/Poll.pm
r302 r315 514 514 sub auth_voting { 515 515 my ($self, $mail, $password) = @_; 516 my $userinfo = $self->voting_info_id($mail) or return; 517 518 $userinfo->{passwd} or return; 519 if (crypt($password, $userinfo->{passwd} || '') eq $userinfo->{passwd}) { 520 return 1; 521 } else { 522 return 0; 523 } 516 $self->voting_from_mail($mail)->auth($password); 524 517 } 525 518 … … 804 797 805 798 sub addupd_voting { 806 my ($self, $mail, $id ) = @_;799 my ($self, $mail, $id, $extern_auth, $extern_uid) = @_; 807 800 808 801 $mail =~ s/\s*$//; … … 814 807 my $upd = $self->db->prepare_cached( 815 808 q{ 816 update voting set label = ? where mail = ? and poll = ?817 } 818 ); 819 820 if ($upd->execute($id, $ mail, $self->voteid) == 0) {809 update voting set label = ?, extern_auth = ?, extern_uid = ? where mail = ? and poll = ? 810 } 811 ); 812 813 if ($upd->execute($id, $extern_auth, $extern_uid, $mail, $self->voteid) == 0) { 821 814 my $add = $self->db->prepare_cached(q{ 822 insert into voting (poll, label, mail) values (?,?,?) 815 insert into voting (poll, label, mail, extern_auth, extern_uid) 816 values (?,?,?,?,?) 823 817 }); 824 818 825 $add->execute($self->voteid, $id || '', $mail );819 $add->execute($self->voteid, $id || '', $mail, $extern_auth, $extern_uid); 826 820 } 827 821 } … … 835 829 } 836 830 837 while (my $line = <$fh>) { 838 chomp($line); 839 my ($mail, $name) = split(';', $line); 840 $mail or do { 831 my $handle = $self->import_handle('csv'); # std import 832 $handle->{handle} = $fh; 833 my @list = $handle->fetch_voters or do { 841 834 $self->rollback; 842 835 return; 836 }; 837 foreach (@list) { 838 $self->addupd_voting($_->[0], $_->[1] || ''); 839 } 840 1; 841 } 842 843 sub voting_from_import { 844 my ($self, $handle, %options) = @_; 845 846 my $ext_auth = $options{ext_auth} && $handle->can_authenticate; 847 my $authid; 848 if ($ext_auth) { # register authentication 849 my $find_next_id = $self->db->prepare_cached( 850 q{select nextval('extern_auth_id_seq'::regclass)} 851 ); 852 $find_next_id->execute(); 853 $authid = $find_next_id->fetchrow_hashref->{nextval}; 854 $find_next_id->finish; 855 856 my $add_auth = $self->db->prepare_cached( 857 q{insert into extern_auth (id, params, owner, auth_type, desc) values 858 (?,?,?,?,?)} 859 ); 860 $add_auth->execute($authid, $handle->xml_params, $self->info('owner'), 861 $handle->auth_type, $options{desc}); 862 } 863 864 my @list = $handle->fetch_voters or do { 865 $self->rollback; 866 return; 867 }; 868 foreach (@list) { 869 $self->addupd_voting($_->[0], $_->[1] || '', $authid, $_->[2]) or do { 870 $self->db->rollback; 871 return; 843 872 }; 844 $self->addupd_voting($self->voteid, $mail, $name || '');845 } 846 1;873 } 874 875 return 1; 847 876 } 848 877 -
trunk/lib/Epoll/DB/Voting.pm
r242 r315 42 42 select *, voting.key as vkey from voting left join signing 43 43 on signing.key = voting.key 44 left join extern_auth on voting.extern_auth = extern_auth.id 44 45 where voting.key = ? 45 46 } … … 56 57 my $userinfo = $self->info or return; 57 58 58 $userinfo->{passwd} or return; 59 if (crypt($password, $userinfo->{passwd} || '') eq $userinfo->{passwd}) { 60 return 1; 59 warn "ee"; 60 if ($userinfo->{extern_auth}) { 61 warn "rr"; 62 my $handle = $self->stored_import_handle($userinfo->{extern_auth}) 63 or return; 64 return $handle->authenticate($userinfo->{mail}, $userinfo->{extern_uid}, $password); 61 65 } else { 62 return 0; 66 $userinfo->{passwd} or return; 67 if (crypt($password, $userinfo->{passwd} || '') eq $userinfo->{passwd}) { 68 return 1; 69 } else { 70 return 0; 71 } 63 72 } 64 73 } … … 83 92 sub gen_passwd { 84 93 my ($self) = @_; 85 my $passwd = Epoll::DB::common::random_string(8); 86 my $encpasswd = $self->gen_enc_passwd($passwd); 94 warn "gotcha"; 95 my $info = $self->info; 96 my $passwd; 87 97 my $upd_voting = $self->db->prepare_cached( 88 98 q{update voting set passwd = ? where key = ?} 89 99 ); 100 if ($info->{extern_auth}) { 101 $upd_voting->execute('EXTERN_AUTH', $self->votingkey); 102 $passwd = $info->{desc} || $info->{auth_type}; 103 } else { 104 $passwd = Epoll::DB::common::random_string(8); 105 my $encpasswd = $self->gen_enc_passwd($passwd); 90 106 91 $upd_voting->execute($encpasswd, $self->votingkey); 107 $upd_voting->execute($encpasswd, $self->votingkey); 108 } 92 109 $self->commit; 93 110 $passwd -
trunk/lib/Epoll/DB/common.pm
r258 r315 9 9 use base 'Exporter'; 10 10 @EXPORT = qw(gen_uid); 11 use Epoll::DB::ImportV; 11 12 12 13 =head1 NAME … … 138 139 } 139 140 141 sub import_handle { 142 my ($self, $type) = @_; 143 return Epoll::DB::ImportV->new($type); 144 } 145 146 sub stored_import_handle { 147 my ($self, $id) = @_; 148 my $fetch = $self->db->prepare_cached( 149 q{select * from extern_auth where id = ?} 150 ); 151 $fetch->execute($id); 152 my $res = $fetch->fetchrow_hashref; 153 $fetch->finish; 154 $res or return; 155 my $handle = $self->import_handle($res->{auth_type}) or return; 156 $handle->load_xml_params($res->{params}); 157 $handle; 158 } 159 140 160 =head1 AUTHOR 141 161 -
trunk/lib/Epoll/I18N/fr.po
r307 r315 53 53 54 54 #: root/templates/admin/ballot.tt:53 root/templates/admin/voters.tt:12 55 #: root/templates/admin/voters.tt:2 255 #: root/templates/admin/voters.tt:25 56 56 msgid "Add" 57 57 msgstr "Ajouter" … … 204 204 msgid "Friday" 205 205 msgstr "Vendredi" 206 207 #: root/templates/admin/voters.tt:15208 msgid "From a csv file"209 msgstr "Depuis un fichier CSV"210 206 211 207 #: root/templates/includes/ballot_form.tt:28 … … 291 287 msgstr "Aucun choix n'est configuré" 292 288 293 #: root/templates/admin/voters.tt:3 6289 #: root/templates/admin/voters.tt:39 294 290 msgid "No subscribed voter" 295 291 msgstr "Pas de votants inscrits" … … 407 403 msgstr "Samedi" 408 404 409 #: root/templates/admin/voters.tt:25 410 msgid "Send password to voting people" 405 #: root/templates/admin/voters.tt:28 406 #, fuzzy 407 msgid "Send password to voters" 411 408 msgstr "Envoyer les mots de passe aux votants" 412 409 … … 596 593 msgstr "date:" 597 594 598 #: root/templates/admin/ballot.tt:45 root/templates/admin/voters.tt:6 1595 #: root/templates/admin/ballot.tt:45 root/templates/admin/voters.tt:64 599 596 msgid "delete" 600 597 msgstr "effacer" 601 598 602 #: root/templates/admin/voters.tt:20 603 msgid "delete voting list" 599 #: root/templates/admin/voters.tt:23 600 #, fuzzy 601 msgid "delete voters list" 604 602 msgstr "SystÚme de vote en ligne" 605 603 … … 609 607 msgstr "pour %1 à élire" 610 608 611 #: root/templates/admin/voters.tt:16612 msgid "format:"613 msgstr "format:"614 615 609 #: root/templates/includes/signing_list.tt:23 616 610 msgid "has vote" … … 662 656 msgstr "necessitant une validation" 663 657 664 #: root/templates/admin/voters.tt:5 6658 #: root/templates/admin/voters.tt:59 665 659 msgid "password sent" 666 660 msgstr "mot de passe envoyé" 661 662 #: root/mail/poll_reminder_voting.tt:26 663 msgid "running" 664 msgstr "" 667 665 668 666 #: root/templates/admin/ballot.tt:32 … … 670 668 msgstr "enregistrer" 671 669 672 #: root/templates/admin/voters.tt: 27670 #: root/templates/admin/voters.tt:30 673 671 msgid "send password" 674 672 msgstr "envoyer les mots de passe" … … 678 676 msgstr "émargement" 679 677 678 #: root/mail/poll_reminder_voting.tt:27 679 msgid "terminated" 680 msgstr "" 681 680 682 #: root/templates/admin/date.tt:122 root/templates/admin/date.tt:131 681 683 msgid "time:" 682 684 msgstr "heure:" 683 685 686 #: root/mail/poll_reminder_voting.tt:25 687 msgid "to come" 688 msgstr "" 689 684 690 #: root/templates/admin/validate.tt:16 685 691 msgid "valid" … … 698 704 msgstr "L'identifiant de vote bulletin est:" 699 705 706 #~ msgid "From a csv file" 707 #~ msgstr "Depuis un fichier CSV" 708 709 #~ msgid "format:" 710 #~ msgstr "format:" 711 700 712 #~ msgid "Voting" 701 713 #~ msgstr "Votant" -
trunk/lib/Epoll/I18N/messages.pot
r307 r315 51 51 msgstr "" 52 52 53 #: root/templates/admin/ballot.tt:53 root/templates/admin/voters.tt:12 root/templates/admin/voters.tt:2 253 #: root/templates/admin/ballot.tt:53 root/templates/admin/voters.tt:12 root/templates/admin/voters.tt:25 54 54 msgid "Add" 55 55 msgstr "" … … 201 201 #: root/templates/admin/date.tt:49 202 202 msgid "Friday" 203 msgstr ""204 205 #: root/templates/admin/voters.tt:15206 msgid "From a csv file"207 203 msgstr "" 208 204 … … 285 281 msgstr "" 286 282 287 #: root/templates/admin/voters.tt:3 6283 #: root/templates/admin/voters.tt:39 288 284 msgid "No subscribed voter" 289 285 msgstr "" … … 400 396 msgstr "" 401 397 402 #: root/templates/admin/voters.tt:2 5403 msgid "Send password to vot ing people"398 #: root/templates/admin/voters.tt:28 399 msgid "Send password to voters" 404 400 msgstr "" 405 401 … … 576 572 msgstr "" 577 573 578 #: root/templates/admin/ballot.tt:45 root/templates/admin/voters.tt:6 1574 #: root/templates/admin/ballot.tt:45 root/templates/admin/voters.tt:64 579 575 msgid "delete" 580 576 msgstr "" 581 577 582 #: root/templates/admin/voters.tt:2 0583 msgid "delete vot inglist"578 #: root/templates/admin/voters.tt:23 579 msgid "delete voters list" 584 580 msgstr "" 585 581 … … 589 585 msgstr "" 590 586 591 #: root/templates/admin/voters.tt:16592 msgid "format:"593 msgstr ""594 595 587 #: root/templates/includes/signing_list.tt:23 596 588 msgid "has vote" … … 641 633 msgstr "" 642 634 643 #: root/templates/admin/voters.tt:5 6635 #: root/templates/admin/voters.tt:59 644 636 msgid "password sent" 637 msgstr "" 638 639 #: root/mail/poll_reminder_voting.tt:26 640 msgid "running" 645 641 msgstr "" 646 642 … … 649 645 msgstr "" 650 646 651 #: root/templates/admin/voters.tt: 27647 #: root/templates/admin/voters.tt:30 652 648 msgid "send password" 653 649 msgstr "" … … 657 653 msgstr "" 658 654 655 #: root/mail/poll_reminder_voting.tt:27 656 msgid "terminated" 657 msgstr "" 658 659 659 #: root/templates/admin/date.tt:122 root/templates/admin/date.tt:131 660 660 msgid "time:" 661 661 msgstr "" 662 662 663 #: root/mail/poll_reminder_voting.tt:25 664 msgid "to come" 665 msgstr "" 666 663 667 #: root/templates/admin/validate.tt:16 664 668 msgid "valid" -
trunk/root/templates/admin/voters.tt
r301 r315 7 7 <div style="float: left; width: 30%;" class="box"> 8 8 <p>[% l('add a voting') %]</p> 9 <form action="[% c.uri_for(poll.uid, 'vot ing') %]" method="POST">9 <form action="[% c.uri_for(poll.uid, 'voters') %]" method="POST"> 10 10 [% l('Name:') _ ' ' %]<input type="text" name="id"><br> 11 11 [% l('Mail:') _ ' ' %]<input type="text" name="mail"><br> 12 12 <input type="submit" value="[% l('Add') %]"> 13 13 </form> 14 14 15 <hr> 15 <p>[% l('From a csv file') %]</p> 16 <p>[% l('format:') _ ' ' %]<i>Mail@domain;Nom</i></p> 17 <form method="POST" ENCTYPE="multipart/form-data" action="[% c.uri_for(poll.uid, 'voting') %]"> 18 <input type="file" name="votinglist"><br> 16 <p> 17 <a href="[% c.uri_for(poll.uid, 'voters', 'import') %]"> 18 Import voters list... 19 </a> 20 </p> 21 19 22 [% IF poll.status == 'BEFORE' %] 20 <input type="checkbox" name="delete">[% l('delete vot inglist') %]<br>23 <input type="checkbox" name="delete">[% l('delete voters list') %]<br> 21 24 [% END %] 22 25 <input type="submit" value="[% l('Add') %]"> 23 26 </form> 24 27 <hr> 25 <p>[% l('Send password to vot ing people') %]</p>26 <form action="[% c.uri_for(poll.uid, 'vot ing') %]" method="POST">28 <p>[% l('Send password to voters') %]</p> 29 <form action="[% c.uri_for(poll.uid, 'voters') %]" method="POST"> 27 30 <input type="submit" name="mailpasswd" value="[% l('send password') %]"> 28 31 </form> … … 48 51 [% IF NOT voting.info.date %] 49 52 [% IF poll.status != 'AFTER' %] 50 <form action="[% c.uri_for(poll.uid, 'vot ing') %]" method="POST">53 <form action="[% c.uri_for(poll.uid, 'voters') %]" method="POST"> 51 54 <input type="hidden" name="delvoting" value="[% voting.votingkey %]"> 52 55 [% END %] -
trunk/root/templates/admin/votersimport.tt
r310 r315 6 6 [% IF poll.status() != 'AFTER' %] 7 7 <div style="float: left; width: 30%;" class="box"> 8 <p>[% l('add a voting') %]</p> 9 <form action="[% c.uri_for(poll.uid, 'voting') %]" method="POST"> 10 [% l('Name:') _ ' ' %]<input type="text" name="id"><br> 11 [% l('Mail:') _ ' ' %]<input type="text" name="mail"><br> 12 <input type="submit" value="[% l('Add') %]"> 8 <form action="[% c.uri_for(poll.uid, 'voters', 'import') %]" method="POST"> 9 <select name="importtype"> 10 <option label="[% l('Dummy') | html %]" value="dummy" [% " selected" IF c.req.param('importtype') == 'dummy' %]"> 11 [% l('Dummy') | html %] 12 </option> 13 <option label="[% l('CSV file') | html %]" value="csv" [% " selected" IF c.req.param('importtype') == 'csv' %]"> 14 [% l('CSV file') | html %] 15 </option> 16 <option label="[% l('LDAP') | html %]" value="ldap" [% " selected" IF c.req.param('importtype') == 'ldap' %]"> 17 [% l('LDAP') | html %] 18 </option> 19 </select> 20 <input type="submit" value="[% l('select') %]"> 13 21 </form> 22 14 23 <hr> 15 <p>[% l('From a csv file') %]</p> 16 <p>[% l('format:') _ ' ' %]<i>Mail@domain;Nom</i></p> 17 <form method="POST" ENCTYPE="multipart/form-data" action="[% c.uri_for(poll.uid, 'voting') %]"> 18 <input type="file" name="votinglist"><br> 19 [% IF poll.status == 'BEFORE' %] 20 <input type="checkbox" name="delete">[% l('delete voting list') %]<br> 24 25 [% IF c.req.param('importtype') %] 26 <form action="[% c.uri_for(poll.uid, 'voters', 'import') %]" ENCTYPE="multipart/form-data" method="POST"> 27 <input type="hidden" value="[% c.req.param('importtype') | html %]" name="importtype"><br> 28 29 [% IF importtt %] 30 [% INCLUDE $importtt %] 21 31 [% END %] 22 <input type="submit" value="[% l('Add') %]"> 32 33 <p><input type="submit" value="[% l('search...') %]"></p> 23 34 </form> 24 <hr> 25 <p>[% l('Send password to voting people') %]</p> 26 <form action="[% c.uri_for(poll.uid, 'voting') %]" method="POST"> 27 <input type="submit" name="mailpasswd" value="[% l('send password') %]"> 28 </form> 35 [% END %][% # if importtype %] 29 36 </div> 30 37 … … 32 39 33 40 <div class="box" style="float: right; width: 60%;"> 34 35 [% IF NOT poll.voting_count %] 36 <p class="alert">[% l('No subscribed voter') %]</p> 37 [% ELSE %] 38 39 [% FOREACH votingkey = poll.voting_keys %] 40 [% voting = poll.voting(votingkey) %] 41 41 [% FOREACH voter = voters %] 42 42 [% IF loop.first %] 43 <table border="1"> 43 <div class="box"> 44 <form action="[% c.uri_for(poll.uid, 'voters', 'import') %]" method="POST"> 45 <input type="hidden" value="[% c.req.param('importtype') | html %]" name="importtype"> 46 [% IF import_handle.can_authenticate %] 47 [% l('Use external authentication') %]<input type="checkbox" name="ext_auth"><br> 48 [% l('Enter here a comment to explain the password to use') %]<br> 49 <textarea rows="3" cols="50" name="desc"></textarea><br> 44 50 [% END %] 45 46 <tr> 47 48 [% IF NOT voting.info.date %] 49 [% IF poll.status != 'AFTER' %] 50 <form action="[% c.uri_for(poll.uid, 'voting') %]" method="POST"> 51 <input type="hidden" name="delvoting" value="[% voting.votingkey %]"> 51 <input type="submit" name="add_import" value="[% l('Import this list') %]"><br> 52 </form> 53 </div> 52 54 [% END %] 55 <p>[% voter.0 | html %]</p> 53 56 [% END %] 54 55 <td>[% voting.label | html %] [% voting.info.mail | html %]</td>56 <td>[% IF voting.info.passwd %]<i>[% l('password sent') %]</i>[% END %]</td>57 58 [% IF NOT voting.info.date %]59 <td>60 [% IF poll.status != 'AFTER' %]61 <input type="submit" name="delete" value="[% l('delete') %]">62 [% END %]63 </td>64 </form>65 [% ELSE %]66 <td>[% voting.info.date %]</td>67 [% END %]68 69 </tr>70 [% IF loop.last %]</table>[% END %]71 72 [% END %][% # FOREACH %]73 74 [% END %][% # IF NOT voting %]75 57 </div> 76 58 <div style="clear: both"></div> -
trunk/root/templates/includes/poll_results.tt
r284 r315 18 18 19 19 <table border="1"> 20 <tr><td>[% l('Participation' %]</td><td>[% poll.signing_count %]</td><td>[% poll.signing_count / poll.voting_count * 100 | format('%.2f %%') IF poll.voting_count %]</td></tr>20 <tr><td>[% l('Participation') %]</td><td>[% poll.signing_count %]</td><td>[% poll.signing_count / poll.voting_count * 100 | format('%.2f %%') IF poll.voting_count %]</td></tr> 21 21 <tr><td>[% l('Ballot Number') %]</td><td>[% poll.ballot_count %]</td><td></td></tr> 22 22 <tr><td>[% l('Number of empty ballot') %]</td><td>[% poll.empty_ballot_count %]</td><td>[% poll.empty_ballot_count / poll.ballot_count * 100 | format('%.2f %%') IF poll.ballot_count %]</td></tr>
Note: See TracChangeset
for help on using the changeset viewer.