BLOGサブスレッドの日常

2025.10.29

(Python + PowerAutomate)GoogleDocsの権限を自動的に変更したい

torikai

サブスレッドでは、毎週全社ミーティングが行われるのですが、そのアジェンダはGoogleDocsで全社員に共有されております。
そして、ミーティングが行われる日の10:00に、アジェンダの権限を「閲覧者(コメント可)」変更するルールとなっております。

毎週忘れずに手ずから権限変更をする…
数年間はそのように運用されていましたが、鳥飼がとうとう我慢出来なくなってきました。
Googleのことなので、GASで…と思いましたが、得意なPythonで対応することにしました。

Google の OAuth クライアントID を取得する

まず、https://console.cloud.google.com/apis/credentials からOAuth2.0のクライアントIDを発行しましょう。

アプリケーションの種類は「デスクトップアプリ」、名前は適当に「GoogleDocsの権限更新」とでもしておきます。
OAuthクライアントIDの作成

「作成」ボタンを押すと、OAuthクライアントが作成され、その情報が入ったJSONファイルがダウンロードできるようになります。忘れずダウンロードしておきましょう。

Pythonスクリプトを用意

いつものように poetry で仮想環境を作りまして。Python のバージョンは、現時点で最新の 3.13.9 としました。
パッケージとして、google-api-python-client google-auth-httplib2 google-auth-oauthlib が必要なので、適宜追加します。

Googleクライアントの認証クラスを、Copilotに手伝ってもらいながら用意しました。

import os
import pickle
from pathlib import Path

from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build


class GoogleClient:
    BASE_DIR = BASE_DIR = Path(__file__).resolve().parent.parent
    # スコープ設定(Driveのフルアクセス)
    SCOPES = ["https://www.googleapis.com/auth/drive"]
    # クレデンシャルファイル
    CREDENTIALS_FILE = BASE_DIR / "oauth_credentials.json"
    # トークン保存ファイル
    TOKEN_PICKLE = BASE_DIR / "token.pickle"

    def __init__(self, *args, **kwargs):
        self.creds = self.authorization()
        # クライアント初期化
        self.drive_service = build("drive", "v3", credentials=self.creds, num_retries=3)

    def authorization(self):
        # 認証処理
        _creds = None
        # 認証済のトークンが存在する場合は、ファイルから認証情報を取得
        if os.path.exists(self.TOKEN_PICKLE):
            with open(self.TOKEN_PICKLE, "rb") as token:
                _creds = pickle.load(token)

        # 認証情報がない、または期限切れの場合
        if not _creds or not _creds.valid:
            if _creds and _creds.expired and _creds.refresh_token:
                # トークンをリフレッシュ
                _creds.refresh(Request())
            else:
                # ブラウザを開いて手動認証(OAuth)
                flow = InstalledAppFlow.from_client_secrets_file(
                    self.CREDENTIALS_FILE, self.SCOPES
                )
                _creds = flow.run_local_server(port=0)
            # 新しいトークンを保存
            with open(self.TOKEN_PICKLE, "wb") as token:
                pickle.dump(_creds, token)
        return _creds

さて、全社ミーティングのアジェンダは、Googleドライブの特定のフォルダに 全社ミーティング_251028 のようなファイル名で保存されています。
そして全社ミーティングは特定の曜日に開催されますが、その曜日が祝日などで休みの場合、別の日に開催されることになります。
という事情から、「毎日10:00にスクリプトを起動して、その日の日付のアジェンダがあれば権限を "閲覧者(コメント可)" に変更する」という仕様で作成します。
処理の内容は割愛します。

ついでに PowerAutomate で通知

サブスレッドは Microsoft365 を使って社内でやり取りしています。
せっかくなので、「権限を変更したよ」という通知を、社内のチャネルに投稿するようにしましょう。
チャネルに対してメールを送信してもいいんですが、今回は「Teams Webhook 要求を受信したとき」のトリガーを使います。

PowerAutomate の「作成」より「インスタント クラウド フロー」を選択し、トリガーには「Teams Webhook 要求を受信したとき」を選択します。
インスタントクラウドフローを構築する(Teams Webhook 要求を受信したとき)

Webhook URL は、フローを保存した時に生成されるのですが、フローを保存するには少なくとも1つのアクションを配置する必要があるので、「チャットまたはチャネルでメッセージを投稿する」を配置しつつ、投稿先を適宜設定します。
Message には、Webhook URL にリクエストされた内容を表示したいので、「式を挿入する」から triggerBody().description を入力して設定します。

せっかくなのでタイトルもほしいですね。「詳細パラメーター」より「Subject」を選択して、これも同様に「式を挿入する」から triggerBody().subject を入力して設定します。
ようやくフローを保存できる状態になりますので、保存しましょう。
すると Webhook URL が生成されます🎉

このURLにリクエストする処理を書きましょう!

today = datetime.now().astimezone()
weekday = ["月", "火", "水", "木", "金", "土", "日"][today.weekday()]
body = f"[{self.file['name']}](https://docs.google.com/document/d/{self.file['id']}) の権限を更新しました。\n"
requests.post(
    "(先程生成した Webhook URL)",
    json={
        "subject": f"{today:%Y年%m月%d日({weekday})}",
        "description": markdown.markdown(body),
    },
)

アジェンダの権限も無事「閲覧者(コメント可)」に変更され、Teamsのチャネルにも通知されました。

めでたしめでたし。

この記事を書いた人

torikai