こんにちは。システム開発事業部のタナカです。
今回は作業効率化のために、SlackワークフローからNotionにデータを登録する方法を試してみましたのでご紹介します。
目次
経緯
シーズでは、業務で使用するアプリケーションは ゆるい許可制 となっていて、所定のGoogleスプレッドシートに必要事項を記入し、Slackの申請用チャンネルで審査を依頼するという運用となっています。
そして審査後、審査結果はスプレッドシートに記入され、Slackにてその連絡が返ってくるのですが、GoogleスプレッドシートとSlackのどちらにも記入するのは手間だなと常々思っていました。
はじめは、ナレッジツールとして社内で使用しているNotionだけで運用しようかと考えたのですが、やはり連絡はSlackの方が使いやすいので、まずはSlackからNotionにデータを登録する方法を調べてみました。
Send to Notion
https://www.notion.so/integrations/slack
最初に見つけたのが、SlackからNotionのデータベースへ直接データを登録することができる「Send to Notion」という機能。
Slackから /notion create コマンドを実行することでSlackワークフローのようなモーダルウィンドウが起動するのですが、Notionのデータベース名を選択してから、プロパティを選んで内容を記入するというもので、Slackワークフローのように予め入力項目を指定しておくことができないようでした。
今回の目的は承認フローなので、Notionへの登録だけでなく、Slackでの承認依頼も絡めたものにしたい。。。
Google Apps Script ( GAS )
https://workspace.google.co.jp/intl/ja/products/apps-script/
そこで、SlackワークフローからNotionにデータを登録する方法を調べてみたところ、Google Apps Script (GAS) を使うことで、ノンプログラマのわたしでもできそうなものを見つけたので試してみることにしたという経緯です。
参考サイト
以下のサイトを参考にさせていただきました。
NotionのAPIを使ってSlack上のフロー情報をストックする仕組みを作ってみた | クラッソーネ開発者ブログhttps://tech.crassone.jp/posts/stock-information-from-slack-to-notion
Slackワークフロー✖️Notion API✖️GASでSlackからNotionに未確認の依頼をリスト化するhttps://zenn.dev/rescuenow/articles/324e3b34a933f5
したいこと
- アプリケーションの使用申請フローの実現
- Slackワークフローを使用
- Notoinのデータベースに登録
- 通知等はSlack
申請フロー(概要)
- Slackワークフローにて必要項目を記入して申請
- 申請内容がNotionに登録される(Slackにも申請内容を投稿)
- Slackにて担当者への通知とNotionへのリンクが届く
- 審査後、担当者がNotionにて審査結果を記入
- Slackにて審査結果が投稿される
作業手順(概要)
Notion
- Notionに登録するデータベースを作成(プロパティは日本語でも可)
- Notionのインテグレーションを作成
- Notionデータベースにインテグレーションを追加して連携
Googleスプレッドシート
- SlackからNotionに経由するためにスプレッドシートを作成
- 作成したスプレッドシートの1行目に列を識別するカラム名を入力
Google Apps Script(GAS)
- 作成したスプレッドシートにApps Scriptを作成
- 作成したApps Scriptのトリガーを設定
Slack
- ワークフローを作成
- 必要なステップを追加
- ワークフローを公開
サンプルコード(GAS)
申請フロー用に作成したNotionデータベースのプロパティ
この画像の内、GASで取得しているのは以下の10項目です。
https://developers.notion.com/reference/property-object
今回作成したプロパティについての補足事項
- 「作成者」にはNotionのインテグレーション名が入ってしまうため、別途「申請者」を作成しています。
- 「ステータス」は基本 新規申請 となるので、Googleスプレッドシートに固定で入力されるよう、Slackワークフロー側で設定しています。
- 過去にスプレッドシートで運用していたリストも、Notionに移行するため、自動で作成されてしまう「作成日時」とは別に、後から編集できるよう「申請日」を作成しています。
- 「タグ」は、Notionに登録された後、使用可能なアプリ一覧のデータベースとして検索する際に活用できるように用意しました。「,(カンマ)」区切りで複数登録できるようにしています。
申請日のサンプルコード
本日の日付を「-(ハイフン)」区切りで用意して
1const date = new Date();
2const yyyy = date.getFullYear();
3const mm = ("0" + (date.getMonth() + 1)).slice(-2);
4const dd = ("0" + date.getDate()).slice(-2);
5const today = yyyy + "-" + mm + "-" + dd;
Notion API に渡します。
1"申請日": {
2 "type": "date",
3 "date": {
4 "start": today
5 }
6},
タグのサンプルコード(multi_select)
「,(カンマ)」で分割して配列にして
1const appTagString = appTag;
2const appTagArray = appTagString.split(",");
3
4var appTagMultiSelect = [];
5var appTagArrayLength = appTagArray.length;
6for (var i = 0; i < appTagArrayLength; i++) {
7 appTagMultiSelect.push({'name': appTagArray[i]});
8}
Notion API に渡します。
1"タグ": {
2 "multi_select": appTagMultiSelect
3},
bookmark のサンプルコード
なくても良かったのですが、登録したNotionページに、URLを bookmark で埋め込みをしてみました。
1"children": [
2 {
3 "object": "block",
4 "type": "bookmark",
5 "bookmark": {
6 "url": appUrl,
7 "caption": [
8 {
9 "type": "text",
10 "text": {
11 "content": appName
12 }
13 }
14 ]
15 }
16 }
17]
https://developers.notion.com/reference/block#bookmark
完成したサンプルコード
- Notion API のバージョンは 2022-06-28 となっています。https://developers.notion.com/reference/versioning
- Notionのトークン , NotionデータベースのID は上記で作成したものに置き換えてください。
1function RequestWishListApp() {
2
3 const wishListAppSheet = SpreadsheetApp.getActiveSheet();
4 const latestEntryRow = wishListAppSheet.getLastRow();
5 const applicationDate = wishListAppSheet.getRange(latestEntryRow, 1).getValue();
6 const appName = wishListAppSheet.getRange(latestEntryRow, 2).getValue();
7 const appUrl = wishListAppSheet.getRange(latestEntryRow, 3).getValue();
8 const appCost = wishListAppSheet.getRange(latestEntryRow, 4).getValue();
9 const appType = wishListAppSheet.getRange(latestEntryRow, 5).getValue();
10 const appTag = wishListAppSheet.getRange(latestEntryRow, 6).getValue();
11 const applicationReason = wishListAppSheet.getRange(latestEntryRow, 7).getValue();
12 const appRisk = wishListAppSheet.getRange(latestEntryRow, 8).getValue();
13 const appSelfJudge = wishListAppSheet.getRange(latestEntryRow, 9).getValue();
14 const appApplicant = wishListAppSheet.getRange(latestEntryRow, 10).getValue();
15
16 const payload = addWishListApp(applicationDate, appName, appUrl, appCost, appType, appTag, applicationReason, appRisk, appSelfJudge, appApplicant);
17 postNotion(payload);
18
19}
20
21
22function postNotion(payload){
23
24 const MY_NOTION_TOKEN = "Notionのトークン";
25 const url = "https://api.notion.com/v1/pages";
26 const options = {
27 "method": "post",
28 "headers": {
29 "Content-type": "application/json",
30 "Authorization": "Bearer " + MY_NOTION_TOKEN,
31 "Notion-Version": "2022-06-28",
32 },
33 "payload": JSON.stringify(payload)
34 };
35 UrlFetchApp.fetch(url, options);
36}
37
38
39function addWishListApp(applicationDate, appName, appUrl, appCost, appType, appTag, applicationReason, appRisk, appSelfJudge, appApplicant){
40 const DATABASE_ID = "NotionデータベースのID";
41
42 const date = new Date();
43 const yyyy = date.getFullYear();
44 const mm = ("0" + (date.getMonth() + 1)).slice(-2);
45 const dd = ("0" + date.getDate()).slice(-2);
46 const today = yyyy + "-" + mm + "-" + dd;
47
48 const appTagString = appTag;
49 const appTagArray = appTagString.split(",");
50
51 var appTagMultiSelect = [];
52 var appTagArrayLength = appTagArray.length;
53 for (var i = 0; i < appTagArrayLength; i++) {
54 appTagMultiSelect.push({'name': appTagArray[i]});
55 }
56
57
58
59 payload = {
60 "parent": {
61 "type": "database_id",
62 "database_id": DATABASE_ID
63 },
64 "properties": {
65 "申請日": {
66 "type": "date",
67 "date": {
68 "start": today
69 }
70 },
71 "アプリ名": {
72 "title": [
73 {
74 "text": {
75 "content": appName
76 }
77 }
78 ]
79 },
80 "URL": {
81 "url": appUrl
82 },
83 "コスト": {
84 "select": {
85 "name": appCost
86 }
87 },
88 "タイプ": {
89 "select": {
90 "name": appType
91 }
92 },
93 "タグ": {
94 "multi_select": appTagMultiSelect
95 },
96 "申請理由": {
97 "rich_text": [
98 {
99 "text": {
100 "content": applicationReason
101 }
102 }
103 ]
104 },
105 "リスク": {
106 "select": {
107 "name": appRisk
108 }
109 },
110 "判断条件": {
111 "rich_text": [
112 {
113 "text": {
114 "content": appSelfJudge
115 }
116 }
117 ]
118 },
119 "申請者": {
120 "rich_text": [
121 {
122 "text": {
123 "content": appApplicant
124 }
125 }
126 ]
127 }
128 },
129
130 "children": [
131 {
132 "object": "block",
133 "type": "bookmark",
134 "bookmark": {
135 "url": appUrl,
136 "caption": [
137 {
138 "type": "text",
139 "text": {
140 "content": appName
141 }
142 }
143 ]
144 }
145 }
146
147 ]
148
149
150 }
151 return payload;
152
153}
最後に
この申請フローのリリース後に早速活用されているのを見て、思い切って常々手間だと思っていたことの改善に取り組んでみて良かったと感じています。
今回は小さなカイゼンでしたが、これを機に他にもカイゼンを積み重ねて行きたいと思います!
おまけ
記事内で使用しているNotion風のイラストは Notion Avatar Maker を使用させていただきました。
CC0 license で利用可能です。