Microsoft Teams: チャンネルに投稿

Microsoft Teams: チャンネルに投稿

Microsoft Teams: Post to Channel

この工程は、Microsoft Teams のチャンネルに、メッセージまたはメッセージへの返信を投稿します。

Basic Configs
工程名
メモ
Auto Step icon
Configs for this Auto Step
conf_OAuth2
C1: OAuth2 設定 *
conf_TargetUrl
C2: 投稿先チャンネル/返信先メッセージの URL *
conf_Subject
C3: メッセージの件名(メッセージへの返信の場合、無視されます)#{EL}
conf_Markdown
C4: 投稿文(Markdown) *#{EL}
conf_PostUrl
C5: 投稿したメッセージ/返信の URL を保存するデータ項目

Notes

  • チャンネル/メッセージの URL は、チャンネル名またはメッセージの横にある 「・・・」アイコン(その他のオプションメニュー)をクリックして「リンクのコピー」 を選択することで取得できます

Capture

See Also

Script (click to open)
  • 次のスクリプトが記述されている XML ファイルをダウンロードできます
    • microsoft-teams-channel-post.xml (C) Questetra, Inc. (MIT License)
    • Professional のワークフロー基盤では、ファイル内容を改変しオリジナルのアドオン自動工程として活用できます

// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize
// - Token Endpoint URL: https://login.microsoftonline.com/organizations/oauth2/v2.0/token
// - Scope: ChannnelMessage.Send offline_access
// - Consumer Key: (Get by Microsoft Azure Active Directory)
// - Consumer Secret: (Get by Microsoft Azure Active Directory)

const GRAPH_URI = 'https://graph.microsoft.com/v1.0/';

const main = () => {
    //// == 工程コンフィグの参照 / Config Retrieving ==
    const oauth2 = configs.getObject('conf_OAuth2');
    const targetUrl = retrieveTargetUrl();
    const subject = configs.get('conf_Subject');
    const markdownText = configs.get('conf_Markdown') ?? '';
    if (markdownText === '') {
        throw new Error('Post Content is empty.');
    }

    //// == 演算 / Calculating ==
    const {teamId, channelId, messageId} = parseTargetUrl(targetUrl);
    const postUrl = post(oauth2, teamId, channelId, messageId, subject, markdownText);

    //// == ワークフローデータへの代入 / Data Updating ==
    saveData('conf_PostUrl', postUrl);
};

/**
 * config から投稿先 URL を読み出す
 * 空の場合はエラー
 * @returns {String}
 */
const retrieveTargetUrl = () => {
    let targetUrl = configs.get('conf_TargetUrl');
    const def = configs.getObject('conf_TargetUrl');
    if (def !== null) {
        targetUrl = engine.findData(def);
    }
    if (targetUrl === null || targetUrl === '') {
        throw new Error('Target URL is empty.');
    }
    return targetUrl;
};

/**
 * 投稿先の URL をパースし、teamId, channelId, messageId を返す
 * チャンネル URL: https://{domain}/{path}/channel/{channelId}/{channelName}?groupId={teamId}&tenantId={tenantId}
 * チャンネルメッセージ URL: https://{domain}/{path}/message/{channelId}/{messageId}?...&groupId={teamId}&...
 * @param {String} targetUrl
 * @returns {Object} teamId, channelId, messageId
 */
const parseTargetUrl = (targetUrl) => {
    const [pathPart, queryPart] = targetUrl.split('?');
    const pathSegments = pathPart.split('/');
    const queryParams = parseQueryParams(queryPart);

    // メッセージ URL の判定
    const messageIndex = pathSegments.indexOf('message');
    if (messageIndex !== -1 && messageIndex + 2 < pathSegments.length) {
        const channelId = decodeURIComponent(pathSegments[messageIndex + 1]);
        const messageId = decodeURIComponent(pathSegments[messageIndex + 2]);
        const teamId = queryParams.groupId;
        if (teamId === undefined) {
            throw new Error(`groupId not found in target URL: ${targetUrl}`);
        }
        engine.log(`teamId: ${teamId}, channelId: ${channelId}, messageId: ${messageId}`);
        return { teamId, channelId, messageId };
    }

    // チャンネル URL の判定
    const channelIndex = pathSegments.indexOf('channel');
    if (channelIndex === -1 || channelIndex + 1 >= pathSegments.length) {
        throw new Error(`Invalid Target URL: ${targetUrl}`);
    }
    const channelId = decodeURIComponent(pathSegments[channelIndex + 1]);
    const teamId = queryParams.groupId;
    if (teamId === undefined) {
        throw new Error(`groupId not found in target URL: ${targetUrl}`);
    }
    engine.log(`teamId: ${teamId}, channelId: ${channelId}`);
    return { teamId, channelId, messageId: null };
};

/**
 * クエリ文字列をパースしてオブジェクトにする
 * @param {String|undefined} queryPart
 * @returns {Object}
 */
const parseQueryParams = (queryPart) => {
    if (queryPart === undefined) {
        return {};
    }
    const params = {};
    queryPart.split('&').forEach(param => {
        const [key, ...rest] = param.split('=');
        params[key] = rest.join('='); // value に = が含まれる場合を考慮
    });
    return params;
};

/**
 * メッセージを投稿する
 * @param {AuthSettingWrapper} oauth2  OAuth2 設定情報
 * @param {String} teamId
 * @param {String} channelId
 * @param {String|null} messageId
 * @param {Strung} subject
 * @param {String} markdownText
 * @returns {String} 投稿したメッセージの URL
 */
const post = (oauth2, teamId, channelId, messageId, subject, markdownText) => {
    let url;
    if (messageId !== null) { // チャンネルメッセージへの返信
        url = `${GRAPH_URI}teams/${encodeURIComponent(teamId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}/replies`;
    } else { // チャンネルへの投稿
        url = `${GRAPH_URI}teams/${encodeURIComponent(teamId)}/channels/${encodeURIComponent(channelId)}/messages`;
    }
    const reqBody = {
        body: {
            contentType: 'html',
            content: markdown.toHtml(markdownText)
        }
    };
    if (subject !== '' && messageId === null) {
        reqBody.subject = subject;
    }
    const response = httpClient.begin()
        .authSetting(oauth2)
        .body(JSON.stringify(reqBody), 'application/json; charset=UTF-8')
        .post(url);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 201) {
        engine.log(responseStr);
        throw new Error(`Failed to post message. status: ${status}`);
    }
    return JSON.parse(responseStr).webUrl;
};

/**
 * データ項目への保存
 * @param {String} configName
 * @param {*} data
 */
const saveData = (configName, data) => {
    const def = configs.getObject(configName);
    if (def === null) {
        return;
    }
    engine.setData(def, data);
};

    
上部へスクロール

Questetra Supportをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む