8 use base 'Bot::BasicBot';
10 use DBI qw/:sql_types/;
15 my $mu_re = qr/^([^ ]+) (https?:\/\/[^ ]+) (.+)$/i;
20 my $fb = Facebook::Graph->new(app_id => $me->{cfg}->{fb_app_id},
21 secret => $me->{cfg}->{fb_app_secret},
22 postback => $me->{cfg}->{fb_postback_url});
24 my $res_token = $fb->request_access_token($me->{cfg}->{fb_access_code});
25 die 'token get error' if (!defined $res_token || !$res_token->response->is_success);
27 my $acts = $fb->fetch('me/accounts');
28 die 'can not get account list' if(!defined $acts || !$acts);
30 my $page_access_token = '';
31 foreach my $d (@{$acts->{data}}) {
32 if ($d->{id} eq $me->{cfg}->{fb_page_id}) {
33 $page_access_token = $d->{'access_token'};
36 die 'can not get access tokenfor page_id=' . $me->{cfg}->{fb_page_id} if ($page_access_token eq '');
38 return $me->{fbo} = Facebook::Graph->new(access_token => $page_access_token);
43 $me->{dbh} = DBI->connect('DBI:mysql:'.$me->{cfg}->{database}, $me->{cfg}->{db_user}, $me->{cfg}->{db_pass}) || die $DBI::errstr;
49 $me->{last_search} = {};
53 my ($me, $text, $uri) = @_;
55 return $me->{fbo}->add_post($me->{cfg}->{fb_page_id})
69 my ($me, $args, $uri) = @_;
73 my $sth = $me->{dbh}->prepare('select * from posts where uri = ? order by post_time desc limit 1');
74 my $rv = $sth->execute($uri);
75 my $res = $sth->fetchrow_hashref;
77 if ($res->{post_time} < time() - 7 * 24 * 60 * 60) {
78 $me->_response($args, 'だいぶ前 '.$me->_format_submit($res).'にいってたにゃー '.$me->_fb_post_uri($res->{fb_post_id}));
80 $me->_response($args, '既に '.$me->_format_submit($res).'に言ってますよ? '.$me->{cfg}->{fb_page_url}.'posts/'.$res->{fb_post_id});
90 my ($me, $db_args) = @_;
92 my ($scheme, $path) = split(!://!, $db_args->{uri});
93 my $sth = $me->{dbh}->prepare("insert into posts (submitter, fb_post_id, uri, prefix, suffix, scheme, path, post_time) values (?, ?, ?, ?, ?, ?)");
94 $sth->bind_param(1, $db_args->{submitter}, SQL_TEXT);
95 $sth->bind_param(2, $db_args->{fb_post_id}, SQL_BIGINT);
96 $sth->bind_param(3, $db_args->{uri}, SQL_TEXT);
97 $sth->bind_param(4, $db_args->{prefix}, SQL_TEXT);
98 $sth->bind_param(5, $db_args->{suffix}, SQL_TEXT);
99 $sth->bind_param(6, $scheme, SQL_TEXT);
100 $sth->bind_param(7, $path, SQL_TEXT);
101 $sth->bind_param(8, time, SQL_BIGINT);
102 my $rv = $sth->execute();
109 my ($me, $db_args) = @_;
110 $db_args->{submitter_type} = 1 unless defined $db_args->{submitter_type};
112 my $sth = $me->{dbh}->prepare("delete from posts where fb_post_id = ? and submitter = ? and submitter_type = ?");
114 $sth->bind_param(1, $db_args->{fb_post_id}, SQL_BIGINT);
115 $sth->bind_param(2, $db_args->{submitter}, SQL_VARCHAR);
116 $sth->bind_param(3, $db_args->{submitter_type}, SQL_INTEGER);
117 my $rv = $sth->execute();
119 my $ret = $rv ? $sth->rows : 0;
127 my ($me, $word) = @_;
129 my $sth = $me->{dbh}->prepare('select * from posts where match(prefix,uri,suffix) against(?) order by post_time desc limit 1000');
130 $sth->bind_param(1, $word, SQL_VARCHAR);
133 my $ret = $sth->fetchall_arrayref({});
140 my ($me, $post_id) = @_;
142 return $me->{cfg}->{fb_page_url} . 'posts/' . $post_id;
148 return decode('utf8', $e->{submitter}).'が「'.decode('utf8', $e->{prefix}).' '.decode('utf8', $e->{uri}).' '.decode('utf8', $e->{suffix}).'」と'.strftime('%Y-%m-%d %H:%M:%S', localtime($e->{post_time}));
152 my ($me, $args, $msg) = @_;
154 $me->say(channel => $args->{channel},
161 my ($resp, $resp_msg);
163 if ($args->{body} =~ /$mu_re/) {
167 my $text = $args->{who} . '曰く、'.$prefix.' '.$suffix;
169 return 0 if ($me->_check_dup($args, $uri));
171 eval{$resp = $me->publish($text, $uri)};
174 eval{$resp = $me->publish($text, $uri)};
175 $post_ok = 0 if ($@);
179 my (undef, $post_id) = split(/_/, $resp->{id});
180 $me->_db_insert({submitter => $args->{who},
181 fb_post_id => $post_id,
185 $resp_msg = $args->{who} . ': うい '.$me->_fb_post_uri($post_id).' で登録';
187 $resp_msg = 'can not post to facebook';
196 my ($me, $args) = @_;
201 sub _delete_post_id {
202 my ($me, $args) = @_;
208 my ($me, $args, $post_id) =@_;
210 $me->{dbh}->begin_work;
211 if ($me->_db_delete(fb_post_id => $post_id, submitter => $args->{who})) {
212 # fb 側のエントリを削除しないといけない
215 $me->{dbh}->rollback;
221 my ($me, $args) = @_;
223 if ($args->{body} =~ /^ふみくん (.+)\?$/) {
224 $me->{last_search}->{$args->{who}} = undef;
225 $me->{last_search}->{$args->{who}} = $me->_db_search($1);
226 return $me->_search_next($args);
231 my ($me, $args) = @_;
233 my $resp_msg = 'ないっす';
234 if (defined $me->{last_search}->{$args->{who}}) {
235 my $ent = pop($me->{last_search}->{$args->{who}});
237 my $count = @{$me->{last_search}->{$args->{who}}};
240 $resp_msg = $args->{who} . ': ' . $me->_format_submit($ent).'に言ってた'.($count ? '[ほか'.$count.'件] ' : '[ほかにはもうないよ] ').$me->_fb_post_uri($ent->{fb_post_id});
251 my ($me, $args) = @_;
254 if ($args->{body} =~ /$mu_re/) {
255 $resp_msg = $me->_add($args) unless ($1 eq 'deb');
256 } elsif ($args->{body} =~ /^ふみくん\s+(.+)\s*$/) {
258 if ($cmd eq 'いまのなし') {
259 $resp_msg = $me->_delete_prev($args);
260 } elsif ($cmd =~ /削除\s+(?:$me->{cfg}->{fb_page_url}posts\/)?([0-9]+)$/) {
261 $resp_msg = $me->_delete_post_id($args, $1);
262 } elsif ($cmd =~ /\?$/) {
263 $resp_msg = $me->_search_start($args);
264 } elsif ($cmd =~ /つぎ/) {
265 $resp_msg = $me->_search_next($args);
269 $me->_response($args, $resp_msg) if ($resp_msg);
279 my $config_name = $ARGV[0] || 'not_found';
282 my $config_path = ('/etc/mubot4fb/', $ENV{HOME} . '/.mubot4fb/', $ENV{PWD} . '/mubot4fb_');
283 foreach my $c ($config_path) {
284 my $config = $c . $config_name . '.conf';
285 Config::Simple->import_from($config, \%cfg) if (-e $config);
287 die 'missing config file' unless (keys %cfg);
289 die 'missing some config parameters should be defined (irc_server, fb_app_id, fb_app_secret, fb_access_code, fb_page_id fb_postback_url)'
290 if (!defined $cfg{'irc_server'}
291 || !defined $cfg{'fb_app_id'}
292 || !defined $cfg{'fb_app_secret'}
293 || !defined $cfg{'fb_access_code'}
294 || !defined $cfg{'fb_page_id'}
295 || !defined $cfg{'fb_postback_url'}
296 || !defined $cfg{'db_user'}
297 || !defined $cfg{'db_pass'}
300 $cfg{irc_port} ||= 6667;
301 $cfg{irc_channels} ||= ['#mubot4fb'];
302 $cfg{irc_nick} ||= 'mubot4fb';
303 $cfg{irc_name}||= $cfg{irc_nick};
304 $cfg{irc_charset} ||= 'utf8';
305 $cfg{database} ||= 'mubot4fb';
307 my $bot = Mubot4FB->new(server => $cfg{'irc_server'},
308 port => $cfg{'irc_port'},
309 channels => $cfg{'irc_channels'},
310 nick => $cfg{'irc_nick'},
311 username => $cfg{'irc_name'},
312 name => $cfg{'irc_name'},
313 charset => $cfg{'irc_charset'},
314 cfg => \%cfg)->run();