はじめに
この記事はノンプログラミングでアプリが作成できるMicrosoftのPowerAppsを使って、同じくMicrosoftの企業向けSNSであるYammerの特定のグループからメッセージを取得しよう、という内容です。
各コントロールの設定のみ説明し、接続やコントロールの配置などの手順については省いています。ご了承ください。
え、20件しか取れないの?
同僚から「Yammerの参加者別に『いいね!』された数を集計出来ないかな?」と相談されたので、そんなの簡単じゃん、とPowerAppsでチョチョっと作ったのですが、どうも数が合わない。調べてみると同じ悩みの人がいて、YammerのAPIでは1回の取得で20メッセージまでしか取れず、呼び出し頻度も30秒に10回以内であることがわかりました。こちらの記事
では3秒待って繰り返せば良い、ということになりますが、困ったことに、PowerAppsには繰り返しのロジックがありません。
普通ならここでMicrosoft Flowに乗り換えるのでしょうが、なんか悔しくて、さらに調べて試してみました。
反復のアイディア
タイマーを使う、という発想
今度はPowerAppsとloopをキーワードに検索してみます。すると**こんな記事**に出合いました。
こちらで質問しているColleenさん、途中で「Timerコントロールを使ってほぼWhileと同じ処理が出来たよ、ちょっと遅いけどね」と書いています。遅くていいんです、どうせ3秒待つんだから。
ではどのように設定するのか
ColleenさんはRe-stateと書いています。本当に状態回復の意味で書いたのかも知れませんが、私はRestartじゃね?、と解釈しました。処理開始でタイマースタート、最初に処理を実行したら3秒待って、Restart。終了条件が来たらRestartをfalseに。いけそうですね。Timerコントロールの設定的には以下のようなものです。
プロパティ | 設定値 | コメント |
---|---|---|
Start | bool値 | trueでタイマースタート |
OnTimerStart | 処理 | メッセージ取得処理を入れる |
Duration | 3000 | 3秒待つ |
Restart | bool値 | trueで繰り返し |
実装してみよう
実装にあたっては、わかりやすくするために以下の要件としました。
- ドロップダウンリストでYammerグループを選択後、ボタンを押して取得開始
- いいねの集計でなく、単にメッセージを取得してギャラリーで内容を表示します(最後でちょっと補足)
- 取得処理では、最初の1回をボタンで処理した後、タイマーを起動します。そのためOnTimerEndに処理を入れます
まずは最終イメージ
これを作ります。投稿者IDを名前にしたい、とか、日本時間にしたい、とか、メッセージの順番が、なんてのは最後でちょっと補足。(肝心のメッセージが15件しか無い!後半までに水増ししておきます)
サンプル投稿は**こちらの記事**から引用しました。ありがとうございます。
Yammerコネクタ
使うコネクタはYammerのみです。接続すると関数が使えるようになります。使う関数は、上記の状態までなら以下の2つだけです。
詳しくはこちらを参照してください
関数 | 用途 | パラメーター |
---|---|---|
Yammer.GetGroups() | 自分が使えるグループを取得します | 今回は設定しません |
Yammer.GetMessagesInGroup(id,{older_than:message.id}) | idで指定したグループのメッセージを取得します | older_than: 指定したmessage.idより古いメッセージを取得 |
各コントロールの設定内容
1.ドロップダウン(最終イメージのDropdown1)
ここではitemsプロパティを設定するだけで、グループ名が表示されると思います。選択した結果のグループIDには、Dropdown1.Selected.id
でアクセス出来ます。
プロパティ | 設定値 | コメント |
---|---|---|
Items | Yammer.GetGroups() | グループ名が表示されなければ、詳細設定のValueでfull_nameを選んでください |
2.取得ボタン(最終イメージのButton1)
こちらも設定はOnSelectプロパティのみですが、設定値は結構長文になります。
処理の中心ですので、ひとつひとつ説明して行きますね。
UpdateContext({timerStart:false,pageCount:1,messageRead:0,oldestMessageId:0,totalMessage:0});
ClearCollect(workCollection,Yammer.GetMessagesInGroup(Dropdown1.Selected.id).messages);
ClearCollect(MessagesInGroup,workCollection);
UpdateContext({messageRead:Count(workCollection.id),oldestMessageId:Last(workCollection).id});
UpdateContext({totalMessage:messageRead});
If(messageRead=20,UpdateContext({timerStart:true,pageCount:2}),UpdateContext({pageCount:0}))
2-1.変数を準備
UpdateContext({timerStart:false,pageCount:1,messageRead:0,oldestMessageId:0,totalMessage:0})
変数名 | 用途 |
---|---|
timerStart | タイマーを開始する時、および繰り返しする場合にtrueを入れます |
pageCount | 取得回数をカウントして、終わると0をセットします。Label1でメッセージを出しわけるために使っています |
messageRead | 取得毎に返されたメッセージ数を保持します。20未満なら最終ページと判断してtimerStartをfalseにします |
oldestMessageId | 取得した中で一番古いメッセージのIDを保持します。次回の取得ではそれより古いメッセージを対象にします |
totalMessage | 読み取ったメッセージ総数を保持します |
2-2.Yammerからメッセージを取得
ClearCollect(workCollection,Yammer.GetMessagesInGroup(Dropdown1.Selected.id).messages)
Yammerからメッセージを取得して一時的なコレクションworkCollection
にセットします。投稿内容自体はさらに内側のmessages
というレコード(構造体?)の中にありますので、ひと皮剥く感じで戻り値に.messages
を付けています。
2-3.取得したメッセージを蓄積
ClearCollect(MessagesInGroup,workCollection)
コレクションMessageInGroup
にメッセージを蓄積します。ここでは初回なのでClearCollectを使っています。
2-4.取得後の変数の更新
UpdateContext({messageRead:Count(workCollection.id),oldestMessageId:Last(workCollection).id});
UpdateContext({totalMessage:messageRead})
変数名 | 設定値 | コメント |
---|---|---|
messageRead | Count(workCollection.id) | このidはメッセージ固有のidで、何メッセージ取ってきたのか数えています。後段で20未満ならtimerStartをfalseにしています |
oldestMessageId | Last(workCollection).id | Yammerは新しい順にメッセージを取ってきているようなので、Lastレコードを選んでそのidをセットしています。次回の取得ではそれより古いメッセージを対象にします |
totalMessage | messageRead | 読み込んだ総メッセージ数ですが、ここでは初回なのでmessageReadを直接セットしています |
2-5.繰り返すかどうかの判断と変数の更新
If(messageRead=20,UpdateContext({timerStart:true,pageCount:2}),UpdateContext({pageCount:0}))
取得したメッセージが20であれば、残りがあるかも知れないため繰り返す必要があります。
ここでは以降タイマーによる処理に移すために、timerStartをtrueにしpageCountも進めています。20未満であればこれで終わりですので、timerStartをtrueにすることなく、表示を変更するためにpageCountを0にしています。
3.タイマー(最終イメージのTimer1)
タイマーはStartにtrueがセットされると動作を開始し、Durationにセットされたミリ秒だけ処理を待ち、その後OnTimerEndに指定された処理を実行します。Restartがtrueの間は繰り返し、falseになると終了します。
プロパティ | 設定値 | コメント |
---|---|---|
Start | startTimer | trueで始まり、終了させる時にfalseをセットします |
Duration | 5000 | 余裕をもって5秒待ちます |
OnTimerEnd | 処理 | 1回目の処理とほぼ同じですが、この後説明します |
Restart | startTimer | trueで始まり、終了させる時にfalseをセットします |
OnTimerEndプロパティに設定する処理
ボタンに設定した処理からの変更点は以下の太字の部分です。
ClearCollect(workCollection,Yammer.GetMessagesInGroup(Dropdown1.Selected.id,{older_than:oldestMessageId}).messages);
Collect(MessagesInGroup,workCollection);
UpdateContext({messageRead:Count(workCollection.id),oldestMessageId:Last(workCollection).id});
UpdateContext({totalMessage:totalMessage+messageRead});
If(messageRead=20,UpdateContext({pageCount:pageCount+1}),UpdateContext({timerStart:false,pageCount:0}))
- 取得済のメッセージを除くために、
older_than:
というオプションを追加しています。 - メッセージの蓄積については2回目以降なので、
ClearCollect
ではなくCollect
を使っています。 - totalMessage、pageCountの計算方法を汎用的にしています。
- 取得メッセージ数が20に満たない場合は最終ページなのでtimerStartをfalseにして繰り返しを終了します。
4.ギャラリー(最終イメージのGallery1)
ギャラリーには蓄積したメッセージを表示しましょう。セットするのはデータソースとレイアウト、データ項目です。画像入りのレイアウトから変更したので、コントロール名の後ろに2が付いたりしています。
プロパティ | 設定値 | コメント |
---|---|---|
Items | MessageInGroup | 蓄積したメッセージを対象にします |
コントロール名 | 設定値 | コメント |
---|---|---|
Body1 | ThisItem.body.plain | 投稿内容です。タグ付きで格納されていますが、plain形式で表示します |
SubTitile2 | ThisItem.created_at | 投稿日時です。UTCで表示されています |
Title2 | ThisItem.sender_id | 投稿者の内部ID番号です。 |
5.ラベル(最終イメージのLabel1)
処理の繰り返しが入ると終了までに時間がかかるので、ラベルで状態を表示しています。設定はTextプロパティひとつです。
プロパティ | 設定値 | コメント |
---|---|---|
Text | If(pageCount>0,"抽出しています..." & totalMessage,If(pageCount=0,"抽出が終わりました..." & totalMessage & "メッセージ","グループを選んでボタンを押してください")) |
動かしてみよう
最後に動作確認しましょう。
20メッセージより少ないグループを選んでボタンを押すと数秒で終了します。20メッセージ以上あるグループでは、20メッセージの表示とともにタイマーが動き始め、5秒後に処理が繰り返されることがわかります。
追加のサンプル投稿は**こちらの記事**から引用しました。ありがとうございます。
最後に
わかってみれば簡単なTimerを使った繰り返しワザ、如何でしたでしょうか。私のニーズにはバッチリでした。
最後にいくつか見た目の改善をしましょう。
投稿者を名前で表示したい!
Title2コントロールのTextプロパティを以下のように変更します。
変更前 | 変更後 |
---|---|
ThisItem.sender_id | Yammer.GetUserDetailsById(ThisItem.sender_id).full_name |
投稿日時を日本時間にしたい!
SubTitle2コントロールのTextプロパティを以下のように変更します。
変更前 | 変更後 |
---|---|
ThisItem.created_at | DateTimeValue(ThisItem.created_at) |
メッセージを古い順にしたい!
ギャラリーのItemsプロパティを以下のように変更します。
変更前 | 変更後 |
---|---|
MessagesInGroup | SortByColumns(MessagesInGroup,"created_at",Ascending) |
ところで「いいね!」のカウントどうするの?
説明しているとまだまだ長くなってしまいますので、関数だけ。
ClearCollect(MessagesByUser,GroupBy(MessagesInGroup,"sender_id","OtherColumns"));
ClearCollect(LikesByUser,SortByColumns(AddColumns(MessagesByUser,"MessageCount",Count(OtherColumns.id),"LikeCount",Sum(OtherColumns,liked_by.count)),"LikeCount",Descending))
それでは、良いお年をお迎えください。