App-RoboBot
view release on metacpan or search on metacpan
lib/App/RoboBot/Network/Slack.pm view on Meta::CPAN
my ($json, $chandata);
# Slack has different API endpooints for channels and private groups, so
# make sure we're using the right one based on the first character of the
# identifier. And some, like direct messages, return fairly different data
# structures, so each type should handle decoding and massaging their own.
if (substr($slack_id, 0, 1) eq 'C') {
$json = get('https://slack.com/api/channels.info?token=' . $self->token . '&channel=' . $slack_id);
eval { $json = decode_json($json) };
return if $@;
return unless exists $json->{'ok'} && $json->{'ok'};
return unless exists $json->{'channel'};
$chandata = $json->{'channel'};
} elsif (substr($slack_id, 0, 1) eq 'G') {
$json = get('https://slack.com/api/groups.info?token=' . $self->token . '&channel=' . $slack_id);
eval { $json = decode_json($json) };
return if $@;
return unless exists $json->{'ok'} && $json->{'ok'};
return unless exists $json->{'group'};
$chandata = $json->{'group'};
} elsif (substr($slack_id, 0, 1) eq 'D') {
# This was a direct message, which requires some additional handling.
$json = get('https://slack.com/api/im.list?token=' . $self->token);
eval { $json = decode_json($json) };
return if $@;
return unless exists $json->{'ok'} && $json->{'ok'};
return unless exists $json->{'ims'} && ref($json->{'ims'}) eq 'ARRAY';
$chandata = (grep { $_->{'id'} eq $slack_id } @{$json->{'ims'}})[0];
return unless defined $chandata && ref($chandata) eq 'HASH';
return unless exists $chandata->{'user'};
return if $chandata->{'user'} eq 'USLACKBOT';
my $nick = $self->resolve_nick($chandata->{'user'});
# Mock up a channel name for the DM history with this user.
$chandata->{'name'} = sprintf('dm:%s', $nick->name);
} else {
# Not a group or a channel or a direct message, bail out.
return;
}
return unless defined $chandata && ref($chandata) eq 'HASH';
$res = $self->bot->config->db->do(q{
select id, name, extradata
from channels
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,
);
$self->channel_cache->{$slack_id} = $channel;
return $channel;
}
$res = $self->bot->config->db->do(q{
insert into channels ??? returning id, name, extradata
}, { name => $chandata->{'name'},
network_id => $self->id,
extradata => encode_json({ slack_id => $slack_id }),
});
if ($res && $res->next) {
$channel = App::RoboBot::Channel->new(
id => $res->{'id'},
name => $res->{'name'},
extradata => decode_json($res->{'extradata'}),
network => $self,
config => $self->bot->config,
);
$self->channel_cache->{$slack_id} = $channel;
return $channel;
}
return;
}
sub resolve_nick {
my ($self, $slack_id) = @_;
# User profile already in our cache (we've seen or created it during this
# session, so simply return what we have.
return $self->profile_cache->{$slack_id} if exists $self->profile_cache->{$slack_id};
# Check database for a nick with this Slack ID. If found, instantiate a new
# App::RoboBot::Nick object with the data, cache it, and return.
my $nick;
my $res = $self->bot->config->db->do(q{
select id, name, extradata
from nicks where extradata @> ?
}, encode_json({ slack_id => $slack_id }));
if ($res && $res->next) {
$nick = App::RoboBot::Nick->new(
id => $res->{'id'},
name => $res->{'name'},
extradata => decode_json($res->{'extradata'}),
network => $self,
config => $self->config,
);
$self->profile_cache->{$slack_id} = $nick;
return $nick;
}
# We haven't encountered this nick before, so we need to query the SlackAPI
# for their handle and other profile details.
my $json = get('https://slack.com/api/users.info?token=' . $self->token . '&user=' . $slack_id);
return unless defined $json;
my $userdata = decode_json($json);
return unless defined $userdata && ref($userdata) eq 'HASH' && exists $userdata->{'ok'} && $userdata->{'ok'};
# Now that we know their handle, we can see if we already have a record for
# that. If so, we update it to include their Slack ID, drop it in our cache,
# and return the nick object.
$res = $self->bot->config->db->do(q{
select id, name, extradata
from nicks
where lower(name) = lower(?)
}, $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,
);
$self->profile_cache->{$slack_id} = $nick;
return $nick;
}
# And finally, we've had no luck finding any matches, so we assume that the
# nick is totally new to us. Create a new record, cache that, and return.
my $extra = { slack_id => $slack_id };
$extra->{'full_name'} = $userdata->{'user'}{'profile'}{'real_name'} if exists $userdata->{'user'}{'profile'}{'real_name'};
$res = $self->bot->config->db->do(q{
insert into nicks ??? returning id, name, extradata
}, { name => $userdata->{'user'}{'name'},
extradata => encode_json($extra),
});
if ($res && $res->next) {
$nick = App::RoboBot::Nick->new(
id => $res->{'id'},
name => $res->{'name'},
extradata => decode_json($res->{'extradata'}),
network => $self,
config => $self->bot->config,
);
$self->profile_cache->{$slack_id} = $nick;
return $nick;
}
return;
}
__PACKAGE__->meta->make_immutable;
1;
( run in 1.208 second using v1.01-cache-2.11-cpan-39bf76dae61 )