loader image

Google Apps Scriptで新規プロジェクトを開始する

みなさん、Google Apps Scriptというツールはご存知でしょうか。
Google Apps Script(GAS)とは、Googleが提供しているWebサービスを拡張するためのJavaScriptベースのスクリプト環境です。ChatGPTの流行により、今ではGASコードはほんの数十秒で作ってくれる時代です。しかし、プロジェクトの開始方法を知らないことには使えません。
今回はこのGASの新規プロジェクトの作り方についてみていきましょう。

Google App Scriptとは

Google App Scriptは、GoogleのWebサービス(Googleドキュメント、Googleシート、Googleフォームなど)を拡張するためのJavaScriptベースのスクリプト環境です。これにより、GoogleのWebサービスを自動化したり、新しい機能を追加したりすることができます。また、他のGoogle APIと統合することもできます。Google App Scriptは、Webブラウザー上で実行されますが、一部のAPIを使用すると、デスクトップやモバイルアプリケーションからも利用することができます。

Udemyメディアより

活用例

–Googleサービス内との連携–

  • Googleドライブ上のファイルが更新されたことをGmailで通知します。
  • Googleスプレッドシートの内容を元にGmailからメールを送信します。
  • Googleカレンダーの予定を自動で登録・編集します。

–Googleサービス以外の外部サービスとの連携–

  • 指定した時間にSlackに自動通知メッセージを送信します。
  • Googleフォームの入力内容をSlackやChatworkなどに送信します。
  • Googleスプレッドに登録したデータをfreeeなどの会計システムに送信します。

GASプロジェクトの開始方法

手順

  1. Google App Script公式ページを開きます。
  2. 左上の「新規プロジェクト」を開きます。
  3. コードを書きます(コピペするなど)。
  4. 「実行」を押してプログラムを起動します。
  5. (初めてプログラムを実行する場合)権限の承認を求められます。そのため、権限を付与するために指示に従います。
  6. メールアドレスを選択して、ポップアップ左下の「詳細」をクリックします。
  7. 「〇〇(安全でないページ)に移動」を開きます。

画像での説明

左上の「新規プロジェクト」を開く
コードが書けたら「実行」を押してプログラムをスタート
初めての場合は承認を求められる
メールアドレス(Googleアカウント)を選択
左下の「詳細」をクリック
「〇〇(安全でないページ)に移動」を開く
「許可」をクリック

最後に

いかがだったでしょうか。

今回はGASでプロジェクトを開始する方法についてご紹介しました。ぜひ、プロジェクトを実際に作って見て下さい。GASを使ってNotionのコンテンツをLINEに流すなどもできますので、興味のある方はぜひご覧ください。

【コピペ可】二つのGoogleカレンダーを片方に自動でコピーする

GASを使ったGoogleカレンダーアイキャッチ

はじめに

Googleカレンダーの仕事用とプライベート用を分けて管理している人も多いのではないでしょうか。そして、予定をご友人や恋人と共有したいという方もいらっしゃるのではないでしょうか。

しかし、仕事用のカレンダーはセキュリティの観点やモラルの観点から共有できないこともあります。また、プライベートカレンダーを共有したとしても仕事用の予定はそのアカウントには入っておらず、結局プライベート用のカレンダーに複製しないといけないことになります。

この記事では仕事用のカレンダーに追加・更新された予定を自動でプライベートカレンダーにコピーすることで違うアカウントのカレンダー情報を一言かすることができるようになります。それでは見ていきましょう。

完成はこちら(Google Apps Scriptに貼り付けてください)

function copyWorkEventsToPrivateCalendar() {
  // 仕事用カレンダーとプライベートカレンダーのIDを設定する
  var workCalendarId = '仕事用のメールアドレスを入力してください(コピー元)';
  var privateCalendarId = 'プライベートのメールアドレスを入力してください(コピー先)';

  var workCalendar = CalendarApp.getCalendarById(workCalendarId);
  var privateCalendar = CalendarApp.getCalendarById(privateCalendarId);

  if (workCalendar === null || privateCalendar === null) {
    console.error("Invalid calendar ID(s). Please check your calendar ID settings.");
    return;
  }

  // 仕事用カレンダーの予定を取得する
  var now = new Date();
  var futureDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30日後までの予定を取得
  var workEvents = workCalendar.getEvents(now, futureDate);

  // 仕事用カレンダーの予定をプライベートカレンダーに同期する
  for (var i = 0; i < workEvents.length; i++) {
    var workEvent = workEvents[i];
    var eventId = workEvent.getId();

    // プライベートカレンダーに同じIDの予定があるか確認する
    var privateEvents = privateCalendar.getEvents(workEvent.getStartTime(), workEvent.getEndTime());
    var privateEvent = null;
    

    for (var j = 0; j < privateEvents.length; j++) {
      if (privateEvents[j].getDescription() === eventId) {
        privateEvent = privateEvents[j];
        break;
      }
    }

    if (privateEvent === null) {
      // 新しい予定をプライベートカレンダーに追加する
      privateEvent = privateCalendar.createEvent(workEvent.getTitle(), workEvent.getStartTime(), workEvent.getEndTime());
      privateEvent.setDescription(eventId);
    } else {
      // 既存の予定を更新する
      privateEvent.setTitle(workEvent.getTitle());
      privateEvent.setTime(workEvent.getStartTime(), workEvent.getEndTime());
    }
  }

  // 変更前の予定を削除する
  var privateEvents = privateCalendar.getEvents(now, futureDate);
  for (var i = 0; i < privateEvents.length; i++) {
    var privateEvent = privateEvents[i];
    var eventId = privateEvent.getDescription();

    var workEvent = workCalendar.getEventById(eventId);
    if (workEvent !== null) {
      if (!(workEvent.getTitle() === privateEvent.getTitle() && workEvent.getStartTime().getTime() === privateEvent.getStartTime().getTime() && workEvent.getEndTime().getTime() === privateEvent.getEndTime().getTime())) {
        privateEvent.deleteEvent();
      }
    }
  }
 
}


function syncCalendars() {
  // 仕事用カレンダーとプライベートカレンダーのIDを設定する
  var workCalendarId = '仕事用のメールアドレスを入力してください(コピー元)';
  var privateCalendarId = 'プライベートのメールアドレスを入力してください(コピー先)';

  var workCalendar = CalendarApp.getCalendarById(workCalendarId);
  var privateCalendar = CalendarApp.getCalendarById(privateCalendarId);

  if (workCalendar === null || privateCalendar === null) {
    console.error("Invalid calendar ID(s). Please check your calendar ID settings.");
    return;
  }

  // 仕事用カレンダーの予定を取得する
  var now = new Date();
  var futureDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30日後までの予定を取得
  var workEvents = workCalendar.getEvents(now, futureDate);

  // 仕事用カレンダーの予定をプライベートカレンダーに同期する
  for (var i = 0; i < workEvents.length; i++) {
    var workEvent = workEvents[i];
    var eventId = workEvent.getId();

    // プライベートカレンダーに同じIDの予定があるか確認する
    var privateEvents = privateCalendar.getEvents(workEvent.getStartTime(), workEvent.getEndTime());
    var privateEvent = null;
    

    for (var j = 0; j < privateEvents.length; j++) {
      if (privateEvents[j].getDescription() === eventId) {
        privateEvent = privateEvents[j];
        break;
      }
    }

    if (privateEvent === null) {
      // 新しい予定をプライベートカレンダーに追加する
      privateEvent = privateCalendar.createEvent(workEvent.getTitle(), workEvent.getStartTime(), workEvent.getEndTime());
      privateEvent.setDescription(eventId);
    } else {
      // 既存の予定を更新する
      privateEvent.setTitle(workEvent.getTitle());
      privateEvent.setTime(workEvent.getStartTime(), workEvent.getEndTime());
    }
  }

  // 変更前の予定を削除する
  var privateEvents = privateCalendar.getEvents(now, futureDate);
  for (var i = 0; i < privateEvents.length; i++) {
    var privateEvent = privateEvents[i];
    var eventId = privateEvent.getDescription();

    var workEvent = workCalendar.getEventById(eventId);
    if (workEvent !== null) {
      if (!(workEvent.getTitle() === privateEvent.getTitle() && workEvent.getStartTime().getTime() === privateEvent.getStartTime().getTime() && workEvent.getEndTime().getTime() === privateEvent.getEndTime().getTime())) {
        privateEvent.deleteEvent();
      }
    }
  }
 
}

// トリガーを設定する関数
function createTrigger() {
  ScriptApp.newTrigger('syncCalendars')
    .timeBased()
    .everyMinutes(30) // 30分ごとに実行されるように設定
    .create();
}

手順について

ステップ1 カレンダーの共有を設定する

二つのアカウント別に設定する必要があります。

–仕事用カレンダー(コピーしたい予定が入っている)側の設定–

  1. Googleカレンダーを開きます。
  2. 右上の設定を開きます。
  3. 左のメニューバーの「マイカレンダーの設定」からコピーしたいカレンダーを選択して下さい。
  4. 「ユーザーやグループを追加」を選択して、プライベート用カレンダー(コピー先のカレンダー)のメールアドレスを入力して下さい。
「ユーザーやグループを追加」を選択
「ユーザーやグループを追加」を選択
プライベート用のカレンダーを招待
プライベート用のカレンダーを招待

–プライベート用カレンダー(コピー先)側の設定–

  1. Googleカレンダーを開きます。
  2. 右上の設定を開きます。
  3. 左のメニューバーの「カレンダーを追加」>「カレンダーに登録」を選択して下さい。
  4. 仕事用カレンダーのメールアドレスを入力してEnterを押して下さい。
「カレンダーを追加」>「カレンダーに登録」を選択
「カレンダーを追加」>「カレンダーに登録」を選択
仕事用カレンダーのメールアドレスを入力してEnter
仕事用カレンダーのメールアドレスを入力してEnter

ステップ2 コードを編集する

変更が必要な部分は「仕事用のメールアドレス」と「プライベート用のメールアドレス」の二つを変更する場所が計4カ所あります。メールアドレスを変更しておいて下さい。

また、コピーする期間はデフォルトで30日間になっています。基本的には30日間で問題がないと思います。もし変更したい場合copyWorkEventsToPrivateCalendar関数及びsyncCalendars関数「// 30日後までの予定を取得」の30の部分の数字を任意の数字に変更して下さい。
※基本的は自動化のプログラムを1時間毎に起動基本的には変更する必要はないかと思います。

var futureDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

ステップ3 Google Apps Scriptのエディターに貼り付ける

こちらを含めると記事が長くなります。Google Apps Scriptのプロジェクトの始め方はこちらの記事をご覧ください。

ステップ4 トリガーを設置する

トリガーとは

Google Apps Scriptのエディタ画面の左のメニューバーにある「トリガー」から設定します。トリガーとはいわば「いつ自動化のシステムを動かしますか」というものです。

トリガーには以下の種類があります。

  • 時間主導型
  • カレンダー更新型
  • フォーム更新型

今回は上二つの「時間主導型」と「カレンダー更新型」を使います。これらを使う理由は以下の通りです。

  • 時間主導型・・・仕事用カレンダーがプライベートカレンダーに追加されているのか定期的にチェックする。もし、仕事用カレンダーの予定がプライベートカレンダーに追加されていなければ追加する。
  • カレンダー更新型・・・仕事用のカレンダーのタイトルや時間が更新された時にプライベートカレンダーの予定も同様の処理をする。

追加の仕方

  1. 左のメニューバーの上から3つ目の「トリガー」を選択する。
  2. 右下の「トリガーを追加」をクリックする。
  3. copyWorkEventsToPrivateCalendar関数を選択。イベントソースを「時間主導型」トリガータイプを「時間ベースのタイマー」時間の間隔を「1時間おき」で設定する。(詳細は下に添付しております画像を参考にして下さい。)
  4. syncCalendars関数を選択してイベントソースを「カレンダーから」カレンダーの詳細を入力を「カレンダー更新済み」オーナーのメールアドレスに「仕事用のメールアドレス」を入力しておいて下さい。(詳細は下に添付しております画像を参考にして下さい。)
左の上から三つ目の「トリガー」を選択
左の上から三つ目の「トリガー」を選択
右下の「トリガーを追加」をクリック
右下の「トリガーを追加」をクリック
copyWorkEventsToPrivateCalendar関数
copyWorkEventsToPrivateCalendar関数
syncCalendars関数を選択して上記のように設定
syncCalendars関数を選択して上記のように設定

注意点

仕事用のカレンダーを削除した際に、プライベートカレンダーは削除されません。そのため、削除の対象を検索する際に「仕事用の予定のタイトル」と「時間」で検索する仕組みになっております。しかし、この精度がGASのみだと低く、他の予定も削除してしまう可能性があります。

仕事用のカレンダーを削除された際にはご自身でプライベート用のカレンダーにコピーされている予定を削除するようにお願い致します。

最後に

いかがだったでしょうか。

今回はGoogle Apps Scriptとカレンダーについてご紹介しました。ぜひ、プロジェクトを実際に作って見て下さい。GASを使ってNotionのコンテンツをLINEに流すなどもできますので、興味のある方はぜひご覧ください。

【コピペでできる!】NotionのデータベースのステータスによってLINEに自動共有する

LINE NotifyとGASの連携アイキャッチ

はじめに

多くの人が仕事や学業、日常生活において情報を整理し、効率的に管理することが求められています。

そのために、さまざまな情報管理ツールが活用されています。この記事では、人気の情報管理アプリ「Notion」と、リアルタイムの通知サービス「LINE Notify」をGoogle Apps Scriptを用いて連携させる方法をご紹介します。これにより、Notionでの情報更新やタスク管理がさらに便利になり、日常生活や仕事での情報の取り扱いが一層スムーズになることでしょう。

それでは、NotionとLINE Notifyの連携方法について詳しく見ていきましょう。

完成はこちら(Google Apps Scriptに貼り付けてください)

const LINE_NOTIFY_API_TOKEN = 'LINE NotifyのAPI keyを入力してください';
const NOTION_API_KEY = 'Notion API keyを入力してください';
const DATABASE_ID = 'NotionのデータベースのIDを入力してください';

function sendNotification() {
  const newArticles = getUnpublishedArticles();

  newArticles.forEach(article => {
    updateArticleStatus(article.id);
    sendLineMessage(article.title, article.url);
  });
}

function getUnpublishedArticles() {
  const url = `https://api.notion.com/v1/databases/${DATABASE_ID}/query`;
  const options = {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${NOTION_API_KEY}`,
      'Content-Type': 'application/json',
      "Notion-Version": "2022-06-28",
    },
    payload: JSON.stringify({
      filter: {
        property: 'ステータス',
        select: {
          equals: '',
        },
      },
    }),
  };

  const response = UrlFetchApp.fetch(url, options);
  const data = JSON.parse(response.getContentText());
  const articles = data.results.map(item => {
    return {
      id: item.id,
      title: item.properties['記事名'].title[0].text.content,
      url: item.url,
    };
  });

  return articles;
}

function updateArticleStatus(pageId) {
  const url = `https://api.notion.com/v1/pages/${pageId}`;
  const options = {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${NOTION_API_KEY}`,
      'Content-Type': 'application/json',
      "Notion-Version": "2022-06-28",
    },
    payload: JSON.stringify({
      properties: {
        'ステータス': {
          select: {
            name: '完了',
          },
        },
      },
    }),
  };

  UrlFetchApp.fetch(url, options);
}

function sendLineMessage(title, url) {
  const message = `新着記事のお知らせ\n${title}が公開されました!以下のリンクから確認してください!\n${url}`;
  const notifyUrl = 'https://notify-api.line.me/api/notify';
  const options = {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${LINE_NOTIFY_API_TOKEN}`,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    payload: {
      message: message,
    },
  };

  UrlFetchApp.fetch(notifyUrl, options);
}

1. LINE NotifyのAPIを取得する

  1. LINE Notifyの公式ページを開いてください。(https://notify-bot.line.me/ja/
  2. 右上のログインをしてください。
  3. LINEに登録しているメールアドレスとパスワードを入力してログインしてください。
  4. 右上の自分の名前>マイページを押してください。
  5. マイページの下層にある「アクセストークンの発行(開発者向け)」の部分の「トークンを発行する」を選択してください。
  6. トークン名と通知するトークまたはグループを選択してください。トークン名はLINEの通知の文章に使われるのでわかる名前にすることをお勧めします。
  7. トークンをコピーしてください。(最初のコードにコピペします)

2. Notion APIの取得

  1. Notion APIの公式ページに移動してください。(https://developers.notion.com/
  2. 右上のMy Integrationを押します。
  3. ご自身がわかるようなインテグレーションの名前を入力して下の写真のようになるように選択してsubmitボタンを押してください。(基本触らなくて良いはずです)
  4. Secretsのトークンキーをコピーしてください。最初のコードにコピペして使います。

3. NotionのデータベースのIDを取得

  1. 自身のNotionページを開きます。(ブラウザ版を奨励します)
  2. データ元(LINEに共有したいデータが集まっているデータベース)を開きます。開くときはデータベース右上にある最大化ボタンを押してください。
  3. データベースのフルページを開くと、右上の3点から連携(connection)を選択してください。こちらから先ほどのステップで追加したAPIをこのページと繋いでいきます。
  4. 3点ボタンを押して、下部にある連携(connection)の中にある先ほどのステップ2で発行したNotion APIの名前を選択してください。
  5. 最後にデータベースのIDを探します。リンクは以下の構成になっています。ワークスペースの部分の文字列をコピーしてください。後ほど最初のコードに埋め込みます。
    ※もしもアプリ版(パソコンソフト版)を使っている場合は⌘+Lでそのページのリンクをコピーできるのでテキストエディタなどに貼り付けて上記の文字列を探してみてください。

補足 データベースのプロパティの調整

以下のテンプレを複製していただくことが一番簡単にできます。(下記の設定をすでに反映させております)
今回のコードを使うためには記事があるデータベースのプロパティを以下のように設定しておく必要があります。

  • 記事のタイトルをテキストプロパティの「記事名」という名前
  • 更新状況を示すためにセレクトプロパティ(単一選択)の「ステータス」をいう名前
    • ステータスの選択肢に「完了」を事前に作成しておく

https://nishiyuki0501.notion.site/Notion-LINE-Notify-0e25f22f450544fa95386c02c695235a

4. コードに反映されていく

  1. Google Apps Script(以下、GASと表記)の公式ページを開きます。(https://script.google.com/home
  2. (初めての方はログインします)
  3. エディタを開いたら、最初のコードを全てコピペしてください。最初のfunction(){}も消して、全て置き換えます。
  4. 保存して、実行を押すと権限確認が必要というポップアップが表示されるので「権限を確認」を押してください。
  5. Googleでログインすると「このアプリはGoogleに接続されていません」と出てくるので左下の「詳細」を押してください。
  6. 「詳細」を押すと「安全でないページへ移動」と出てくるので押してください。
    ※外部サービスとの連携により、情報漏洩などのリスクがあるという意味で接続には注意してくださいという意味です。
  7. 外部サービスとの接続を許可してください。(GASでプロジェクトを初めて動かすときは毎回この作業が必須になります。)

実際に動かした通知

実際に動かしてみるとLINEに記事名とそのリンクが共有されます。
記事の共有権限が「リンクを知っている人が閲覧可能」になっていることが前提ですが、通知を受け取った人が見ることができます。

通知のタイミングはGASのトリガーを用いて指定の時間にチェックするなどすれば完全に自動で送られるようになります。

最後に

いかがだったでしょうか。

少し長編にわたる内容でしたが、Notion内の情報をLINEに自動で送信することでコミュニティの運営や情報共有が円滑になる可能性が高いと思います。

こうした記事を今後も発信していきますので、ぜひ参考にしていただけますと嬉しいです。

ありがとうございました。