source: trunk/lib/Epoll/DB/Poll.pm @ 319

Last change on this file since 319 was 319, checked in by nanardon, 14 years ago
  • support of several poll type
  • remove static result storage
  • Property svn:keywords set to Id Rev
File size: 25.1 KB
Line 
1package Epoll::DB::Poll;
2
3# $Id$
4
5use strict;
6use warnings;
7use base 'Epoll::DB::common';
8use Crypt::RSA;
9use Crypt::RSA::Key::Public::SSH;
10use Crypt::RSA::Key::Private::SSH;
11use MIME::Base64;
12use Epoll::DB::Ballot;
13use Epoll::DB::Voting;
14use Epoll::DB::Choice;
15use Epoll::DB::Poll::Bdata;
16use Epoll::DB::Poll::BSubmit;
17use YAML;
18
19=head1 NAME
20
21Epoll::Model::Vote - Catalyst Model
22
23=head1 DESCRIPTION
24
25Catalyst Model.
26
27=head1 POLL PROPERTIES
28
29=head2 INLINES PROPERTIES
30
31=over 4
32
33=item id
34
35Unique identifier
36
37=item label
38
39The poll label
40
41=item start
42
43The timestamp when poll start
44
45=item end
46
47The timestamp when poll stop
48
49=item password
50
51The poll password encrypted using crypt()
52
53=item owner
54
55The mail of the owner
56
57=back
58
59=head2 EXTENDED PROPERTIES
60
61=over 4
62
63=item uid
64
65The anonyme uid of the poll (to use in url)
66
67=item choice_count
68
69The count of possible choice in ballot
70
71=item elected_choice
72
73Count of select from voting list
74
75=item free_choice
76
77The count of free text input on ballot
78
79=item description
80
81The long description of the poll
82
83=item procedure
84
85A text about rules of the poll
86
87=item private_key
88
89The RSA private key of the poll (if any)
90
91=item public_key
92
93The RSA public key of the poll (if any)
94
95=item no_mail_confirm_vote
96
97Do not sent mail to voting to confirm vote
98
99=item no_mail_ballot_id
100
101Don't include ballot id in mail confirmation
102
103=item no_ballot_id_voting
104
105Do not give ballot's id to voting people on website
106
107=back
108
109=cut
110
111sub new {
112    my ($class, $dbstring, $voteid) = @_;
113   
114    $voteid && $voteid =~ /^\d+$/ or return;
115
116    my $poll = bless {
117        voteid => $voteid,
118        dbstring => $dbstring,
119        db => Epoll::DB::common::_newdb($dbstring),
120    }, $class;
121
122    my $type = $poll->type;
123
124    $type = ucfirst(lc($type));
125    eval "require Epoll::DB::Poll::Type::$type;";
126    if ($@) {
127        return;
128    } else {
129        return bless($poll, "Epoll::DB::Poll::Type::$type");
130    }
131}
132
133sub type { lc($_[0]->info('type') || 'binary') }
134
135sub voteid { $_[0]->{voteid} }
136
137sub uid {
138    my ($self) = @_;
139    # UID will come only with epoll 2.0, if no uid, using key
140    return $self->info('uid') || $self->voteid;
141}
142
143sub setup {
144    my ($self) = @_;
145    $self->param(
146        free_choice => 0,
147        choice_count => 1,
148        uid => Epoll::DB::common::random_string(),
149    );
150}
151
152sub _online_f { qw(label start end owner password) }
153
154sub param {
155    my ($self, %attr) = @_;
156
157    keys %attr or return;
158    my @online_f = _online_f();
159
160    $self->db->do(q{set DATESTYLE to 'DMY'});
161    if (grep { exists($attr{$_}) } @online_f) {
162        my $sth = $self->db->prepare_cached(
163            q{update poll set } .
164            join(',', map { qq("$_" = ?) } grep { exists $attr{$_} } @online_f) .
165            q{ where id = ?}
166        );
167        $sth->execute((map { $attr{$_} } grep { exists $attr{$_} } @online_f), $self->voteid)
168            or do {
169            $self->rollback;
170            return;
171        };
172    }
173
174    # vote settings in settings table
175    foreach my $var (keys %attr) {
176        grep { $var eq $_ } @online_f and next;
177        $self->set_settings($var, $attr{$var});
178    }
179    1
180}
181
182sub status {
183    my ($self) = @_;
184   
185    my $sth = $self->db->prepare_cached(
186        q{
187        select (start > now() or start is null) as before,
188               "end" < now() as after
189        from poll
190        where id = ?
191        }
192    );
193    $sth->execute($self->voteid);
194    my $res = $sth->fetchrow_hashref;
195    $sth->finish;
196    $res or return;
197    if ($res->{before}) {
198        return 'BEFORE';
199    } elsif ($res->{after}) {
200        return 'AFTER';
201    } else {
202        return 'RUNNING';
203    }
204}
205
206sub _info {
207    my ($self) = @_;
208
209    my $sth = $self->db->prepare_cached(
210        q{
211        select *,
212        to_char("start", 'DD/MM/YYYY') as dstart,
213        to_char("start", 'HH24:MI:SS') as hstart,
214        to_char("end", 'DD/MM/YYYY') as dend,
215        to_char("end", 'HH24:MI:SS') as hend
216        from poll where id = ?
217        }
218    );
219
220    $sth->execute($self->voteid);
221    my $res = $sth->fetchrow_hashref;
222    $sth->finish;
223    $res
224}
225
226sub raw_info {
227    my ($self, $var) = @_;
228
229    if ($var) {
230        if (grep { $var eq $_ } (_online_f(), qw(dstart hstart dend hend))) {
231            return ( $self->_info || {} )->{$var};
232        } else {
233            my $sth = $self->db->prepare_cached(
234                q{select val from settings where poll = ? and var = ?}
235            );
236            $sth->execute($self->voteid, $var);
237            my $res = $sth->fetchrow_hashref;
238            $sth->finish;
239            return $res->{val}
240        }
241    }
242
243    if (my $res = $self->_info) {
244        my $get = $self->db->prepare_cached(
245            q{select var, val from settings where poll = ?}
246        );
247        $get->execute($self->voteid);
248        while (my $set = $get->fetchrow_hashref) {
249            $res->{$set->{var}} = $set->{val};
250        }
251        return $res
252    }
253    return;
254}
255
256sub info {
257    my ($self, $var) = @_;
258
259    my $default = {
260        free_choice => 0, # avoid undef in some case
261        elected_count => $self->raw_info('choice_count'),
262    };
263
264    if ($var) {
265        my $val = $self->raw_info($var);
266        return defined($val)
267            ? $val
268            : $default->{$var};
269    } elsif (my $res = $self->raw_info) {
270        foreach (keys %$default) {
271            $res->{$_} = $default->{$_} if (!defined($res->{$_}));
272        }
273        return $res
274    }
275    return;
276}
277
278sub set_settings {
279    my ($self, $var, $val) = @_;
280
281    $val = undef if(defined($val) && $val eq '');
282    my $upd = $self->db->prepare_cached(
283        q{update settings set val = ? where poll = ? and var = ?}
284    );
285
286    if ($upd->execute($val, $self->voteid, $var) == 0) {
287        my $add = $self->db->prepare_cached(
288            q{insert into settings (poll, var, val) values (?,?,?)}
289        );
290
291        $add->execute($self->voteid, $var, $val);
292    }
293}
294
295sub signing {
296    my ($self) = @_;
297
298    my $sth = $self->db->prepare_cached(
299        q{
300        select *, voting.key as vkey from voting left join signing
301        on signing.key = voting.key
302        where poll = ? order by voting.mail
303        }
304    );
305    $sth->execute($self->voteid);
306    my @people;
307    while (my $res = $sth->fetchrow_hashref) {
308        push(@people, $res);
309    }
310    @people
311}
312
313sub voting {
314    my ($self, $votingkey) = @_;
315
316    my $sth = $self->db->prepare_cached(
317        q{
318        select key from voting where poll = ? and key = ?
319        }
320    );
321
322    $sth->execute($self->voteid, $votingkey);
323    my $res = $sth->fetchrow_hashref;
324    $sth->finish;
325    return $res ? Epoll::DB::Voting->new($self->{dbstring}, $votingkey) : undef;
326}
327
328sub voting_from_mail {
329    my ($self, $mail) = @_;
330
331    my $sth = $self->db->prepare_cached(
332        q{
333        select key from voting where poll = ? and mail = ?
334        }
335    );
336
337    $sth->execute($self->voteid, $mail);
338    my $res = $sth->fetchrow_hashref;
339    $sth->finish;
340    return $res ? Epoll::DB::Voting->new($self->{dbstring}, $res->{key}) : undef;
341}
342
343sub voting_keys {
344    my ($self) = @_;
345
346    my $sth = $self->db->prepare_cached(
347        q{
348        select key from voting
349        where poll = ? order by voting.mail
350        }
351    );
352    $sth->execute($self->voteid);
353    my @people;
354    while (my $res = $sth->fetchrow_hashref) {
355        push(@people, $res->{key});
356    }
357    @people
358}
359
360sub voting_info {
361    my ($self) = @_;
362
363    my $sth = $self->db->prepare_cached(
364        q{
365        select *, voting.key as vkey from voting left join signing
366        on signing.key = voting.key
367        where voting.key = ?
368        }
369    );
370    $sth->execute($self->voteid);
371
372    my $res = $sth->fetchrow_hashref;
373    $sth->finish;
374    $res
375}
376
377sub choice {
378    my ($self, $chid) = @_;
379   
380    my $sth = $self->db->prepare_cached(
381        q{
382        select key from choice where poll = ? and key = ?
383        }
384    );
385    $sth->execute($self->voteid, $chid);
386    my $res = $sth->fetchrow_hashref;
387    $sth->finish;
388    return $res ? Epoll::DB::Choice->new($self->{dbstring}, $chid) : undef;
389}
390
391sub choices_keys {
392    my ($self) = @_;
393
394    my $sth = $self->db->prepare_cached(
395        q{
396        select key from choice where poll = ?
397        order by label
398        }
399    );
400    $sth->execute($self->voteid);
401    my @ch;
402    while (my $res = $sth->fetchrow_hashref) {
403        push(@ch, $res->{key});
404    }
405    @ch
406}
407
408# TODO: replaced, to kill
409sub choices {
410    my ($self) = @_;
411
412    my $sth = $self->db->prepare_cached(
413        q{
414        select key from choice where poll = ?
415        order by label
416        }
417    );
418    $sth->execute($self->voteid);
419    my @ch;
420    while (my $res = $sth->fetchrow_hashref) {
421        push(@ch, $res->{key});
422    }
423    @ch
424}
425
426sub add_choice {
427    my ($self, $label) = @_;
428
429    my $sth = $self->db->prepare_cached(
430        q{insert into choice (poll, label) values (?,?)}
431    );
432
433    $sth->execute($self->voteid, $label) or do {
434        $self->rollback;
435        return;
436    };
437
438    1
439}
440
441sub delete_choice {
442    my ($self, $chid) = @_;
443
444    my $sth = $self->db->prepare_cached(
445        q{delete from choice where key = ?}
446    );
447
448    $sth->execute($chid);
449}
450
451sub _register_signing {
452    my ($self, $mail, $referal) = @_;
453
454    my $vinfo = $self->voting_info_id($mail) or return;
455
456    my $sth = $self->db->prepare_cached(
457        q{
458        insert into signing (key, referal) values (?,?)
459        }
460    );
461    $sth->execute($vinfo->{key}, $referal) or do {
462        $self->rollback;
463        return;
464    };
465
466    1;
467}
468
469sub find_choice_key {
470    my ($self, $value) = @_;
471
472    my $sth = $self->db->prepare_cached(
473        q{select key from choice where lower(label) = ? and poll = ?}
474    );
475    $sth->execute(lc($value), $self->voteid);
476    my $res = $sth->fetchrow_hashref;
477    $sth->finish;
478    $res->{key}
479}
480
481sub decrypted_ballots {
482    my ($self, $password) = @_;
483    my $privkey;
484    if ($self->is_crypted) {
485        $privkey = $self->private_key($password) or return;
486    }
487    my $fetch_data = $self->db->prepare_cached(
488        q{select * from ballot_enc where decrypted = false and poll = ?
489            order by id}
490    );
491    $fetch_data->execute($self->voteid);
492    while (my $res = $fetch_data->fetchrow_hashref) {
493        my $bdata = $self->bdata;
494        $bdata->decrypt_data($res->{id}, $res->{data}, $res->{enckey}, $privkey)
495            and return;
496    }
497    1
498}
499
500sub register_ballot {
501    my ($self, $vmail, $choice, $referal) = @_;
502    # TODO: warn, deprecated
503
504    my $bdata = $self->bsubmit;
505    if (!$choice) {
506    } elsif (ref $choice eq 'ARRAY') {
507        foreach (@{ $choice || []}) {
508            $bdata->add_item($_, 1);
509        }
510    } else {
511        foreach (keys %{ $choice || {}}) {
512            $bdata->add_item($_, $choice->{$_});
513        }
514    }
515    $bdata->set_voter($vmail, $referal);
516    return $bdata->submit($vmail, $referal);
517}
518
519sub is_crypted {
520    my ($self) = @_;
521    return $self->info->{public_key} ? 1 : 0;
522}
523
524sub voting_info_id {
525    my ($self, $mail) = @_;
526
527    my $sth = $self->db->prepare_cached(
528        q{
529        select * from voting where mail = ? and poll = ?
530        }
531    );
532    $sth->execute($mail, $self->voteid);
533    my $res = $sth->fetchrow_hashref();
534    $sth->finish;
535    $res
536}
537
538sub auth_voting {
539    my ($self, $mail, $password) = @_;
540    if (my $voter = $self->voting_from_mail($mail)) {
541        return $voter->auth($password);
542    } else {
543        return;
544    }
545}
546
547sub auth_poll {
548    my ($self, $passwd) = @_;
549
550    my $vinfo = $self->info or return;
551
552    $vinfo->{password} or return;
553    $passwd or return;
554    if (crypt($passwd, $vinfo->{password} || '') eq $vinfo->{password}) {
555        return 1;
556    } else {
557        return 0;
558    }
559}
560
561sub voting_has_sign {
562    my ($self, $user) = @_;
563    $self->voting_from_mail($user)->has_sign;
564}
565
566# Requete de decompte des voix:
567
568sub can_show_result {
569    my ($self) = @_;
570
571    # If ballot are encrypted, no
572    if ($self->list_ballot_need_dec) {
573        return;
574    }
575
576    return 1;
577}
578
579sub bdata {
580    my ($self) = @_;
581    Epoll::DB::Poll::Bdata->new($self->{dbstring}, $self);
582}
583
584sub bsubmit {
585    my ($self) = @_;
586    Epoll::DB::Poll::BSubmit->new($self->{dbstring}, $self);
587}
588
589sub ballot {
590    my ($self, $id) = @_;
591
592    my $sth = $self->db->prepare_cached(
593        q{
594        select id from ballot where poll = ? and id = ?
595        }
596    );
597
598    $sth->execute($self->voteid, $id);
599    my $res = $sth->fetchrow_hashref;
600    $sth->finish;
601    return $res ? Epoll::DB::Ballot->new($self->{dbstring}, $id) : undef;
602}
603
604# TODO kill this:
605sub list_ballot {
606    ballot_keys(@_);
607}
608
609sub ballot_keys {
610    my ($self) = @_;
611
612    my $sth = $self->db->prepare_cached(
613        q{
614        select id from ballot where poll = ?
615        order by id
616        }
617    );
618    $sth->execute($self->voteid);
619    my @ids;
620    while (my $res = $sth->fetchrow_hashref) {
621        push(@ids, $res->{id});
622    }
623    @ids
624}
625
626sub list_ballot_enc {
627    my ($self) = @_;
628
629    my $sth = $self->db->prepare_cached(
630        q{
631        select id from ballot_enc where poll = ?
632        order by id
633        }
634    );
635    $sth->execute($self->voteid);
636    my @ids;
637    while (my $res = $sth->fetchrow_hashref) {
638        push(@ids, $res->{id});
639    }
640    @ids
641}
642
643sub list_ballot_need_dec {
644    my ($self) = @_;
645
646    my $sth = $self->db->prepare_cached(
647        q{
648        select id from ballot_enc where poll = ? and decrypted = 'false'
649        order by id
650        }
651    );
652    $sth->execute($self->voteid);
653    my @ids;
654    while (my $res = $sth->fetchrow_hashref) {
655        push(@ids, $res->{id});
656    }
657    @ids
658}
659
660sub list_ballot_needvalid {
661    my ($self) = @_;
662
663    my $sth = $self->db->prepare_cached(
664        q{
665        select id from ballot where poll = ?
666        and invalid is null order by id
667        }
668    );
669    $sth->execute($self->voteid);
670    my @ids;
671    while (my $res = $sth->fetchrow_hashref) {
672        push(@ids, $res->{id});
673    }
674    @ids
675}
676
677sub list_ballot_valid {
678    my ($self) = @_;
679
680    my $sth = $self->db->prepare_cached(
681        q{
682        select id from ballot where poll = ?
683        and invalid = false order by id
684        }
685    );
686    $sth->execute($self->voteid);
687    my @ids;
688    while (my $res = $sth->fetchrow_hashref) {
689        push(@ids, $res->{id});
690    }
691    @ids
692}
693
694sub list_ballot_invalid {
695    my ($self) = @_;
696
697    my $sth = $self->db->prepare_cached(
698        q{
699        select id from ballot where poll = ?
700        and invalid = true order by id
701        }
702    );
703    $sth->execute($self->voteid);
704    my @ids;
705    while (my $res = $sth->fetchrow_hashref) {
706        push(@ids, $res->{id});
707    }
708    @ids
709}
710
711sub ballot_untrusted_values {
712    my ($self, $noinvalid) = @_;
713
714    my $getval = $self->db->prepare_cached(
715        q{
716        select value from ballot join ballot_item
717        on ballot.id = ballot_item.id
718        where poll = ? and fromlist = false
719        } . ($noinvalid
720            ? ' and (ballot.invalid = false or ballot.invalid is null) '
721            : ''
722        ) . q{
723        group by value order by value
724        }
725    );
726    $getval->execute($self->voteid);
727    my @vals;
728    while (my $res = $getval->fetchrow_hashref) {
729        push(@vals, $res->{value});
730    }
731    @vals
732}
733
734sub ballot_untrusted_ids {
735    my ($self) = @_;
736
737    my $getval = $self->db->prepare_cached(
738        q{
739        select ballot.id from ballot join ballot_item
740        on ballot.id = ballot_item.id
741        where poll = ? and fromlist = false
742        group by ballot.id order by id
743        }
744    );
745    $getval->execute($self->voteid);
746    my @vals;
747    while (my $res = $getval->fetchrow_hashref) {
748        push(@vals, $res->{id});
749    }
750    @vals
751}
752
753sub ballot_by_value {
754    my ($self, $value) = @_;
755
756    my $getval = $self->db->prepare_cached(
757        q{
758        select ballot.id from ballot join ballot_item on ballot.id =
759        ballot_item.id
760        where ballot.poll = ? and "value" = ?
761        group by ballot.id order by id
762        }
763    );
764    $getval->execute($self->voteid, $value);
765    my @vals;
766    while (my $res = $getval->fetchrow_hashref) {
767        push(@vals, $res->{id});
768    }
769    @vals
770}
771
772sub ballot_values {
773    my ($self, $noinvalid) = @_;
774
775    my $getval = $self->db->prepare_cached(
776        q{
777        select value as value from ballot join ballot_item
778        on ballot.id = ballot_item.id
779        where poll = ?
780        } . ($noinvalid
781            ? ' and (ballot.invalid = false or ballot.invalid is null) '
782            : ''
783        ) . q{
784        group by value order by value
785        }
786    );
787    $getval->execute($self->voteid);
788    my @vals;
789    while (my $res = $getval->fetchrow_hashref) {
790        push(@vals, $res->{value});
791    }
792    @vals
793}
794
795sub value_map_to {
796    my ($self, $from) = @_;
797    my $sth = $self->db->prepare_cached(
798        q{select "to" from ballot_map where poll = ? and "from" = ?}
799    );
800    $sth->execute($self->voteid, $from);
801    my $res = $sth->fetchrow_hashref;
802    $sth->finish;
803    $res->{to}
804}
805
806sub map_value {
807    my ($self, $from, $to) = @_;
808
809    if (!$to) {
810        my $sth = $self->db->prepare_cached(
811            q{delete from ballot_map where poll = ? and "from" = ?}
812        );
813        $sth->execute($self->voteid, $from);
814    } else {
815        my $sthup = $self->db->prepare_cached(
816            q{update ballot_map set "to" = ? where poll = ? and "from" = ?}
817        );
818        if ($sthup->execute($to, $self->voteid, $from) == 0) {
819            my $sth = $self->db->prepare_cached(
820                q{
821                insert into ballot_map (poll, "from", "to") values (?,?,?)
822                }
823            );
824
825            $sth->execute($self->voteid, $from, $to) or do {
826                $self->rollback;
827                return;
828            };
829        }
830    }
831    $self->commit;
832    return 1;
833}
834
835sub addupd_voting {
836    my ($self, $mail, $id, $extern_auth, $extern_uid) = @_;
837
838    $mail =~ s/\s*$//;
839    $mail =~ s/^\s*//;
840    $mail = lc($mail);
841    $id ||= '';
842    $id =~ s/\s*$//;
843    $id =~ s/^\s//;
844    my $upd = $self->db->prepare_cached(
845        q{
846        update voting set label = ?, extern_auth = ?, extern_uid = ? where mail = ? and poll = ?
847        }
848    );
849
850    if ($upd->execute($id, $extern_auth, $extern_uid, $mail, $self->voteid) == 0) {
851        my $add = $self->db->prepare_cached(q{
852            insert into voting (poll, label, mail, extern_auth, extern_uid)
853            values (?,?,?,?,?)
854        });
855
856        return $add->execute($self->voteid, $id || '', $mail, $extern_auth, $extern_uid);
857    } else {
858        return 1;
859    }
860}
861
862sub voting_from_file {
863    my ($self, $fh, $delete) = @_;
864
865    if ($delete) {
866        my $sth = $self->db->prepare(q{delete from voting where poll = ?});
867        $sth->execute($self->voteid);
868    }
869
870    my $handle = $self->import_handle('csv'); # std import
871    $handle->{handle} = $fh;
872    my @list = $handle->fetch_voters or do {
873            $self->rollback;
874            return;
875    };
876    foreach (@list) {
877        $self->addupd_voting($_->[0], $_->[1] || '');
878    }
879    1;
880}
881
882sub voting_from_import {
883    my ($self, $handle, %options) = @_;
884
885    my $ext_auth = $options{ext_auth} && $handle->can_authenticate;
886    my $authid;
887    if ($ext_auth || $options{save_param}) {
888        my $find_next_id = $self->db->prepare_cached(
889            q{select nextval('extern_auth_id_seq'::regclass)}
890        );
891        $find_next_id->execute();
892        $authid = $find_next_id->fetchrow_hashref->{nextval};
893        $find_next_id->finish;
894
895        my $add_auth = $self->db->prepare_cached(
896            q{insert into extern_auth (id, params, owner, auth_type, "desc") values
897            (?,?,?,?,?)}
898        );
899        $add_auth->execute($authid, $handle->xml_params, $self->info('owner'),
900            $handle->auth_type, $options{desc});
901    }
902
903    my @list = $handle->fetch_voters or do {
904        $self->rollback;
905        return;
906    };
907    foreach (@list) {
908        $self->addupd_voting(
909            $_->[0], $_->[1] || '', $authid, ($ext_auth ? $_->[2]: undef)
910        ) or do {
911            $self->db->rollback;
912            return;
913        };
914    }
915
916    return 1;
917}
918
919sub delete_voting {
920    my ($self, $key) = @_;
921    $self->voting($key)->has_sign and return;
922    my $sth = $self->db->prepare_cached(
923        q{delete from voting where key = ? and poll = ?}
924    );
925
926    $sth->execute($key, $self->voteid);
927}
928
929sub list_voting_no_passwd {
930    my ($self) = @_;
931
932    my $list_voting = $self->db->prepare_cached(
933        q{select key from voting where poll = ? and passwd is null or passwd = ''}
934    );
935
936    $list_voting->execute($self->voteid);
937    my @ids;
938    while (my $res = $list_voting->fetchrow_hashref) {
939        push(@ids, $res->{key});
940    }
941    @ids
942}
943
944sub mail_voting_passwd {
945    my ($self, $id, $mailinfo) = @_;
946    $self->voting($id)->mail_voting_passwd($mailinfo); 
947}
948
949# crypto part
950
951sub rsa {
952    my ($self) = @_;
953    $self->{rsa} ||= new Crypt::RSA ES => 'PKCS1v15';
954}
955
956sub gen_poll_keys {
957    my ($self, $password) = @_;
958    my ($public, $private) = $self->rsa->keygen (
959        Identity  => 'Epoll Vote ' . $self->voteid,
960        Size      => 768,
961        Password  => $password,
962        Verbosity => 0,
963        KF=>'SSH',
964    ) or die $self->rsa->errstr(); # TODO avoid die
965    $self->param(
966        public_key => $public->serialize,
967        private_key => encode_base64($private->serialize),
968    );
969}
970
971sub public_key {
972    my ($self) = @_;
973    my $serialize = $self->info->{public_key} or return;
974    my $pubkey = Crypt::RSA::Key::Public::SSH->new;
975    $pubkey->deserialize(String => [ $serialize ]);
976    $pubkey
977}
978
979sub private_key {
980    my ($self, $password) = @_;
981    my $serialize = $self->info->{private_key} or return;
982    my $privkey = Crypt::RSA::Key::Private::SSH->new;
983    $privkey->deserialize(String => [ decode_base64($serialize) ], Passphrase => $password);
984    $privkey
985}
986
987
988
989#########
990# Count #
991#########
992
993sub ballot_count {
994    ballots_count(@_);
995}
996
997sub ballots_count {
998    my ($self) = @_;
999    return $self->ballot_count_crypt;
1000}
1001
1002sub ballot_count_clear {
1003    my ($self) = @_;
1004
1005    my $sth = $self->db->prepare_cached(
1006        q{select count(*) from ballot where poll = ?}
1007    );
1008
1009    $sth->execute($self->voteid);
1010    my $res = $sth->fetchrow_hashref;
1011    $sth->finish;
1012    $res->{count} || 0
1013}
1014
1015sub ballot_count_crypt {
1016    my ($self) = @_;
1017
1018    my $sth = $self->db->prepare_cached(
1019        q{select count(*) from ballot_enc where poll = ?}
1020    );
1021
1022    $sth->execute($self->voteid);
1023    my $res = $sth->fetchrow_hashref;
1024    $sth->finish;
1025    $res->{count} || 0
1026}
1027
1028sub voting_count { voters_count(@_) }
1029
1030sub voters_count {
1031    my ($self) = @_;
1032
1033    my $sth = $self->db->prepare_cached(
1034        q{
1035        select count(*) from voting
1036        where poll = ?
1037        }
1038    );
1039    $sth->execute($self->voteid);
1040    my $res = $sth->fetchrow_hashref;
1041    $sth->finish;
1042    $res->{count}
1043}
1044
1045sub signing_count {
1046    my ($self) = @_;
1047
1048    my $sth = $self->db->prepare_cached(
1049        q{
1050        select count(*) from signing join voting
1051        on voting.key = signing.key where poll = ?
1052        }
1053    );
1054
1055    $sth->execute($self->voteid);
1056    my $res = $sth->fetchrow_hashref;
1057    $sth->finish;
1058    $res->{count}
1059}
1060
1061sub not_signing_count {
1062    my ($self) = @_;
1063    $self->voters_count - $self->signing_count;
1064}
1065
1066sub valid_ballot_count {
1067    my ($self) = @_;
1068
1069    my $sth = $self->db->prepare_cached(
1070        q{
1071        select count(*) from ballot where poll = ?
1072            and (invalid = 'f' or invalid is NULL)
1073        }
1074    );
1075
1076    $sth->execute($self->voteid);
1077    my $res = $sth->fetchrow_hashref;
1078    $sth->finish;
1079    $res->{count}
1080}
1081
1082sub invalid_ballot_count {
1083    my ($self) = @_;
1084
1085    my $sth = $self->db->prepare_cached(
1086        q{
1087        select count(*) from ballot where poll = ?
1088        and invalid = 't'
1089        }
1090    );
1091
1092    $sth->execute($self->voteid);
1093    my $res = $sth->fetchrow_hashref;
1094    $sth->finish;
1095    $res->{count} || 0
1096}
1097
1098sub empty_ballot_count {
1099    my ($self) = @_;
1100
1101    my $sth = $self->db->prepare_cached(
1102        q{
1103        select count(*) from ballot where poll = ?
1104        and id not in (select id from ballot_item)
1105        and (invalid = 'false' or invalid is null)
1106        }
1107    );
1108
1109    $sth->execute($self->voteid);
1110    my $res = $sth->fetchrow_hashref;
1111    $sth->finish;
1112    $res->{count}
1113}
1114
1115sub not_empty_ballot_count {
1116    my ($self) = @_;
1117
1118    my $sth = $self->db->prepare_cached(
1119        q{
1120        select count(*) from ballot where poll = ?
1121        and id in (select id from ballot_item)
1122        and (invalid = 'false' or invalid is null)
1123        }
1124    );
1125
1126    $sth->execute($self->voteid);
1127    my $res = $sth->fetchrow_hashref;
1128    $sth->finish;
1129    $res->{count} || 0
1130}
1131
1132sub compute_results {
1133    my ($self) = @_;
1134    $self->param('static_results',
1135        YAML::Dump($self->_compute_results));
1136}
1137
1138sub results {
1139    my ($self) = @_;
1140    if (my $res = YAML::Load($self->info('static_results'))) {
1141        return $res
1142    } else {
1143        return;
1144    }
1145}
1146
1147#################
1148# CLEANING DATA #
1149#################
1150
1151sub delete_ballots {
1152    my ($self) = @_;
1153
1154    $self->store_results;
1155    $self->_delete_ballot;
1156    $self->commit;
1157}
1158
1159sub _delete_ballot {
1160    my ($self) = @_;
1161
1162    foreach (
1163        q{delete from ballot_item where id in (select id from ballot where
1164        ballot.poll = ?)},
1165        q{delete from ballot where poll = ?},
1166        q{delete from ballot_enc where poll = ?},) {
1167        my $req = $self->db->prepare($_);
1168        $req->execute($self->voteid) or return;
1169    }
1170
1171    return 1;
1172}
1173
1174=head1 AUTHOR
1175
1176Thauvin Olivier
1177
1178=head1 LICENSE
1179
1180This library is free software, you can redistribute it and/or modify
1181it under the same terms as Perl itself or CeCILL.
1182
1183=cut
1184
11851;
Note: See TracBrowser for help on using the repository browser.