【図解】社内外へのアウトプット/インプット同時投稿をノーコードで~Microsoft TeamsとTwitterを連携~
社外へのアウトプットをTwitterでツイートし、同時に社内インプットとしてTeamsへの投稿をFlowで連携してみます。
目次[非表示]
社外アウトプットと社内インプットを同時にする目的
こんにちは。ラーニングサービス本部 テクニカルトレーニング第一部 山下です。
今年もre:Invent 2019に参加できることになり(多分?)ものすごくテンションがあがっております。
AWS認定インストラクターというクラウド時代の人材育成な仕事をしながら、re:Inventに行きたいエンジニアさんはお気軽にご相談ください!
(re:InventとはAWSが開催している世界規模の年次カンファレンスです!)
さて、昨年のre:Inventの記録を確認しようと、弊社で利用しているMicrosoft Teamsの関連チャネルを確認しました。
チャネルが散らばっていて我ながら見づらいです。
あと、Twitterにも書いてるのでTeamsにすべての情報がないです。
他の勉強会やカンファレンスでもTwitterがメインになっているので、社内でTwitter見てない人にはまったく届けられないことになります。
だからといって、Twitter投稿して、Teams書いてというのは面倒なので、やりたくないです。
なので連携します。
Microsoft Flowというサービスを使うとコードをまったく書かずに連携することもできます。
Microsoft Power Platformド素人な私ですが、後から発生した課題もあわせて、調べながら3時間ほどで実現できました。
APIや機能が充実しているので、普段コードを書いてない人やエンジニアではない人もチャレンジしてみる価値があると思いました!
連携イメージ(Twitter, Microsoft Flow, Microsoft Teams)
Twitterユーザーなら誰でもいいのですが、私( @yamamanx )がTwitterに #trainocate_teams とハッシュタグをつけてツイートします。
Microsoft Flowで定義済みのタスクがTwitterのツイートを拾って、Teamsの特定チャネルに投稿します。
では設定した内容を図解していきます。
Microsoft Teamsの設定
対象のチームを選択して、チャネルを作成します。
「Twitter共有」というチャネル名にしました。
余談ですが、最近はチャネル名に絵文字を使うようにしてます。
Microsoft Flowの設定
Microsoft Flow(https://flow.microsoft.com/ja-jp/)にOffice365アカウントでサインインします。
とりあえず "twitter" でフローを検索してみます。
たくさん出てきました。
"twitter teams"で絞り込んでみます。
「新しいツイートが指定したハッシュタグと一致したときに Microsoft Teamsに投稿する」というドンピシャなフローがあります!
これを使います。
他にはSlack向けのものや、「否定的なツイートが投稿された場合に通知する」というのもあるのですね。
Translateも気になります。
「新しいツイートが指定したハッシュタグと一致したときに Microsoft Teamsに投稿するを選択します。
TwitterとTeamsの認証が必要なのですね。
Twitterを認証してできることは、
- タイムラインのツイートを見る。
- フォローしている人を見る、新しくフォローする。
- プロフィールを更新する。
- ツイートする。
タイムラインを見る以外は要らないだろうと思いつつも、大丈夫だろうと認証しました。
(もしも思いがけない何かがあればこちらで共有します。)
Twitter側には検索文字列(今回はハッシュタグ)を、Teams側は投稿先のチャネルとメッセージの形式を設定しました。
[保存]をクリックすると「種類が必要です」というエラーになりました。
"Alert the team"という名前もなんだかなので、変更します。
[設定]メニューに[種類]という設定がありましたが、エラーメッセージの「種類」とはこれではないようです。
結局エラーは解消できなかったので、連携先のTeamsのコネクタを削除して、コネクタの追加から、Teamsへの投稿を追加しました。
最終的にこうなりました。
テストしてみての課題
放置しておいても結果は見えますが、[テスト]からすぐに確認することもできました。
これはこれで設定どおりにうまくいきました!
でも今回やりたかったことでは、これじゃない感があります。
- 投稿者が自分になっている。
- 写真が投稿されない。
この2点をクリアしたいです。
せっかくなので調べながらチャレンジしてみます。
課題1 「投稿者が自分になっている」
Office365ユーザーを専用で作る、でもOKかもしれませんが、それはなんだか本来のユーザーの用途とは違うのかなと思います。
ですので、これはIncoming Webhookで解決してみます。
(社内ですでに設定済のフローがあって、それを元に調査しました。)
まずTeamsのチャネル側でコネクタの設定をします。
Incoming Webhookの[構成]を選択します。
接続の名前を設定(今回はShareTweet)、イメージを設定(非公式キャラクターのとれのCATに連携してもらいます)して作成します。
生成されたURLをFlowで使用するのでコピーしておきます。
(後から構成済みメニューで確認することもできます)
Flowで元のTeamsのアクションを削除して追加のアクションを "http"で検索し、HTTPを選択します。
候補が3つ表示されるので、HTTPを選択しました。
方法はPOST、URIにIncoming Webhookで生成されたURL、本文を指定すれば良さそうです。
本文はカード形式にするときには作法があるようで、その作法に則ります。
カードはJSONで記述します。
先ほどのリファレンスを見ると画像は heroImage キーを使えば実現できそうです。
最初の@2つはこうしてエスケープしておかないと「テンプレートの検証に失敗しました: '行 '1'、列 '1665' のテンプレート アクション 'HTTP' は無効です: "テンプレート言語式 'type' を解析できません: 必要なトークンは 'LeftParenthesis' で、実際は 'EndOfData' です。"。'。」というエラーになるためです。
画面では、ツイートの名前やテキストを動的要素としてドラッグ&ドロップでコードを書かずに追加しているのですが、コピーして貼り付けると次のコードのようになります。
{ "@@type": "MessageCard", "@@context": "http://schema.org/extensions", "themeColor": "0076D7", "sections": [ { "activityTitle": @{triggerBody()?['UserDetails']?['FullName']}, "activityImage": @{triggerBody()?['UserDetails']?['ProfileImageUrl']}, "activityText": @{triggerBody()?['TweetText']}, "markdown": true } ]}
triggerBody()?['TweetText']
上の図でTwitterアイコンが表示された要素部分は関数になっているのですね。
これでテストしてみたところ、「Summary or Text is required.」 Summaryキーがないのでエラーです。
リファレンスを見るとSummaryは統一されたテキストでいいそうなので、"ShareTweet"にします。
Summaryキーを足してもう一度です。
{ "@@type": "MessageCard", "@@context": "http://schema.org/extensions", "themeColor": "0076D7", "Summary": "ShareTweet", "sections": [ { "activityTitle": @{triggerBody()?['UserDetails']?['FullName']}, "activityImage": @{triggerBody()?['UserDetails']?['ProfileImageUrl']}, "activityText": @{triggerBody()?['TweetText']}, "markdown": true } ]}
とれのCATからの投稿でツイートをシェアできました。
ハッシュタグが見出しになってるのはmarkdown: true だからですね。
これを false にしてもう一回。
できました!
次は写真です。
課題2 「写真が投稿されない」
リファレンスを見ていると、heroImage というキーが使えそうです。
まず固定の画像URLでやってみます。
{ "@@type": "MessageCard", "@@context": "http://schema.org/extensions", "themeColor": "0076D7", "sections": [ { "activityTitle": @{triggerBody()?['UserDetails']?['FullName']}, "activityImage": @{triggerBody()?['UserDetails']?['ProfileImageUrl']}, "activityText": @{triggerBody()?['TweetText']}, "markdown": false, "heroImage": { "image": "https://www.trainocate.co.jp/top_common/img/trainocate_logo.gif" } } ], "summary": "ShareTweet"}
これでやってみても全然表示されません。
情報も検索できなかったので、別の方法を考えます。
写真付きのツイートでテストをして、リクエスト側の本文を見てみたら、MediaUrlsという項目がありました。
ここに画像のURLがあるので、これを表示してやればよさそうです。
sections の中でマークダウン表記でHTMLを書こうかと思いましたが、ハッシュタグを見出しにしない対応で markdown: falseにしてます。
ダウンがだめならアップだ!ということで<img>タグを書きます。
@{triggerBody()?['TweetText']}のように、@{triggerBody()?['MediaUrls']} とすれば画像のURLがとれそうです。
これをtextキーとしてsectionsの中で<img src>で指定するとよさそうです。
でもここで問題が2点あります。
- MediaUrls は配列なのでこのままじゃ多分だめ
- 画像があるときないときでtext キーのふるまいを変える必要あり
関数を使うことでなんとかならないか、関数のリファレンスを確認してみました。
配列操作も、if分岐もできるようです。
残念ながらループはないように見えます。
FlowのアクションとしてForeachがあるので、おそらくそっちでループをまわして、1画像づつTeams連携アクションで処理する方法があるように思われます。
でも写真を何枚も1ツイートで貼ることはあまり考えたくないので、画像が1つでもあれば1つ目の画像を表示する、で今回は処理したいと思います。
該当の関数式はこちらになりました。
設定は1行で書いてますが、長いので当記事ではインデントと改行を入れてます。
if( equals( length( triggerBody()?['MediaUrls'] ), 0 ), '', concat( '<img src="', first(triggerBody()?['MediaUrls']), '">' ) )
さらにreplace関数を使って、テキストの改行対応もできました。
uriComponentToString(replace(uriComponent(triggerBody()?['TweetText']),'%0A','<br>'))
最終的にFlowのHTTP POSTの本文はこうなりました。
{ "@@type": "MessageCard", "@@context": "http://schema.org/extensions", "themeColor": "0076D7", "sections": [ { "activityTitle": @{triggerBody()?['UserDetails']?['FullName']}, "activityImage": @{triggerBody()?['UserDetails']?['ProfileImageUrl']}, "activityText": @{uriComponentToString(replace(uriComponent(triggerBody()?['TweetText']),'%0A','<br>'))}, "markdown": false, "text": @{if(equals(length(triggerBody()?['MediaUrls']),0),'',concat('<img src="',first(triggerBody()?['MediaUrls']),'">'))} } ], "summary": "ShareTweet"}
想定どおりの動作となりました。 これから使っていくにあたってもっとこうしたい、ああしたい、は出てくるとは思いますが、ひとまずこれで使い始めます。
当日の勉強会で使ってみました
この仕組みを構築した当日にちょうど勉強会「DevLOVE関西 グローバルの現場でのチームづくりの話(https://devlove-kansai.doorkeeper.jp/events/93083)」に参加予定でしたので早速使ってみました。
ばっちりTeamsにも連携されました。
これを見た社内メンバーがコメントを書いて議論したり、勉強会に行ったことない人が勉強会に参加してみようって思ったり、単に情報ソースとして使ってもらったり、これきっかけで何か調べて結果を教えてくれたり、イベントのヒントにしたり、広がっていくといいなあ、と妄想しております。
やってみてのまとめ
Microsoft Flow初体験でした。
ノーコードで出来ることも、以前に比べてどんどん増えていってます。
それによって簡単に「システムとシステム」「システム間のデータ」「1つのインプット、複数のアウトプット」といった連携ができます。
TwitterにもTeamsにもAPIがあるから連携が簡単にできるのですね。
ということは、何かシステムの利用やSaaSの導入を検討するときに、そのサービスにはAPIがあるのか、使えるのか、ということをより意識しないといけないなと感じました。
今後できるようになるかもしれませんが、今回のように現時点では、JSONで本文を書かないといけなかったり、関数で分岐しないといけなかったりというようなローコードな要件もあるかもしれません。
ですが、できないから、で諦めるのではなく、少し調べればできることを知っておくと、いざというときの課題解決に役立ちます。
0をいきなり100にしなくても「ゼロをイチ」にして選択肢を増やしておくって本当に価値があることだと思いました。
最後にこのブログを書くにあたり当社のTeamsのブログレビューのスレッドで約50件ものリプライや質問がありました。
その中から生まれた言葉で締めくくりたいと思います。
Know Chords by NoCode
(ノーコードで本当に必要な、チームの和音に気づきましょう)
※ノーコード/ローコードの区別は意見が分かれることも多々ありますが、当記事ではGUIだけで構築できるものをノーコード、JSONや関数など簡単なコードを記述するものをローコードとして書いています。
すべてのビルダーにおすすめ
エンジニアだけでなく、システムや仕組みを構築するすべてのビルダーにおすすめのコースです。
PowerAppsで実践する業務アプリのローコード開発ハンズオン
このコースでは、Office 365にてローコーディング開発をするために必要な、PowerApps、Common Data Service (CDS)、Microsoft Flowについてハンズオン形式で学習します。
自社のPC発注のストーリーをもとに、PC&タブレット用の入力フォームビジュアルの作成、Common Data Serviceでのデータ管理、Microsoft Flowによる自動化処理の作成について学習します。
kintoneのアプリの利用方法とアプリの作成方法・各パーツの機能を学び、目的に応じたアプリを構築するスキルを習得