PlayFrameworkでTwitter4Jを使ってTwitterアプリと連携をする

#はじめに
## 概要
WeekendEngineerというグループの中で9月にPlayFrameworkを使ったTwitterツールの開発をしました。

その時に勉強した技術の一つである「PlayFrameworkでTwitter4jを使ったOauth認証とAPIの利用方法」について説明をします。
[Playframework/ScalaとTwitter4jでOAuthログインするサンプル](https://qiita.com/omiend/items/90163d29b465fb7ab8f0)にも記事がありましたが、Play2.6に対応していないようなので、僭越ながらScala初心者がPlay2.6ver.でお送りします。

コードの全容はこちらのリポジトリにあります。
[controllers.auth.AuthController](https://github.com/seven0525/ochiai_auto_tweets/)

## 今回のプログラムで実現していること
- Twitterアカウントでログインをする
- ログインしたアカウントでツイートを投稿する

## 環境
MacOSX
Intellij
Java 10
sbt 0.13.17
scala 2.12.2
playframework 2.6.19

# 手順
参考→[Playframework/ScalaとTwitter4jでOAuthログインするサンプル](https://qiita.com/omiend/items/90163d29b465fb7ab8f0)

## Twitter4jプラグインを依存ライブラリに追加
今回はTwitter4jプラグインを使ってTwitterのAPIを叩きます。
以下を追記して、プラグインをインポートします。

```build.sbt
// https://mvnrepository.com/artifact/org.twitter4j/twitter4j-core
libraryDependencies += "org.twitter4j" % "twitter4j-core" % "4.0.4"
```

## Twitterアプリケーションを登録
+ 開発者アカウントの作成
[開発者向けTwitterページ](https://developer.twitter.com/)にアクセスして、Twitterでログインをする。
+ 新規Twitterアプリの作成
[アプリ作成ページ](https://developer.twitter.com/en/apps/create)にアクセスして、アプリの登録をしましょう。<br>
sign in with twitterを有効化して、callback先URLに「[http://127.0.0.1:9000/callback](http://127.0.0.1:9000/callback)」を指定します。

## 認証用のControllerを用意
Oauthは以下のようなフローで実現されます。

+ Twitterの認証ページにリダイレクトする。
+ ユーザがTwitterアカウントでログインをする。
+ Twitterからユーザのトークンとともにアプリケーションへリダイレクトされる。

こちらで用意するのは、以下2つのアクションです。

+ Twitterの認証ページにリダイレクトする「loginアクション」
+ Twitterからのリダイレクトの受け口になる「callbackアクション」

### AuthControllerクラスを作成
app>controllersにAuthControllerを作成し、
SyncCacheApiをDIします。

```controllers.auth.AuthController.scala
@Singleton
class AuthController @Inject()(cc: ControllerComponents, cacheApi: SyncCacheApi) extends AbstractController(cc) {
}
```

### loginアクションを実装

```controllers.auth.AuthController.scala
def login = Action {implicit request =>
  // twitter4jのtwitterインスタンスを取得
  val twitter: Twitter = (new TwitterFactory()).getInstance()
  // twitterからリダイレクトするURL(twitterアプリ作成時に指定したURL)を指定して、リクエストトークンを取得
  val requestToken: RequestToken = twitter.getOAuthRequestToken("http://127.0.0.1:9000/callback")

  // cacheにtwitterとrequestTokenを保存
  cacheApi.set("twitter", twitter, 120)
  cacheApi.set("requestToken", requestToken, 120)

  // Twitterの認証ページにリダイレクト
  Redirect(requestToken.getAuthorizationURL)
}

```

### twitter4j.propertiesを作成
confディレクトリにtwitter4j.propertiesを作成し、twitterアプリページのkey and tokenタブにあるconsumer keyを転記します。

```conf/twitter4j.properties
oauth.consumerKey=twitterアプリのAPIkey
oauth.consumerSecret=twitterアプリのAPI secret key
```

routesに```GET     /login                      controllers.auth.AuthController.login```を追記すれば、[http://127.0.0.1/login](http://127.0.0.1/login)を叩いてTwitterの認証ページにアクセスできるはずです。


### callbackアクションの作成
login時に保存した`requestToken`とtwitterからのリクエストに保存された`oauthVerifier`を使用して、ユーザのアクセストークンを取得しています。

```controllers.auth.AuthController.scala
def twitterOAuthCallback = Action { implicit request =>
// TwitterのオブジェクトをCacheから取得
val getTwitter     : Option[Twitter] = Option(cacheApi.get("twitter"))

// 取得できない場合はトップ画面へ
getTwitter match {
  case Some(twitter) => {
    // RequestTokenのオブジェクトをCacheから取得
    val getRequestToken: Option[RequestToken] = Option(cacheApi.get("requestToken"))

    // 取得できない場合はトップ画面へ
    getRequestToken match {
      case Some(requestToken) => {

        // authVerifierを取得する
        var authVerifier: String = request.queryString.get("oauth_verifier").get.head

        // AccessTokenを取得する
        val accessToken: AccessToken = twitter.getOAuthAccessToken(requestToken, authVerifier)
        cacheApi.set("accessToken", accessToken, 4320)

        // Twitterオブジェクトの認証
        twitter.verifyCredentials()

        // Cacheに認証情報を保存(私はTwitterSessionクラスのインスタンスを生成し、保存しました。)
        val twitterSession: TwitterSession =
                new TwitterSession(accessToken.getToken, accessToken.getTokenSecret, accessToken.getScreenName)
        cacheApi.set("twitterSession", twitterSession, 4320)

        // 不要なのでCacheから削除
        cacheApi.remove("twitter")
        cacheApi.remove("requestToken")

      }
      case _ =>
    }
  }
  case _ =>
}
Redirect("/")
}
```

routesに```GET     /callback                      controllers.auth.AuthController.callback```を追記すれば、Oauthログインができているはずです。

## APIを使用する
Twitterクラスのインスタンスを生成するときに、Oauthで取得したAccessTokenを突っ込むだけで、TwitterAPIを使えます。以下の例はツイートを投稿するUpdateStatusというメソッドを使っている例です。

```client.Twitter4JClient.scala
@Singleton
class Twitter4JClient{
  /**
    * TweetをPostする.
    * @param accessToken
    * @param tweetText
    * @throws TwitterException
    * @return
    */
  def updateStatus(token: String, secret: String, tweet: Tweet): Tweet = {
    val accessToken: AccessToken = new AccessToken(token, secret)
    val twitter: Twitter = (new TwitterFactory()).getInstance(accessToken)
    try {
      val status: Status = twitter.updateStatus(tweet.getBody())
      return Tweet(status.getText, status.getUser.getScreenName)
    } catch {
      case e:TwitterException => throw e
    }
  }
}
```


# 参考URL
[Playframework/ScalaとTwitter4jでOAuthログインするサンプル](https://qiita.com/omiend/items/90163d29b465fb7ab8f0)