【Power Apps+Automate】Teamsで「いいね」してない人に対してメンションするアプリ

Teamsで「いいね」をしてない人に対してスケジュール実行でメンションをするというフローをわたるふさんという方が2022年に作成しており、私も使わせていただいていました。

しかし、

  • チームメンバー全員ではなく、特定の人物だけにメンションしたい
  • 予約した投稿を簡単に取り消したい

といったことができませんでした。

上の機能をPower Appsと組み合わせることで実装しましたので紹介します。

アプリ・フローのダウンロード

アプリとフローはGitHubに公開しています。下記URLからダウンロードしてご利用いただけます。

機能など

実際のアプリ画面はこちらです。

アプリでリマインド先を設定し実行することで、チャネルにメンションしたり、いいねしてない指定した人にメンションしたり、予約投稿したりできます。

根本的にはわたるふさんのフローで、アプリでは下記2つの機能を追加しています。

  • チームメンバー全員ではなく、特定の人物だけにメンションしたい
  • 予約した投稿を簡単に取り消したい

解説

各パーツの機能や設定値などを紹介していきます。

データ

データとして下記3つを追加します。

  • Microsoft Teams
  • Office365グループ
  • PowerAutomate管理

「予約投稿取り消し機能」OnStart

予約投稿を取り消す方法として、下記方法で実装しています。

  1. 予約投稿時、自分宛てにアプリ起動URLにパラメータを付与したURLを通知する
  2. 通知されたURLからアプリを起動すると、Power Apps上でフローの取り消しを実行する。

アプリのAPP>OnStartに下記を設定します。

コピーしました!

OnStart
//URLから起動
If(IsBlank(Param("Category")) = false, //URLパラメータに何か入っていれば
    //パラメーターをグローバル変数に格納
	Set(varParamCategory,Text(Param("Category")));
    Set(varParamId,Text(Param("Id")));

    //フローキャンセル処理
    PowerAutomate管理.CancelFlowRun(
    "Default-99b882ac-a043-4d2e-9579-dbbef4dff629",
    "006e853e-817a-4a13-2a04-6045298f4c69",
    varParamId
    );
    Notify("予約投稿を取り消しました",NotificationType.Information)

);

URL構成は下記のように”Category”と”Id”を付け加えています。

URL
https://apps.powerapps.com/play/e/【環境ID等・略】&Category=ReminderCancel&Id=【フロー実行ID】

このURLをPower Automateで作成し、Teamsへ通知。取り消す際は通知されたURLへアクセスすることで、フローが取り消されるという動作になっています。

チーム

まずは、Teamsのチームを選択できるようにします。ドロップダウンのパーツのそれぞれのプロパティに下記を設定します。

コピーしました!

Items
Sort(MicrosoftTeams.GetAllTeams().value,displayName,SortOrder.Ascending)

次に、下記2つもここで実装します。

  • チャネル情報も取得し、グローバル変数に格納する
  • チームメンバーをPower Automate経由で取得する

もう少し別のパーツで機能として付けてもいいと思いますが、チームが確定したタイミングで上記2つが確定するため、このタイミングでデータの取得・準備を済ませます。

同じくチームのドロップダウンのパーツのOnChangeに下記を設定します。

コピーしました!

OnChange
//loading画面
UpdateContext({_loadingMenu:true});

//チームIDを格納
Set(ChannelData,Blank());
Set(ChannelData,MicrosoftTeams.GetChannelsForGroup(drp_team.Selected.id).value);
//Chatデータをリセット
Set(chatData,Blank());

//チームメンバーをリセット
UpdateContext({_colMemberList: Blank()});
//エラー検知:チームIDの空白を検知
If(
    IsBlank(
        drp_team.Selected.id),
    UpdateContext( { _teamIdError: "true" } ),
    UpdateContext( { _teamIdError: "false" } )
    );


// 条件判定と処理
If(
    Or(
        _teamIdError="true"
    )
    ,// エラーメッセージ
    Notify("エラーです。確認をお願いします。" & 
    If(_teamIdError="true","「チームが選択されていません」 ","")
    , NotificationType.Warning);

    ,
        
    //Power Automate実行
    UpdateContext({_colMemberListtmp: メンバーリスト取得.Run(drp_team.Selected.id)});
    
    //実行結果をテーブルへ変換
    UpdateContext(
        {
            _colMemberList: ForAll(
                Table(ParseJSON(_colMemberListtmp.memberlist)),
                {
                    id: Text(ThisRecord.Value.id),
                    displayName: Text(ThisRecord.Value.displayName),
                    jobTitle: Text(ThisRecord.Value.jobTitle),
                    mail: Text(ThisRecord.Value.mail),
                    preferredLanguage: Text(ThisRecord.Value.preferredLanguage)
        
                }
            )
        }
    );
    
    
);
//loading画面
    UpdateContext({_loadingMenu:false});

Power Appsではチームメンバーを100人以上取得できないため、Power Automate経由で取得します。

また、取得するデータや後続の操作等で分かりやすさやエラー防止の為、すでに取得したデータについてはクリアしてからデータを取得し直しています。

ローディング画面も準備していますが、データ取得中の誤操作を防ぐためです。

Power Automateは下記の様になっています。

特に特別なことはせず、Power AppsからTeamIDを受け取り、「グループメンバーの一覧表示」でメンバーを取得しアプリへ文字列にして返してています。(有料プランの場合はHTTPアクション等で返却しても良いと思います)

「グループメンバーの一覧表示」の設定の改ページを設定することで、より多くの人数分のデータが取得できます。

チャネル

選択したチームに応じて、チャネルを表示し選択できるようにします。チーム選択時、「ChannelData」というグローバル変数に格納しているので、Itemsにそのまま入れます。(Sortで並べ替えしています)

コピーしました!

Items
Sort(ChannelData,displayName,SortOrder.Ascending)

チャネルを選択することで、リマインド投稿したい投稿先が確定します。このタイミングでチャットデータを取得します。

コピーしました!

OnChange
//チャットデータを変数に格納
Set(chatData,Blank());
Set(chatData,MicrosoftTeams.GetMessagesFromChannel(drp_team.Selected.id,drp_channel.Selected.id).value);

リマインド先

リマインドをしたい投稿を選択できるようにします。閉じたり開いたりできるようにしていますが、ギャラリーに直接表示するだけで十分だと思います。閉じたり開いたりする設定などは、GitHubからダウンロードしたアプリをインポートしてご確認ください。ココでは最低限紹介します。

ギャラリーに下記を設定します。

コピーしました!

Items
chatData

メンションの宛先

「チャネルにメンションする」か「いいねしてない人にメンションする」かを選択できるようにします。

ドロップダウンのItemsに下記を設定します。

コピーしました!

Items
Table( 
    { id: 1,choices: "チャネルにメンションする" },
    { id: 2,choices: "いいねしてない人にメンションする" }
    
)

メンションの宛先

「いいねしてない人にメンションする」の場合にのみ表示させ、チームメンバーを選択できるようにします。チームメンバーはチーム選択時にAutomate経由で取得したデータを利用します。

わたるふさんのフローでは決まってチームメンバー全員が対象でしたが、ここでチームメンバー内の特定の数人を選択して実行することが可能になります。

コンテナで囲っているので、コンテナのVisibleに、「いいねしてない人にメンションする」(idが2)のときに表示できるように設定します。

コピーしました!

Visible
If(drp_メンション宛先.Selected.id=2,true,false)

メンバー選択のコンボボックスには下記を設定します。

コピーしました!

Items
_colMemberList

複数人に対してのメンションも動作するようになっていますので、「複数人の選択を許可」をONにします。

いつ実施するか

「いますぐ」か「日時を指定する」かを選択できるようにします。

ドロップダウンのItemsに下記を設定します。

コピーしました!

Items
Table( 
    { id: 1,choices: "いますぐ" },
    { id: 2,choices: "日時を指定する" }
    
)

予約日時

予約投稿の場合のみ表示し、予約する日時を設定できるように、日付の選択やドロップダウンを配置しています。

コンテナで囲っているので、コンテナのVisibleに、「日時を指定する」(idが2)のときに表示できるように設定します。

コピーしました!

Visible
If(drp_いつ.Selected.id=2,true,false)

予約日時

予約投稿の場合にのみ表示し、選択肢として「チャネルに投稿する」、「自分だけに知らせる」を選択できるようにします。

予約投稿の場合にのみ表示させる方法は先程と同じですので、割愛します。

選択肢として、ドロップダウンに下記を設定します。

コピーしました!

Items
Table( 
    { id: 1,choices: "チャネルに投稿する" },
    { id: 2,choices: "自分だけに知らせる" }
    
)

本文

リマインド時にテキストを付けられるように、リッチテキストエディターを作成します。

ボタン

一番下に配置している実行ボタンです。

処理をいくつかに分けて説明します。

エラーフラグ設定

チームの未選択や、メンション先の未選択の場合、フローが動作する条件を満たさない為、未選択かどうかを判定し、コンテキスト変数に格納しています。

コピーしました!

OnSelect
// ---  基本エラーフラグ(boolean)を一括設定 -------------------------------
UpdateContext({
    _teamIdErrorB:             IsBlank(drp_team.Selected.id),   //エラー検知:チームIDの空白を検知
    _channelIdErrorB:          IsBlank(drp_channel.Selected.id),    //エラー検知:チャネルIDの空白を検知
    _channelReplyIdErrorB:     IsBlank(gal_リマインド先.Selected.id),   //エラー検知:リマインド先、返信用IDの空白を検知
    _mentionAtesakiErrorB:     IsBlank(drp_メンション宛先.Selected.id),  //エラー検知:メンションの宛先の空白を検知
    _implementationTimingErrorB: IsBlank(drp_いつ.Selected.id)     //エラー検知:いつ実施かの空白を検知
});

予約投稿のチェック等

予約投稿の場合のエラーチェックや日時をAutomateに渡す形に加工しています。

エラーのチェックは下記2つのチェックです。

  • 設定した日時が過去ではないか
  • 設定した日時は30日以内か(Automateの実行最大時間)

コピーしました!

OnSelect
// 予約投稿のタイミングの選択状態を保持(boolean)
Set(_isReserveB, drp_いつ.Selected.id = 2);


// --- 予約投稿のときだけ日時を合成 & 差分(分)を計算 ----------------------
If(
    _isReserveB,
    // SelectedDateTime = 選択した日付 + 時 + 分
    Set(
        SelectedDateTime,
        DateAdd(
            DateAdd(
                DateValue(dte_予約日時_日.SelectedDate),
                Value(drp_予約日時_時.Selected.Value),
                TimeUnit.Hours
            ),
            Value(drp_予約日時_分.Selected.Value),
            TimeUnit.Minutes
        )
    );
    Set(DaysDifference, DateDiff(Now(), SelectedDateTime, TimeUnit.Minutes));
    UpdateContext({
        _yoyakuJouhouErrorB:     IsBlank(drp_予約情報.Selected.id),  //エラー検知:予約情報の通知先空白
        _dateTimeErrorB:     DaysDifference >= 43200, // 30日 = 43200分
        _dateTimeMiniErrorB: DaysDifference <= 0      // 過去
    }),
    // 日時指定でない場合は日時系エラーなし
    UpdateContext({ _yoyakuJouhouErrorB: false,_dateTimeErrorB: false, _dateTimeMiniErrorB: false })
);

メンションの宛先メンバー作成等

メンションの宛先が「いいねしてない人」の場合、対象者のメールアドレスを配列でまとめておきます。また、チャネル宛の場合は空白を渡してエラーになるので、適当に「1」を渡すように設定します。

コピーしました!

OnSelect
// --- メンションの宛先作成:メンションの宛先------------------
    If(
        drp_メンション宛先.Selected.id=2
        ,
        //いいねしてない人にメンションの場合:宛先のメールアドレスだけを配列で渡す為に変換
        Set(_channelMentionMember, JSON(ShowColumns(cmb_メンションメンバー.SelectedItems,mail),JSONFormat.Compact));
        
        ,
        //チャネルにメンションの場合:フローで不要なので適当に「1」を送る
        Set(_channelMentionMember, "1");
        );

メンションの宛先メンバー作成等

エラーの変数とメッセージのコレクションを作り、エラーの判定を行い、エラーがゼロの場合、Power Automateを実行する形にしています。

コピーしました!

OnSelect
// --- エラーコレクションを作って、まとめて通知 or 成功処理 ------------------
ClearCollect(
    _errorsB,
    { flag: _teamIdErrorB,              msg: "「チームが選択されていません」" },
    { flag: _channelIdErrorB,           msg: "「チャネルが選択されていません」" },
    { flag: _channelReplyIdErrorB,      msg: "「リマインド先が選択されていません」" },
    { flag: _mentionAtesakiErrorB,      msg: "「メンションの宛先が選択されていません」" },
    { flag: _implementationTimingErrorB,msg: "「『いつ実施しますか?』が選択されていません」" },
    { flag: _dateTimeErrorB,            msg: "「予約投稿は720時間(30日)未満で設定してください」" },
    { flag: _dateTimeMiniErrorB,        msg: "「予約投稿が過去の日時になっています。」" },
    { flag: _yoyakuJouhouErrorB,        msg: "「予約投稿の通知先が選択されていません。」" }
);

If(
    CountRows(Filter(_errorsB, flag)) > 0,
    // ---- エラーあり:まとめて警告 ----
    Notify(
        "エラーです。確認をお願いします。 " &
        Concat(Filter(_errorsB, flag), msg & " "),
        NotificationType.Warning
    ),

    // ---- エラーなし:Power Automate 実行 → JSON をテーブル化 ----
    Powerapps_リマインド.Run(
        drp_team.Selected.id,   //チームID
        drp_channel.Selected.id,    //チャネルID
        gal_リマインド先.Selected.id,    //リマインド先チャットID
        drp_メンション宛先.Selected.id,    //メンションの宛先
        _channelMentionMember,    //メンションの宛先メンバー
        drp_いつ.Selected.id,    //いつ実行か
        Text(SelectedDateTime,DateTimeFormat.UTC),    //予約投稿日時
        drp_予約情報.Selected.id, //予約情報どこに投稿か
        User().Email,         //実行者メール
        drp_channel.Selected.displayName,    //チャネル名
        rtx_本文.HtmlText //本文




    );

);

参考記事など

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA