App-RoboBot

 view release on metacpan or  search on metacpan

doc/conf.py  view on Meta::CPAN

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {'**': ['localtoc.html', 'custom_sidebar.html', 'searchbox.html']}
html_sidebars = {'**': ['custom_sidebar.html']}

# Additional templates that should be rendered to pages, maps page names to

doc/lang/types/index.rst  view on Meta::CPAN


Which invokes the ``my-cool-function`` function, providing it with a single
string argument of ``foo``. Some functions take functions as their arguments

Macros
======

Macros bear striking resemblance in their operation to functions, with the most
distinguishing feature being that macros are user-defined by anyone on your
connected chat networks with access to the :ref:`function-core-macro-defmacro`
function. They exist within the :ref:`lang-scope-network`, and may be updated
and invoked at will using the same, fundamental S-expression syntax used
everywhere else. For example::

    (defmacro my-cool-macro [input-string]
        '(format "I just did something with %s!" input-string))
    (my-cool-macro "foo")
    "I just did something with foo!"

Numerics
========

lib/App/RoboBot/Network/Slack.pm  view on Meta::CPAN

        where network_id = ? and lower(name) = lower(?)
    }, $self->id, $chandata->{'name'});

    if ($res && $res->next) {
        $res->{'extradata'} = decode_json($res->{'extradata'});
        $res->{'extradata'}{'slack_id'} = $slack_id;

        $self->bot->config->db->do(q{
            update channels
            set extradata = ?,
                updated_at = now() where id = ?
        }, encode_json($res->{'extradata'}), $res->{'id'});

        $channel = App::RoboBot::Channel->new(
            id          => $res->{'id'},
            name        => $res->{'name'},
            extradata   => $res->{'extradata'},
            network     => $self,
            config      => $self->bot->config,
        );

lib/App/RoboBot/Network/Slack.pm  view on Meta::CPAN

    }, $userdata->{'user'}{'name'});

    if ($res && $res->next) {
        $res->{'extradata'} = decode_json($res->{'extradata'});
        $res->{'extradata'}{'slack_id'} = $slack_id;
        $res->{'extradata'}{'full_name'} = $userdata->{'user'}{'profile'}{'real_name'} if exists $userdata->{'user'}{'profile'}{'real_name'};

        $self->bot->config->db->do(q{
            update nicks
            set extradata = ?,
                updated_at = now()
            where id = ?
        }, encode_json($res->{'extradata'}), $res->{'id'});

        $nick = App::RoboBot::Nick->new(
            id        => $res->{'id'},
            name      => $res->{'name'},
            extradata => $res->{'extradata'},
            network   => $self,
            config    => $self->bot->config,
        );

lib/App/RoboBot/Plugin/API/Kegerator.pm  view on Meta::CPAN


    return if $@;
    return $json;
}

sub _run_watcher {
    my ($self, $bot) = @_;

    # TODO: Call base API path, get JSON

    # TODO: Loop through keg list, compare each one's last_updated with the
    #       plugin's last_check attribute. Any with a new update should be
    #       added to a list of tap#->beerid

    # TODO: If any tap#'s were marked as new, call the beer detail API endpoint
    #       to get beer name, ABV, IBU, etc.

    # TODO: If any @output to send, construct a mock Response object for each
    #       plugin->notice[server+channel], and send notifications out.

    # TODO: Update plugin's last_check timestamp.

lib/App/RoboBot/Plugin/Bot/Alarm.pm  view on Meta::CPAN

        from alarms_alarms a
        where a.id = ?
    }, $alarm_id);

    return unless $res && $res->next;

    $res->{'exclusions'} = decode_json($res->{'exclusions'});

    if ($res->{'do_recalc'} && $res->{'recurrence'}) {
        # Alarm's recorded next occurrence has expired, so we need to recalc
        # and updated the database before we send the alarm back to the caller.

        # Pad the clause so a lack of exclusions doesn't generate bad SQL.
        my @where = qw( false );
        my @binds;

        foreach my $excl (@{$res->{'exclusions'}}) {
            push(@where, 'to_char(s.new_emit, ?) ~* ?');
            push(@binds, $excl->{'format'}, $excl->{'pattern'});
        }

lib/App/RoboBot/Plugin/Bot/Autoreply.pm  view on Meta::CPAN

    }, {
        condition  => $condition->flatten,
        response   => $response->flatten,
        created_by => $message->sender->id,
        created_at => 'now',
    }, $message->channel->id, $name);

    if ($res && $res->next) {
        $self->log->debug('Autoreplier update successful.');

        $message->response->push(sprintf('Autoreply %s has been updated.', $name));
    } else {
        $self->log->debug(sprintf('No existing autoreplier to update. Creating new record.'));

        $res = $self->bot->config->db->do(q{
            insert into autoreply_autoreplies ??? returning *
        }, {
            channel_id  => $message->channel->id,
            name        => lc($name),
            condition   => $condition->flatten,
            response    => $response->flatten,

lib/App/RoboBot/Plugin/Bot/Autoreply.pm  view on Meta::CPAN

        if ($res && $res->next) {
            $message->response->push(sprintf('Autoreply %s has been added.', $name));
        } else {
            $self->log->error(sprintf('Could not create autoreplier record: %s', $res->error));

            $message->response->raise('Could not create the autoresponse. Please check your arguments and try again.');
            return;
        }
    }

    $self->log->debug(sprintf('Caching new/updated autoreplier %s.', $name));

    $self->reply_cache->{$message->channel->id}{lc($name)} = {
        condition   => $condition,
        response    => $response,
    };

    return;
}

sub autoreply_list {

lib/App/RoboBot/Plugin/Core/Variables.pm  view on Meta::CPAN

        return $self->unset_global($message, $command, $var_name);
    }

    my $res = $self->bot->config->db->do(q{
        update global_vars
        set ???
        where network_id = ?
            and lower(var_name) = lower(?)
    }, {
        var_values => \@values,
        updated_at => 'now',
    }, $message->network->id, $var_name);

    if ($res && $res->count > 0) {
        $message->response->push(sprintf('Global variable %s has been updated.', $var_name));
        return;
    }

    $res = $self->bot->config->db->do(q{
        insert into global_vars ??? returning *
    }, {
        network_id => $message->network->id,
        var_name   => $var_name,
        var_values => \@values,
        created_by => $message->sender->id,

lib/App/RoboBot/Plugin/Fun/Factoid.pm  view on Meta::CPAN

        from factoids
        where network_id = ? and lower(name) = lower(?)
    }, $message->network->id, $name);

    if ($res && $res->next) {
        $res = $self->bot->config->db->do(q{
            update factoids
            set name       = ?,
                factoid    = ?,
                terms      = setweight(to_tsvector(?), 'A') || setweight(to_tsvector(?), 'B'),
                updated_by = ?,
                updated_at = now()
            where id = ?
            returning *
        }, $name, $fact_body, $name, $fact_body, $message->sender->id, $res->{'id'});

        if ($res && $res->next) {
            $message->response->push(sprintf('Factoid %s (%d) updated.', $res->{'name'}, $res->{'id'}));
        } else {
            $message->response->raise('Could not update existing factoid. Please try again.');
        }
    } else {
        $res = $self->bot->config->db->do(q{
            insert into factoids (network_id, name, factoid, created_by, terms) values
                (?, ?, ?, ?, setweight(to_tsvector(?), 'A') || setweight(to_tsvector(?), 'B'))
            returning *
        }, $message->network->id, $name, $fact_body, $message->sender->id, $name, $fact_body);

lib/App/RoboBot/Plugin/Fun/Markov.pm  view on Meta::CPAN

    return ($l,$r);
}

sub save_phrases {
    my ($self, $message, $phrases) = @_;

    foreach my $phrase (@{$phrases}) {
        my $res = $self->bot->config->db->do(q{
            update markov_phrases
            set used_count = used_count + 1,
                updated_at = now()
            where nick_id = ? and phrase = ?
            returning id
        }, $message->sender->id, $phrase->{'phrase'});

        next if $res && $res->next;

        $res = $self->bot->config->db->do(q{
            insert into markov_phrases ??? returning id
        }, { nick_id         => $message->sender->id,
             structure       => $phrase->{'structure'},

lib/App/RoboBot/Plugin/Fun/Markov.pm  view on Meta::CPAN

                }, $message->sender->id, '%' . $neighbor);

                next NEIGHBOR unless $res && $res->next;

                $neighbor_id = $phrase_ids{$neighbor} = $res->{'id'};
            }

            $res = $self->bot->config->db->do(q{
                update markov_neighbors
                set occurrences = occurrences + 1,
                    updated_at = now()
                where phrase_id = ? and neighbor_id = ?
            }, $phrase_id, $neighbor_id);

            next NEIGHBOR if $res && $res->count > 0;

            $res = $self->bot->config->db->do(q{
                insert into markov_neighbors ???
            }, {
                phrase_id   => $phrase_id,
                neighbor_id => $neighbor_id,

lib/App/RoboBot/Plugin/Fun/Markov.pm  view on Meta::CPAN


    return unless defined $form;

    my @parts_of_speech = $form =~ m{\b([A-Z]+)\b}og;

    $form = join(' ', @parts_of_speech);

    my $res = $self->bot->config->db->do(q{
        update markov_sentence_forms
        set used_count = used_count + 1,
            updated_at = now()
        where nick_id = ? and structure = ?
        returning id
    }, $message->sender->id, $form);

    return 1 if $res && $res->next;

    $res = $self->bot->config->db->do(q{
        insert into markov_sentence_forms ??? returning id
    }, { nick_id         => $message->sender->id,
         structure       => $form,

lib/App/RoboBot/Plugin/Social/Locations.pm  view on Meta::CPAN


<nick>

=head3 Examples

    :emphasize-lines: 2-4

    (where-is Beauford)
    Beauford: Vancouver Campus
    I'll be working out of Vancouver HQ for the week.
    Last updated: Thursday, 28th April 2016 at 11:15am

=cut

has '+commands' => (
    default => sub {{
        'set-location' => { method      => 'location_set',
                            description => 'Sets your most recent location, along with an optional message, which others may view with the (where-is) function.',
                            usage       => '<location name> [<detailed message>]',
                            example     => '"Working from home" "doc appt this afternoon, taking an extended lunch"' },

lib/App/RoboBot/Plugin/Social/Locations.pm  view on Meta::CPAN

        nick_id     => $message->sender->id,
        loc_name    => $location,
        loc_message => $detail_msg,
    });

    unless ($res && $res->next) {
        $message->response->raise('Could not set your location. Please try again.');
        return;
    }

    $message->response->push('Your location has been updated.');
    return;
}

sub location_nick {
    my ($self, $message, $command, $rpl, $name) = @_;

    unless (defined $name && $name =~ m{\w+}) {
        $message->response->raise('You must provide the name of the person whose location you want to see.');
        return;
    }

lib/App/RoboBot/Plugin/Social/Locations.pm  view on Meta::CPAN

    }, $message->network->id, "%${name}%");

    unless ($res && $res->next) {
        $message->response->push(sprintf('No location information found for %s.', $name));
        return;
    }

    $message->response->push(sprintf('*%s*: %s', $res->{'name'}, $res->{'loc_name'}));
    $message->response->push(sprintf('%s', $res->{'loc_message'}))
        if $res->{'loc_message'} && $res->{'loc_message'} ne 'no-message';
    $message->response->push(sprintf('Last updated: %s', $res->{'created_at'}));

    return;
}

__PACKAGE__->meta->make_immutable;

1;

lib/App/RoboBot/Plugin/Social/Skills.pm  view on Meta::CPAN

        set description = ?
        where lower(?) = lower(name)
        returning *
    }, $desc, $skill);

    unless ($res && $res->next) {
        $message->response->raise('Could not add a description to the skill "%s". Please make sure the skill exists and try again.', $skill);
        return;
    }

    $message->response->push(sprintf('Description for %s has been updated.', $skill));
    return;
}

sub skill_dontknow {
    my ($self, $message, $command, $rpl, @skills) = @_;

    unless (@skills) {
        $message->response->push('Must supply skill name(s) to remove.');
        return;
    }

lib/App/RoboBot/Plugin/Social/Voting.pm  view on Meta::CPAN

                       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) = @_;

lib/App/RoboBot/Plugin/Social/Voting.pm  view on Meta::CPAN

        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));

share/migrations/deploy/base.sql  view on Meta::CPAN


BEGIN;

CREATE SCHEMA robobot AUTHORIZATION robobot;

CREATE TABLE robobot.nicks (
    id          serial not null,
    name        text not null,
    extradata   jsonb not null default '{}'::jsonb,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE UNIQUE INDEX ON robobot.nicks (lower(name));

CREATE TABLE robobot.networks (
    id          serial not null,
    name        text not null,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE UNIQUE INDEX ON robobot.networks (lower(name));

CREATE TABLE robobot.channels (
    id          serial not null,
    network_id  integer not null references robobot.networks (id) on update cascade on delete cascade,
    name        text not null,
    log_enabled boolean not null default true,
    extradata   jsonb not null default '{}'::jsonb,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE UNIQUE INDEX ON robobot.channels (network_id, lower(name));

COMMIT;

share/migrations/deploy/p-auth-20161128164909.sql  view on Meta::CPAN

BEGIN;

CREATE TABLE robobot.auth_permissions (
    permission_id   serial not null,
    network_id      integer not null references robobot.networks (id) on update cascade on delete cascade,
    nick_id         integer references robobot.nicks (id) on update cascade on delete cascade,
    command         text not null,
    state           text not null,
    granted_by      integer not null references robobot.nicks (id) on update cascade on delete restrict,
    created_at      timestamp with time zone not null default now(),
    updated_at      timestamp with time zone,

    PRIMARY KEY (permission_id)
);
CREATE UNIQUE INDEX ON robobot.auth_permissions (network_id, nick_id, lower(command));
CREATE INDEX ON robobot.auth_permissions (nick_id);
CREATE INDEX ON robobot.auth_permissions (lower(command));
CREATE INDEX ON robobot.auth_permissions (granted_by);

COMMIT;

share/migrations/deploy/p-factoids-20161128182038.sql  view on Meta::CPAN

BEGIN;

CREATE TABLE robobot.factoids (
    id          serial not null,
    network_id  integer not null references robobot.networks (id) on update cascade on delete cascade,
    name        text not null,
    factoid     text not null,
    terms       tsvector not null,
    created_by  integer not null references robobot.nicks (id) on update cascade on delete cascade,
    created_at  timestamp with time zone not null default now(),
    updated_by  integer references robobot.nicks (id) on update cascade on delete set null,
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE UNIQUE INDEX ON robobot.factoids (network_id, lower(name));
CREATE INDEX ON robobot.factoids (lower(name));
CREATE INDEX ON robobot.factoids (created_by);
CREATE INDEX ON robobot.factoids (updated_by);

COMMIT;

share/migrations/deploy/p-markov-20161128212720.sql  view on Meta::CPAN


BEGIN;

CREATE TABLE robobot.markov_phrases (
    id          serial not null,
    nick_id     integer not null references robobot.nicks (id) on update cascade on delete cascade,
    structure   text not null,
    phrase      text not null,
    used_count  integer not null default 1,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE INDEX ON robobot.markov_phrases (nick_id);
CREATE INDEX ON robobot.markov_phrases (structure);

CREATE TABLE robobot.markov_sentence_forms (
    id              serial not null,
    nick_id         integer not null references robobot.nicks (id) on update cascade on delete cascade,
    structure       text not null,
    structure_jsonb jsonb,
    used_count      integer not null default 1,
    created_at      timestamp with time zone not null default now(),
    updated_at      timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE INDEX ON robobot.markov_sentence_forms (nick_id);

CREATE TABLE robobot.markov_neighbors (
    phrase_id   integer not null references robobot.markov_phrases (id) on update cascade on delete cascade,
    neighbor_id integer not null references robobot.markov_phrases (id) on update cascade on delete cascade,
    occurrences integer not null default 1,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (phrase_id, neighbor_id)
);
CREATE INDEX ON robobot.markov_neighbors (neighbor_id);

COMMIT;

share/migrations/deploy/p-variables-20161128195027.sql  view on Meta::CPAN


BEGIN;

CREATE TABLE robobot.global_vars (
    id          serial not null,
    network_id  integer not null references robobot.networks (id) on update cascade on delete cascade,
    var_name    text not null,
    var_values  text[] not null,
    created_by  integer not null references robobot.nicks (id) on update cascade on delete cascade,
    created_at  timestamp with time zone not null default now(),
    updated_at  timestamp with time zone,

    PRIMARY KEY (id)
);
CREATE UNIQUE INDEX ON robobot.global_vars (network_id, var_name);
CREATE INDEX ON robobot.global_vars (created_by);

COMMIT;



( run in 0.366 second using v1.01-cache-2.11-cpan-05444aca049 )