source: trunk/lib/Vote/Model/Vote.pm @ 84

Last change on this file since 84 was 84, checked in by nanardon, 15 years ago
  • oops
File size: 19.2 KB
Line 
1package Vote::Model::Vote;
2
3use strict;
4use warnings;
5use base 'Catalyst::Model';
6use Vote;
7use DBI;
8use Mail::Mailer;
9
10=head1 NAME
11
12Vote::Model::Vote - Catalyst Model
13
14=head1 DESCRIPTION
15
16Catalyst Model.
17
18=cut
19
20sub new {
21    my ($class) = @_;
22    my $db = DBI->connect(
23        'dbi:Pg:' . Vote->config->{db},
24        undef, undef,
25        {
26            RaiseError => 0,
27            AutoCommit => 0,
28            PrintWarn => 0,
29            PrintError => 1,
30        }
31    ) or return;
32    $db->do(q{set DATESTYLE to 'DMY'});
33   
34    bless {
35        db => $db,
36    }, $class;
37}
38
39sub db { $_[0]->{db} }
40
41sub random_string {
42    my $lenght = $_[-1] || 8;
43
44    return join('', map { ('a'..'z', 'A'..'Z', 0..9)[rand 62] } (1..$lenght));
45}
46
47sub gen_enc_passwd {
48    my ($self, $passwd) = @_;
49
50    $passwd ||= random_string(8);
51    return(crypt($passwd, '$1$' . random_string(8) . '$'));
52}
53
54sub list_comming_vote {
55    my ($self) = @_;
56
57    my $sth = $self->db->prepare_cached(
58        q{
59        select id from poll where
60        (start > now() and "end" > now()) or
61        "end" is null or start is null
62        }
63    );
64
65    $sth->execute;
66    my @id;
67    while(my $res = $sth->fetchrow_hashref) {
68        push(@id, $res->{id});
69    }
70
71    @id
72}
73
74
75sub list_running_vote {
76    my ($self) = @_;
77
78    my $sth = $self->db->prepare_cached(
79        q{
80        select id from poll where start < now() and "end" > now()
81        }
82    );
83
84    $sth->execute;
85    my @id;
86    while(my $res = $sth->fetchrow_hashref) {
87        push(@id, $res->{id});
88    }
89
90    @id
91}
92
93sub list_closed_vote {
94    my ($self) = @_;
95
96    my $sth = $self->db->prepare_cached(
97        q{
98        select id from poll where
99        start < now() and "end" < now()
100        }
101    );
102
103    $sth->execute;
104    my @id;
105    while(my $res = $sth->fetchrow_hashref) {
106        push(@id, $res->{id});
107    }
108
109    @id
110}
111
112sub vote_param {
113    my ($self, $voteid, %attr) = @_;
114
115    keys %attr or return;
116    my @online_f = qw(label start end owner password);
117
118    if (grep { exists($attr{$_}) } @online_f) {
119        my $sth = $self->db->prepare_cached(
120            q{update poll set } .
121            join(',', map { qq("$_" = ?) } grep { exists $attr{$_} } @online_f) .
122            q{ where id = ?}
123        );
124        $sth->execute((map { $attr{$_} } grep { exists $attr{$_} } @online_f), $voteid)
125            or do {
126            $self->db->rollback;
127            return;
128        };
129    }
130
131    # vote settings in settings table
132    foreach my $var (keys %attr) {
133        grep { $var eq $_ } @online_f and next;
134        $self->vote_set_settings($voteid, $var, $attr{$var});
135    }
136    1
137}
138
139sub vote_status {
140    my ($self, $id) = @_;
141   
142    my $sth = $self->db->prepare_cached(
143        q{
144        select (start > now() or start is null) as before,
145               "end" < now() as after
146        from poll
147        where id = ?
148        }
149    );
150    $sth->execute($id);
151    my $res = $sth->fetchrow_hashref;
152    $sth->finish;
153    $res or return;
154    if ($res->{before}) {
155        return 'BEFORE';
156    } elsif ($res->{after}) {
157        return 'AFTER';
158    } else {
159        return 'RUNNING';
160    }
161}
162
163sub vote_info {
164    my ($self, $id) = @_;
165
166    my $sth = $self->db->prepare_cached(
167        q{
168        select *,
169        to_char("start", 'DD/MM/YYYY') as dstart,
170        to_char("start", 'HH24:MI:SS') as hstart,
171        to_char("end", 'DD/MM/YYYY') as dend,
172        to_char("end", 'HH24:MI:SS') as hend
173        from poll where id = ?
174        }
175    );
176
177    $sth->execute($id);
178    my $res = $sth->fetchrow_hashref;
179    $sth->finish;
180    if ($res) {
181        my $get = $self->db->prepare_cached(
182            q{select var, val from settings where poll = ?}
183        );
184        $get->execute($id);
185        while (my $set = $get->fetchrow_hashref) {
186            $res->{$set->{var}} = $set->{val};
187        }
188    }
189    $res->{free_choice} ||= 0; # avoiding undef
190    $res
191}
192
193sub vote_set_settings {
194    my ($self, $poll, $var, $val) = @_;
195
196    my $upd = $self->db->prepare_cached(
197        q{update settings set val = ? where poll = ? and var = ?}
198    );
199
200    if ($upd->execute($val, $poll, $var) == 0) {
201        my $add = $self->db->prepare_cached(
202            q{insert into settings (poll, var, val) values (?,?,?)}
203        );
204
205        $add->execute($poll, $var, $val);
206    }
207}
208
209sub vote_signing {
210    my ($self, $id) = @_;
211
212    my $sth = $self->db->prepare_cached(
213        q{
214        select *, voting.key as vkey from voting left join signing
215        on signing.key = voting.key
216        where poll = ? order by voting.mail
217        }
218    );
219    $sth->execute($id);
220    my @people;
221    while (my $res = $sth->fetchrow_hashref) {
222        push(@people, $res);
223    }
224    @people
225}
226
227sub vote_voting {
228    my ($self, $voteid) = @_;
229
230    my $sth = $self->db->prepare_cached(
231        q{
232        select key from voting
233        where poll = ? order by voting.mail
234        }
235    );
236    $sth->execute($voteid);
237    my @people;
238    while (my $res = $sth->fetchrow_hashref) {
239        push(@people, $res->{key});
240    }
241    @people
242}
243
244sub voting_info {
245    my ($self, $id) = @_;
246
247    my $sth = $self->db->prepare_cached(
248        q{
249        select *, voting.key as vkey from voting left join signing
250        on signing.key = voting.key
251        where voting.key = ?
252        }
253    );
254    $sth->execute($id);
255
256    my $res = $sth->fetchrow_hashref;
257    $sth->finish;
258    $res
259}
260
261sub vote_choices {
262    my ($self, $id) = @_;
263
264    my $sth = $self->db->prepare_cached(
265        q{
266        select key from choice where poll = ?
267        order by label
268        }
269    );
270    $sth->execute($id);
271    my @ch;
272    while (my $res = $sth->fetchrow_hashref) {
273        push(@ch, $res->{key});
274    }
275    @ch
276}
277
278sub choice_info {
279    my ($self, $chid) = @_;
280    my $sth = $self->db->prepare_cached(
281        q{select * from choice where key = ?}
282    );
283    $sth->execute($chid);
284    my $res = $sth->fetchrow_hashref;
285    $sth->finish;
286    $res
287}
288
289sub vote_add_choice {
290    my ($self, $voteid, $label) = @_;
291
292    my $sth = $self->db->prepare_cached(
293        q{insert into choice (poll, label) values (?,?)}
294    );
295
296    $sth->execute($voteid, $label) or do {
297        $self->db->rollback;
298        return;
299    };
300
301    1
302}
303
304sub modify_choice {
305    my ($self, $chid, $label) = @_;
306
307    my $sth = $self->db->prepare_cached(
308        q{update choice set label = ? where key = ?}
309    );
310    $sth->execute($label, $chid);
311}
312
313sub delete_choice {
314    my ($self, $chid) = @_;
315
316    my $sth = $self->db->prepare_cached(
317        q{delete from choice where key = ?}
318    );
319
320    $sth->execute($chid);
321}
322
323sub voting_info_id {
324    my ($self, $mail, $voteid) = @_;
325
326    my $sth = $self->db->prepare_cached(
327        q{
328        select * from voting where mail = ? and poll = ?
329        }
330    );
331    $sth->execute($mail, $voteid);
332    my $res = $sth->fetchrow_hashref();
333    $sth->finish;
334    $res
335}
336
337sub _register_signing {
338    my ($self, $mail, $voteid, $referal) = @_;
339
340    my $vinfo = $self->voting_info_id($mail, $voteid) or return;
341
342    my $sth = $self->db->prepare_cached(
343        q{
344        insert into signing (key, referal) values (?,?)
345        }
346    );
347    $sth->execute($vinfo->{key}, $referal) or do {
348        $self->db->rollback;
349        return;
350    };
351
352    1;
353}
354
355sub gen_uid {
356    unpack("H*", join("", map { chr(rand(256)) } (0..15)))
357}
358
359sub _register_ballot {
360    my ($self, $voteid, $choice, $fchoice) = @_;
361
362    my $addb = $self->db->prepare_cached(
363        q{
364        insert into ballot (id, poll, invalid) values (?,?,?)
365        }
366    );
367    my $uid = gen_uid;
368    $addb->execute($uid, $voteid, scalar(@{$fchoice || []}) ? undef : 'f') or do {
369        self->db->rollback;
370        return;
371    };
372
373    my $addbc = $self->db->prepare_cached(
374        q{
375        insert into ballot_item (id, value, fromlist) values (?,?,?)
376        }
377    );
378    foreach (@{ $choice || []}) {
379        $addbc->execute($uid, $_, 't') or do {
380            $self->db->rollback;
381            return;
382        };
383    }
384    foreach (@{ $fchoice || []}) {
385        $_ or next;
386        $addbc->execute($uid, $_, 'f') or do {
387            $self->db->rollback;
388            return;
389        };
390    }
391
392    $uid;
393}
394
395sub register_ballot {
396    my ($self, $vid, $voteid, $choice, $fchoice, $referal) = @_;
397
398    # First we register voting has voted
399    $self->_register_signing($vid, $voteid, $referal) or return; # TODO error ?
400
401    # registring choices
402    my $uid = $self->_register_ballot($voteid, $choice, $fchoice) or return;
403
404    # everything went fine, saving!
405    $self->db->commit;
406
407    $uid
408}
409
410sub vote_voting_count {
411    my ($self, $id) = @_;
412
413    my $sth = $self->db->prepare_cached(
414        q{
415        select count(*) from voting
416        where poll = ?
417        }
418    );
419    $sth->execute($id);
420    my $res = $sth->fetchrow_hashref;
421    $sth->finish;
422    $res->{count}
423}
424
425sub signing_count { vote_signing_count(@_) }
426
427sub vote_signing_count {
428    my ($self, $voteid) = @_;
429
430    my $sth = $self->db->prepare_cached(
431        q{
432        select count(*) from signing join voting
433        on voting.key = signing.key where poll = ?
434        }
435    );
436
437    $sth->execute($voteid);
438    my $res = $sth->fetchrow_hashref;
439    $sth->finish;
440    $res->{count}
441}
442
443sub ballot_count { vote_ballot_count(@_) }
444
445sub vote_ballot_count {
446    my ($self, $voteid) = @_;
447
448    my $sth = $self->db->prepare_cached(
449        q{
450        select count(*) from ballot where poll = ?
451        }
452    );
453
454    $sth->execute($voteid);
455    my $res = $sth->fetchrow_hashref;
456    $sth->finish;
457    $res->{count}
458}
459
460sub ballot_count_nonull { vote_ballot_count_nonull(@_) }
461
462sub vote_ballot_count_nonull {
463    my ($self, $voteid) = @_;
464
465    my $sth = $self->db->prepare_cached(
466        q{
467        select count(*) from ballot where poll = ?
468        and id in (select id from ballot_item) and
469        (invalid = 'false' or invalid is null)
470        }
471    );
472
473    $sth->execute($voteid);
474    my $res = $sth->fetchrow_hashref;
475    $sth->finish;
476    $res->{count}
477}
478
479sub auth_voting {
480    my ($self, $poll, $mail, $password) = @_;
481    my $userinfo = $self->voting_info_id($mail, $poll) or return;
482
483    $userinfo->{passwd} or return;
484    if (crypt($password, $userinfo->{passwd} || '') eq $userinfo->{passwd}) {
485        return 1;
486    } else {
487        return 0;
488    }
489}
490
491sub auth_poll {
492    my ($self, $voteid, $passwd) = @_;
493
494    my $vinfo = $self->vote_info($voteid) or return;
495
496    $vinfo->{password} or return;
497    $passwd or return;
498    if (crypt($passwd, $vinfo->{password} || '') eq $vinfo->{password}) {
499        return 1;
500    } else {
501        return 0;
502    }
503}
504
505sub voting_has_sign {
506    my ($self, $poll, $user) = @_;
507
508    my $sth = $self->db->prepare_cached(
509        q{
510        select date from signing join voting
511        on voting.key = signing.key
512        where poll = ? and mail = ?
513        }
514    );
515
516    $sth->execute($poll, $user);
517    my $res = $sth->fetchrow_hashref;
518    $sth->finish;
519    return $res->{date}
520}
521
522# Requete de decompte des voix:
523
524sub vote_results_count {
525    my ($self, $voteid) = @_;
526
527    my $sth = $self->db->prepare(
528        q{
529        select count(ballot.id), value from ballot left join ballot_item
530        on ballot.id = ballot_item.id where ballot.poll = ? and invalid = 'false'
531        group by value
532        order by count
533        }
534    );
535    $sth->execute($voteid);
536    my @results;
537    while (my $res = $sth->fetchrow_hashref) {
538        push(@results, $res);
539    }
540    @results;
541}
542
543sub vote_results_nonull {
544    my ($self, $voteid) = @_;
545
546    my $sth = $self->db->prepare(
547        q{
548        select count(ballot.id), coalesce(corrected, value) as value
549        from ballot join ballot_item
550        on ballot.id = ballot_item.id where ballot.poll = ? and
551        (invalid = 'false' or invalid is null)
552        group by coalesce(corrected, value)
553        order by count desc
554        }
555    );
556    $sth->execute($voteid);
557    my @results;
558    while (my $res = $sth->fetchrow_hashref) {
559        push(@results, $res);
560    }
561    \@results;
562}
563
564sub list_vote_ballot {
565    my ($self, $voteid) = @_;
566
567    my $sth = $self->db->prepare_cached(
568        q{
569        select id from ballot where poll = ?
570        order by id
571        }
572    );
573    $sth->execute($voteid);
574    my @ids;
575    while (my $res = $sth->fetchrow_hashref) {
576        push(@ids, $res->{id});
577    }
578    @ids
579}
580
581sub list_vote_ballot_needvalid {
582    my ($self, $voteid) = @_;
583
584    my $sth = $self->db->prepare_cached(
585        q{
586        select id from ballot where poll = ?
587        and invalid is null order by id
588        }
589    );
590    $sth->execute($voteid);
591    my @ids;
592    while (my $res = $sth->fetchrow_hashref) {
593        push(@ids, $res->{id});
594    }
595    @ids
596}
597
598sub ballot_info {
599    my ($self, $ballotid) = @_;
600
601    my $sth = $self->db->prepare_cached(
602        q{ select * from ballot where id = ? }
603    );
604
605    $sth->execute($ballotid);
606    my $res = $sth->fetchrow_hashref;
607    $sth->finish;
608    $res
609}
610
611sub mark_ballot_invalid {
612    my ($self, $ballotid, $invalid) = @_;
613
614    my $sth = $self->db->prepare_cached(
615        q{update ballot set invalid = ? where id = ?}
616    );
617
618    $sth->execute($invalid ? 't' : 'f', $ballotid);
619}
620
621sub ballot_items {
622    my ($self, $ballotid) = @_;
623
624    my $sth = $self->db->prepare_cached(
625        q{select *, value as v from ballot_item where id = ?}
626    );
627    $sth->execute($ballotid);
628    my @ids;
629    while (my $res = $sth->fetchrow_hashref) {
630        push(@ids, $res);
631    }
632    \@ids
633}
634
635sub vote_ballot_untrusted_values {
636    my ($self, $voteid) = @_;
637
638    my $getval = $self->db->prepare_cached(
639        q{
640        select value from ballot join ballot_item
641        on ballot.id = ballot_item.id
642        where poll = ? and fromlist = false and corrected is null
643        group by value order by value
644        }
645    );
646    $getval->execute($voteid);
647    my @vals;
648    while (my $res = $getval->fetchrow_hashref) {
649        push(@vals, $res->{value});
650    }
651    @vals
652}
653
654sub vote_ballot_values {
655    my ($self, $voteid) = @_;
656
657    my $getval = $self->db->prepare_cached(
658        q{
659        select coalesce(corrected, value) as value from ballot join ballot_item
660        on ballot.id = ballot_item.id
661        where poll = ?
662        group by coalesce(corrected, value) order by coalesce(corrected, value)
663        }
664    );
665    $getval->execute($voteid);
666    my @vals;
667    while (my $res = $getval->fetchrow_hashref) {
668        push(@vals, $res->{value});
669    }
670    @vals
671}
672
673sub vote_map_value {
674    my ($self, $voteid, $from, $to) = @_;
675
676    my $sth = $self->db->prepare_cached(
677        q{
678        update ballot_item set corrected = ? where
679        id in (select id from ballot where poll = ?)
680        and value = ?
681        }
682    );
683
684    $sth->execute($to, $voteid, $from) or $self->db->rollback;
685    $self->db->commit;
686}
687
688sub addupd_voting {
689    my ($self, $voteid, $mail, $id) = @_;
690
691    my $upd = $self->db->prepare_cached(
692        q{
693        update voting set label = ? where mail = ? and poll = ?
694        }
695    );
696
697    if ($upd->execute($id, $mail, $voteid) == 0) {
698        my $add = $self->db->prepare_cached(q{
699            insert into voting (poll, label, mail) values (?,?,?)
700        });
701
702        $add->execute($voteid, $id, $mail);
703    }
704}
705
706sub delete_voting {
707    my ($self, $key) = @_;
708
709    $self->voting_has_sign($key) and return;
710    my $sth = $self->db->prepare_cached(
711        q{delete from voting where key = ?}
712    );
713
714    $sth->execute($key);
715}
716
717sub voting_from_file {
718    my ($self, $voteid, $fh, $delete) = @_;
719
720    if ($delete) {
721        my $sth = $self->db->prepare(q{delete from voting where poll = ?});
722        $sth->execute($voteid);
723    }
724
725    while (my $line = <$fh>) {
726        chomp($line);
727        warn $line;
728        my ($mail, $name) = split(';', $line);
729        $mail or do {
730            $self->db->rollback;
731            return;
732        };
733        $self->addupd_voting($voteid, $mail, $name);
734    }
735    1;
736}
737
738sub mail_passwd_ifnul {
739    my ($self, $voteid, $mailinfo) = @_;
740
741    my $list_voting = $self->db->prepare_cached(
742        q{select key from voting where poll = ? and passwd is null or passwd = ''}
743    );
744
745    $list_voting->execute($voteid);
746    while (my $res = $list_voting->fetchrow_hashref) {
747        $self->mail_voting_passwd($res->{key}, $mailinfo);
748    }
749}
750
751sub mail_voting_passwd {
752    my ($self, $id, $mailinfo) = @_;
753   
754    my $vinfo = $self->voting_info($id) or return;
755    my $voteinfo = $self->vote_info($vinfo->{poll});
756
757    my $passwd = random_string(8);
758    my $encpasswd = $self->gen_enc_passwd($passwd);
759
760    my $upd_voting = $self->db->prepare_cached(
761        q{update voting set passwd = ? where key = ?}
762    );
763
764    $upd_voting->execute($encpasswd, $id);
765
766    my $date = $voteinfo->{dstart} && $voteinfo->{dend}
767        ? sprintf("\n" . 'Vous pourrez voter entre le %s %s et le %s %s' . "\n",
768            $voteinfo->{dstart}, $voteinfo->{hstart}, $voteinfo->{dend}, $voteinfo->{hend})
769        : '';
770
771    # TODO complete this properly:
772    my $mailer = new Mail::Mailer 'smtp', Server => 'mailhost';
773    $mailer->open({
774        From => $voteinfo->{owner},
775        To => $vinfo->{mail},
776        Subject => 'Invitation a voter: ' . $voteinfo->{label},
777        'X-Epoll-poll' => $id,
778        'X-Epoll-version' => $Vote::VERSION,
779    });
780    print $mailer <<EOF;
781Vous etes convie à participer a ce vote:
782$voteinfo->{label}
783
784a l'adresse:
785
786$mailinfo->{voteurl}
787$date
788Votre identifiant est: $vinfo->{mail}
789Votre mot de passe est: $passwd
790
791Conserver precieusement ces identifiants, il ne vous seront pas redonner.
792
793Cordialement.
794EOF
795    $mailer->close;
796
797    $self->db->commit;
798}
799
800sub poll_request_info {
801    my ($self, $rid) = @_;
802
803    my $sth = $self->db->prepare_cached(
804        q{select * from poll_request where id = ?}
805    );
806
807    $sth->execute($rid);
808    my $res = $sth->fetchrow_hashref;
809    $sth->finish;
810    $res
811}
812
813sub poll_from_request {
814    my ($self, $rid, $passwd) = @_;
815    my $rinfo = $self->poll_request_info($rid) or return;
816
817    my $encpasswd = $self->gen_enc_passwd($passwd);
818
819    my $getpollid = $self->db->prepare_cached(
820        q{select nextval('poll_id_seq')}
821    );
822    $getpollid->execute();
823    my $newpollid = $getpollid->fetchrow_hashref->{nextval};
824   
825    my $newpoll = $self->db->prepare_cached(
826        q{insert into poll (id, label, owner, password) values (?,?,?,?)}
827    );
828
829    $newpoll->execute($newpollid, $rinfo->{label}, $rinfo->{mail}, $encpasswd);
830    # set some default
831    $self->vote_param($newpollid,
832        free_choice => 0,
833        choice_count => 1,
834    );     
835
836    my $delreq = $self->db->prepare_cached(
837        q{delete from poll_request where id = ?}
838    );
839
840    $delreq->execute($rid);
841    $self->db->commit;
842
843    $newpollid
844}
845
846sub create_poll_request {
847    my ($self, %info) = @_;
848
849    $info{mail} or return;
850    my $addreq = $self->db->prepare_cached(
851        q{insert into poll_request (id, label, mail) values (?,?,?)}
852    );
853
854    my $reqid = gen_uid;
855
856    $addreq->execute($reqid, $info{label}, $info{mail});
857    my $mailer = new Mail::Mailer 'smtp', Server => 'mailhost';
858    $mailer->open({
859        From => 'Voting system <nomail@nomail.com>', # TODO allow to configure this
860        To => $info{mail},
861        Subject => 'Votre nouveau vote',
862    });
863    print $mailer <<EOF;
864
865Vous avez demandez la création d'un nouveau vote:
866$info{label}
867
868Pour valider votre demande, veuiller allez visitez la page:
869$info{url}/$reqid
870
871A bientot
872EOF
873    $mailer->close;
874    $self->db->commit;
875    1;
876}
877
878=head1 AUTHOR
879
880Thauvin Olivier
881
882=head1 LICENSE
883
884This library is free software, you can redistribute it and/or modify
885it under the same terms as Perl itself.
886
887=cut
888
8891;
Note: See TracBrowser for help on using the repository browser.