Skip to content

Instantly share code, notes, and snippets.

@Ningensei848
Created June 29, 2022 02:32
Show Gist options
  • Save Ningensei848/e8cfdbdc83c5b65efce14c16ecdf5dbc to your computer and use it in GitHub Desktop.
Save Ningensei848/e8cfdbdc83c5b65efce14c16ecdf5dbc to your computer and use it in GitHub Desktop.
TwitterWebService.gs の複数アカウント対応

What is it ?

GAS こと Google App Script で Twitter に代理ログインし、自動で DM を送れるようにしたかった。 そのためには、OAuth1.0a を実装する必要がある。

幸い、TwitterWebService.gs (1rgo8rXsxi1DxI_5Xgo_t3irTw1Y5cxl2mGSkbozKsSXf2E_KBBPC3xTF) がシェアライブラリとして登録されているが、いまいちよくわからない。 M-Igashi/TwitterWebService.gs という元ソースらしきものを参照しつつ、class に書き換えた。

複数アカウント対応

しかし、上記まででは一つのアカウントしか認証できなかった(複数認証すると上書きされてしまう)。

これを回避するために、OAuth1.createService(this.username) というように、引数に複数のキーが与えられるように改変した。 こうすることで、PropertiesService は複数の値を保持できるし、authCallback(request)request からも request.parameter.serviceName という形で逆引きできる。

この gist ではここまでしか書いていないが、後は適宜リスト等で複数アカウント用意して処理するとよい。

/*
GAS では dotenv が使えない(ファイルとして値を持つことはできない)ので、代わりに properties を用いる
cf. https://developers.google.com/apps-script/guides/properties
*/
const scriptProperties = PropertiesService.getScriptProperties()
const props = scriptProperties.getProperties()
/*
スクリプトを実行する前に、手作業で必要な変数を[プロパティ]に入力しておくこと:
(1)「プロジェクトの設定」(左のバーにある歯車アイコン)を開く
(2)一番下にある「スクリプト プロパティ」の[編集]を押すと、入力ボックスが出現する
(3)左の欄に値を取り出す時に使う名前(キー)、右の欄にAPIトークンなどの値を入れて「保存」をクリック
*/
const ACCESS_TOKEN = props.ACCESS_TOKEN
const SECRET_TOKEN = props.SECRET_TOKEN
class TwitterWebService {
/*
cf. [M-Igashi/TwitterWebService.gs](https://gist.github.com/M-Igashi/750ab08718687d11bff6322b8d6f5d90)
*/
constructor(consumer_key, consumer_secret, username) {
this.consumer_key = consumer_key
this.consumer_secret = consumer_secret
this.username = username
}
getService() {
return OAuth1.createService(this.username)
.setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
.setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
.setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
.setConsumerKey(this.consumer_key)
.setConsumerSecret(this.consumer_secret)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
}
authorize() {
const service = this.getService()
if (service.hasAccess()) {
Logger.log('Already authorized')
} else {
const authorizationUrl = service.authorize()
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl)
return authorizationUrl
}
return
}
reset() {
const service = this.getService()
service.reset()
}
authCallback(request) {
const service = this.getService()
const isAuthorized = service.handleCallback(request)
const mimeType = ContentService.MimeType.TEXT
// TODO: text output じゃなくて、HTMLTemplateでレンダリングしたい
if (isAuthorized) {
return ContentService.createTextOutput('Success').setMimeType(mimeType)
} else {
return ContentService.createTextOutput('Denied').setMimeType(mimeType)
}
}
}
const getTwitterInstance = (username) => new TwitterWebService(ACCESS_TOKEN, SECRET_TOKEN, username)
// 認証
const authorize = (username) => {
const twitter = getTwitterInstance(username)
twitter.authorize()
}
// 認証後のコールバック
const authCallback = (request) => {
// OAuth1.createService(username) で渡した文字列は serviceName で逆引きできる
const username = request.parameter.serviceName
const twitter = getTwitterInstance(username)
return twitter.authCallback(request);
}
/* References
- [googleworkspace/apps-script-oauth1](https://github.com/googleworkspace/apps-script-oauth1)
- [M-Igashi/TwitterWebService.gs](https://gist.github.com/M-Igashi/750ab08718687d11bff6322b8d6f5d90)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment