Skip to content
Extraits de code Groupes Projets
Valider eb7cef7b rédigé par TC's avatar TC
Parcourir les fichiers

Add vote module

New module to propose a yes-or-no vote.
This still needs a timer for memory cleaning purpose.
parent 5924057a
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
package Vote; # command = vote
use strict;
use warnings;
use Storable;
# Tableau des votes
# On les stocke de telle manière :
# "#chan id" --> "chan" --------> chan/reply name
# |----> "id" ----------> vote id
# |----> "added date" --> timestamp
# |----> "question" ----> yes/no question to answer
# |----> "voters" ------> [user@host voters]
# |----> "results" -----> ("yes" => nb, "no" => nb)
# `----> "author" ------> user@host
# ...
our %votes = ();
# Tableau des derniers votes ajoutés
# Format :
# "chan1" --> dernier vote id
# ...
our %last_added = ();
# ###
# vote_main
# Permet de gérer des votes
#
# Usage :
# !vote new <question>
# !vote del <id>
# !vote list [#chan]
# !vote see <id>
# !vote [<id>] {yes|no}
# ###
sub vote_main
{
my ($conn, $event, $reply_to, $ref_params) = @_;
# Don't use in query, only on chans
unless(substr($reply_to, 0, 1) eq '#')
{
$::displayer->sendto($reply_to, "Can't operate in query, sorry.");
return 1;
}
if(defined($ref_params->[0]) && $ref_params->[0])
{
if($ref_params->[0] eq 'new')
{
return 1 if(new_vote($conn, $event, $reply_to, $ref_params));
}
elsif($ref_params->[0] =~ m'del(ete)?|remove')
{
return 1 if(del_vote($conn, $event, $reply_to, $ref_params));
}
elsif($ref_params->[0] eq 'list')
{
return 1 if(list_votes($conn, $event, $reply_to, $ref_params));
}
elsif($ref_params->[0] eq 'see')
{
return 1 if(see_vote($conn, $event, $reply_to, $ref_params));
}
else
{
return 1 if(vote($conn, $event, $reply_to, $ref_params));
}
}
$ref_params->[0] = 'vote';
Help::help_main($conn, $event, $reply_to, $ref_params);
} # Fin vote_main
# ###
# new_vote
# Enregistre un nouveau vote
# ###
sub new_vote
{
my ($conn, $event, $reply_to, $ref_params) = @_;
# On enlève le 'new'
shift @{$ref_params};
unless(defined($ref_params->[0]) && $ref_params->[0])
{
$::displayer->sendto($reply_to, "Didn't find your question.");
return 0;
}
my $lc_reply_to = lc $reply_to;
my $id = get_next_id($lc_reply_to);
my (undef, $vote_id) = split / +/, $id;
my $question = join(' ', @{$ref_params});
my $full_user = (lc $event->{'nick'}).'!'.(lc $event->{'userhost'});
my %new_vote = (
'chan' => $lc_reply_to,
'id' => $vote_id,
'added date' => time(),
'question' => $question,
'voters' => [],
'results' => {
'yes' => 0,
'no' => 0
},
'author' => $full_user
);
$votes{$id} = \%new_vote;
$last_added{$lc_reply_to} = $vote_id;
my $add_date = localtime($votes{$id}->{'added date'});
$::displayer->sendto($reply_to, "Vote \x0304[\x0303id #$vote_id\x0304]\x03 added on $add_date");
$::logger->info("New vote: '$question', id='$id', added by $full_user");
return 1;
} # Fin new_vote
# ###
# del_vote
# Supprime un vote
# ###
sub del_vote
{
my ($conn, $event, $reply_to, $ref_params) = @_;
# On enlève le 'del' ou autre
shift @{$ref_params};
unless(defined($ref_params->[0]))
{
$::displayer->sendto($reply_to, "Didn't find the id.");
return 0;
}
my $lc_reply_to = lc $reply_to;
my $vote_id = $ref_params->[0];
if($ref_params->[0] =~ /^#?(\d+)$/)
{
$vote_id = $1;
}
my $id = $lc_reply_to.' '.$vote_id;
my $full_user = (lc $event->{'nick'}).'!'.(lc $event->{'userhost'});
# On vérifie que c'est bien l'auteur qui demande la suppression du vote
if(defined($votes{$id}) && $votes{$id}->{'author'} eq $full_user)
{
return real_del_vote($id, $lc_reply_to);
}
$::displayer->sendto($reply_to, "Can't find this vote on this chan or you're not authorized.");
return 1;
} # Fin del_vote
# ###
# real_del_vote
# S'occupe de vraiment supprimer le vote et d'émettre le résultat à l'utilisateur
# ###
sub real_del_vote
{
my ($id, $reply_to) = @_;
my $question = $votes{$id}->{'question'};
my $yes = $votes{$id}->{'results'}->{'yes'};
my $no = $votes{$id}->{'results'}->{'no'};
delete $votes{$id};
$::displayer->sendto($reply_to, "Vote for '$question' deleted");
$::displayer->sendto($reply_to, "Final results: yes = \x0303$yes\x03 - no = \x0304$no\x03");
$::logger->info("Vote removed: '$question', id='$id'. Results: yes=$yes, no=$no");
return 1;
} # Fin real_del_vote
# ###
# list_votes
# Liste les votes en cours sur le chan actuel
# ###
sub list_votes
{
my ($conn, $event, $reply_to, $ref_params) = @_;
shift @{$ref_params};
my $to_check_chan = lc $reply_to;
if(defined($ref_params->[0]) && substr($ref_params->[0], 0, 1) eq '#')
{
$to_check_chan = lc $ref_params->[0];
}
my %current_votes = ();
foreach my $id (sort keys %votes)
{
if($votes{$id}->{'chan'} eq $to_check_chan)
{
$current_votes{$id} = $votes{$id};
}
}
my @curr_votes = sort keys %current_votes;
my $msg = "";
if(@curr_votes)
{
foreach my $id (@curr_votes)
{
$msg .= "\x0307{#" . $votes{$id}->{'id'} . "\x03";
$msg .= " Added by \x0304" . $votes{$id}->{'author'};
$msg .= "on \x0302" . localtime($votes{$id}->{'added date'});
$msg .= "\x0307}\x03 ";
}
}
else
{
$msg = "There's currently no vote on $to_check_chan";
}
$::displayer->sendto($reply_to, $msg);
return 1;
} # Fin list_votes
# ###
# see_vote
# Affiche un vote particulier
# ###
sub see_vote
{
my ($conn, $event, $reply_to, $ref_params) = @_;
# On enlève le 'see'
shift @{$ref_params};
unless(defined($ref_params->[0]))
{
$::displayer->sendto($reply_to, "Didn't find the id.");
return 0;
}
my $lc_reply_to = lc $reply_to;
my $vote_id = $ref_params->[0];
my $id = $lc_reply_to." ".$vote_id;
# On vérifie que le vote existe
if(defined($votes{$id}))
{
my $msg = "Vote \x0304[\x0303id #$vote_id\x0304]\x03: ";
$msg .= $votes{$id}->{'question'};
$msg .= " -- \x0302Added on " . localtime($votes{$id}->{'added date'});
$::displayer->sendto($reply_to, $msg);
# Public/private?
# if(lc $event->{'nick'} eq $votes{$id}->{'author'})
{
my $yes = $votes{$id}->{'results'}->{'yes'};
my $no = $votes{$id}->{'results'}->{'no'};
$msg = "Current results: yes = \x0303$yes\x03 - no = \x0304$no\x03";
$::displayer->sendto($reply_to, $msg);
}
}
else
{
$::displayer->sendto($reply_to, "Can't find this vote. It has either expired or been deleted.");
}
return 1;
} # Fin see_vote
# ###
# vote
# Enregistre le vote d'un votant
# ###
sub vote
{
my ($conn, $event, $reply_to, $ref_params) = @_;
my $lc_reply_to = lc $reply_to;
my $vote_id = $last_added{$lc_reply_to};
my $voter = $event->{'userhost'};
my $code = real_vote(join(' ', @{$ref_params}), $lc_reply_to, $vote_id, $voter);
if($code == 0)
{
$::displayer->sendto($reply_to, "You've already answered to this vote \x0304[\x0303id #$vote_id\x0304]\x03");
}
elsif($code == 1)
{
$::displayer->sendto($reply_to, "Your vote has been added.");
}
else
{
$::displayer->sendto($reply_to, "Can't find your answer.");
}
return 1;
} # Fin vote
# ###
# real_vote
# Enregistre vraiment le vote d'un votant
# ###
sub real_vote
{
my ($params, $chan, $vote_id, $voter) = @_;
my $id = $chan." ".$vote_id;
print Data::Dumper->Dump([$votes{$id}, $params], [qw(vote_struct params)]);
if($params =~ /^(?:y(?:es)?|oui)$/i)
{
if(can_vote($id, $voter))
{
$votes{$id}->{'results'}->{'yes'} += 1;
push @{$votes{$id}->{'voters'}}, $voter;
return 1;
}
return 0;
}
elsif($params =~ /^n(?:o(?:n)?)?$/i)
{
if(can_vote($id, $voter))
{
$votes{$id}->{'results'}->{'no'} += 1;
push @{$votes{$id}->{'voters'}}, $voter;
return 1;
}
return 0;
}
elsif($params =~ /^#?(\d+)\s+(.+)$/i)
{
$vote_id = $1;
my $answer = $2;
$id = $chan." ".$vote_id;
if(can_vote($id, $voter))
{
return real_vote($answer, $chan, $vote_id, $voter);
}
}
return -1;
} # Fin real_vote
# ###
# can_vote
# Vérifie qu'un utilisateur n'a pas déjà voté
# ###
sub can_vote
{
my ($id, $user) = @_;
my $lc_user = lc $user;
if(grep { $_ eq $lc_user } @{$votes{$id}->{'voters'}})
{
return 0;
}
$::logger->info("$user can vote for $id");
return 1;
}
# ###
# get_next_id
# Renvoie le prochain vote_id libre
# ###
sub get_next_id
{
my $base = shift;
my $cpt = 0;
$cpt++ while(defined($votes{$base." ".$cpt}));
return $base." ".$cpt;
} # Fin get_next_id
# ###
# vote_help
# Affiche l'aide de la commande '!vote'
# ###
sub vote_help
{
my ($conn, $event, $reply_to, $ref_params) = @_;
$conn->privmsg($reply_to, "`".$Config::command_sign."vote new <question>` => "
."suggest a new vote");
$conn->privmsg($reply_to, "`".$Config::command_sign."vote {del|see} <id>` => "
."remove or see the vote with id <id>");
$conn->privmsg($reply_to, "`".$Config::command_sign."vote list [<#chan>]` => "
."list votes on <#chan> or the current one by default");
$conn->privmsg($reply_to, "`".$Config::command_sign."vote [<id>] {yes|no}` => "
."vote for the last created vote or the one specified by its <id>");
return 1;
} # Fin vote_help
# ###
# vote_save
# Sauvegarde les postit
# ###
sub vote_save
{
my (undef, $folder, $reloading) = @_;
my $file_votes = $folder."/vote".$Config::suffixe.".sav";
store [\%votes, \%last_added], $file_votes;
return 1;
} # Fin vote_save
# ###
# vote_load
# Remplis %postits au démarrage
# ###
sub vote_load
{
shift; # Pas besoin de la connexion au serveur
my $folder = shift;
my $file_votes = $folder."/vote".$Config::suffixe.".sav";
my $file_content = retrieve $file_votes;
my ($ref_votes, $ref_last_added) = @{$file_content};
%votes = %{$ref_votes};
%last_added = %{$ref_last_added};
return 1;
} # Fin vote_load
1;
__END__
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter