タム
2024.04.08
113
こんにちは。タムです。
今回はGoogleでログインの4回目ということで、Googleカレンダー連携を行ってみました。
↓
↓
↓
↓
↓
↓
"yyyy/mm/dd hh:MM:ss ~ yyyy/mm/dd hh:MM:ss hogehoge"というパターンの投稿がされた場合に、
予定に関する投稿とみなしてGoogleカレンダーに登録する仕様です。
実装のポイントとしては、
というところです。
ベースの実装ができているのでほんの少しの修正だけで実現できます。
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 910dc9d..ad79e35 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -10,7 +10,7 @@
const params = {
response_type: 'code',
client_id: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com',
- scope: 'openid profile email',
+ scope: 'openid profile email https://www.googleapis.com/auth/calendar',
redirect_uri: 'https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/callback',
state: Math.random().toString(32).substring(2),
nonce: Math.random().toString(32).substring(2)
@@ -33,7 +33,7 @@
const params = {
response_type: 'token id_token',
client_id: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com',
- scope: 'openid profile email',
+ scope: 'openid profile email https://www.googleapis.com/auth/calendar',
redirect_uri: 'https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/implicit/callback',
state: Math.random().toString(32).substring(2),
nonce: Math.random().toString(32).substring(2)
diff --git a/src/routes/microposts/+page.svelte b/src/routes/microposts/+page.svelte
index 7dbfe73..8bad0ee 100644
--- a/src/routes/microposts/+page.svelte
+++ b/src/routes/microposts/+page.svelte
@@ -27,7 +27,7 @@
async function post() {
// 投稿
- await axios.post('https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/api/microposts', {content: content}, {headers: {Authorization: `Bearer ${id_token}`}});
+ await axios.post('https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/api/microposts', {content: content, access_token: access_token}, {headers: {Authorization: `Bearer ${id_token}`}});
// リロード
micropostRes = await axios.get('https://nfk13r40e6.execute-api.ap-northeast-1.amazonaws.com/api/microposts', {headers: {Authorization: `Bearer ${id_token}`}});
console.log(micropostRes);
diff --git a/app.py b/app.py
index bd01a93..df4073e 100644
--- a/app.py
+++ b/app.py
@@ -3,6 +3,7 @@ import logging
import requests
import boto3
import urllib
+from datetime import datetime, timedelta, timezone
from chalicelib.models import Microposts
from chalicelib.utils import login
@@ -57,6 +58,27 @@ def post():
micropost = user.post(req["content"])
micropost.save()
+ if "access_token" in req:
+ start, end, summary = _parse_schedule(req["content"])
+ if start and end and summary:
+ app.log.info(f"googleカレンダーに予定({summary})を作成します")
+ token = req["access_token"]
+ res = requests.post(
+ "https://www.googleapis.com/calendar/v3/calendars/primary/events",
+ headers={"Authorization": f"Bearer {token}"},
+ json={
+ "summary": summary,
+ "description": "これはサンプルアプリで作成した予定です",
+ "start": {"dateTime": start.isoformat()},
+ "end": {"dateTime": end.isoformat()},
+ },
+ )
+ if res.status_code >= 300:
+ app.log.error(res.json())
+ return Response(body={"message": "server error"}, status_code=500)
+
+ app.log.info(f"googleカレンダーに予定({summary})を作成しました")
+
return Response(body={"posted_at": micropost.postedAt.isoformat()}, status_code=201)
@@ -70,3 +92,23 @@ def get_list():
posts = Microposts.query(user.id)
res = [post.to_simple_dict() for post in posts]
return Response(body=res, status_code=200)
+
+
+def _parse_schedule(schedule_str):
+ # 文字列をスペースで分割して情報を取得
+ parts = schedule_str.split()
+
+ if len(parts) < 5 or parts[2] != "~":
+ return None, None, None
+
+ # 日付と時間をパースしてdatetimeオブジェクトに変換
+ start_str = f"{parts[0]} {parts[1]}"
+ end_str = f"{parts[3]} {parts[4]}"
+
+ start = datetime.strptime(start_str, "%Y/%m/%d %H:%M").replace(tzinfo=timezone(timedelta(hours=9)))
+ end = datetime.strptime(end_str, "%Y/%m/%d %H:%M").replace(tzinfo=timezone(timedelta(hours=9)))
+
+ # サマリを取得
+ summary = " ".join(parts[5:])
+
+ return start, end, summary
今回はGoogleカレンダー権限をスコープに追加してアクセスする実装を試してみました。
今回はAPIの中で直接GoogleカレンダーAPIを叩いてしまっていますが、
Googleカレンダーに登録するまでユーザを待たせてしまうのも微妙なので、
非同期で登録するようにしたほうがいいと思いました。
その場合は非同期キューにアクセストークンを含ませたリクエストを登録する形になりそうです。
今回、IDトークンはAuthorizationヘッダに含ませていますが、
アクセストークンはリクエストボディに含ませました。
なんか不格好な気がしますが、一般的なOIDCを利用したAPIの設計はどうするのが普通なんでしょうか・・・
今後やってみたいこととしては、
などがあります。
際限なく出てきますね・・・
また実装でき次第記事にしようと思います。
11
原
2024.07.31
64
原
2024.07.31
1,211
だいち
2024.05.30