Fix issues with Users and add `date` command

This commit is contained in:
Pragmatic Software 2020-01-25 14:13:57 -08:00
parent 718b52bc03
commit 4e27b036cd
4 changed files with 138 additions and 40 deletions

View File

@ -140,48 +140,55 @@ sub save {
$self->{users}->save;
}
sub hostmask_or_account_name {
sub find_user_account {
my ($self, $channel, $hostmask) = @_;
$channel = lc $channel;
$hostmask = lc $hostmask;
$channel = '.*' if $channel !~ /^#/;
my ($found_channel, $found_hostmask) = ($channel, $hostmask);
if (exists $self->{users}->{hash}->{$channel}) {
if (not exists $self->{users}->{hash}->{$channel}->{$hostmask}) {
my $last_level = 0;
# find hostmask by account name or wildcard
foreach my $mask (keys %{ $self->{users}->{hash}->{$channel} }) {
next if $mask eq '_name';
if (lc $self->{users}->{hash}->{$channel}->{$mask}->{name} eq $hostmask) {
if ($last_level < $self->{users}->{hash}->{$channel}->{$mask}->{level}) {
$hostmask = $mask;
$last_level = $self->{users}->{hash}->{$channel}->{$mask}->{level};
foreach my $chan (keys %{ $self->{users}->{hash} }) {
if ($channel !~ m/^#/ or $channel =~ m/^$chan$/i) {
if (not exists $self->{users}->{hash}->{$chan}->{$hostmask}) {
my $last_level = 0;
# find hostmask by account name or wildcard
foreach my $mask (keys %{ $self->{users}->{hash}->{$chan} }) {
next if $mask eq '_name';
if (lc $self->{users}->{hash}->{$chan}->{$mask}->{name} eq $hostmask) {
if ($last_level <= $self->{users}->{hash}->{$chan}->{$mask}->{level}) {
$found_hostmask = $mask;
$found_channel = $chan;
$last_level = $self->{users}->{hash}->{$chan}->{$mask}->{level};
}
}
}
if ($mask =~ /[*?]/) {
# contains * or ? so it's converted to a regex
my $mask_quoted = quotemeta $mask;
$mask_quoted =~ s/\\\*/.*?/g;
$mask_quoted =~ s/\\\?/./g;
if ($hostmask =~ m/^$mask_quoted$/i) {
if ($last_level < $self->{users}->{hash}->{$channel}->{$mask}->{level}) {
$hostmask = $mask;
$last_level = $self->{users}->{hash}->{$channel}->{$mask}->{level};
if ($mask =~ /[*?]/) {
# contains * or ? so it's converted to a regex
my $mask_quoted = quotemeta $mask;
$mask_quoted =~ s/\\\*/.*?/g;
$mask_quoted =~ s/\\\?/./g;
if ($hostmask =~ m/^$mask_quoted$/i) {
if ($last_level <= $self->{users}->{hash}->{$chan}->{$mask}->{level}) {
$found_hostmask = $mask;
$found_channel = $chan;
$last_level = $self->{users}->{hash}->{$chan}->{$mask}->{level};
}
}
}
}
}
}
}
return $hostmask;
return ($found_channel, $found_hostmask);
}
sub find_admin {
my ($self, $channel, $hostmask, $min_level) = @_;
$min_level //= 1;
($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
$channel = $self->{pbot}->{registry}->get_value('irc', 'botnick') if not defined $channel;
$hostmask = '.*' if not defined $hostmask;
$hostmask = lc $hostmask;
@ -199,13 +206,13 @@ sub find_admin {
$hostmask_quoted =~ s/\\\?/./g;
if ($hostmask =~ m/^$hostmask_quoted$/i) {
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex};
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} < $temp->{level});
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} <= $temp->{level});
}
} else {
# direct comparison
if ($hostmask eq lc $hostmask_regex) {
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex};
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} < $temp->{level});
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} <= $temp->{level});
}
}
}
@ -271,6 +278,15 @@ sub logout {
delete $user->{loggedin} if defined $user;
}
sub get_loggedin_user_metadata {
my ($self, $channel, $hostmask, $key) = @_;
my $user = $self->loggedin($channel, $hostmask);
if ($user) {
return $user->{lc $key};
}
return undef;
}
sub logincmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $channel = $from;
@ -314,6 +330,7 @@ sub useradd {
my $admin = $self->{pbot}->{users}->find_admin($channel, "$nick!$user\@$host");
if (not $admin) {
$channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot add users to that channel.\n";
}
@ -335,8 +352,7 @@ sub userdel {
return "/msg $nick Usage: userdel <channel> <hostmask or account name>";
}
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
$channel = '.*' if $channel !~ /^#/;
($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
return $self->remove_user($channel, $hostmask);
}
@ -348,15 +364,16 @@ sub userset {
return "Usage: userset <channel> <hostmask or account name> [key] [value]";
}
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
my $admin = $self->find_admin($channel, "$nick!$user\@$host");
my $target = $self->find_user($channel, $hostmask);
if (not $admin) {
$channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot modify their users.";
}
if (not $target) {
$channel = 'global' if $channel eq '.*';
return "There is no user $hostmask in channel $channel.";
}
@ -369,7 +386,7 @@ sub userset {
return "You may not modify users higher in level than you.";
}
$channel = '.*' if $channel !~ /^#/;
($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
my $result = $self->{users}->set($channel, $hostmask, $key, $value);
$result =~ s/^password => .*;$/password => <private>;/m;
return $result;
@ -384,22 +401,23 @@ sub userunset {
}
my $admin = $self->find_admin($channel, "$nick!$user\@$host");
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
my $target = $self->find_user($channel, $hostmask);
if (not $admin) {
$channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot modify their users.";
}
if (not $target) {
$channel = 'global' if $channel eq '.*';
return "There is no user $hostmask in channel $channel.";
}
if ($target->{level} >= $user->{level}) {
return "You may not modify users equal or higher in level than you.";
if ($target->{level} > $admin->{level}) {
return "You may not modify users higher in level than you.";
}
$channel = '.*' if $channel !~ /^#/;
($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
return $self->{users}->unset($channel, $hostmask, $key);
}
@ -411,14 +429,11 @@ sub mycmd {
return "Usage: my <key> [value]";
}
$key = lc $key;
my $channel = $from;
$channel = '.*' if $channel !~ /^#/;
my $hostmask = $self->hostmask_or_account_name($channel, "$nick!$user\@$host");
my $u = $self->find_user($channel, $hostmask);
my $hostmask = "$nick!$user\@$host";
print "hostmask: $hostmask\n";
use Data::Dumper;
print Dumper \$u;
my $u = $self->find_user($channel, $hostmask);
if (not $u) {
$channel = '.*';
@ -428,13 +443,15 @@ sub mycmd {
$u->{loggedin} = 1;
}
if ($u->{level} == 0) {
if (defined $value and $u->{level} == 0) {
my @disallowed = qw/level autoop autovoice/;
if (grep { lc $key } @disallowed) {
if (grep { $_ eq $key } @disallowed) {
return "You must be an admin to set $key.";
}
}
($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
my $result = $self->{users}->set($channel, $hostmask, $key, $value);
$result =~ s/^password => .*;$/password => <private>;/m;
return $result;

55
Plugins/Date.pm Normal file
View File

@ -0,0 +1,55 @@
# File: Date.pm
# Author: pragma-
#
# Purpose: Adds command to display time and date for timezones.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
package Plugins::Date;
use warnings;
use strict;
use feature 'unicode_strings';
use Carp ();
sub new {
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref $_[1] eq 'HASH';
my ($class, %conf) = @_;
my $self = bless {}, $class;
$self->initialize(%conf);
return $self;
}
sub initialize {
my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'date', 'default_timezone', 'UTC');
$self->{pbot}->{commands}->register(sub { $self->datecmd(@_) }, "date", 0);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("date");
}
sub datecmd {
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
my $timezone = $self->{pbot}->{registry}->get_value('date', 'default_timezone') // 'UTC';
my $tz_override = $self->{pbot}->{users}->get_loggedin_user_metadata($from, "$nick!$user\@$host", 'timezone');
$timezone = $tz_override if $tz_override;
my $newstuff = {
from => $from, nick => $nick, user => $user, host => $host,
command => "date_module $timezone", root_channel => $from, root_keyword => "date_module",
keyword => "date_module", arguments => "$timezone"
};
$self->{pbot}->{factoids}->{factoidmodulelauncher}->execute_module($newstuff);
}
1;

13
data/factoids vendored
View File

@ -5540,6 +5540,19 @@
"ref_user" : "esselfe!~bsfc@unaffiliated/esselfe",
"type" : "text"
},
"date_module" : {
"_name" : "date_module",
"action" : "date.sh",
"add_nick" : 1,
"created_on" : 1579985843.56774,
"enabled" : 1,
"nooverride" : 1,
"owner" : "pragma-!~chaos@unaffiliated/pragmatic-chaos",
"rate_limit" : "15",
"ref_count" : 0,
"ref_user" : "nobody",
"type" : "module"
},
"ddd" : {
"_name" : "ddd",
"action" : "a graphical front end to gdb and other debuggers (http://www.gnu.org/software/ddd/)",

13
modules/date.sh vendored Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
export TZ=UTC
if (( $# )) && ! read -r TZ < <(IFS=_; find -L /usr/share/zoneinfo/posix -type f -iname "*$**" -printf '%P\n' -quit); then
echo "No match for '$*'." >&2
exit 1
fi
if [[ $TZ != UTC ]]; then
_city=${TZ##*/}
echo "It's $(date) in ${_city//_/ }."
else
echo "It's $(date)."
fi