daab 仕様

daab は GitHub社の Hubot を拡張したものです。 基本的なスクリプトの書き方は公式ドキュメントを参考にしてください。 以下では、direct 用に Hubot を拡張した点について記述しています。


メッセージの送信

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    robot.respond(/.../i, (res) => {
        // here
    });
}

上記のコードブロック外から送信するときは、以下のようにします。idの部分は後述の「トークルームの識別」を参照してください。

module.exports = (robot) => {
    robot.send({ room: '...id...' }, '...message...');

    // もしくは
    robot.send({ room: '...id...' }, { text: '...message...' });
}

テキスト (Hubot)

res.send('This message is text.');

もしくは、以下も同等です。

res.send({ text: 'This message is text.' });

スタンプ

res.send({
    stamp_set: '3',
    stamp_index: '1152921507291203198',
    text: 'おはよう'  // (Option) テキスト付きスタンプの場合のみ
});

※ stamp_set と stamp_index は、ブラウザの「要素の検証」等で確認してください。

<img src='./images/stamp/3/1152921507291203198.png'>

Yes/No スタンプ

res.send({
    question: '質問内容'
});

送信したYes/Noスタンプは締め切ることができます。

res.send({
    close_yesno: sent.message.id
});

sent.message.id については「メッセージの送信完了」を参照してください。

セレクトスタンプ

res.send({
    question: '質問内容',
    options: ['選択肢1', '選択肢2', '選択肢3']
});

送信したセレクトスタンプは締め切ることができます。

res.send({
    close_select: sent.message.id
});

sent.message.id については「メッセージの送信完了」を参照してください。

タスクスタンプ

res.send({
    title: 'すること',
    closing_type: 0  // (Option) 誰かが:0, 全員が:1
});

送信したタスクスタンプは締め切ることができます。

res.send({
    close_task: sent.message.id
});

sent.message.id については「メッセージの送信完了」を参照してください。

ファイル

res.send({
    path: 'your/file/name.png',
    name: 'name.png',    // (Option) アップロード名
    type: 'image/png',   // (Option) MIME
    text: 'send file',   // (Option) ファイルと同時に送信するテキスト
});

※ 複数ファイルを送信するときは、path や name に配列を渡してください。

res.send({
    path: ['your/file1.png', 'your/file2.png'],
    name: ['name1.png', 'name2.png']   // (Option)
});

メッセージの受信

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    // here
}

テキスト (Hubot)

robot.respond(/(.*)/, (res) => {
    res.send(`Your message is ${res.match[1]}`);
}

※ メッセージ本文は res.message.text で参照できます。

スタンプ

robot.respond('stamp', (res) => {
    res.send(`${res.json.stamp_set} - ${res.json.stamp_index}`);
}

Yes/No スタンプ

robot.respond('yesno', (res) => {
    if (res.json.response === null) {
        res.send(`Your question is ${res.json.question}.`);
    } else {
        res.send(`Your answer is ${res.json.response}.`);
    }
});

受信したYes/Noスタンプに返信できます。

robot.respond('yesno', (res) => {
    res.send({
        in_reply_to: res.message.id,
        response: true
    });
});

セレクトスタンプ

robot.respond('select', (res) => {
    if (res.json.response === null) {
        res.send(`Your question is ${res.json.question}.`);
    } else {
        res.send(`Your answer is ${res.json.options[res.json.response]}.`);
    }
});

受信したセレクトスタンプに返信できます。

robot.respond('select', (res) => {
    res.send({
        in_reply_to: res.message.id,
        response: 0
    });
});

タスクスタンプ

robot.respond('task', (res) => {
    if (res.json.done === null) {
        res.send(`Your task is ${res.json.title}.`);
    } else {
        res.send(`Your task is ${ res.json.done ? 'done' : 'undone' }.`);
    }
});

受信したタスクスタンプに返信できます。

robot.respond('task', (res) => {
    res.send({
        in_reply_to: res.message.id,
        done: true
    });
});

ファイル

const onfile = (res, file) => {
    res.send({
        text: 'File received.',
        name: file.name,
        type: file.content_type,
        size: `${file.content_size}bytes`,
    });
    res.download(file, (path) => {
        res.send(`downloaded to ${path}`);
    });
};

# ファイルが1つだけの場合
robot.respond('file', (res) => {
    onfile(res, res.json);
});

# ファイルが複数の場合
robot.respond('files', (res) => {
    for (const file of res.json.files) {
        onfile(res, file);
        if (res.json.text) {
            res.send(`with text: ${res.json.text}`);
        }
    }
});

位置情報

robot.respond('map', (res) => {
    res.send(`Your location is ${res.json.place} at ${res.json.lat}, ${res.json.lng}`);
});

トークルーム情報

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    robot.respond(/room/i, (res) => {
        // here
    });
}

トークルームの識別 (Hubot)

res.send(`This room id is ${res.message.room}`);

※ direct特有のトークルーム情報は以下のようにして取得できます。

console.log(res.message.rooms[res.message.room]);

トークルームの種類

res.send(`This room type is ${['unknown', 'pair', 'group'][res.message.roomType]}`);

トークルーム名

if (res.message.roomType === 2) {
    // Group talk
    res.send(`Group name is ${res.message.roomTopic}`);
}

トークルーム名の変更 (Hubot)

res.topic('BotGroup');

トークルームの参加者情報

const text = res.message.roomUsers.map(user => `${user.name} ${user.email} ${user.profile_url}`).join('\n\n');
res.send(text);

トークルームの一覧

const text = Object.entries(res.message.rooms)
    .map(([id, talk]) => `name:${talk.topic} type:${talk.type} users:${talk.users.map(user => user.name).join(',')}`)
    .join('\n\n');

res.send(text);

※ res オブジェクトが利用できない場合は、res.message.rooms の代わりに robot.brain.rooms() も利用できます (注:関数呼出しになります)。


連絡先情報の取得

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    robot.respond(/users/i, (res) => {
        // here
    });
}

メッセージ送信者の連絡先 (hubot)

res.send(`Sender is ${res.message.user.name}.`);

連絡先の一覧 (hubot)

const users = robot.brain.users();
console.log(users);  // { id0:user0, id1:user1, ... }

IDによる連絡先の検索 (hubot)

const userId = Object.keys(users)[0];
console.log(robot.brain.userForId(userId));

名前による連絡先の検索 (hubot)

const user = users[userId];
console.log(robot.brain.userForName(user.name));

※ その他にも、usersForRawFuzzyName (先頭一致)、usersForFuzzyName (先頭一致、ただし、完全一致を優先) も利用できます。


組織情報の取得

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    robot.respond(/domains/i, () => {
        // here
    });

所属する組織の一覧

const domains = robot.brain.domains();
console.log(domains);

アクションスタンプの回答情報

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    robot.respond(/answers/i, (res) => {
        res.send({
            ...各スタンプの内容...
            onsend: (sent) => {
                setTimeout(() => {
                    // here
                }, 5000);
            }
        });
    });
}

※ 例として、5秒後の回答状況を取得しています。

Yes/No スタンプ

sent.answer((trueUsers, falseUsers) => {
    console.log('YES', trueUsers);
    console.log('NO', falseUsers);
});

セレクトスタンプ

sent.answer((optionUsers) => {
    optionUsers.forEach((users, i) => {
        console.log(sent.message.content.options[i], users);
    });
});

タスクスタンプ

sent.answer((doneUsers, undoneUsers) => {
    console.log('DONE', doneUsers);
    console.log('UNDONE', undoneUsers);
});

イベント

以下のコードブロックの内側についてのものとします。

module.exports = (robot) => {
    // here
}

ペアトークでのメッセージ受信 (Hubot)

robot.respond(/.../, (res) => {
    res.send('');
});

respond はグループトーク中の「@hubot名 メッセージ」の場合でも呼ばれます。厳密にペアトークのみに対応させたいときはif (res.message.roomType === 1) で場合分けしてください。

グループトークでのメッセージ受信 (Hubot)

robot.hear(/.../, (res) => {
    res.send('');
});

トークルーム名の変更 (Hubot)

robot.topic((res) => {
    res.send(`Topic is changed: ${res.message.text}`);
});

トークルームへのユーザーの参加 (Hubot)

robot.enter((res) => {
    res.send(`Hi! ${res.message.user.name}`);
});

トークルームからのユーザーの退出 (Hubot)

robot.leave((res) => {
    res.send(`Good bye! ${res.message.user.name}`);
});

招待による自分自身のトークルームへの参加

robot.join((res) => {
    res.send('Nice to meet you!');
});

メッセージの送信完了

送信メッセージに onsend を付与することで、そのメッセージの送信完了後に処理を行うことができるようになります。

res.send({
    text: 'Now sending...',
    onsend: (sent) => {
        res.send(`completed. messageId: ${sent.message.id}`);
    }
});

メッセージの未読・既読

送信メッセージに onread を付与することで、そのメッセージの未読・既読情報を取得できるようになります。

robot.respond(/read after/, (res) => {
    res.send({
        text: 'Read thie message, please!',
        onread: () => true,
        onsend: (sent) => {
            setTimeout(() => {
                const text = [
                    ...sent.readUsers.map(user => `${user.name} read after 5sec.`),
                    ...sent.unreadUser.map(user => `${user.name} did't read after 5sec.`),
                ].join('\n');
                res.send(text);
            }, 5000);
        }
    });

未読・既読の変更を監視したい場合は、以下のようにします。 (24時間たっても変更がなければ監視は終了します。)

robot.respond(/read now/, (res) => {
    res.send({
        text: 'Read thie message, please!',
        onread: (readNowUsers, readUsers, unreadUsers) => {
            const text = readNowUsers.map(user => `${user.name} read now.`).join('\n');
            res.send(text);
        }
    });
});

その他

トークルームからの退出

res.leave();

指定したユーザをトークルームから退出

robot.hear(/banned word/, (res) => {
    res.leave(res.message.user);
});

一斉連絡の送信

# メッセージを受けとった組織に送信
res.announce('THIS IS AN ANNOUNCEMENT!');

# 任意の組織に送信 (domain = { id: domain.id })
robot.announce(domain, 'ANNOUNCEMENT!');

※ アカウントに管理者権限が必要です。