Initial poll support added. There will likely be bugs.

This commit is contained in:
Storm Dragon
2025-07-26 11:10:28 -04:00
parent 3a394e0a4d
commit cac1c0f3a9
+166
View File
@@ -2566,6 +2566,8 @@ Example:
/url a5 - opens all URLs in post a5
/delete a5 - deletes post a5, if it's your post
/boost a5 - boosts post a5
/vote a5 2 - vote for option 2 on poll in post a5
/vote a5 1,3 - vote for options 1 and 3 (if multiple choice)
Abbreviations: /re, /th, /url, /del
Menu codes wrap around at end.
@@ -3566,6 +3568,13 @@ EOF
return &common_split_post($_, undef, $1);
}
# vote on polls
if (m#^/vote\s+([a-z]\d+)\s+(.+)$#i) {
my $post_code = $1;
my $choices = $2;
return &vote_on_poll($post_code, $choices);
}
# follow and leave users
if (m#^/(follow|leave|unfollow) \@?([^\s/]+)$#) {
my $m = $1;
@@ -3935,6 +3944,95 @@ sub common_split_post {
return 1;
}
# vote on a poll
sub vote_on_poll {
my $post_code = shift;
my $choices = shift;
# Find the post by its menu code
my $post_ref = &findtarget($post_code);
unless ($post_ref) {
print $stdout "-- no such post: $post_code\n";
return 0;
}
# Check if post has a poll
unless (exists($post_ref->{'poll'}) && $post_ref->{'poll'}) {
print $stdout "-- post $post_code does not have a poll\n";
return 0;
}
my $poll = $post_ref->{'poll'};
# Check if poll is expired or already voted
if ($poll->{'expired'}) {
print $stdout "-- poll has expired\n";
return 0;
}
if ($poll->{'voted'}) {
print $stdout "-- you have already voted on this poll\n";
return 0;
}
# Parse choices (support both single numbers and comma-separated)
my @choice_nums = split(/[\s,]+/, $choices);
my @valid_choices = ();
my $max_options = scalar(@{$poll->{'options'}});
foreach my $choice (@choice_nums) {
$choice =~ s/\D//g; # remove non-digits
if ($choice < 1 || $choice > $max_options) {
print $stdout "-- invalid choice: $choice (must be 1-$max_options)\n";
return 0;
}
push @valid_choices, ($choice - 1); # Convert to 0-based index
}
unless (@valid_choices) {
print $stdout "-- no valid choices specified\n";
return 0;
}
# Check if multiple choices are allowed
if (!$poll->{'multiple'} && scalar(@valid_choices) > 1) {
print $stdout "-- this poll only allows single choice\n";
return 0;
}
# Submit the vote
my $post_id = $post_ref->{'id_str'} || $post_ref->{'id'};
my $vote_url = "$apibase/polls/$poll->{'id'}/votes";
# Build POST data with choices
my $post_data = '';
foreach my $choice_idx (@valid_choices) {
$post_data .= "&choices[]=$choice_idx";
}
$post_data =~ s/^&//; # remove leading &
print $stdout "-- submitting vote on poll...\n";
my $result = &backticks($useragent, '/dev/null', undef, $vote_url, $post_data, 1, @agentopts);
if ($result) {
print $stdout "-- vote submitted successfully\n";
# Show which options were selected
my @chosen_titles = ();
foreach my $choice_idx (@valid_choices) {
my $title = $poll->{'options'}->[$choice_idx]->{'title'} || '';
push @chosen_titles, ($choice_idx + 1) . ". $title";
}
print $stdout "-- voted for: " . join(', ', @chosen_titles) . "\n";
return 1;
} else {
print $stdout "-- failed to submit vote\n";
return 0;
}
}
# helper functions for the command line processor.
sub add_history {
my $h = shift;
@@ -5721,6 +5819,12 @@ sub standardpost {
my $booster = &descape($ref->{'boost_attribution'});
$post = "[boosted $booster] $post";
}
# Add poll information if this post has a poll
if (exists($ref->{'poll'}) && $ref->{'poll'}) {
my $poll_info = &format_poll_display($ref->{'poll'});
$post .= "\n$poll_info" if ($poll_info);
}
my $colour;
my $g;
my $h;
@@ -5789,6 +5893,50 @@ s/(^|[^a-zA-Z0-9_])\@([a-zA-Z0-9_\/]+)/\1\@${UNDER}\2${colour}/g;
return $post;
}
# format poll information for display
sub format_poll_display {
my $poll = shift;
return '' unless ($poll && ref($poll) eq 'HASH');
my @options = @{$poll->{'options'} || []};
return '' unless (@options);
my $poll_text = "Poll:";
my $option_num = 1;
# Display each option with number and vote count
foreach my $option (@options) {
my $title = &descape($option->{'title'} || '');
my $votes = $option->{'votes_count'} || 0;
$poll_text .= "\n $option_num. $title ($votes votes)";
$option_num++;
}
# Add poll metadata
my $total_votes = $poll->{'votes_count'} || 0;
my $expires_at = $poll->{'expires_at'};
my $expired = $poll->{'expired'} || 0;
my $multiple = $poll->{'multiple'} || 0;
my $voted = $poll->{'voted'} || 0;
$poll_text .= "\n Total: $total_votes votes";
$poll_text .= $multiple ? " (multiple choice)" : " (single choice)";
if ($expired) {
$poll_text .= " - EXPIRED";
} elsif ($expires_at) {
$poll_text .= " - expires $expires_at";
}
if ($voted) {
$poll_text .= " - Already voted";
} else {
$poll_text .= " - Use /vote to participate";
}
return $poll_text;
}
# format a DM based on standard user options
sub standarddm {
my $ref = shift;
@@ -7664,6 +7812,24 @@ sub normalizejson {
print $stdout "-- DEBUG: Final boost data applied - text: '$boost_content', attribution: '$boost_attribution'\n" if ($verbose);
}
# Handle poll data - check for polls in boost-aware manner (Bifrost pattern)
my $poll_data = undef;
if (exists($i->{'reblog'}) && exists($i->{'reblog'}->{'poll'})) {
# Poll is in the boosted post
$poll_data = $i->{'reblog'}->{'poll'};
print $stdout "-- DEBUG: Found poll in boosted post\n" if ($verbose);
} elsif (exists($i->{'poll'})) {
# Poll is in the main post
$poll_data = $i->{'poll'};
print $stdout "-- DEBUG: Found poll in main post\n" if ($verbose);
}
# Store poll data for display
if ($poll_data) {
$i->{'poll'} = $poll_data;
print $stdout "-- DEBUG: Poll data stored for display\n" if ($verbose);
}
return $i;
}