구글 앱스 스크립트(Google Apps Script)란?
구글에서 개발한 스크립팅 플랫폼으로 구글 메일, 구글 드라이브, 구글 문서, 구글 스프레드 시트 등 구글 서비스가 통하는 구글 워크스페이스에서 반복적인 매크로 기능이나, 간단한 업부를 수행하는 기능을 개발할 수 있으며, 자바스크립트에 기반을 두고 있다.
function createCalendar() {
//스프래드시트의 하단에 있는 Sheet tab의 이름
const SheetTabName = "시트1";
//필요한 데이터의 스프래드시트 Header명
const HeaderTitle = "Name";
const HeaderTime = "Upcoming Interview Time";
const HeaderStartTime = "Upcoming Interview Date";
const HeaderDescription = "Status";
const DescriptionProject = "Project";
const DescriptionClient = "Client";
const CalId = "id"; // 캘린더이벤트 고유값
const HeaderDel = "isdel"; // 삭제여부 확인
const HeaderRegState = "calendar"; // 업데이트항목 확인
//처음 데이터가 시작하는 표의 시작점(row)
const startRow = 5;
//처음 데이터가 시작하는 표의 시작점(column)
const startColumn = 1;
//등록할 캘린더의 ID값 (상단 설명 참고)
const calendarId = "59496b1aaa********생략********";
/***************************************************************************************/
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SheetTabName);
const eventCal = CalendarApp.getCalendarById(calendarId);
const endRow = spreadsheet.getLastRow();
const endColumn = spreadsheet.getLastColumn();
const count = spreadsheet.getRange(startRow, startColumn, endRow, endColumn).getValues(); // getRange(row, column, numRows, numColumns)
//해당 header의 스프레드시트 ColumnIndex
const colHeaderStartTime = spreadsheet.createTextFinder(HeaderStartTime).findNext().getColumnIndex() - startColumn;
const colHeaderTitle = HeaderTitle ? spreadsheet.createTextFinder(HeaderTitle).findNext().getColumnIndex() - startColumn : "";
const colHeaderTime = HeaderTime ? spreadsheet.createTextFinder(HeaderTime).findNext().getColumnIndex() - startColumn : "";
const colHeaderDescription = HeaderDescription ? spreadsheet.createTextFinder(HeaderDescription).findNext().getColumnIndex() - startColumn : "";
const colDescriptionProject = DescriptionProject ? spreadsheet.createTextFinder(DescriptionProject).findNext().getColumnIndex() - startColumn : "";
const colDescriptionClient = DescriptionClient ? spreadsheet.createTextFinder(DescriptionClient).findNext().getColumnIndex() - startColumn : "";
const colCalId = CalId ? spreadsheet.createTextFinder(CalId).findNext().getColumnIndex() - startColumn : "";
const colHeaderDel = HeaderDel ? spreadsheet.createTextFinder(HeaderDel).findNext().getColumnIndex() - startColumn : "";
const colHeaderState = HeaderRegState ? spreadsheet.createTextFinder(HeaderRegState).findNext().getColumnIndex() - startColumn : "";
const KR_TIME_DIFF = 9 * 60 * 60 * 1000;
//시트 Row 수 만큼 반복
for (x = 0; x < count.length; x++) {
// 한꺼번에 많은 캘린더를 등록하면 오류가 발생함
if (x === 15) Utilities.sleep(2 * 1000);
const shift = count[x]; // 시트 row (하단 설명 참고)
//한국 시간은 UTC보다 9시간 빠름
const startTime = new Date(shift[colHeaderTime]);
const startTimeUtc = startTime.getTime() + startTime.getTimezoneOffset() * 60 * 1000;
const startTimeKor = new Date(startTimeUtc + KR_TIME_DIFF);
const time = startTimeKor.toTimeString().split(':')[0] + ":" + startTimeKor.toTimeString().split(':')[1];
// var data = shift[가져오고 싶은 header ColumnIndex];
const name = shift[colHeaderTitle] ? shift[colHeaderTitle] : "";
const headerDescription = shift[colHeaderDescription] ? shift[colHeaderDescription] : "";
const descriptionProject = shift[colDescriptionProject] ? shift[colDescriptionProject] : "";
const descriptionClient = shift[colDescriptionClient] ? shift[colDescriptionClient] : "";
// 캘린더 해당 이벤트 고유값 (캘린더 내용 수정 시 필요)
const calId = shift[colCalId] ? shift[colCalId] : "";
// 캘린더 이벤트 삭제 여부
const isdel = shift[colHeaderDel] ? shift[colHeaderDel] : "";
// 캘린더 이벤트 등록 상태
const state = shift[colHeaderState] ? shift[colHeaderState] : "";
const titleSum = name + "(" + time + ")" + " - " + headerDescription;
const descriptionSum = "Client : " + " " + descriptionClient + "\n" + "Project : " + " " + descriptionProject;
// EST시간을 KOR시간으로 치환 시작
const startCurr = new Date(shift[colHeaderStartTime]);
const startUtc = startCurr.getTime() + startCurr.getTimezoneOffset() * 60 * 1000;
const startT = new Date(startUtc + KR_TIME_DIFF);
// 캘린더에 등록할 이벤트 내용
const event = {
description: descriptionSum
};
// 캘린더 등록 상태 "Y"가 아니라면, 등록
if (state != "Y" && !isNaN(startCurr) && name !== "") {
if(calId !== null && calId !== "") {
// 기존 캘린터 이벤트 id값 삭제
eventCal.getEventById(calId).deleteEvent();
}
let newEvent = eventCal.createAllDayEvent(titleSum, startT, event);
spreadsheet.getRange(Number(startRow + x), colHeaderState + startColumn).setValue("Y"); // 등록 상태 "Y"로 업데이트
spreadsheet.getRange(Number(startRow + x), colCalId + startColumn).setValue(newEvent.getId()); // 새로 등록한 이벤트 Id값 입력
}
// iddel 체크 후, 이벤트 삭제
if (isdel === "DEL" || isdel === "del" || isdel === "D" || isdel === "d") {
const events = eventCal.getEventsForDay(startT, { search: titleSum });
for (y = 0; y < events.length; y++) {
events[y].deleteEvent();
}
spreadsheet.deleteRow(Number(startRow + x));
}
}
}
앱스 스크립트 코드 추가
// 스프레드시트에 버튼 생성
function onOpenSchedule() {
const ui = SpreadsheetApp.getUi();
ui.createMenu("캘린더동기화").addItem("업데이트", "createCalendar").addToUi();
}
스크립트 실행 시, 해당 함수 선택 후 동작
해당 시트에 버튼 생성 완료
하지만 시트를 새로 열때마다 함수실행을 시켜줘야 버튼이 나타난다.
그래서 트리거로 함수 실행 시키는게 편리함!
Apps Script 왼쪽 메뉴 중 트리거 선택 > 트리거 추가
실행할 함수 선택에서 아까 만들었던 함수 선택
( * 이벤트 유형에는 스프레드시트 열릴 시, 이외에도 수정 / 변경 / 양식 제출 등 다양하게 존재)
스크립트 실행 시 “권한이 필요합니다” 뜨는 경우, 아래 사이트 참고