🔰

GASでGoogleCalendarにあっさりアクセス

2021/11/18に公開

GASとは!?

GoogleAppsScript(GAS)は、Googleのサービスを自動化するスクリプト言語です。
JavaScriptで記述する事が出来るので、気軽に開発をする事ができます。
今回はGASを利用して、GoogleCalendarにアクセスしてみます。

Class Calendar

GoogleCalendarの準備

GASを使ってCalendarにアクセスするには、アクセス先のIDが必要になります。
次の手順に従って、CalendarのIDを取得します。

1,Settingsをクリックする

Calendarの右上にある歯車アイコンをクリックし、"Settings"をクリックします。

2,Calendarを選択してIDをコピーする

画面の左側にあるメニューから、操作対象のCalendarを選択し、
右側(下にスクロールしましょう)の"Integrate Calendar"にあるIDをコピーします。

GoogleAppsScriptにアクセスする

専用の"ScriptEditor"を利用してコードを記述します。

1,ScriptEditorを立ち上げる

次のリンクから"Start Scripting"をクリックしましょう。

Google Apps Script

次に、"Apps Script"をクリックして"ScriptEditor"を立ち上げます。

次の様な画面が"ScriptEditor"と呼ばれる物です。

2,コードを編集する

カレンダーに対して様々な命令を実行するには、"CalendarApp"オブジェクトを利用します。
ここでは、Calendarの名前を取得するコードを記述してみる事にしましょう。

操作対象のカレンダーを取得する為に、"getCalendarById"関数を実行します。
この関数の引数には、最初にアクセスしたカレンダーのIDを指定します。
次のコードを記述、保存して"Debug"ボタンを押します。

Code.gs
function myFunc(){
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
}

3,認証設定

初回実行時には、次の様に認証を求める手続きがあるので次の手順に沿って認証を行います。

3-1, 認証ダイアログ

認証ダイアログが出るので、"Review permissions"をクリックします。

3-2, ユーザーを選択する

スクリプトを実行するユーザーを選択します。

3-3, 実行許可を与える

"Show Advanced"をクリックし、"Go to Untitled project(unsafe)"をクリックします。

3-4, 許可ボタンを押す

最後に"Allow"ボタンを押します。

実行が成功すると、"Executing log"の画面に実行結果として、カレンダー名が表示されます。(やりました!!)

Calendarにイベントを登録する

カレンダーにイベントを登録してみます。
カレンダーに当日のイベントを追加するには、"createEvent"関数を使います。
第一引数には"イベント名"を、そして第二、三引数には"開始日"と"終了日"を次の様に指定します。

Code.gs
function myFunc(){
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
  // カレンダーにイベントを登録する
  let start = new Date(2022, 0, 1);// 2022/01/01
  calendar.createEvent("お正月!!", start, start);
}

これだけでカレンダーにイベントを追加する事ができます。(やりました!!)

イベント登録については、他にも関連した関数が多数用意されています。

Class Calendar

よく使うと思われる関数を次にまとめておきますね。

関数名 意味 リファレンス
createAllDayEvent(タイトル, 日付) 日中のイベント リンク
createEvent(タイトル, 日時) 日時のイベント リンク

Calendarのイベントを取得する

カレンダーからイベントを取得してみます。
カレンダーから範囲を指定してイベントを取得するには、"getEvents"関数を使います。
第一、二引数には"開始日"と"終了日"を指定し、次の様に記述します。

Code.gs
function myFunc(){
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
  // カレンダーのイベントを取得する
  let start = new Date(2022, 0, 1);// 2022/01/01
  let end = new Date(2022, 0, 31);// 2022/01/31
  let events = CalendarApp.getEvents(start, end);
  for(let event of events){
    console.log(event.getTitle());// タイトル
  }
}

これだけで、カレンダーのイベントを取得する事ができます。(やりました!!)

イベントで取得できるパラメーターは他にも様々なものがあります。

Class Calendar Event

代表的なものを次にまとめておきますね。

関数名 内容
getId() ID
getTitle() タイトル
getDescription() 詳細
getLocation() 場所
getCreators() 作成者
getStartTime() イベント開始時間
getEndTime() イベント終了時間

Calendarのイベントを削除する

カレンダーからイベントを削除してみます。
カレンダーから特定のイベントを削除するには、"deleteEvent"関数を使います。

Code.gs
function myFunc(){
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
  // カレンダーからイベントを削除する
  let date = new Date(2022, 0, 1);// 2022/01/01
  let events = calendar.getEventsForDay(date);
  for(let event of events){
    event.deleteEvent();// イベント削除
  }
}

これだけで、カレンダーのイベントを削除する事ができます。(やりました!!)

インターネットからアクセスする

"GoogleCalendar"にインターネットからアクセスしてみます。
次の手順に従って"Deploy"をしていきましょう。

doGet関数を用意する

"myFunction"関数を"doGet"関数に書き換えます。
この関数は、インターネットからアクセスされるタイミングで実行されます。
return値には実行元への出力値を指定します。(ここでは仮にJSON形式の文字列として出力します)

Code.js
function doGet(e) {
  const json = JSON.stringify({"items": "Great Work!!"}, null, 2);
  const type = ContentService.MimeType.JSON;
  return ContentService.createTextOutput(json).setMimeType(type);
}

Deployする

"Deploy" -> "New deployment"の順にクリックします。

Deployment typeを選択する

"歯車ボタン" -> "Web App"の順にクリックします。

アクセス権限を選択する

"Who has access"で、"Anyone"を選択し"Deploy"をクリックします。

アクセス先のURLを取得する

アクセス先のURLが表示されるので、"Copy"をクリックします。

ブラウザからURLへアクセスする

コピーしたURLをブラウザに入力してアクセスすると、"doGet"関数のreturn値で生成した文字列(JSON)がブラウザに表示されます。(やりました!!)

カレンダーの名前をブラウザに表示する

先程のスクリプトを次の様に書き換える事で、
カレンダーの名前をブラウザに表示する事ができます。

Code.gs
function doGet(e) {
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  let calendarName = calendar.getName();
  // JSON
  const json = JSON.stringify({"YourCalendar": calendarName}, null, 2);
  const type = ContentService.MimeType.JSON;
  return ContentService.createTextOutput(json).setMimeType(type);
}

とりあえずカレンダーの名前を取得してみました。(やりました!!)

登録フォームから指定日にイベント登録をする

自分でフォームを用意し、そのフォームからCalendarにイベントを登録してみます。

次の様に、簡単なフォームを用意してみましょう。
formタグの"action"パラメーターには、WebAppへのURLを記述します。

index.html
<html>
<head>
	<meta charset="UTF-8"/>
</head>
<body>
	<p>Calendarに登録</p>
	<form method="GET" action="WebAppへのURL">
		<p>タイトル:<input type="text" name="title" value="お買い物"/></p>
		<p>年:<input type="text" name="y" value="2022"/></p>
		<p>月:<input type="text" name="m" value="1"/></p>
		<p>日:<input type="text" name="d" value="1"/></p>
		<p><button type="submit">送信</button>
	</form>
</body>
</html>

次はコードです。次の様にコードを記述してDeployします。
(DeployされたURLは、先程のHTMLのactionに記述しましょう)

Code.gs
function doGet(e){
  // Parameter
  if(typeof e === "undefined") return;
  let title = e.parameter.title;
  let y = parseInt(e.parameter.y);
  let m = parseInt(e.parameter.m) - 1;
  let d = parseInt(e.parameter.d);
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
  // カレンダーにイベントを登録する
  let start = new Date(y, m, d);
  calendar.createEvent(title, start, start);
}

formの"送信"を実行をすると、カレンダーに予定が登録されている事を確認できます。(やりました!!)

Calendarから指定期間のイベントを取得する

指定の期間に存在する全てのイベントを、JSON形式のデータとして取得してみます。

次の様に、簡単なフォームを用意してみましょう。
formタグの"action"パラメーターには、WebAppへのURLを記述します。

index.html
<html>
<head>
	<meta charset="UTF-8"/>
</head>
<body>
	<p>Calendarから取得</p>
	<form method="GET" action="WebAppへのURL">
		<p>期間(開始)</p>
		<p>年:<input type="text" name="y_start" value="2022"/></p>
		<p>月:<input type="text" name="m_start" value="1"/></p>
		<p>日:<input type="text" name="d_start" value="1"/></p>
		<p>期間(終了)</p>
		<p>年:<input type="text" name="y_end" value="2022"/></p>
		<p>月:<input type="text" name="m_end" value="1"/></p>
		<p>日:<input type="text" name="d_end" value="31"/></p>
		<p><button type="submit">送信</button>
	</form>
</body>
</html>

次はコードです。次の様にコードを記述してDeployします。
(DeployされたURLは、先程のHTMLのactionに記述しましょう)

Code.gs
function doGet(e){
  // Parameter
  if(typeof e === "undefined") return;
  let y_start = parseInt(e.parameter.y_start);
  let m_start = parseInt(e.parameter.m_start) - 1;
  let d_start = parseInt(e.parameter.d_start);
  let y_end = parseInt(e.parameter.y_end);
  let m_end = parseInt(e.parameter.m_end) - 1;
  let d_end = parseInt(e.parameter.d_end);
  // カレンダーを取得する
  let calendar = CalendarApp.getCalendarById("*************@gmail.com");
  console.log(calendar.getName());
  // カレンダーからイベントを取得する
  let start = new Date(y_start, m_start, d_start);
  let end = new Date(y_end, m_end, d_end);
  let events = CalendarApp.getEvents(start, end);
  let arr = [];
  for(let event of events){
    let obj = new Object();
    obj.title = event.getTitle();// タイトル
    obj.description = event.getDescription();// 詳細
    obj.year = event.getAllDayStartDate().getFullYear();// 年
    obj.month = event.getAllDayStartDate().getMonth();// 月
    obj.date = event.getAllDayStartDate().getDate();// 日
    arr.push(obj);
  }
  // JSON文字列に変換して出力する
  const json = JSON.stringify(arr, null, 2);
  const type = ContentService.MimeType.JSON;
  return ContentService.createTextOutput(json).setMimeType(type);
}

特定の期間でのイベントを、JSON形式で取得する事ができました。(やりました!!)

それっぽく作ってみる(おまけ)

Vue.jsとAxiosを利用して、それっぽく作ってみましょう。(おまけです)
詳細についての解説はここでは割愛致しますが、簡単な解説記事もありますのでよろしければ是非!!

Vue.jsをかじる本

Axiosであっさりファイルアクセス

HTMLを編集する

HTMLを用意し、次のコードを記述します。

index.html
<html>
<head>
	<meta charset="UTF-8"/>
	<link rel="stylesheet" href="./custom.css"/>
	<script src="https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js" defer></script>
	<script src="https://unpkg.com/vue@next" defer></script>
	<script src="./main.js" defer></script>
</head>
<body>
	<div id="app">
		<h1>{{ appName }}</h1>
		<p>
			<input type="text" v-model="y_in" /><br/>
			<input type="text" v-model="m_in" /><br/>
			<input type="text" v-model="d_in" /><br/>
			<input type="text" v-model="title_in" /><br/>
			<input type="text" v-model="description_in" /><br/>
			<input type="text" v-model="id_in" /><br/>
			<button v-on:click="submitData">Submit</button>
		</p>
		<table>
			<tr>
				<th></th>
				<th></th>
				<th>Year</th>
				<th>Month</th>
				<th>Date</th>
				<th>Title</th>
				<th>Description</th>
				<th>Id</th>
			</tr>
			<tr v-for="event in events">
				<td><button v-on:click="selectData(event)">Select</button></td>
				<td><button v-on:click="deleteData(event)">Delete</button></td>
				<td>{{ event.y }}</td>
				<td>{{ event.m }}</td>
				<td>{{ event.d }}</td>
				<td>{{ event.title }}</td>
				<td>{{ event.description }}</td>
				<td>{{ event.id }}</td>
			</tr>
		</table>
	</div>
</body>
</html>

Vue.js、Axiosの読み込みと、カレンダーからの一覧を表示するエリアを設けています。

JavaScriptを編集する

JavaScriptファイルを用意し、次のコードを記述します。

main.js
console.log("main.js!!");

// SpreadSheet
const J_GOOGLE = "https://script.google.com/macros/s/";
const J_DEPLOY = "Deployment ID";
const J_EXEC   = "/exec";
const J_URL    = J_GOOGLE + J_DEPLOY + J_EXEC;

// MyData
const myData = {
	appName: "Hello Calendar!!",
	events: [],
	y_in: 2022,
	m_in: 1,
	d_in: 1,
	title_in: "お買い物",
	description_in: "カレーの食材一式",
	id_in: ""
}

const app = Vue.createApp({
	data(){
		return myData;
	},
	created(){
		this.readData();// Read
	},
	methods:{
		readData(){
			console.log("readData");
			// Today
			const today = new Date();
			const y = today.getFullYear();
			const m = today.getMonth();
			const d = today.getDate();
			// Axios
			const vue = this;// Important
			const option = {
				responseType: "blob",
				params: {
					"mode": "read",
					"y_start": y,
					"m_start": m-1,
					"d_start": d,
					"y_end":   y,
					"m_end":   m+6,
					"d_end":   d
				}
			};
			axios.get(J_URL, option).then(res=>{
				res.data.text().then(str=>{
					//console.log(str);
					vue.events = JSON.parse(str);// Parse
				});
			});
		},
		createData(){
			console.log("createData");
			// Axios
			const vue = this;// Important
			const option = {
				responseType: "blob",
				params: {
					"mode": "create",
					"y": this.y_in,
					"m": this.m_in,
					"d": this.d_in,
					"title": this.title_in,
					"description": this.description_in
				}
			};
			axios.get(J_URL, option).then(res=>{
				res.data.text().then(str=>{
					console.log(str);
					vue.readData();// Read
				});
			});
		},
		updateData(){
			console.log("updateData");
			// Axios
			const vue = this;// Important
			const option = {
				responseType: "blob",
				params: {
					"mode": "update",
					"y": this.y_in,
					"m": this.m_in,
					"d": this.d_in,
					"title": this.title_in,
					"description": this.description_in,
					"id": this.id_in
				}
			};
			axios.get(J_URL, option).then(res=>{
				res.data.text().then(str=>{
					console.log(str);
					vue.readData();// Read
				});
			});
		},
		deleteData(event){
			console.log("deleteData");
			// Axios
			const vue = this;// Important
			const option = {
				responseType: "blob",
				params: {
					"mode": "delete",
					"id": event.id
				}
			};
			axios.get(J_URL, option).then(res=>{
				res.data.text().then(str=>{
					console.log(str);
					vue.readData();// Read
				});
			});
		},
		submitData(){
			console.log("submitData");
			if(this.id_in == ""){
				this.createData();// Create
			}else{
				this.updateData();// Update
			}
		},
		selectData(event){
			console.log("selectData");
			this.y_in = event.y;
			this.m_in = event.m;
			this.d_in = event.d;
			this.title_in = event.title;
			this.description_in = event.description;
			this.id_in = event.id;
		}
	}
});
app.mount("#app");

"Deployment ID"の部分に、カレンダーの"Deployment ID"を記述しておきましょう。

GASを編集する

GAS側へのコードは次の通りです。

Code.gs
function doGet(e){
  // Parameter
  if(typeof e === "undefined") return;
  // カレンダーを取得する
  const calendar = CalendarApp.getCalendarById("あなたのID@gmail.com");
  const type     = ContentService.MimeType.JSON;
  const param    = e.parameter;
  const mode     = param.mode;// create / read / update / delete

  //==========
  // カレンダーに追加する(create)
  if(mode == "create"){
    const y           = parseInt(param.y);
    const m           = parseInt(param.m) - 1;
    const d           = parseInt(param.d);
    const title       = param.title;
    const description = param.description;
    // カレンダーにイベントを登録する
    const date = new Date(y, m, d);
    calendar.createAllDayEvent(title, date, {
      "description": description
    });
    // JSON
    const json = JSON.stringify({"mode": mode}, null, 2);
    return ContentService.createTextOutput(json).setMimeType(type);
  }

  //==========
  // カレンダー読み込み(read)
  if(mode == "read"){

    const y_start = parseInt(param.y_start);
    const m_start = parseInt(param.m_start);
    const d_start = parseInt(param.d_start);
    const y_end   = parseInt(param.y_end);
    const m_end   = parseInt(param.m_end);
    const d_end   = parseInt(param.d_end);
    const start   = new Date(y_start, m_start, d_start);
    const end     = new Date(y_end, m_end, d_end);
    const events  = CalendarApp.getEvents(start, end);

    const arr = [];
    for(const event of events){
      const obj = new Object();
      obj.y           = event.getStartTime().getFullYear();// 年
      obj.m           = event.getStartTime().getMonth() + 1;// 月
      obj.d           = event.getStartTime().getDate();// 日
      obj.title       = event.getTitle();// タイトル
      obj.description = event.getDescription();// 詳細
      obj.id          = event.getId();// ID
      arr.push(obj);
    }
    // JSON
    const json = JSON.stringify(arr, null, 2);
    return ContentService.createTextOutput(json).setMimeType(type);
  }

  //==========
  // カレンダーを更新(update)
  if(mode == "update"){
    const event = calendar.getEventById(param.id);
    event.getStartTime().setFullYear(parseInt(param.y));
    event.getStartTime().setMonth(parseInt(param.m));
    event.getStartTime().setDate(parseInt(param.d));
    event.setTitle(param.title);
    event.setDescription(param.description);
    // JSON
    const json = JSON.stringify({"mode": mode}, null, 2);
    return ContentService.createTextOutput(json).setMimeType(type);
  }

  //==========
  // カレンダーから削除(delete)
  if(mode == "delete"){
    const event = calendar.getEventById(param.id);
    event.deleteEvent();
    // JSON
    const json = JSON.stringify({"mode": mode}, null, 2);
    return ContentService.createTextOutput(json).setMimeType(type);
  }
}

getCalendarByIdの引数には、自分のGoogleアカウントを記述しておきましょう。

最後に

駆け足でありましたが、GoogleCalendarに対してデータの登録、取得、削除までご紹介致しました。いかたでしたでしょうか?
記述ルールもとてもシンプルで、直感的に作れる事が伝われば幸いです。
"SpreadSheet"や"GoogleForms"と連携したアプリケーションも作る事が出来るので、是非挑戦してみてくださいね。
ここまで読んでいただき有難うございました。

Discussion