LoginSignup
21
17

More than 5 years have passed since last update.

つい消しをSlackで知らせるBot作ってみた

Last updated at Posted at 2016-08-02

ついけしを知らせるBot作ってみた

目次

  1. 本文の前に
  2. Botの説明
  3. コードと説明(各自Session有り)
  4. まとめ

本文の前に

この記事はTwitterAPIに触れたことはないけど他のAPIなら触ったことあるお!ってぐらいのレベルの人向けですので、あしからず
Twitterって便利ですよね。リアルタイムに皆が思ってることを投げまくって、TLにリスト表示してくれて。
けどその反面、炎上とか炎上とか自宅特定とか、あることないこととか、色々投稿されてて割りと怖い
(いつ炎上するか割と怯えてる)

そんで、Twitterには削除機能というものがある。編集機能も早くつけて欲しいが、削除はある。
削除があるってことは、自分がフォローしてるフォロワーさんの投稿を見逃す可能性があるということだ、これは悲しいと言うか
悔しい気持ちになる(知らぬが仏)後で、有名な人のツイ消しが話題になったりして、見逃した日には、夜も寝れないことだろう

なので、つい消しされたらSlackに消された文章と一緒に通知してくれる、迷惑なBotを作ってみた。

Botの説明

TwitterにはAPIがある。まあどこのサービスにもAPIはあるのだが、TwitterにはTweetが消された場合にアクションを起こす物がある。
今回はそれを使って、つい消しを判定することにした。だが!そのTwitterから送られてくるDeleteActionに
メッセージ(本文)などは付いておらす、前世の記憶はTwieetIDしかしらないらしい。ので!普通のStreamingActionが送られてきた時には、以下の写真のように、色々なデータが入ってくる。これを受信するたびにDBに保存して、削除された時に呼び出してこよう!って魂胆である。

スクリーンショット 2016-08-02 12.01.17.png

サービスのモデルに関してはこんな感じ

スクリーンショット 2016-08-02 11.56.12.png

BotはTwitterAPIと常に対話させておき、データが飛んできたらSinatraAPI(自作API)にJSONでデータを飛ばして、DBにSinatraAPIが保存させるといった感じで、それそれの機能ごとに分割してます。

コードの説明

コードの全文はGitHubこちらら(変更しまくってるので、応用編的なのりで見てください)

そんでもって、まずはBotの作り方、コードはRubyで書いていきます。
RubyにはTwitter gemというTwitter非公式のTwitter専用のgemがあるので、それを使うと簡単に実装ができます。

ではまず適当に、Botとかいうフォルダーを作りましょう

$ mkdir TweetDeletedAlertBot

Gem(ライブラリ)のインストール

GemをインストールするのにGemfileを作成してその中に必要なGemを入れましょう($ bundle init で簡単に作成できます)

bundlerをインストールしてない方はまず[gem install bundler]でbundlerをインストールしてください

gem 'twitter'
gem 'rake'
gem 'sinatra'
gem 'sinatra-activerecord'
gem 'curb'
gem 'sqlite3'

次に$ bundle install --path vondor/をしてgemをインストールします。これでgemのインストールは完了です!

DataBaseの作成

ではでは、次にDBを作成するために'config.ru','database.yml','models.rb’,’Rakefile’ を作成していきます

cnfig.ru

requie 'bundler'
Bundler.require
require './app'
run Sinatra::Application

database.yml

development:
  adapter: sqlite3
  database: db/development.db
  pool: 20
  timeout: 5000

models.rb

require 'bundler/setup'
Bundler.require
after do
  ActiveRecord::Base.connection.close
end

if development?
  ActiveRecord::Base.establish_connection("sqlite3:db/development.db")
end

class Tweet < ActiveRecord::Base
end

Rakefile

require 'sinatra/activerecord'
require 'sinatra/activerecord/rake'
namespace :db do
  task :load_config do
    require File.expand_path('../app', __FILE__)
  end
end

これでDBの下準備は整いました!
次は、テーブルの作成をしていきましょう!!

$ bundle exec rake db:create_migration NAME=create_tweets

とやって、migrationファイルを作成します。
vimやらなんやらで、db/migrate/*************create_tweets.rb みたいのを開きましょう

そしたら、つい消しされた時に見たい内容を入れるためのcolumnをを追加していきましょう
ちなみに僕は、UserNameとTextとUserID(必須)だけの簡単な仕様にしてみました。もし他にも入れたいものがあったら各自設定してください

class CreateTweets < ActiveRecord::Migration
  def change
    create_table :tweets do |t|
      t.string :tweet_id #こいつは必須
      t.string :user_name
      t.string :icon_url
      t.text :text
    end
  end
end

では、いよいよ、DB作成編も終了間近です。最後に

$ bundle exec rake:db migrate

とやって、DBの完成です!
次に作るのはDataBaseさんと対話してくれるSinatraAPIを作成していきます

SinatraAPI

まずは

$ touch app.rb

で、app.rbというファイルを作成してください
そしたらまず、ライブラリ(gem)を読み込みます。

require 'bundler/setup'
Bundler.require
require './models.rb'
require 'json'

を記述したら、Bot.rbからTweetデータを受け取り保存するコードを書いていきます

post '/stocking_tweet', provides: :json do
  data = JSON.parse(request.body.read)
  Tweet.create(
    tweet_id: data["tweet_id"],
    user_name: data["user_name"],
    text: data["text"],
    icon: data["icon"],
    url: data["url"]
  )
end

これで、TweetData をjsonで受け取るコードはできました
次に作るのは、DeleteActionが来た時にBotは、「このTweetIDと一致するデータって持ってる?」
と聞いてくるので、それを受信して、返信する、コードを書いていきます

get '/find_tweet/:id' do
    if tweet = Tweet.find_by(tweet_id: params[:id])
      { tweet_id: tweet.tweet_id, user_name: tweet.user_name, text: tweet.text , icon: tweet.icon, url: tweet.url}.to_json 
    else
      {error: "404"}.to_json 
    end
  end
end

Bot(本体)の作成

いよいよ、本番!Botの作成です!!!!まずはさっきと同じく

$ touch bot.rb

でBot.rbのファイルを作成してください

まずインストールしたライブラリ(gem)をインポートします

require 'twitter'
require 'curb'

次に、Twitter API の設定をしていきます。

Twitter API を使うには TwitterDeveloper 登録をして AccessKey を取得してください
ここから取得してきてください-> Application Management

#bot.rbに記述
client = Twitter::Streaming::Client.new do |config|
  config.consumer_key    = QCxSr1Fq6We9C8xhIx5agkTOs
  config.consumer_secret = V6mAznyD2mdTxCoYYkQvkDbsdAz1au52KTojS1SwZ9yrkba3T3
  config.access_token    = 1793252213-6L9Vda4qXYzrgg2vDlcJ7MWZqhCZHpim5ZayDa1
  config.access_token_secret = FifsbD45igXiLLw7698ykNLD1h4hmyGd374RS9jYDmx75
end

Configの設定が終わったら次は削除された時のActionを取得してきます

#bot.rbに記述↓
client.user do |tweet|
  case tweet #なんのアクションが起きてるかのcase文
  when Twitter::Tweet #普通のTweetだった場合
    puts "#{tweet.user.name} -> #{tweet.full_text}\n\n" #テストコード
    database_post(tweet) #DataBase に保存するために database_post という関数にデータを投げる
  when Twitter::Streaming::DeletedTweet #削除アクションだった場合
    data = JSON.parse(Curl.get("http://localhost:4567/find_tweet/#{tweet.id}").body_str)
    if "#{tweet.id}" == data["tweet_id"]# SinatraAPIから撮ってきたデータが有ってるかどうか
      deleted_tweet(data) #あっていた場合削除通知をSlackにPostするためのDeleted_tweetという関数に投げる
    else 
      puts ("誰かがつい消ししたっぽい")#もし削除されたものがDataBaseに保存されてなかったらLogとして残す
    end
  end
end

ここまでで一応動くようにはなってます(嘘)関数を幾つか呼び出しているので、関数の定義してあげましょう

def database_post(bot.rb)

#これはSinatraAPIに流し込む
def database_post(tweet)
  Curl.post(
    "http://localhost:4567/stocking_tweet", 
    ({ 
      tweet_id: tweet.id,
      user_name: tweet.user.name,
      text: tweet.full_text,
      url:tweet.uri, 
      icon: tweet.user.profile_image_url,
    }).to_json)
end

def database_postでは、SinatraAPI にTweetのデータを投げるためのcurlを定義してます
次に、DeleteActionが起こった時の関数を定義していきます

def deleted_tweet(bot.rb)

#これはslackに直接流しこむ
def deleted_tweet(tweet)
  web_hooks = "https://hooks.slack.com/services/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"
  #↑こいつはSlackのWebHooksってやつで、これの取得方法はSlack Incoming WebHooks でぐぐってくれ
  attachments = { attachments: [{
      author_icon: tweet["icon"],
      author_name: tweet["user_name"],
      text: "Delete:\n #{tweet["text"]}",
      author_link: tweet["url"],
      color: "red",
    }]
  })
  conf = { channel: "#random", username: "TwitterBot", icon_url: "http://goo.gl/5sotqB"}.merge(attachments)
  Curl.post( web_hooks,JSON.pretty_generate(conf))
end

これですべての準備が整いました!ではapp.rbとbot.rbの両方を一気に実行してみましょう!

できましたかね?これで取り敢えずコードの説明は、終了です

まとめ

実際ヤッてみてどうでした?疲れました?でも記事書いてる僕はもう90代のおっさんみたいな格好して記事書いてます

最後、コードの全文見て終わりにしますかね

app.rb

require 'bundler/setup'
Bundler.require
require './models.rb'
require 'json'

post '/stocking_tweet', provides: :json do
  data = JSON.parse(request.body.read)
  Tweet.create(
    tweet_id: data["tweet_id"],
    user_name: data["user_name"],
    text: data["text"],
    icon: data["icon"],
    url: data["url"]
  )
end

get '/find_tweet/:id' do
    if tweet = Tweet.find_by(tweet_id: params[:id])
      { tweet_id: tweet.tweet_id, user_name: tweet.user_name, text: tweet.text , icon: tweet.icon, url: tweet.url}.to_json 
    else
      {error: "404"}.to_json 
    end
  end
end

bot.rb

require 'twitter'
require 'curb'

client = Twitter::Streaming::Client.new do |config|
  config.consumer_key    = QCxSr1Fq6We9C8xhIx5agkTOs
  config.consumer_secret = V6mAznyD2mdTxCoYYkQvkDbsdAz1au52KTojS1SwZ9yrkba3T3
  config.access_token    = 1793252213-6L9Vda4qXYzrgg2vDlcJ7MWZqhCZHpim5ZayDa1
  config.access_token_secret = FifsbD45igXiLLw7698ykNLD1h4hmyGd374RS9jYDmx75
end

def deleted_tweet(tweet)
  web_hooks = "https://hooks.slack.com/services/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"
  #↑こいつはSlackのWebHooksってやつで、これの取得方法はSlack Incoming WebHooks でぐぐってくれ
  attachments = { attachments: [{
      author_icon: tweet["icon"],
      author_name: tweet["user_name"],
      text: "Delete:\n #{tweet["text"]}",
      author_link: tweet["url"],
      color: "red",
    }]
  })
  conf = { channel: "#random", username: "TwitterBot", icon_url: "http://goo.gl/5sotqB"}.merge(attachments)
  Curl.post( web_hooks,JSON.pretty_generate(conf))
end

def database_post(tweet)
  Curl.post(
    "http://localhost:4567/stocking_tweet", 
    ({ 
      tweet_id: tweet.id,
      user_name: tweet.user.name,
      text: tweet.full_text,
      url:tweet.uri, 
      icon: tweet.user.profile_image_url,
    }).to_json)
end

client.user do |tweet|
  case tweet #なんのアクションが起きてるかのcase文
  when Twitter::Tweet #普通のTweetだった場合
    puts "#{tweet.user.name} -> #{tweet.full_text}\n\n" #テストコード
    database_post(tweet) #DataBase に保存するために database_post という関数にデータを投げる
  when Twitter::Streaming::DeletedTweet #削除アクションだった場合
    data = JSON.parse(Curl.get("http://localhost:4567/find_tweet/#{tweet.id}").body_str)
    if "#{tweet.id}" == data["tweet_id"]# SinatraAPIから撮ってきたデータが有ってるかどうか
      deleted_tweet(data) #あっていた場合削除通知をSlackにPostするためのDeleted_tweetという関数に投げる
    else 
      puts ("誰かがつい消ししたっぽい")#もし削除されたものがDataBaseに保存されてなかったらLogとして残す
    end
  end
end

~雑談~

TwitterAPIのDeleteActionも不親切だよなあーIDだけしか渡してこないから、こっちでDB作らなきゃいけなくなったし、
そのせいでconfigfileとか作るから、ファイルが増えるし管理めんどいしで、なんかもう。。。メンドーッて感じっだった
まあActiveRecordとSinatraがあるから楽に実装出来たっちゃできたから◎

ではではーおつかれさまですー

21
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
17