💬 Microsoft Teams 開発の初心者向けガイド その3: メッセージ・エクステンション


みなさんこんにちは〜。この記事は、Microsoft Teams 開発の初心者向けガイド第３弾になります。前回の2つのチュートリアル ( [タブの開発](https://qiita.com/girlie_mac/items/97fa81e67ad6ba0f6f35) と [Bot 開発](https://qiita.com/girlie_mac/items/18cb83a021f3412317c6)）も楽しんでもらえていたらうれしいです。

今回は、Teams UI からのユーザからのアクションで検索結果やメッセージを書き出す方法について説明します。
![3-ext1-cover-1000x420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/c97928d9-2a4d-2d7f-cc2c-19af73a54b81.png)
Teams アプリの作成にはいくつもの方法やツールがあるのですが、このチュートリアルでは、コンセプトを学んでもらうことを重視したいので、最低限のコードと最小限のツールセットを使用しています。また、マイクロソフト Azure から 環境をセットアップすることもできますが、今回はそのプロセスを使わず、気軽に学んでもらえるようにブラウザ上でコードを実行していきます。

---

このチュートリアルでは、[メッセージング・エクステンション](https://docs.microsoft.com/ja-jp/microsoftteams/platform/messaging-extensions/what-are-messaging-extensions?WT.mc_id=m365-9174-timura) (Messaging Extensions / メッセージング拡張機能)という機能をつかった開発について紹介します。

メッセージング拡張機能には、アクションと検索という 2 種類があるのですが、今回は「**アクション・コマンド**」（操作コマンド）について紹介します。


# チームの機能: 「アクション・コマンド」

アクション・コマンドを使用すると、情報を収集または表示するためのモーダル ポップアップをユーザーに表示できます。フォームを送信すると、アプリ、つまり Web サービスは、メッセージを会話に直接挿入したり、メッセージ作成ボックスに挿入してユーザーの選択でグループにメッセージを送信できるようにしたりできます。

![Teams action command](https://docs.microsoft.com/en-us/microsoftteams/platform/assets/images/task-module.png)


## メッセージ・アクションをつかって、メッセージ内容をモールス コードに変換するサービスを作る！

いまから作成していくアプリは、ユーザーが選んだ任意のメッセージに含まれるテキストを抽出してモールスコードに変換する、というものです。

アプリの動作は次のとおりです。

1. ユーザーがメッセージをマウスオーバーしてメッセージメニューを開き、「そのほかの操作」(More actions) メニューからモールス bot を選択
2. ユーザーからの操作がトリガーされると、ペイロードがメッセージングエンドポイントに送信。 (/api/messages)
3. fetchTask の呼び出し。ここでメッセージ テキスト データが抽出されます。
4. ポップアップ ダイアログが表示されます。ユーザーは必要に応じてテキストコンテンツを編集し、送信
5. アプリは、テキストをモールスコードに変換し、コンテンツを返信として表示
6. ユーザーは結果をクライアントに新規メッセージとして送信

結果は次のようになります。
![morsebot-final.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/1544c785-8e60-e1ef-9b40-befe90cf6b55.gif)

### 📓 必須科目

Teams にアプリをインストールできるようにするには、組織の管理者がアクセス許可を付与する必要があります。
それ以外の場合は、無料の**Microsoft 365 開発者プログラム** に登録しましょう。このプログラムでは、開発者テナントのサンドボックス、サンプル データ パックに付属しているモック ユーザーデータなどが使え、サブスクリプションはなどでもリニューアルできます。

- 開発の許可がある Teams テナント、または開発専用テナント ([M365 開発者プログラムにサインアップしよう](https://developer.microsoft.com/ja-jp/microsoft-365/dev-program/?WT.mc_id=m365-devto-timura))
- App Studio - チームクライアントのアプリメニューからアプリを探し、テナントのワークスペースにインストールしてね
- JavaScript の基礎知識

### 👾 このチュートリアルで使用する技術

- Node.js
- [Microsoft Bot Framework](https://dev.botframework.com/?WT.mc_id=m365-devto-timura)  
- [Adaptive Cards](https://adaptivecards.io/?WT.mc_id=m365-9173-timura) for building some UI snippets


## アクションの構築

###🎏 コード サンプルの取得

このチュートリアル シリーズでは、プロジェクトのコードのホスティングと実行を簡略化するために、サードパーティのツール、[Glitch](https://glitch.com/)を使用しています。

Glitch は、node.jsコードを記述して実行できるWebベースのIDEなので、少なくとも今のところ、localhostのトンネル、デプロイを気にすることなく、Teamsアプリ開発の概念と基本を学ぶことに集中できます。

まず、この Glitch プロジェクトの [*remix* ができるリンク](https://glitch.com/edit/#!/remix/msteams-msg-extension-action)、または下のボタンをクリックしてください。リミックスとは GitHub で言うところのリポジトのをフォークのようなようなもので、自分用のプロジェクトのコピーが生成されるため、元のコードに影響なく自分用に好きなように変更できます。
[![Remix on Glitch](https://cdn.glitch.com/2703baf2-b643-4da7-ab91-7ee2a2d00b5b%2Fremix-button.svg)](https://glitch.com/edit/#!/remix/msteams-msg-extension-action)
さて、自分専用プロジェクトのリポを取得すると、自動的に独自のWebサーバーURLを取得します。たとえば、生成されたプロジェクトは、３単語ほどでできたランダムな語で構成されています。たとえばそのプロジェクト名が *achieved-diligent-bell* だったら、ウェブサーバーのURLは `https://achieved-diligent-bell.glitch.me` になります。必要に応じて名前をカスタマイズすることもできます。

### ⚙️ App Configuration: App Studioを使ってアプリ マニフェストを作成

Teams アプリパッケージの基本については[前のチュートリアル](https://dev.to/azure/beginners-guide-to-ms-teams-development-2-bots-590m)を参照してください。

### 🎛 App Studio を使う

App Studio 上部の **Manifest Editor**（マニフェスト エディター） タブをクリックし、**Create a new app**（新しいアプリの作成]）を選択します。必要事項を入力してください。

そして App ID を生成してください。
![exts00-app-studio-ext.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/20fb3626-fb67-15a0-e75a-a8a665bef4b9.png)


### 🔖 メッセージ・エクステンションの設定

左側のメニューから、 Capabilities > **Massaging Extensions** を選択
![exts01-app-studio-ext.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/107d69ee-5ebf-2e85-3247-7916bb31e1ae.png)
先に進み、設定するボタンをクリック。
![exts02-app-studio-ext1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/86a9aaf1-86b4-f736-a3cf-fafb1e71c43b.png)
名前を付けます。

### 🔐 App credentials

ボット名の横にある ID ('2cd53e8a-e698-4exx-...' のように見える) をコピーし、隠しファイルである_.env_ファイルに環境変数として貼り付けます ('.env-sample' の名前を '.env' に変更します)。

**App Passwords**の下で新規パスワードを生成し、それをコピーし、これも _.env_ファイルに貼り付けます。

これらの情報は、bot アダプターを初期化するために使用されます。(index.js を参照してください。
![exts03-app-studio-ext2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/93fb2bb4-900e-9b43-5f99-96c8fdcf0af5.png)
(上記の画面画像のステップ3は、このすぐ後に説明します。)

### 🎬 アクションの設定

**Messaging Endpoint** で、サーバーを入力します。今回は、Glitch サーバ上でコードを動かしているので、 `https://[your project].glitch.me/api/messages`  のように自分のプロジェクト名が入った URL がサーバとなります。

 **Command** までスクロールし [Add] をクリック

ダイアログ ボックスで 
1. **Allow users to trigger actions in external service...** を選択
2. **Fetch a dynamic set of parameters from your bot** を選択
3. **command ID** と **title text** を入力。 **Massage** チェックボックスを選択 (他のチェックボックスが事前に選択されている場合は、そのチェックボックスをオフにします。) 残りは空白のままにして保存します。
![exts04a-app-studio-ext3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/b36c77b4-b309-2a25-630b-2ca7034eb45b.png)
![exts04b-app-studio-ext4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/ab7ac3bd-927c-89ce-a6b1-cf4bc0d8324d.png)
![exts04c-app-studio-ext5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/a0d22922-a244-5183-8d56-bddb6910db34.png)

### 📦 App manifest パッケージをインストール

**Finish > Test and distribute** へ行きます。

エラーが発生した場合は、それを修正してください、そうでなければ、**Install** をクリックしてください。
![exts05-app-studio-install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/40505326-948e-6ac9-f214-18f12fdd449c.png)
また、'manifest.json' を含む zip ファイルと、後でインストールまたは配布する 2 つのアイコン イメージをダウンロードすることもできます。

コード サンプルをそのままリミックスしている限り、この bot は既に動作するはずでが、試してみる前に、これがどのようにコーディングされているかを簡単に説明してみます。

## 🤖 Microsoft Bot Framework

[マイクロソフトボットフレームワーク](https://dev.botframework.com/?WT.mc_id=m365-9174-timura) は、インテリジェントなエンタープライズグレードのボットを構築できるオープンソースSDKです。

この SDK は、Teams だけでなく、Web やモバイル チャット、Skype、Facebook、Amazon Alexa、Slack、Twilio など、幅広い種類のチャット ボットで動作するように設計された強力なプラットフォームです。

### 🔧 Initiating the bot service

まず、Glitch コード サンプル Repo に 2 つの JS ファイルがあります。 **index.js** and **bots.js** です。

ここでは、Express を使用して HTTP サーバーを設定し、HTTP リクエストをルーティングしています。サービスを開始する方法は、前の Bots チュートリアルと同じですが、これは初期化とボット アダプタの作成について、もう一度要約したコードが下のようになります。

```js
// Import bot services
const { BotFrameworkAdapter } = require('botbuilder');

// Bot's main dialog
const { ReverseBot } = require('./bot');

// App credentials from .env
const adapter = new BotFrameworkAdapter({
  appId: process.env.MicrosoftAppId,
  appPassword: process.env.MicrosoftAppPassword
});

// Create the main dialog
const myBot = new MorseBot();
```

*注:この例では、私はボットビルダーのバージョン4.10.0を使用しています。コードが期待どおりに動作しない場合は、使用しているバージョンを確認してください!*

### 🦉 Bot ロジックへの要求の転送

Express を使用して、着信リクエストをリッスンするルーティングを処理します。

```js
app.post('/api/messages', (req, res) => {
  adapter.processActivity(req, res, async context => {
    await myBot.run(context);
  });
});
```
前の手順で、 App Studio で URL を設定しました。`/api/messages` は、クライアント要求に応答するアプリケーションのエンドポイント URL です。

### 🙋‍♀️ リクエストの処理

エンドポイントで要求を受信し、ボット ロジックに転送すると、アプリは要求のコンテクストを受け取り、**bots.js** でカスタム応答を作成します。

要求に対する適切なハンドラーを作成するために拡張された `TeamsActivityHandler` を参照してください。

```js
class ReverseBot extends TeamsActivityHandler {

  // ユーザからのアクションによってトリガー
  handleTeamsMessagingExtensionFetchTask(context, action) {
    /*
         ここで表示するダイアログのコンテンツを adaptive card UI (modal dialog)を作成。
         ユーザがダイアログを確認して送信。
    */
  }
  
// FetchTask からユーザによって送信されたらトリガー
  handleTeamsMessagingExtensionSubmitAction(context, action) {
    // display the result 
  }
```

`TeamsActivityHandler` は、メッセージ イベント (*例えば `onMembersAdded` メソッドが会話にメンバーが追加されるたびに呼び出される) などのメッセージを処理し、返信を送信するチーム固有のクラスです。

ここでは、ユーザがメッセージに対しアクションを起こすと、`handleTeamsMessagingExtensionFetchTask` がトリガーされ、ボットが元のメッセージに関する情報を受け取ります。

これらについてはドキュメント「[タスクモジュールを作成して送信する](https://docs.microsoft.com/ja-jp/microsoftteams/platform/messaging-extensions/how-to/action-commands/create-task-module?tabs=javascript/?WT.mc_id=m365-9174-timura) 」でもっと詳しく学ぶことができます。


### 📇 アダプティブ カードを使用したモーダル ダイアログの表示

ダイアログ UI は、 Microsoft のオープン ソースである　[**アダプティブ カード**](https://adaptivecards.io/?WT.mc_id=m365-9174-timura)を使って JSON で UI を構築することができます。アダプティブ カードは、Teams の他、Outlook のアクション可能なメッセージ、Cortana スキルなどさまざまな Microsoft ファミリーのサービスの開発で使うことができます。

`handleTeamsMessagingExtensionFetchTask` が呼び出されると、メッセージ コンテンツ テキストを取得し、応答としてダイアログとしてアダプティブ カードに表示します。
![adaptive-card-message-action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/60c90880-845f-c478-faf1-9e898764c457.png)

アダプティブ カードとコンテンツを定義するには:
 
```js
const card = {
  type: 'AdaptiveCard',
  version: '1.0'
};

card.body = [
        { type: 'TextBlock', text: 'The message to be encoded to Morse code:', weight: 'bolder'},
        { id: 'editedMessage', type: 'Input.Text', value: content },
      ];
      card.actions = [{
        data: { submitLocation: 'messagingExtensionFetchTask'},
        title: 'Encode to Morse!',
        type: 'Action.Submit'
      }];

const adaptiveCard = CardFactory.adaptiveCard(card);

return {
      task: {
        type: 'continue',
        value: {
          card: adaptiveCard
        }
      }
    };
```

抽出されたメッセージテキストを `type: 'Input.Text'` で表示し、ユーザーがモールスコード化するテキストを編集できるようにします。

完全なコードを表示するには、グリッチのコード サンプルの **bot.js** ファイルを参照してください。

### 📮 ユーザーの送信を処理する

ユーザーがタスク モジュールを送信すると、`handleTeamsMessagingExtensionSubmitAction` がトリガーされ、Web サービスはコマンド ID とパラメーター値が設定されたオブジェクトを受け取ります。

このサンプル コードでは、カスタム データ `editedMessage` が存在するかどうかだけを確認します。その場合は、値（ここでは文字列) を取得し、それをモールスに変換して、新しいメッセージとして作成するコンテンツを表示します。

```js
async handleTeamsMessagingExtensionSubmitAction(context, action) {

    if(action.data.editedMessage) {
      const text = action.data.editedMessage;
      const morseText = await encodeToMorse(text);

  return {
    composeExtension: {
    type: 'result',
      attachmentLayout: 'list',
      attachments: [
        // the message UI component here
      ]
    }
  }

}
```

**bots.js** に示されているコードサンプルでは、結果メッセージを作成するために Bot Framework に付属の[サムネイルカード](https://docs.microsoft.com/ja-jp/microsoftteams/platform/task-modules-and-cards/cards/cards-reference#adaptive-card/?WT.mc_id=m365-9174-timura)と呼ばれるシンプルなUI カードを使用していますが、もちろん前述のアダプティブカードも使用できます。

### 🤖💬 メッセージアクションを試してみる

それでは、アクションを試してみましょう!
Teams クライアントに移動し、リッチ フォーマットや画像ではない、シンプルテキストで構成されたメッセージのいずれかをクリックしてみてください。

すべてが期待どおりに動作する場合は、任意のテキスト メッセージをモールス コードに変換できるはずです。

![more-actions-ja.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663749/ec0a9417-54aa-afe4-5ed7-80d68c61cd02.png)

🎉

チュートリアルを楽しんでいただけましたか？モールス・コードへの変換は正直、あまり普段役に立つものではないでしょうけれど、みなさんはもっと良いユースケースを見つけて素晴らしいアプリを作成することを願っています!

次のチュートリアルでは、検索コマンドである別の種類のメッセージング拡張機能を構築する方法について説明します。次回お会いしましょう 👋

🇺🇸 *この記事を英語で読みたいという方は [dev.to](https://dev.to/azure/beginners-guide-to-ms-teams-development-3-messaging-action-5ejc) のリンクからどうぞ！*

## 📚 Learn more

- MS Teams Documentation - [メッセージング・エクステンション](https://docs.microsoft.com/ja-jp/microsoftteams/platform/messaging-extensions/what-are-messaging-extensions?WT.mc_id=m365-9174-timura) 
- [Microsoft Bot Frameworks](https://dev.botframework.com/?WT.mc_id=m365-devto-timura)
- Bot Services Documentation - [How bot works?](https://docs.microsoft.com/ja-jp/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0&tabs=javascript&WT.mc_id=m365-devto-timura)
- [アダプティブ カード](https://adaptivecards.io/?WT.mc_id=m365-9174-timura)
- [[完全無料で] Microsoft Teams で動く オレオレ bot を 1 時間で作る](https://qiita.com/chomado/items/6bda10abde0551f25723?WT.mc_id=M365-qiita-timura) - Azure からボットを作っていきます 
- [Microsoft @ Qiita](https://qiita.com/organizations/microsoft?WT.mc_id=m365-qiita-timura)