From 4b7aef8f868826c0bffe3113eb86bd04512b22ce Mon Sep 17 00:00:00 2001 From: daiki Date: Sun, 12 Jan 2025 15:00:19 +0900 Subject: [PATCH] =?UTF-8?q?calendar=E9=80=A3=E6=90=BA=E6=B6=88=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy-google-calendar.yml | 45 --------- packages/google-calendar/.gitignore | 4 - packages/google-calendar/LICENSE | 21 ---- packages/google-calendar/appsscript.json | 18 ---- packages/google-calendar/build.js | 10 -- packages/google-calendar/package.json | 21 ---- .../src/functions/fetchCalendarChanges.ts | 78 --------------- packages/google-calendar/src/main.ts | 97 ------------------- 8 files changed, 294 deletions(-) delete mode 100644 .github/workflows/deploy-google-calendar.yml delete mode 100644 packages/google-calendar/.gitignore delete mode 100644 packages/google-calendar/LICENSE delete mode 100644 packages/google-calendar/appsscript.json delete mode 100644 packages/google-calendar/build.js delete mode 100644 packages/google-calendar/package.json delete mode 100644 packages/google-calendar/src/functions/fetchCalendarChanges.ts delete mode 100644 packages/google-calendar/src/main.ts diff --git a/.github/workflows/deploy-google-calendar.yml b/.github/workflows/deploy-google-calendar.yml deleted file mode 100644 index 90117f5..0000000 --- a/.github/workflows/deploy-google-calendar.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Build & Deploy Uplim Google Calendar Notificator - -on: - push: - branches: - - main - paths: - - packages/google-calendar/** - - packages/utils/** - workflow_dispatch: - -jobs: - deploy: - runs-on: ubuntu-22.04 - timeout-minutes: 15 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js 20.11.0 - uses: actions/setup-node@v4 - with: - node-version: '20.11.0' - - - name: Install Packages - run: | - corepack enable - yarn workspaces focus google-calendar - - - name: Create .clasprc.json - run: | - echo "${{ secrets.TRIPLATE_DEV_BASE64 }}" | base64 --decode > ~/.clasprc.json - - - name: Create .clasp.json - run: | - cat > ./packages/google-calendar/.clasp.json < process.exit(1)); diff --git a/packages/google-calendar/package.json b/packages/google-calendar/package.json deleted file mode 100644 index 819f40c..0000000 --- a/packages/google-calendar/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "google-calendar", - "version": "1.0.0", - "packageManager": "yarn@4.1.0", - "description": "Google カレンダーの変更通知を Discord に飛ばす Google Apps Script", - "license": "MIT", - "private": true, - "scripts": { - "build": "node build.js && cp appsscript.json dist/", - "push": "yarn build && clasp push" - }, - "devDependencies": { - "@google/clasp": "2.4.2", - "@types/google-apps-script": "1.0.57", - "esbuild": "0.19.4", - "esbuild-gas-plugin": "0.8.0" - }, - "dependencies": { - "utils": "workspace:*" - } -} diff --git a/packages/google-calendar/src/functions/fetchCalendarChanges.ts b/packages/google-calendar/src/functions/fetchCalendarChanges.ts deleted file mode 100644 index 62c7d21..0000000 --- a/packages/google-calendar/src/functions/fetchCalendarChanges.ts +++ /dev/null @@ -1,78 +0,0 @@ -type CalendarChangeState = "created" | "updated" | "deleted"; - -interface CustomCalendarChangeEvent - extends GoogleAppsScript.Calendar.Schema.Event { - changeState: CalendarChangeState; -} - -export function fetchCalendarChanges( - calendarId: string, -): CustomCalendarChangeEvent[] { - if (!Calendar.Events) throw new Error(); - - const properties = PropertiesService.getUserProperties(); - const syncToken = - properties.getProperty("syncToken") || fetchSyncToken(calendarId); - - let res: GoogleAppsScript.Calendar.Schema.Events; - try { - res = Calendar.Events.list(calendarId, { - calendarId, - syncToken, - showDeleted: true, - }); - if (!res.nextSyncToken) throw new Error("nextSyncToken is undefined"); - properties.setProperty("syncToken", res.nextSyncToken); - } catch (e) { - properties.deleteProperty("syncToken"); - throw e; - } - - if (!res.items) return []; - - return res.items.map( - (event) => - ({ - changeState: detectChangeState(event), - ...event, - }) as CustomCalendarChangeEvent, - ); -} - -/** - * フルスキャンを実行して syncToken を返す - */ -function fetchSyncToken(calendarId: string) { - const now = new Date(); - let pageToken: string | undefined = undefined; - let res: GoogleAppsScript.Calendar.Schema.Events | undefined = undefined; - - // 現在時刻以降のイベントを取得し続ける - while (true) { - res = Calendar.Events?.list(calendarId, { - calendarId, - pageToken, - showDeleted: true, - timeMin: now.toISOString(), - maxResults: 2500, - }); - - // syncToken が得られたら終了する - if (res?.nextSyncToken) return res.nextSyncToken; - if (!res?.nextPageToken) throw new Error(); - pageToken = res.nextPageToken; - } -} - -/** - * イベントデータから変更内容を推定する - */ -function detectChangeState( - event: GoogleAppsScript.Calendar.Schema.Event, -): CalendarChangeState { - if (!event.status || !event.created) throw new Error(); - if (event.status === "cancelled") return "deleted"; - // 作成と更新の区別がつかないが、作成時刻が10秒以上前であれば「更新」と思われる - if (Date.now() - Date.parse(event.created) > 10 * 1000) return "updated"; - return "created"; -} diff --git a/packages/google-calendar/src/main.ts b/packages/google-calendar/src/main.ts deleted file mode 100644 index 9f8a922..0000000 --- a/packages/google-calendar/src/main.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { postMessage } from "utils"; -import { fetchCalendarChanges } from "./functions/fetchCalendarChanges"; - -function main({ calendarId }: { calendarId: string }) { - for (const event of fetchCalendarChanges(calendarId)) { - console.log(event); - - if (!event.start || !event.end) continue; - - postMessage({ - username: "Google Calendar Notifications", - parse: "full", - avatar_url: - "https://cdn.discordapp.com/attachments/792765244040675389/921661726863282176/pngegg.png", - content: `予定が${switchState(event.changeState).state}されました。`, - embeds: [ - { - title: event.summary, - url: event.htmlLink, - color: switchState(event.changeState).color, - fields: [ - { - name: ":calendar: 日付", - value: buildDateTimeString(event.start, event.end), - }, - ], - }, - ], - }); - } -} - -function switchState(state: "created" | "updated" | "deleted") { - if (state === "created") return { state: "作成", color: 0x008000 }; - if (state === "deleted") return { state: "削除", color: 0xff0000 }; - return { state: "変更", color: 0xffff00 }; -} - -function buildDateTimeString( - start: GoogleAppsScript.Calendar.Schema.EventDateTime, - end: GoogleAppsScript.Calendar.Schema.EventDateTime, -): string { - let text = ""; - // 時間指定の予定 - if (start.dateTime && end.dateTime) { - text += formatDate(new Date(start.dateTime), "yyyy/MM/dd(A) HH:mm"); - // 同日内の予定 - if (start.dateTime.substring(0, 10) === end.dateTime.substring(0, 10)) { - text += ` - ${formatDate(new Date(end.dateTime), "HH:mm")}`; - } - // 日をまたぐ予定 - else { - text += ` - ${formatDate(new Date(end.dateTime), "yyyy/MM/dd(A) HH:mm")}`; - } - } - // 終日予定 - else if (start.date && end.date) { - const startDate = formatDate(new Date(start.date), "yyyy/MM/dd(A)"); - const endDate = formatDate( - // 1日のみの終日予定であっても end.date は翌日の値が得られてしまうため、1日分戻す - new Date(Date.parse(end.date) - 60 * 60 * 24 * 1000), - "yyyy/MM/dd(A)", - ); - text += startDate; - if (startDate !== endDate) text += ` - ${endDate}`; - } - return text; -} - -function formatDate(date: Date, format: string) { - // パディングを追加するユーティリティ関数 - const pad = (num: number, length = 2) => num.toString().padStart(length, "0"); - - // 日付の各部分をマッピング - const replacements: { [key: string]: string } = { - yyyy: date.getFullYear().toString(), - MM: pad(date.getMonth() + 1), - dd: pad(date.getDate()), - HH: pad(date.getHours()), - mm: pad(date.getMinutes()), - ss: pad(date.getSeconds()), - SSS: pad(date.getMilliseconds(), 3), - A: "日月火水木金土"[date.getDay()] || "日", - }; - - // フォーマット文字列の置換 - return Object.keys(replacements).reduce( - (acc, key) => acc.replace(new RegExp(key, "g"), replacements[key] ?? ""), - format, - ); -} - -declare const global: Record< - string, - ({ calendarId }: { calendarId: string }) => void ->; -global.main = main;