App-RoboBot
view release on metacpan or search on metacpan
lib/App/RoboBot/Plugin/Social/Voting.pm view on Meta::CPAN
package App::RoboBot::Plugin::Social::Voting;
$App::RoboBot::Plugin::Social::Voting::VERSION = '4.004';
use v5.20;
use namespace::autoclean;
use Moose;
extends 'App::RoboBot::Plugin';
has '+name' => (
default => 'Social::Voting',
);
has '+description' => (
default => 'Provides functions for creating, voting on, and tallying polls.',
);
has '+commands' => (
default => sub {{
'propose' => { method => 'voting_propose',
description => 'Creates a new poll question, with allowed responses (and optional write-in). Displays the poll ID and instructions on voting.',
usage => '"<question>" <response1> ... <responseN> [:write-in]',
example => '"What should we get for lunch?" Pizza Indian "Bucket of cookies" :write-in', },
'poll' => { method => 'voting_poll',
description => 'Displays the given polling question and available options (with the respective tallies if any votes have already been cast).',
usage => '<poll id>', },
'polls' => { method => 'voting_polls',
description => 'Displays the current list of open questions for the current channel.', },
'vote' => { method => 'voting_vote',
description => 'Casts a vote on the given poll. If you have alredy voted, your ballot will be updated with your new choice. Votes cannot be cast on closed polls. If the poll allows write-ins, you may cast your vote for any arbitra...
example => '<poll id> <choice>', },
'tally' => { method => 'voting_tally',
description => 'Closes the named poll and displays the final tally of votes. Only the user who created the poll may close it.',
usage => '<poll id>', },
}},
);
sub voting_propose {
my ($self, $message, $command, $rpl, $question, @choices) = @_;
unless ($message->has_channel) {
$message->response->raise('Polls may only be created inside a channel.');
return;
}
unless (@choices && (@choices > 1 || lc($choices[0]) eq 'write-in')) {
$message->response->raise('Polls must have at least two choices (or allow write-ins).');
return;
}
my $poll = {
name => $question,
channel_id => $message->channel->id,
created_by => $message->sender->id,
can_writein => 'f'
};
$poll->{'can_writein'} = 't' if grep { lc($_) eq 'write-in' } @choices;
my $res = $self->bot->config->db->do(q{ insert into voting_polls ??? returning poll_id }, $poll);
unless ($res && $res->next) {
$message->response->raise('Could not create poll. Please check your syntax and try again. Use (help propose) to see options.');
return;
}
my $poll_id = $res->{'poll_id'};
foreach my $choice (grep { lc($_) ne 'write-in' } @choices) {
$self->bot->config->db->do(q{ insert into voting_poll_choices ??? }, { poll_id => $poll_id, name => $choice });
}
return $self->voting_poll($message, 'poll', $rpl, $poll_id);
}
sub voting_poll {
my ($self, $message, $command, $rpl, $poll_id) = @_;
unless (defined $poll_id && $poll_id =~ m{^\d+$}) {
$message->response->raise('A poll number is required to view poll details.');
return;
}
unless ($message->has_channel) {
$message->response->raise('Polls may only be conducted inside a channel.');
return;
}
my $poll = $self->bot->config->db->do(q{
select p.poll_id, p.name, p.can_writein, p.created_at, p.closed_at,
lib/App/RoboBot/Plugin/Social/Voting.pm view on Meta::CPAN
$choice =~ s{(^\s+|\s+$)}{}gs;
$choice =~ s{\s+}{ }gs;
my $poll = $self->bot->config->db->do(q{
select * from voting_polls where poll_id = ? and channel_id = ?
}, $poll_id, $message->channel->id);
unless ($poll && $poll->next) {
$message->response->raise('That poll number is not valid. To view the open polls for this channel, use: (polls)');
return;
}
if ($poll->{'closed_at'}) {
$message->response->raise('That poll has already closed and no new votes are being accepted. To view the results, use: (poll %d)', $poll->{'poll_id'});
return;
}
my $poll_choice = $self->bot->config->db->do(q{
select * from voting_poll_choices where poll_id = ? and lower(name) = lower(?)
}, $poll_id, $choice);
my $choice_id;
if ($poll_choice && $poll_choice->next) {
$choice_id = $poll_choice->{'choice_id'};
} elsif ($poll->{'can_writein'}) {
$poll_choice = $self->bot->config->db->do(q{
insert into voting_poll_choices ??? returning choice_id
}, {
poll_id => $poll_id,
name => $choice,
is_writein => 't',
writein_by => $message->sender->id,
writein_at => 'now'
});
if ($poll_choice && $poll_choice->next) {
$choice_id = $poll_choice->{'choice_id'};
} else {
$message->response->raise('Could not create your write-in vote. Please check your ballot and try again.');
return;
}
} else {
$message->response->raise(sprintf('The choice "%s" is not valid for this poll (and it does not accept write-ins). Please use (poll %d) to view choices and try again.', $choice, $poll_id));
return;
}
my $vote = $self->bot->config->db->do(q{
update voting_votes
set choice_id = ?,
voted_at = now()
where vote_id = ( select v.vote_id
from voting_votes v
join voting_poll_choices c on (c.choice_id = v.choice_id)
where v.nick_id = ? and c.poll_id = ?)
returning vote_id
}, $choice_id, $message->sender->id, $poll_id);
if ($vote && $vote->next) {
$message->response->push(sprintf('Your ballot has been updated. To view poll results, use: (poll %d)', $poll_id));
} else {
$vote = $self->bot->config->db->do(q{
insert into voting_votes ??? returning vote_id
}, {
choice_id => $choice_id,
nick_id => $message->sender->id,
});
if ($vote && $vote->next) {
$message->response->push(sprintf('Your ballot has been cast. To view poll results, use: (poll %d)', $poll_id));
} else {
$message->response->raise('Could not record your vote. Please check your ballot and try again.');
}
}
return;
}
sub voting_tally {
my ($self, $message, $command, $rpl, $poll_id) = @_;
unless ($message->has_channel) {
$message->response->raise('Polls may only be conducted within channels.');
return;
}
unless (defined $poll_id && $poll_id =~ m{^\d+$}) {
$message->response->raise('You must supply a valid poll number. To see a list of current polls for this channel, use: (polls)');
return;
}
my $poll = $self->bot->config->db->do(q{
select * from voting_polls where poll_id = ? and channel_id = ?
}, $poll_id, $message->channel->id);
unless ($poll && $poll->next) {
$message->response->raise('That poll number is not valid for this channel. To see the open polls in this channel, use: (polls)');
return;
}
if ($poll->{'closed_at'}) {
$message->response->raise('That poll has already closed. To view the results, use: (poll %d)', $poll_id);
return;
}
unless ($poll->{'created_by'} == $message->sender->id) {
$message->response->raise('Only the person who created a poll may close it and tally the votes. You did not create this poll.');
return;
}
my $poll_close = $self->bot->config->db->do(q{
update voting_polls set closed_at = now() where poll_id = ? and channel_id = ? and created_by = ? returning *
}, $poll_id, $message->channel->id, $message->sender->id);
unless ($poll_close && $poll_close->next) {
$message->response->raise('Could not close the requested poll and tally results. Please try again.');
return;
}
return $self->voting_poll($message, 'poll', $rpl, $poll_id);
( run in 0.921 second using v1.01-cache-2.11-cpan-39bf76dae61 )