구글 캘린더 Api | 달력(Fullcalendar)과 구글 캘린더 Api 연동 (30분만에 관리형 달력 완성!) 빠른 답변

당신은 주제를 찾고 있습니까 “구글 캘린더 api – 달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!)“? 다음 카테고리의 웹사이트 you.maxfit.vn 에서 귀하의 모든 질문에 답변해 드립니다: you.maxfit.vn/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 소스놀이터 이(가) 작성한 기사에는 조회수 4,598회 및 좋아요 37개 개의 좋아요가 있습니다.

구글 캘린더 api 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!) – 구글 캘린더 api 주제에 대한 세부정보를 참조하세요

회사 일정만 간단히 나오면 되는데, 작업할 엄두가 안나오시나요?
일정 관리 기능에, 날짜 다루기까지 쉽지 않죠?
구글 캘린더로 일정을 관리하고, 몇 줄의 코딩만으로 일정 소개 페이지를 완성할 수 있습니다.
이 강의는 fullcalendar 플러그인 + Google Calendar API로 손쉽게 막강한 일정 관리 프로그램을 얻는 방법을 소개합니다.

구글 캘린더 api 주제에 대한 자세한 내용은 여기를 참조하세요.

구글 캘린더 API 뽀개기 – 기록으로 채워가는 개발자 이야기

구글 캘린더 API는 정확한(explicit) HTTP 호출 혹은 구글 클라이언트 라이브러리를 통해 접근 가능한 RESTful API입니다. API는 구글 웹 인터페이스에서 …

+ 여기를 클릭

Source: gaebalsogi.tistory.com

Date Published: 10/4/2021

View: 873

구글 캘린더 API

Google Console에서 API키 얻기. Google Console 사이트. 1) 캘린더 라이브러리. Lib. 라이브러리를 누릅니다. calendar를 검색하고. CalendarStart.

+ 여기를 클릭

Source: docfriends.github.io

Date Published: 12/26/2021

View: 8728

구글 OpenAPI 활용 – 캘린더 (2. 개념 : 함수/데이터 편)

앞서 구글 캘린더 API가 제공하는 자원들을 살펴보았습니다. … 파라미터와 데이터 형식의 차이(예 : 특정 캘린더의 일정을 조회할 때) …

+ 여기에 더 보기

Source: ai-creator.tistory.com

Date Published: 12/14/2022

View: 1285

[Python] 구글 Open API로 캘린더 활용해보기 – velog

라이브러리에서 Calendar를 검색해준다. Google Calendar API 를 선택해서 사용설정을 해준다. 사용자 인증 정보 탭에 들어가서 API키를 얻는다.

+ 여기에 표시

Source: velog.io

Date Published: 6/30/2021

View: 2968

Sign in – Google Cloud Platform

Google Cloud Platform lets you build, deploy, and scale applications, websites, and services on the same infrastructure as Google.

+ 여기에 자세히 보기

Source: console.developers.google.com

Date Published: 2/24/2021

View: 4268

구글 캘린더 API 자바 연동

구글 캘린더 API 자바 연동 · 프로젝트를 만들어줍니다. · 라이브러리 -> Calendar API 클릭 · 사용 설정 클릭 · 사용자 인증 정보 만들기 클릭 · java로 구현 …

+ 자세한 내용은 여기를 클릭하십시오

Source: sizin.tistory.com

Date Published: 3/5/2022

View: 1725

react-google-calendar-api – npm

An api to manage your google calendar. Latest version: 2.0.3, last published: 2 months ago. Start using react-google-calendar-api in your …

+ 여기에 표시

Source: www.npmjs.com

Date Published: 6/28/2022

View: 6187

Python) Google Calendar API 사용 방법 – 분석뉴비

Python에서 Google Calendar API를 사용하여 내 계정의 이벤트를 가져오는 것을 해보고자 한다. 일단 구글 캘린더 API를 사용하기 위해서는 Open API …

+ 여기에 더 보기

Source: data-newbie.tistory.com

Date Published: 5/2/2022

View: 7905

주제와 관련된 이미지 구글 캘린더 api

주제와 관련된 더 많은 사진을 참조하십시오 달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!). 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!)
달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!)

주제에 대한 기사 평가 구글 캘린더 api

  • Author: 소스놀이터
  • Views: 조회수 4,598회
  • Likes: 좋아요 37개
  • Date Published: 2021. 4. 26.
  • Video Url link: https://www.youtube.com/watch?v=MUJ_Z6ev-Mo

기록으로 채워가는 개발자 이야기

시작하기 앞서

프로젝트에 구글 캘린더 API를 적용해야 하는데, 스스로의 검색 능력 한계로 적합한 가이드 자료를 찾을 수 없어 google developers에 있는 공식 문서를 읽으며 해당 기능을 사용하는 방법을 정리하기로 마음 먹었다. 영어로 된 문서라 빠르게 정보를 습득하는데 한계가 있어, 필요한 부분을 번역해서 나중에 필요할 때 참고하면 좋을거 같아 블로그에 공식 문서를 번역하는 글을 쓴다!

* 전문적으로 교육받은 번역가가 작성한 글이 아니기 때문에 문서에 작성자가 인지하지 못한 오역과 의역이 다수 존재할 수 있습니다.

2022. 1. 8 (글을 쓴 다음 날) 첨언

아래의 글을 읽기 전, 만약 API, OAuth 2.0 혹은 인증/인가에 관한 지식이 없는 상태에서 구글 캘린더를 구동하려 하는 경우 아래의 강의를 시청하길 강력 권장한다. 생활코딩에서 만든 OAuth 2.0 수업인데, API를 사용하는 방법을 아주 잘 설명해 놓았다. (마침 예제로 사용되는 API가 구글 캘린더다!) API를 사용하는 메커니즘을 한 눈에 익힐 수 있는 훌륭한 강의다.

시작

1. Google Calendar API Overview

The Google Calendar API is a RESTful API that can be accessed through explicit HTTP calls or via the Google Client Libraries. The API exposes most of the features available in the Google Calendar Web interface.

Following is a list of common terms used in the Google Calendar API:

(Event, Calendar, Calendar List, Setting, ACL에 대한 설명이 각각 나와 있다.)

구글 캘린더 API는 정확한(explicit) HTTP 호출 혹은 구글 클라이언트 라이브러리를 통해 접근 가능한 RESTful API입니다. API는 구글 웹 인터페이스에서 사용할 수 있는 대부분의 기능을 제공합니다.

아래는 구글 캘린더 API에서 사용되는 공통 용어 목록입니다:

Next steps

To get started with Google Calendar API:

* To learn about developing with Google Workspace APIs, including handling authentication and authorization, refer to Get started as a Workspace developer.

* To learn how to configure and run a simple Google Calendar API app, read the Quickstarts overview.

구글 캘린더 API를 시작하기 위해:

인증 및 권한 부여를 포함한 구글 워크스페이스 API 개발에 대한 자세한 내용은 워크스페이스 개발자로 시작하기를 참조하여 주십시오.

간단한 구글 캘린더 API 애플리케이션을 구동하는 부분에 대한 자세한 내용은 빨리 시작하기를 참조하여 주십시오.

2. Develop on Google Workspace (워크스페이스 개발자로 시작하기)

Google Workspace offers a wide range of developer products and tools that let you connect your service with Google Workspace or extend Google Workspace apps like Gmail, Drive, and Chat. Each Workspace app or integration has its own Google Cloud project where you configure APIs, set up authentication, and manage deployments.

구글 워크스페이스는 구글 워크스페이스에 서비스를 연결하거나 Gmail, Drive, Chat과 같은 확장 앱을 확장할 수 있는 다양한 제품과 도구들을 제공합니다. 각각의 워크스페이스 앱 혹은 통합(integration)은 API 구성, 인증 설정, 배포 관리와 같은 고유한 구글 클라우드 프로젝트를 가지고 있습니다.

5 steps to get started

1. Create a Google Cloud project for your Google Workspace app, extension, or integration.

2. Enable the APIs you want to use in your Google Cloud project.

3. Learn how authentication and authorization works when developing for Google Workspace.

4. Configure OAuth consent to ensure users can understand and approve what access your app has to their data.

5. Create access credentials to authenticate your app’s end users or service accounts.

2-1. Create a Google Cloud project (구글 클라우드 프로젝트 생성하기)

A Google Cloud project is required to use Google Workspace APIs and build Google Workspace add-ons or apps. This project forms the basis for creating, enabling, and using all Google Cloud services, including managing APIs, enabling billing, adding and removing collaborators, and managing permissions.

구글 클라우드 프로젝트를 이용하기 위해서는 구글 워크스페이스 API를 사용해 add-ons 혹은 앱을 빌드해야 합니다. 이 프로젝트는 API 관리, 청구 이용, 공동작업자 추가 및 제거, 권한 관리를 포함하는 모든 구글 클라우드 서비스를 생성, 활성화, 혹은 사용하기 위한 기본적인 기반을 제공합니다.

To create a Google Cloud project:

1. Open the Google Cloud Console.

2. At the top-left, click Menu > IAM & Admin > Create a Project.

3. In the Project Name field, enter a descriptive name for your project.

Optional: To edit the Project ID, click Edit. The project ID can’t be changed after the project is created, so choose an ID that meets your needs for the lifetime of the project.

4. In the Location field, click Browse to display potential locations for your project. Then, click Select.

Caution: Can’t find your Google Workspace organization?

This means you aren’t signed in to a Google Workspace account. Some of the features described in Google Workspace developer documentation are only available to projects associated with an organization.

5. Click Create. The console navigates to the Dashboard page and your project is created within a few minutes.

For further information on Google Cloud projects, refer to Creating and managing projects.

구글 클라우드 프로젝트를 생성하기 위해:

구글 클라우드 콘솔을 여십시오. 왼쪽 상단, 메뉴 버튼 > IAM & Admin > Create a Project를 클릭하십시오. 프로젝트 이름(Project Name) 영역에 당신의 프로젝트를 설명하는 이름을 입력하십시오. 선택 : 프로젝트 ID(Project ID)를 편집하려면 Edit을 누르십시오. 프로젝트 ID는 생성되면 바꿀 수 없습니다. 따라서 프로젝트 기간 동안 피요한 ID를 선택하십시오. 프로젝트의 잠재적 위치를 표시하기 위해 위치(Location) 영역의 Browse를 클릭하십시오. 다음 Select를 클릭하십시오. 주의 : 구글 워크스페이스 organization을 찾을 수 없습니까?

이는 구글 워크스페이스 계정에 로그인되어 있지 않음을 의미합니다. 구글 워크스페이스 개발자 문서에 설명된 기능의 일부는 오직 프로젝트가 organization과 연결된 경우만 사용할 수 있습니다. Create을 누르십시오. 콘솔이 대시보드 창으로 이동하고 프로젝트가 몇 분 내로 생성될 것입니다.

2-2. Enable Google Workspace APIs (구글 워크스페이스 API 활성화하기)

To enable an API in your Google Cloud project:

1. Open the Google Cloud Console.

2. At the top-left, click Menu menu > APIs & Services > Library.

3. In the search field, enter the name of the API you want to enable and press Enter.

4. In the list of search results, click the API you want to enable.

5. Click Enable.

6. To enable more APIs, repeat steps 2–5.

구글 클라우드 프로젝트 내의 API를 활성화하기 위해:

구글 클라우드 콘솔을 여십시오. 왼쪽 상단, 메뉴 > APIs & Services > Library를 클릭하십시오. 검색 영역에 당신이 활성화하고자 하는 API 이름을 기입하고 엔터를 누르십시오. 검색 결과 중, 활성화하고자 하는 API를 클릭하십시오. Enable을 누르십시오. 더 많은 API를 활성화하려면 2 ~ 5번을 반복하십시오.

2-3. Learn about authentication & authorization (인증 & 인가 작업 학습하기)

<이 장은 문서 양이 방대하여 원본 첨부 없이 번역합니다. 원본은 아래의 링크를 클릭하면 확인할 수 있습니다.>

https://developers.google.com/workspace/guides/auth-overview

인증과 인가는 ID와 리소스 각각을 검증하는데 사용되는 메커니즘입니다. 이 문서는 당신이 당신의 앱을 구현하기 전 알아야 할 인증과 인가의 핵심 용어를 알아봅니다.

참고: 이 문서는 구글 워크스페이스 API를 위한 인증과 인가에 중점을 둡니다. 이 문서의 특정한 정보는 다른 구글 API에 적용되지 않을 수 있습니다.

프로세스 개요

아래의 그림은 구글 워크스페이스 API 인증 및 인가의 상위 수준의 단계를 보여줍니다.

출처 :&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;https://developers.google.com/workspace/guides/auth-overview

구글 클라우드 프로젝트와 앱 설정 : 개발하는 동안, API 키, 최종 사용자의 자격 증명 또는 서비스 계정 자격 증명으로 앱을 인증하기 위한 가격 증명과 인증 범위를 정의하는 구글 클라우드 콘솔을 앱 내에 등록합니다. 접근을 위한 앱 인증 : 앱이 실행될 때, 등록된 자격 증명이 평가됩니다. 앱이 최종 사용자로 인증하는 경우 로그인 프롬프트가 표시될 수 있습니다. 리소스 요청 : 앱이 구글 자원에 접근해야 할 경우 이전에 등록한 관련 접근 범위를 사용하여 구글에 요청합니다. 사용자 동의 요청 : 앱이 최종 사용자로 인증하는 경우, 구글은 유저가 요청된 데이터에 대한 접근을 앱에 부여할 지 결정할 수 있는 OAuth 동의 화면을 출력합니다. 리소스 승인 요청 전송 : 사용자가 접근 범위에 동의하면 앱은 자격 증명과 사용자가 승인한 접근 범위를 하나의 요청으로 묶습니다. 요청은 엑세스 토큰을 받기 위해 구글 인증 서버로 전송됩니다. 구글, 엑세스 토큰 반환 : 엑세스 토큰은 승인된 접근 범위의 리스트를 포함합니다. 만약 반환된 범위의 리스트가 요청했던 접근의 범위보다 제한적일 경우, 앱은 토큰으로부터 제한된 모든 기능을 비활성화합니다. 요청된 자원으로 접근 : 앱은 구글의 엑세스 토큰을 사용하여 관련 API를 호출하고 자원에 접근합니다. 새로 고침 토큰 받기 (선택사항) : 앱이 단일 엑세스 토큰의 생명주기를 넘어 구글 API에 접근해야 하는 경우 새로 고침 토큰을 얻을 수 있습니다. 더 많은 자원 요청 : 추가 접근이 필요한 경우 앱에서 사용자에게 새로운 접근 범위를 부여하도록 요청하여 엑세스 토큰을 위한 새로운 요청을 생성합니다. (3 ~ 6번)

중요 용어

아래는 인증과 인가와 관련된 용어의 리스트를 보여줍니다.

인증(Authentication)

사용자 혹은 사용자를 대신하는 앱을 포괄하는 주체가 자신이 누구인지 확인하는 행위입니다. 구글 워크스페이스 앱을 작성할 때, 다음과 같은 인증 종류를 반드시 알아야 합니다:

사용자 인증

사용자가 앱에 인증(로그인)하는 행위입니다. 사용자 인증은 앱에 등록된 사용자의 ID와 비밀번호를 사용하여 로그인을 하는 방식을 사용하여 주로 인증합니다. 사용자 인증은 구글로 로그인을 사용하여 앱과 통합할 수 있습니다.

앱 인증

사용자를 대신하여 구동 중인 앱이 구글 서비스로 직접 인증하는 행위입니다. 앱 인증은 일반적으로 앱 내에 있는 코드 속에 미리 생성된 자격 증명을 통해 수행됩니다.

인가(Authorization)

주체가 데이터에 접근하거나 작업을 수행하기 위해 필요한 승인 혹은 “권한”. 인가 행위는 앱 내에 작성된 코드를 통해 수행됩니다. 이 코드는 앱이 사용자를 대신하여 작업하기를 원한다는 것을 사용자에게 알리고, 승인되는 경우 앱의 고유 자격 증명을 이용하여 데이터에 접근하거나 작업을 수행할 수 있는 엑세스 토큰을 얻습니다.

자격 증명(Credential)

소프트웨어 보안에 사용되는 식별 형태입니다. 인증의 관점에서, 자격 증명(credential)은 종종 사용자명/비밀번호를 조합한 것으로 표현됩니다. 구글 워크스페이스 API를 위한 인가적 관점에서 자격 증명(credential)은 인가 서버와 앱 개발자만이 알고 있는 특수한 비밀 문자열과 같은 식별 형태로 표현됩니다. 구글은 API 키, OAuth 2.0 Client ID, 서비스 계정과 같은 인가 자격 증명을 지원합니다.

API 키

구글 워크스페이스 공유 설정 내에서 ‘이 링크가 있는 인터넷상의 모든 사용자’ 설정을 사용하여 공유된 구글 워크스페이스 파일 또는 Maps API를 사용하여 제공된 데이터와 공공 데이터에 대한 접근을 요청하는데 사용되는 자격 증명입니다.

OAuth2 Client ID

사용자가 소유한 데이터에 대한 접근을 요청하는 자격 증명입니다. 구글 워크스페이스 API를 사용하여 데이터에 대한 접근을 요청할 대 사용되는 기본 자격 증명입니다. 이 자격 증명은 사용자의 동의가 필요합니다.

Client secret

애플리케이션과 인가 서버 사이에만 공유되는 문자열입니다. client secret은 인증된 요청자에게만 토큰을 승인함으로써 사용자의 데이터를 보호합니다. 앱 내의 코드에는 절대 client secret을 포함하면 안됩니다.

서비스 계정 키

구글 서비스에 인가를 획득하기 위한 서비스 계정에 사용됩니다.

범위(Scope)

앱에 부여된 리소스 혹은 작업에 대한 접근 수준을 정의하는 OAuth 2.0 URI 문자열입니다. 구글 워크스페이스의 경우 승인 범위 URI에는 구글 워크스페이스 앱 이름, 접근하는 데이터 유형, 접근 수준이 포함됩니다. 앱 사용자는 요청된 범위를 검토하고 부여할 접근 권한을 선택할 수 있습니다. 그러면 구글 인증 서버는 엑세스 토큰을 이용해 앱으로 허용된 범위를 반환합니다. 자세한 내용은 앱의 범위를 설정하는 방법을 참조하십시오.

인가 서버(Authorization server)

엑세스 토큰을 이용하여 요청된 앱의 데이터나 작동에 대한 접근을 승인하는 구글 서버입니다.

인가 코드(Authorization code)

엑세스 토큰을 획득하기 위해 인가 서버에서 전송하는 코드입니다. 이 코드는 귀하의 애플리케이션이 웹 서버 앱이거나 an installed 앱인 경우에만 필요합니다.

리소스 서버

앱이 호출하고자 하는 API를 호스팅하는 서버입니다.

OAuth 2.0 framework

앱에서 ‘보안 위임된 접근’ 혹은 앱 사용자를 대신하여 데이터 및 작업에 대한 접근을 제공하는 데 사용될 수 있는 표준입니다. 앱에서 사용하는 인증 및 인가 메커니즘은 OAuth 2.0 framework의 구현을 나타냅니다.

주체(Principle)

리소스에 대한 접근이 허가된 엔티티이며 식별자(ID, Identity)라고도 불립니다. 구글 워크스페이스 API는 구 종류의 주체를 제공합니다: 사용자 계정과 서비스 계정. 더 자세한 사항은, 주체를 참고해 주십시오.

데이터 타입

인증과 인가적 관점에서 데이터 타입은 앱이 접근하고자 하는 데이터를 소유한 엔티티를 의미합니다. 데이터 타입에는 세 종류가 있습니다.

공공 도메인 데이터

구글 maps 데이터와 같이 누구라도 접근할 수 있는 데이터입니다. 이 종류의 데이터는 주로 API 키를 이용해 접근합니다.

최종 사용자 데이터(End-user data)

특정 사용자의 구글 드라이브 파일과 같이 특정 사용자 혹은 집단에 속한 데이터입니다. 이 종류의 데이터는 주로 OAuth 2 client ID 혹은 서비스 계정을 통해 접근합니다.

클라우드 데이터

구글 클라우드 프로젝트가 소유한 데이터입니다. 이 종류의 데이터는 주로 서비스 계정을 통해 접근합니다.

사용자 동의(User conset)

앱이 데이터에 접근하고 사용자를 대신해 작동을 수행할 때 앱에 권한을 부여하기 위해 사용자가 수행하는 인가 절차입니다.

애플리케이션 종류(Application type)

귀하가 생성하고자 하는 앱의 종류입니다. 구글 클라우드 콘솔을 통해 자격 증명을 생성할 때, 애플리케이션 종류를 선택할 수 있습니다. 애플리케이션 종류는: 웹 애플리케이션(JavaScript), 안드로이드, 크롬 앱, iOS, TVs와 Limited Input divices, 데스크탑 앱(“installed app”이라고도 불립니다), 그리고 UWP(Universal Widows Platform)이 있습니다.

서비스 계정

인증이 필요하거나 데이터에 접근하기 위한 인가가 필요한 사람이 아닌(non-human) 사용자를 대표할 수 있도록 의도된 특수한 형태의 구글 계정입니다. 애플리케이션은 구글 API를 호출해 서비스 계정의 식별자(ID)를 처리함으로 사용자가 직접적으로 관련되지 않습니다. 서비스 계정 그 자체로는 사용자 데이터에 접근할 수 없습니다. 데이터는 관례적으로 워크스페이스 API를 통해 접근 가능합니다. 그러나 서비스 계정은 domain-wide delegation of authority(권한에 대한 도메인-와이드 위임?)을 구현함으로써 사용자 데이터에 접근할 수 있습니다. 보다 자세한 사항은 서비스 계정 이해를 참조해 주십시오.

Domain-Wide delegation of authority

애플리케이션이 구글 워크스페이스 조직(organization) 내의 사용자를 대신하여 사용자 데이터에 접근할 수 있도록 허가할 수 있는 관리 기능입니다. Domain-wide delegation은 사용자 데이터의 관리 관련 업무를 수행하는데 이용될 수 있습니다. 이러한 방식으로 권한을 위임하기 위해서, 구글 워크스페이스 관리자는 OAuth 2.0을 사용해 서비스 계정을 사용합니다. 이 기능은 강력한 권한을 가지고 있기 때문에, domain-wide delegation of authority를 부여할 수 있는 권한은 최고 관리자에게로만 제한됩니다. 보다 자세한 사항은 서비스 계정으로의 Delegating domain-wide authority를 참조해 주십시오.

2-4. Configure the OAuth consent screen (OAuth 동의 화면 구성)

<이 장도 문서 양이 많아 원본 첨부 없이 진행합니다. 원본은 아래의 링크를 통해 확인할 수 있습니다.>

https://developers.google.com/workspace/guides/configure-oauth-consent

권한 부여를 위해 OAuth 2.0을 사용할 때, 구글은 귀하의 프로젝트에 대한 요약, 정책, 접근 범위에 대한 요청된 권한 등을 동의 화면에 사용자에게 출력합니다. 귀하의 앱의 OAuth 동의 화면을 구성하는 것은 사용자와 앱 리뷰어(reviewers)에게 출력될 화면을 구성하는 것입니다. 또한 추후에 앱을 출시하기 위해 등록하는 것을 의미합니다.

OAuth 2.0을 이용하는 모든 앱은 동의 화면 구성이 필요하지만 구글 워크스페이스 조직(organization) 외부의 사용자가 사용하는 앱의 범위만 나열하면 됩니다.

조언: 필수 동의 화면 정보에 관해 모르는 경우, 출시 이전 placeholder information을 이용할 수도 있습니다.

OAuth 동의 구성 & 앱 등록하기

구글 클라우드 콘솔을 여십시오. 왼쪽 상단, 메뉴 > APIs & Services > OAuth consent screen을 클릭하십시오. 앱의 종류를 선택한 후, create를 클릭하십시오. 앱 등록 형식을 완성한 후, save and continue을 클릭하십시오. 만약 구글 워크스페이스 조직 외부에서 사용할 앱을 만드는 경우, Add or Remove Scopes를 클릭하십시오. 귀하의 앱에 필요한 권한 범위를 추가 및 확인한 후 Save and Continue를 클릭하십시오. 참고: 일부 범위는 구글의 추가 검토가 필요합니다. 구글 워크스페이스 조직 내부적으로만 사용하는 앱의 경우 범위가 동의 화면에 나열되지 않으며 제한되거나 민감한 범위를 사용하더라도 구글의 검토가 필요하지 않습니다. For apps used only internally by your Google Workspace organization, scopes aren’t listed on the consent screen and use of restricted or sensitive scopes does not require further review by Google. 자세한 사항은 아래에 기술한 ‘앱에 부여할 범위 선택하기’를 살펴보시기 바랍니다. “테스트 사용자” 아래, Add users를 클릭하십시오. 귀하의 이메일과 인증이 필요한 다른 테스트 사용자를 입력한 후 Save and Continue를 클릭하십시오. 귀하의 앱 등록 요약을 검토하십시오. 수정하고 싶으면 Edit을, 그렇지 않다면 Back to Dashboard를 클릭하십시오.

앱에 부여할 범위 선택하기

귀하의 앱에 부여할 접근 수준을 설정하기 위해 권한 범위를 명시하고 확인할 필요가 있습니다. 권한 범위는 구글 워크스페이스 앱 이름, 접근 가능한 데이터 종류, 접근 수준을 포함한 OAuth 2.0 URI 문자열입니다.

예를 들어, 아래의 범위는 구글 캘린더 설정을 볼 수 있는 접근 권한을 부여하지만 수정은 할 수 없습니다.

https://www.googleapis.com/auth/calendar.settings.readonly

가능한 범위에 관한 정보는 구글 API를 위한 OAuth 2.0 범위를 참고해 주십시오.

범위 범주

일부 범위는 부여된 접근 수준 혹은 유형으로 인해 추가 검토 및 요구 사항이 필요합니다. 다음은 고려해야 할 범위 유형입니다.

출처 :&amp;nbsp;https://developers.google.com/workspace/guides/configure-oauth-consent

앱에 필요한 범위 선택

개발을 시작하기 전, 사용할 범위를 식별하는 것이 좋습니다. 이렇게 하면 구글 클라우드 콘솔에서 앱 구성 속도가 빨라지고 추가 보안 검토를 준비하는 데 도움이 됩니다.

앱의 승인 범위를 선택하려면:

위 단계에서 OAuth 동의 화면을 구성하는 동안 Add or remove scopes를 클릭하십시오. GCP 프로젝트에서 사용 설정한 각 API의 범위 목록이 포함된 패널이 나타납니다. 앱에 필요한 최소 접근 수준을 제공하는 범위를 선택한 다음 update를 클릭하십시오. 민감하지 않은 범위, 민감한 범위 및 제한된 범위의 세 섹션 각각에 나열된 범위를 컴토합니다. “귀하의 민감한 범위” 또는 “제한된 범위” 섹션에 나열된 범위의 경우 불필요한 추가 검토를 피하기 위해 민감하지 않은 대체 범위를 식별하십시오. 범위 목록이 완료되면 Save and continue를 클릭하십시오.

2-4. Create access credentials (접근 자격 증명 생성)

<이하 필요하다고 판단되는 부분만 번역>

자격 증명은 앱이 구글 워크스페이스 API를 호출할 수 있도록 구글 인가 서버에서 생성하는 토근을 획득하는데 사용됩니다.

(자격 증명의 종류는 API 키, OAuth client ID, 서비스 계정이 있다.)

API 키 자격 증명

API는 대문자와 소문자, 숫자, 대시를 포함한 문자열. ex) a4db08b7-5729-4ba9-8c08-f2df493465a1

API 키를 이용한 자격 증명은 “이 링크가 있는 모든 인터넷 사용자”와 같이 공개적으로 사용 가능한 데이터에 익명으로 접근하는데 사용됨.

키를 생성하기 위해:

구글 클라우드 콘솔을 연다. 왼쪽 상단 메뉴 > APIs & Services > Credentials를 클릭한다. Create credentials > API Key를 누른다. 새로운 API 키가 출력될 것이다. (API 키는 프로젝트 자격 증명 섹션의 “API Keys”에서도 확인 가능) 추가적인 설정이 필요하거나 API 키에 더 많은 제한을 두고 싶은 경우 Restrict key를 누른다.

OAuth 클라이언트 ID 자격 증명

최종 사용자로 인증하고 앱의 사용자 데이터에 접근하려면 하나 이상의 OAuth 2.0 클라이언트 ID가 필요하다.

클라이언트 ID는 구글의 OAuth 서버에서 단일 앱을 식별하는데 사용됨. 앱이 여러 플랙폼에서 실행되는 경우 각 플랫폼에 대해 별도의 클라이언트 ID를 만들어야 함.

앱 종류가 다양하기 때문에 각 종류에 따라 OAuth 클라이언트 ID를 만드는 방법이 다른 것 같다. 그 중 나는 웹 애플리케이션을 만들 예정이므로 웹 애플리케이션 파트만 보도록 하겠다.

구글 클라우드 콘솔을 연다. 왼쪽 상단, 메뉴 > APIs & Services > Credentials 클릭 Create Credentials > OAuth client ID 클릭 Application type > Web application 클릭 “Name” 영역에 자격 증명 이름을 입력. 이 이름은 클라우드 콘솔에만 보여짐. 앱과 관련된 승인된 URI를 추가 클라이언트 측 앱(Javascript) – 승인된 Javascript 원본에서 Add URI 를 클릭. 이후 브라우저 요청에 사용될 URI를 입력. 이것은 애플리케이션이 OAuth 2.0 서버에 API 요청을 보낼 수 있는 도메인을 식별.

– 승인된 Javascript 원본에서 를 클릭. 이후 브라우저 요청에 사용될 URI를 입력. 이것은 애플리케이션이 OAuth 2.0 서버에 API 요청을 보낼 수 있는 도메인을 식별. 서버 측 앱(Java, Python, .NET 등) – “승인된 리다이렉션 URI”에서 Add URI를 클릭. 그 후 OAuth 2.0 서버가 응답할 수 있는 endpoint URI를 입력. Create 클릭. OAuth 클라이언트 생성 화면이 나타나고 새 클라이언트 ID와 클라이언트 암호가 표시됨. 클라이언트 ID를 적어둬야 함. 암호는 웹 애플리케이션에서는 사용되지 않음. OK를 클릭. 새로 생성된 자격 증명이 “OAuth 2.0 Client IDs” 밑에 표시됨.

서비스 계정 자격 증명 생성

구글 클라우드 콘솔을 연다. 왼쪽 상단 메뉴 > IAM & Admin > Service Accounts 클릭 Create service account 클릭 세부 사항을 작성한 후 Create and continue를 클릭 (ID는 구글이 만들어준다. ID를 바꾸고 싶으면 서비스 계정 ID 영역에서 ID를 수정할 수 있다!) 선택사항 : 리소스에 대한 역할 권한 부여 Continue 클릭 선택사항 : 서비스 계정을 관리할 수 있는 사용자나 조직을 입력. Done 클릭

서비스 계정에 자격 증명 부여하기

public / private 키를 쌍으로 한 형태로 자격 증명을 얻어야 한다. 이 자격 증명은 서비스 계정에 행동 권한을 부여하기 위해 앱 내의 코드에서 사용됨.

구글 클라우드 콘솔을 연다. 왼쪽 상단, 메뉴 > IAM & Admin > Service Accounts를 클릭한다. 서비스 계정을 선택한다. Keys > Add keys > Create new key를 누른다. JSON을 선택하고 Create를 누른다. 새로운 public / private 키 쌍이 시스템 내에 새 파일로 다운로드됨. 이 파일은 이 키의 유일한 복사본. 키를 안전하게 저장하는 방법은 서비스 계정 키 관리 참조. Close 클릭

선택사항: 서비스 계정에 domain-wide delegation 설정하기

일단 패스

3. 구글 캘린더 빠른 시작하기

빠른 시작은 Google Workspace API를 호출하는 간단한 앱을 구성하고 실행하는 방법을 설명하는 문서입니다.

빠른 시작은 인증 및 권한 부여 흐름의 일부 세부 정보를 숨기는 API 클라이언트 라이브러리를 사용합니다. 자신의 앱에 클라이언트 라이브러리를 사용하는 것이 좋습니다.

전제 조건으로 빠른 시작에서는 인증 및 권한 부여를 활성화해야 합니다. Workspace API에 대한 인증 및 권한 부여에 대해 잘 모르는 경우 인증 및 권한 부여 개요를 읽으십시오 .

선호하는 프로그래밍 언어에 해당하는 빠른 시작을 클릭합니다. (각 언어에 대한 빠른 시작이 다 다르기 때문에 언어를 선택할 수 있는 페이지를 링크하고 글을 마무리 하도록 하겠다.)

https://developers.google.com/calendar/api/quickstart/quickstarts-overview

구글 캘린더 API

const https = require ( ‘ https ‘ ); const util = require ( ‘ util ‘ ); exports . handler = ( event , context , callback ) => { var todayDate = new Date (); // var yesterdayDate = new Date(todayDate.getTime() – 1000*60*60*24); // var tomorrowDate = new Date(todayDate.getTime() + 1000*60*60*24); // var twoDayAgoDate = new Date(todayDate.getTime() + 1000*60*60*24*2); var calendarID = “” ; var googleKey = “” ; requestAPI ({ ” method ” : ” GET ” , ” port ” : 443 , ” hostname ” : ” www.googleapis.com ” , ” path ” : `/calendar/v3/calendars/ ${ calendarID } /events?orderBy=startTime&singleEvents=true&timeMax= ${ maxRFC3339 ( todayDate )} &timeMin= ${ minRFC3339 ( todayDate )} &key= ${ googleKey } ` , ” content ” : “” , }, function ( data ) { var data = JSON . parse ( data ); console . log ( data ); }, function ( e ) { console . log ( e ); }); const response = { statusCode : 200 , headers : { ” Access-Control-Allow-Origin ” : ” * ” }, body : ” Success ” }; callback ( null , response ); }; // 통신 API function requestAPI ( request , callback , errorCallback ) { const options = { method : ( request [ ” method ” ] || ” GET ” ), hostname : ( request [ ” hostname ” ] || “” ), port : ( request [ ” port ” ] || 443 ), headers : ( request [ ” headers ” ] || { ” Content-Type ” : ” application/json ” }), path : ( request [ ” path ” ] || “” ) }; const req = https . request ( options , ( res ) => { res . setEncoding ( ‘ utf8 ‘ ); var body = ” ; res . on ( ‘ data ‘ , ( chunk ) => { body = body + chunk ; }); res . on ( ‘ end ‘ , function () { if ( res . statusCode == 200 || res . statusCode == ‘ 200 ‘ ) { callback ( body ); } else { errorCallback ( `statusCode Error: ${ res . statusCode } ` ); } }); }); req . on ( ‘ error ‘ , function ( e ) { errorCallback ( e . responseText ) }); req . write ( util . format ( ” %j ” , ( request [ ” content ” ] || “” ))); req . end (); } // 시간 function minRFC3339 ( date ) { var year = date . getFullYear (); var month = ( date . getMonth () + 1 < 10 ) ? `0 ${ date . getMonth () + 1 } ` : ` ${ date . getMonth () + 1 } ` ; var day = ( date . getDate () < 10 ) ? `0 ${ date . getDate ()} ` : ` ${ date . getDate ()} ` ; return ` ${ year } - ${ month } - ${ day } T00:00:00Z` ; } // 시간 function maxRFC3339 ( date ) { var year = date . getFullYear (); var month = ( date . getMonth () + 1 < 10 ) ? `0 ${ date . getMonth () + 1 } ` : ` ${ date . getMonth () + 1 } ` ; var day = ( date . getDate () < 10 ) ? `0 ${ date . getDate ()} ` : ` ${ date . getDate ()} ` ; return ` ${ year } - ${ month } - ${ day } T23:59:59Z` ; }

캘린더 (2. 개념 : 함수/데이터 편)

반응형

앞서 구글 캘린더 API가 제공하는 자원들을 살펴보았습니다.

참고 : [오늘 배워 오늘 쓰는 OpenAPI] – 구글 API_캘린더 (1. 개념 : 자원편)

이번 글에서는 일정 자원을 사용하는

– 함수(Insert, List, Update, Delete)와 조건을 주는 파라미터(calendarId, timeMin 등)

그리고 자원을 표현하는

– 데이터 형식({“summary” : “캘린더 제목”} 등)

을 알아보겠습니다.

* 파라미터와 데이터 형식의 차이(예 : 특정 캘린더의 일정을 조회할 때)

용어 예 파라미터 어떤 캘린더에 있는 일정을 조회할 것인지( calendarId ), 그 캘 린더의 일정을 몇 개 까지 가져올 것인지( maxResults ), 일정을 언제부터 언제까지 조회할 것인지( timeMin , timeMax ) 등 데이터 형식 요청한 캘린더의 제목({” summary” : “캘린더 제목”} ), 요청한 캘린더의 상세 설명({” description” : “캘린더 설명”} ), 요청한 캘린더에 등록된 일정들({“items”: …}) 등

** 이번 글에서는 일정(Event)을 중심으로 생성(Insert), 조회(List), 수정(Update), 삭제(Delete)하는 것에 대해서 다룰 것입니다. 다른 자원들에 관한 내용은 공식 문서를 참고하세요.

<< 목표 >>

일정 생성하기 – Insert 함수, 파라미터, 데이터 형식

일정 조회하기 – List 함수, 파라미터, 데이터 형식

일정 수정하기 – Update 함수, 파라미터, 데이터 형식

일정 삭제하기 – Delete 함수, 파라미터, 데이터 형식

<< 사전 준비 >>

OAuth 2.0 클라이언트 ID 인증 파일 – [오늘 배워 오늘 쓰는 OpenAPI] – (완료) 카카오 API 사용하기 – 준비 사항

언어 & 환경(IDE) : Python3.6 & Jupter notebook

<< 순서 >>

Step 1 구글 API 인증(Python) Step 2 일정 생성(Insert) Step 3 일정 조회(List) Step 4 일정 수정(Update) Step 5 일정 삭제(Delete)

Step 1) 구글 API 인증(Python)

구글은 API들을 쉽게 사용할 수 있도록 Python 라이브러리를 제공하고 있습니다.

Python 라이브러리 설치

pip install –upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

인증

from google_auth_oauthlib.flow import InstalledAppFlow # 구글 클라우드 콘솔에서 다운받은 OAuth 2.0 클라이언트 파일경로 creds_filename = ‘credentials.json’ # 사용 권한 지정 # https://www.googleapis.com/auth/calendar 캘린더 읽기/쓰기 권한 # https://www.googleapis.com/auth/calendar.readonly 캘린더 읽기 권한 SCOPES = [‘https://www.googleapis.com/auth/calendar’] # 파일에 담긴 인증 정보로 구글 서버에 인증하기 # 새 창이 열리면서 구글 로그인 및 정보 제공 동의 후 최종 인증이 완료됩니다. flow = InstalledAppFlow.from_client_secrets_file(creds_filename, SCOPES) creds = flow.run_local_server(port=0)

OAuth 클라이언트 ID JSON 파일 경로를 지정해주고 코드를 실행하면, 새 창으로 연결되어 로그인과 정보 제공 동의를 요구합니다.

해당 과정을 완료하면 마지막으로 창을 닫아도 된다는 메시지가 나옵니다. 그러면, 인증 완료!!

서비스 객체 생성

import datetime # 구글 캘린더 API 서비스 객체 생성 from googleapiclient.discovery import build today = datetime.date.today().isoformat() service = build(‘calendar’, ‘v3’, credentials=creds)

Step1) 일정 생성(Insert)

참고 : https://developers.google.com/calendar/v3/reference/events/insert

Step 1-1) Python 예제

event = { ‘summary’: ‘itsplay의 OpenAPI 수업’, # 일정 제목 ‘location’: ‘서울특별시 성북구 정릉동 정릉로 77’, # 일정 장소 ‘description’: ‘itsplay와 OpenAPI 수업에 대한 설명입니다.’, # 일정 설명 ‘start’: { # 시작 날짜 ‘dateTime’: today + ‘T09:00:00’, ‘timeZone’: ‘Asia/Seoul’, }, ‘end’: { # 종료 날짜 ‘dateTime’: today + ‘T10:00:00’, ‘timeZone’: ‘Asia/Seoul’, }, ‘recurrence’: [ # 반복 지정 ‘RRULE:FREQ=DAILY;COUNT=2’ # 일단위; 총 2번 반복 ], ‘attendees’: [ # 참석자 {’email’: ‘[email protected]’}, {’email’: ‘[email protected]’}, ], ‘reminders’: { # 알림 설정 ‘useDefault’: False, ‘overrides’: [ {‘method’: ’email’, ‘minutes’: 24 * 60}, # 24 * 60분 = 하루 전 알림 {‘method’: ‘popup’, ‘minutes’: 10}, # 10분 전 알림 ], }, } # calendarId : 캘린더 ID. primary이 기본 값입니다. event = service.events().insert(calendarId=’primary’, body=event).execute() print(‘Event created: %s’ % (event.get(‘htmlLink’)))

예제에서는 “itsplay의 OpenAPI 수업” 이라는 제목과 장소, 설명, 날짜, 반복여부, 알림 등의 정보를 담은 데이터 형식을 가지고 일정을 생성합니다.

파라미터로 calendarId를 ‘primary’로 준 것은 기본 캘린더를 사용하겠다는 뜻입니다. 실행에 문제가 발생하지 않았다면 생성된 일정의 정보를 담은 결과가 반환이 되며, 생성된 일정의 상세 페이지로 이동할 수 있는 링크인 htmlLink를 출력해주고 있습니다.

Step 1-2) 파라미터

Insert 함수를 사용할 때, 주요 파라미터는 다음과 같습니다.

이름 설명 필수 파라미터 calendarId 일정을 생성할 캘린더 ID. 기본 값은 ‘primary’. 선택 파라미터 maxAttendees 응답에 가져올 참석자의 명수 sendUpdates 새 일정을 생성할 때, 알림에 대한 설정 – all : 모든 참석자에게 알림이 보내집니다. – externalOnly : 구글 캘린더를 사용하지 않는 참석자에게만 알림이 보내집니다. – none : 알림을 사용하지 않습니다.

나머지 파라미터 보기

* 캘린더 ID를 확인하려면 [더보기]를 눌러주세요.

더보기 1. 우측 상단 [설정] 클릭 2. 좌측에서 원하는 캘린더를 선택 후, [캘린더 통합]으로 이동 > [캘린더 ID] 우측에 표시됨을 확인

Step 2-2) 생성 요청(request) 시 사용되는 데이터 형식

위 코드에서 event에 담긴 JSON 형식의 데이터처럼 일정을 생성할 때 사용하는 주요 데이터를 자세히 살펴보겠습니다.

속성 이름 데이터 타입 설명 쓰기여부 필수 속성들 start nested object 해당 일정의 시작 시간입니다. (x >= start time) end nested object 해당 일정의 종료 시간입니다. (x < end time) 선택 속성들 summary string 일정의 제목을 뜻합니다. writable location string 위치 정보를 나타냅니다. writable description string 일정의 설명입니다 . HTML을 포함할 수 있습니다. 선택사항 writable start.dateTime datetime 종일 일정이 아닌 특정 날짜와 시간 값(datetime)을 가진 시작 시간을 말합니다. writable start.timeZone string 시작 시간의 시간대를 뜻합니다. writable end.dateTime datetime 종일 일정이 아닌 특정 날짜와 시간 값(datetime)을 가진 종료 시간을 말합니다. writable end .timeZone string 종료 시간의 시간대를 뜻합니다. writable recurrence[] list 일정을 반복할 때 사용하는 규칙입니다. 본 글에서는 RRULE를 사용할 것이며, RFC5545에 정의된 규칙을 따라서 정의하면 됩니다. writable attendees[] list 일정 참석자입니다. writable attendees[].email string 일정 참석자의 이메일 주소입니다. writable reminders object 인증된 사용자를 위한 일정의 알림에 대한 정보입니다. reminders.useDefault boolean 해당 일정을 소유한 캘린더에 적용된 기본 알림을 사용할지의 여부입니다. writable reminders.overrides[] list 해당 일정이 기본 알림을 사용하지 않는다면, 이 속성은 해당 일정에 할당된 알림 들을 나열합니다. writable reminders.overrides[].method string 알림을 위해 사용되는 방식을 정의합니다. 이메일, SMS, Popup 알림이 있습니다. writable reminders.overrides[].minutes integer 해당 일정의 알림이 몇 분 전에 울릴지 설정합니다. 0 ~ 40320 사이로 입력합니다. writable Step 2-3) 생성 응답(response) 시 사용되는 데이터 형식 생성(Insert) 요청을 통해 작업이 성공적으로 수행하게 되면 일정 결과 값을 받게 됩니다. 위의 Python 예제를 통해 받게 된 결과 값을 중심으로 각 속성들을 살펴보겠습니다. { "kind": "calendar#event", "etag": "3163187849198222", "id": "fraof7dh0g0ene8kdcfl3h2222", "status": "confirmed", "htmlLink": "https://www.google.com/calendar/event?eid=ZnJhb2Y3ZGgwZzBlbmU4a2RjZmwzaGc0cDRfMjAyMDAyMTNUMDAwMDAwWiBpYW1leGFtcGxl2222", "created": "2020-02-13T11:38:44.000Z", "updated": "2020-02-13T11:38:44.679Z", "summary": "itsplay의 OpenAPI 수업", "description": "itsplay와 OpenAPI 수업에 대한 설명입니다.", "location": "서울특별시 성북구 정릉동 정릉로 77", "creator": { "email": "[email protected]", "self": True }, "organizer": { "email": "[email protected]", "self": True }, "start": { "dateTime": "2020-02-13T09:00:00+09:00", "timeZone": "Asia/Seoul" }, "end": { "dateTime": "2020-02-13T10:00:00+09:00", "timeZone": "Asia/Seoul" }, "recurrence": [ "RRULE:FREQ=DAILY;COUNT=2" ], "iCalUID": "[email protected]", "sequence": 0, "attendees": [ { "email": "[email protected]", "responseStatus": "needsAction" }, { "email": "[email protected]", "responseStatus": "needsAction" } ], "reminders": { "useDefault": False, "overrides": [ { "method": "popup", "minutes": 10 }, { "method": "email", "minutes": 1440 } ] } } 속성 이름 데이터 타입 설명 쓰기여부 kind string 자원의 유형을 뜻합니다. ("calendar#event") etag etag Etag 값. 해당 컨텐츠가 변경됬는지를 판별할 수 있는 값입니다. id string 각 캘린더마다 일정을 구분할 수 있는 식별자입니다. writable status string 해당 일정의 상태입니다. 선택사항. - "confirmed" : 일정이 확정됨. 기본값 - "tentative" : 일정이 잠정적으로 확정됨. - "cancelled" : 일정이 취소됨(삭제됨) writable htmlLink string 읽기 전용의 구글 캘린더 웹 UI 상 일정에 대한 주소. created datetime 일정이 생성된 시각입니다. updated datetime 마지막으로 수정된 시각입니다. summary string 일정의 제목을 뜻합니다. writable description string 일정의 설명입니다 . HTML을 포함할 수 있습니다. 선택사항 writable location string 위치 정보를 나타냅니다. writable creator object 일정을 생성한 사용자입니다. 읽기 전용 writable creator.email string 일정을 생성한 사용자의 이메일 주소입니다. writable creator.self boolean 일정을 생성한 사용자가 본인인지의 여부입니다. organizer object 일정의 주최자입니다. (생성자와 일정을 주최하는 자는 다를 수 있습니다.) writable organizer.email string 일정의 주최자 의 이메일 주소입니다. writable organizer.self boolean 일정의 주최자가 본인인지의 여부입니다. start nested object 해당 일정의 시작 시간입니다. (x >= start time) start.date date 종일 일정일 경우 “yyyy-mm-dd” 형식을 지닌 시작 날짜입니다. writable start.dateTime datetime 종일 일정이 아닌 특정 날짜와 시간 값(datetime)을 가진 시작 시간을 말합니다. writable start.timeZone string 시작 시간의 시간대를 뜻합니다. writable end nested object 해당 일정의 종료 시간입니다. (x < end time) end.date date 종일 일정일 경우 "yyyy-mm-dd" 형식을 지닌 종료 날짜입니다. writable end.dateTime datetime 종일 일정이 아닌 특정 날짜와 시간 값(datetime)을 가진 종료 시간을 말합니다. writable end.timeZone string 종료 시간의 시간대를 뜻합니다. writable recurrence[] list 일정을 반복할 때 사용하는 규칙입니다. 본 글에서는 RRULE를 사용할 것이며, RFC5545에 정의된 규칙을 따라서 정의하면 됩니다. writable iCalUID string RFC5545 에 정의된 일정의 고유 식별자입니다. 일정 관리 시스템에서 사용될 수 있습니다. id와는 중복해서 쓸 수 없으며 두 속성의 차이 점은 반복 일정을 생성한 경우 모든 일정은 id값이 다르지만 icalUID 값은 동일합니다. sequence integer iCalendar(일정 관리 프로그램들 사이에서 통용되는 스펙)에 따른 순서 번호 입니다. writable attendees[] list 일정 참석자입니다. writable attendees[] .email string 일정 참석자의 이메일 주소입니다. writable attendees[].responseStatus string 참석자의 응답 상태입니다. - "needsAction" : 참석자가 초대에 응하지 않은 상태 - "declined" : 참석자가 초대를 거절한 상태 - "tentative" : 참석자가 잠정적으로 초대를 승낙한 상태 - "accepted" : 참석자가 초대를 승낙한 상태 writable reminders object 인증된 사용자를 위한 일정의 알림에 대한 정보입니다. reminders.useDefault boolean 해당 일정을 소유한 캘린더에 적용된 기본 알림을 사용할지의 여부입니다. writable reminders.overrides[] list 해당 일정이 기본 알림을 사용하지 않는다면, 이 속성은 해당 일정에 할당된 알림 들을 나열합니다. writable reminders.overrides[].method string 알림을 위해 사용되는 방식을 정의합니다. 이메일, SMS, Popup 알림이 있습니다. writable reminders.overrides[].minutes integer 해당 일정의 알림이 몇 분 전에 울릴지 설정합니다. 0 ~ 40320 사이로 입력합니다. writable recurringEventId string 반복 일정의 모든 일정들이 속한 인스턴스 ID 값입니다. Step 3) 일정 조회(List) 참고 : https://developers.google.com/calendar/v3/reference/events/list Step 3-1) Python 예제 코드 import datetime calendar_id = 'primary' today = datetime.date.today().isoformat() time_min = today + 'T00:00:00+09:00' time_max = today + 'T23:59:59+09:00' max_results = 5 is_single_events = True orderby = 'startTime' events_result = service.events().list(calendarId = calendar_id, timeMin = time_min, timeMax = time_max, maxResults = max_results, singleEvents = is_single_events, orderBy = orderby ).execute() Step 3-2) 파라미터 이름 설명 필수 파라미터 calendarId 일정을 생성할 캘린더 ID. 기본 값은 'primary'. 선택 파라미터 timeMin 결과로 요청할 날짜 시작 범위. timeMax 결과로 요청할 날짜 종료 범위. maxResults 한 번의 결과에 가져올 최대 일정 수. 기본 값 250 singleEvents 반복 일정을 묶은 하나의 객체로 가져올 것인지 아니면, 각 일정을 단일로 가져올 지 여부. 기본 값 False (단일로 가져옴) orderBy 결과로 반환된 일정들의 순서 정렬. - startTime : 시작 날짜/시간으로 정렬(단일 일정만 해당) - updated : 최근 수정된 날짜로 정렬(오름차순) 나머지 파라미터 보기 Step 3-3) 조회 요청(request) 시 사용되는 데이터 형식 일정의 조회 요청 시에는 사용되지 않습니다. Step 3-4) 응답(response) 시 사용되는 데이터 형식 일정들을 조회하게 되면, 일정들의 모음(collection)인 해당 캘린더의 정보가 반환됩니다. 그 정보들 중에서 "items" 속성 값으로 일정들이 반환됩니다. event_result.get('items') Property name Value Description Notes kind string 모음(collection)의 유형을 뜻합니다. ("calendar#events"). summary string 캘린더의 제목입니다. 읽기 전용 값입니다. description string 캘린더의 설명입니다. timeZone string 캘린더의 시간대입니다. accessRole string 해당 캘린더의 사용자 접근 권한입니다. 읽기 전용 값입니다. - "none" : 사용자는 접근할 수 없습니다. - "freeBusyReader" - 사용자는 약속 있음/없음 정보만 조회할 수 있습니다. - "reader" : 사용자는 캘린더 조회 권한을 가집니다. 비공개 일정에 대한 상세 내용은 숨겨집니다. - "writer" : 사용자는 읽기 쓰기 권한을 가집니다. 비공개 일정에 대한 상세 내용이 표출됩니다. - "owner" : 사용자는 캘린더의 소유 권한(모든 권한)을 가집니다. defaultReminders[] list 인증된 사용자의 캘린더에 설정된 기본 알림입니다. 이 알림들은 override 속성을 부여하지 않은 모든 일정들에 적용됩니다. defaultReminders[].method string 캘린더에서 알림을 위해 사용되는 기본 방식을 정의합니다. 이메일, SMS, Popup 알림이 있습니다. writable defaultReminders[].minutes integer 해당 캘린더의 일정의 알림이 몇 분 전에 울릴지 기본 값을 설정합니다. 0 ~ 40320 사이로 입력합니다. writable nextPageToken string 결과를 페이징 할 때 사용되는 토큰 값입니다. items[] list 캘린더의 모든 일정들의 목록입니다 . Step 4) 일정 수정(Update) 참고 : https://developers.google.com/calendar/v3/reference/events/update Step 4-1) Python 예제 # eventId : 일정을 조회한 후 얻은 id 값을 말합니다. # 먼저 수정할 일정을 가져옵니다. # 방법 1 : get 함수를 통해서 가져오기 # eventId = 'fraof7dh0g0ene8kdcfl3hg4p4_20200213T000000Z' # event = service.events().get(calendarId='primary', eventId=eventId).execute() # 방법 2 : list 함수에서 반환된 일정 사용하기 event = events_result.get('items')[0] event_id = event.get('id') # 원하는 일정의 속성 값을 변경합니다. event['summary'] = "(수정된)" + event['summary'] # 일정 수정 요청하기 updated_event = service.events().update(calendarId='primary', eventId=event_id, body=event).execute() updated_event # 제목이 "(수정된)itsplay의 OpenAPI 수업"로 바뀌었습니다. Step 4-2) 파라미터 이름 설명 필수 파라미터 calendarId 일정을 생성할 캘린더 ID. 기본 값은 'primary'. eventId 일정의 고유한 ID 값. 선택 파라미터 sendUpdates 새 일정을 생성할 때, 알림에 대한 설정 - all : 모든 참석자에게 알림이 보내집니다. - externalOnly : 구글 캘린더를 사용하지 않는 참석자에게만 알림이 보내집니다. - none : 알림을 사용하지 않습니다. Step 4-3) 요청(request) 시 사용되는 데이터 Step 2. 일정 생성(Insert)에서 사용된 데이터 형식과 동일합니다. Step 4-4) 응답(response) 시 사용되는 데이터 Step 2. 일정 생성(Insert)에서 사용된 파라미터와 동일합니다. 위 Python 예제의 결과로 나온 값을 보시면 "updated"와 "summary" 값이 바뀐 것을 확인할 수 있습니다. { "kind": "calendar#event", "etag": "3163191126892222", "id": "fraof7dh0g0ene8kdcfl3hg4p4_20200213T0002222", "status": "confirmed", "htmlLink": "https://www.google.com/calendar/event?eid=ZnJhb2Y3ZGgwZzBlbm2222RjZmwzaGc0cDRfMjAyMDAyMTNUMDAwMDAwWiBpYW1leGFtcGxlMkBt", "created": "2020-02-13T11:38:44.000Z", "updated": "2020-02-13T12:06:03.526Z", "summary": "(수정된)itsplay의 OpenAPI 수업", "description": "itsplay와 OpenAPI 수업에 대한 설명입니다.", "location": "서울특별시 성북구 정릉동 정릉로 77", "creator": { "email": "[email protected]", "self": True }, "organizer": { "email": "[email protected]", "self": True }, "start": { "dateTime": "2020-02-13T09:00:00+09:00", "timeZone": "Asia/Seoul" }, "end": { "dateTime": "2020-02-13T10:00:00+09:00", "timeZone": "Asia/Seoul" }, "recurringEventId": "fraof7dh0g0ene8kdcfl3hg4p4", "originalStartTime": { "dateTime": "2020-02-13T09:00:00+09:00", "timeZone": "Asia/Seoul" }, "iCalUID": "[email protected]", "sequence": 0, "attendees": [ { "email": "[email protected]", "responseStatus": "needsAction" }, { "email": "[email protected]", "responseStatus": "needsAction" } ], "reminders": { "useDefault": False, "overrides": [ { "method": "email", "minutes": 1440 }, { "method": "popup", "minutes": 10 } ] } } Step 5) 일정 삭제(Delete) Step 5-1) Python 예제 # 위에서 수정된 일정 updated_event # eventId : 일정을 조회한 후 얻은 id 값을 말합니다. eventId = updated_event.get('id') service.events().delete(calendarId='primary', eventId=eventId).execute() Step 5-2) 파라미터 Step 4. 일정 수정(Update)에서 사용된 파라미터와 동일합니다. Step 5-3) 요청(request) 시 사용되는 데이터 요청에 사용되는 속성은 없습니다. Step 5-4) 응답(response) 시 사용되는 데이터 삭제 요청이 성공적으로 처리되었다면 값을 반환하지 않습니다. 이것으로 일정을 다루는 4가지의 기본 함수에 대해서 모두 살펴보았습니다. << trouble shooting >>

# 아래 함수 수행시 에러 발생시

events_result = service.events().list(calendarId = calendar_id,

timeMin = time_min,

timeMax = time_max,

maxResults = max_results,

singleEvents = is_single_events,

orderBy = orderby).execute()

에러에 주어진 링크를 클릭하여, api 활성화를 시켜준다.

저작물의 저작권은 작성자에게 있습니다.

공유는 자유롭게 하시되 댓글 남겨주세요~

상업적 용도로는 무단 사용을 금지합니다.

끝까지 읽어주셔서 감사합니다^^

반응형

[Python] 구글 Open API로 캘린더 활용해보기

📆 구글 Open API로 구글 캘린더에 있는 내용을 확인해보기

현재 우리 팀에서는 구글 캘린더로 다음 이미지 처럼 휴가를 사용했을 경우 공유하고 있다.

또한, 작업 후 Pull Request하여 코드 리뷰를 하고 있다.

그래서 이 코드 리뷰를 할 리뷰어들을 2명씩 지정하는 스크립트를 간단히 만들어서 사용중이다.

🔖 리뷰어 지정 스크립트

import sys import random project_list = [ “1” , “2” , “3” ] all_name_list = [ “리뷰어1” , “리뷰어2” , “리뷰어3” , “리뷰어4” , “리뷰어5” , “리뷰어6” , “리뷰어7” ] input_project = input ( “”” Pr프로젝트 입력하세요 : – 프로젝트 1 : 1 – 프로젝트 2 : 2 – 프로젝트 3 : 3 “”” ) if input_project not in project_list : sys . exit ( “잘못된 프로젝트 입력 입니다.” ) input_name = input ( f””” 이름을 입력하세요 : – 이름 리스트 : “리뷰어1”, “리뷰어2”, “리뷰어3”, “리뷰어4”, “리뷰어5”, “리뷰어6”, “리뷰어7” “”” ) if input_name not in all_name_list : sys . exit ( “잘못된 이름 입력 입니다.” ) first_approve_list = [ ] second_approve_list = [ ] if input_project == “1” : first_approve_list = [ “리뷰어1” , “리뷰어2” , “리뷰어3” ] elif input_project == “2” : first_approve_list = [ “리뷰어1” , “리뷰어4” ] else : first_approve_list = [ “리뷰어1” , “리뷰어3” ] second_approve_list = list ( set ( all_name_list ) – set ( first_approve_list ) ) try : first_approve_list . remove ( input_name ) except ValueError : pass try : second_approve_list . remove ( input_name ) except ValueError : pass print ( “첫번째 승인자 : {}” . format ( random . choice ( first_approve_list ) ) ) print ( “두번째 승인자 : {}” . format ( random . choice ( second_approve_list ) ) )

어느 프로젝트를 리뷰받을것인지 정하고 해당 프로젝트에는 고정적으로 리뷰되는 사람들이 first_approve_list 에 지정되어있는 상황이다.

여기에 본인 + 고정리뷰어 제외하고 나머지 사람들 중 랜덤으로 지정하여 총 2명의 리뷰어를 뽑게된다.

하지만 현재는 누군가 휴가일 때 해당 인원을 제외하는 로직이 없다.

그래서 구글캘린더에 있는 정보를 이용하여 당일 휴가인 사람들을 제외하고 리뷰어들을 지정하게끔 만들어본다.

🍥 구글 API 연동하기

구글 클라우드 콘솔에서 API 키 생성하기

구글 클라우드 콘솔

해당 콘솔에서 라이브러리에 들어간다.

라이브러리에서 Calendar를 검색해준다.

Google Calendar API 를 선택해서 사용설정을 해준다.

사용자 인증 정보 탭에 들어가서 API키를 얻는다.

API 키가 생성완료되었고, 해당 키로 캘린더API만 사용가능하게 제한 사항등을 추가하는 것도 가능하다.

OAuth 클라이언트 ID로 들어가서 클라이언트 ID도 생성한다.

이미지 맨 오른쪽에서 해당 파일을 json형식으로 다운로드 받을 수 있다.

OAuth 동의 화면 또한 절차에 따라서 생성해준다. 캘린더 ID는 캘린더의 설정 및 공유에 들어가서 얻을 수 있다.

🗓 구글 캘린더 API 요청하기

위 사이트에서 구글 캘린더 API에 접근하는 쉽고 빠른 방법이 자세히 설명되어있다.

파이썬의 구글 클라이언트 패키지 설치하기

pip install – – upgrade google – api – python – client google – auth – httplib2 google – auth – oauthlib

토큰 생성 샘플 스크립트

샘플 스크립트

이 스크립트를 실행할 때 위에서 생성한 클라이언트 ID가 필요하다.

같은 폴더에 credentials.json 이라는 이름으로 위치시켜 준다. 위 스크립트를 실행하면 같은 폴더에 token.json이라는 파일이 생성되고 이 파일안에는 API 요청 시

필요한 token이 포함되어있다. list 샘플 테스트 링크에 들어가면 이미지처럼 바로 테스트도 가능하게 되어있다. 위를 이용해서 포스트맨으로 API요청을 해본 결과이다. summary에 있는 값을 활용하면 될 것으로 보인다.

🌴 리뷰어 리스트에서 휴가자 제외하기

휴가자 목록 조회하기

def get_vacationer_list ( ) : url = f”https://www.googleapis.com/calendar/v3/calendars/ { config . calendar_id } /events” now = datetime . datetime . now ( datetime . timezone . utc ) now2 = now + datetime . timedelta ( hours = 1 ) time_min = now . isoformat ( ) time_max = now2 . isoformat ( ) params = { “key” : config . google_api_key , “timeMax” : time_max , “timeMin” : time_min } response = requests . get ( url , params = params , headers = { “Authorization” : f”Bearer { config . token } ” } ) response = response . json ( ) vacationer_list = [ ] if response . get ( “items” ) : for item in response [ “items” ] : vacationer_list . append ( item . get ( “summary” ) ) return vacationer_list

오늘 날짜 기준으로 휴가인 사람들 목록을 조회해온다.

만약 오늘 휴가자가 리뷰어1, 리뷰어4 연차 + 리뷰어2 오후반차 라고 한다면

vacationer_list 는 [‘리뷰어1, 리뷰어4 연차’, ‘리뷰어2 오후반차’] 의 결과 값을 얻을 수 있다.

이름만 추출하기

def convert_reviewer ( vacationer_list ) : status_list = [ “연차” , “오후반차” , “오전반차” , “오전반반차” , “오후반반차” ] for i , vacationer in enumerate ( vacationer_list ) : for vacation in status_list : if vacationer . find ( vacation ) != – 1 : vacationer_list [ i ] = vacationer . replace ( f” { vacation } ” , “” ) . split ( “,” ) reviewer_list = list ( itertools . chain ( * vacationer_list ) ) return [ review . strip ( ) for review in reviewer_list ]

해당 summary(캘린더에 등록한 일정내용)에 휴가 상태(연차, 오후반차 등)가 포함되어 있는지 확인을 한다.

일정이 휴가에 대한 일정이 맞다면 앞에 있는 내용들을 휴가자들로 간주하고 리스트에 담는다.

그렇게되면 결과 값이 [[‘리뷰어1’, ‘ 리뷰어4’], [‘리뷰어2’]] 이런 형태로 반환된다.

그 다음 리스트들의 원소를 합치는 list(itertools.chain(*vacationer_list)) 를 이용하여 하나로 합치고

‘ 리뷰어4’같은 경우처럼 앞에 공백이 들어가는 것을 방지하기 위해 마지막에 한번 더 strip()으로 공백을 제거해준다.

전체코드

import itertools import sys import random import requests import datetime import config def get_vacationer_list ( ) : url = f”https://www.googleapis.com/calendar/v3/calendars/ { config . calendar_id } /events” now = datetime . datetime . now ( datetime . timezone . utc ) now2 = now + datetime . timedelta ( hours = 1 ) time_min = now . isoformat ( ) time_max = now2 . isoformat ( ) params = { “key” : config . google_api_key , “timeMax” : time_max , “timeMin” : time_min } response = requests . get ( url , params = params , headers = { “Authorization” : f”Bearer { config . token } ” } ) response = response . json ( ) vacationer_list = [ ] if response . get ( “items” ) : for item in response [ “items” ] : vacationer_list . append ( item . get ( “summary” ) ) return vacationer_list def convert_reviewer ( vacationer_list ) : status_list = [ “연차” , “오후반차” , “오전반차” , “오전반반차” , “오후반반차” ] for i , vacationer in enumerate ( vacationer_list ) : for vacation in status_list : if vacationer . find ( vacation ) != – 1 : vacationer_list [ i ] = vacationer . replace ( f” { vacation } ” , “” ) . split ( “,” ) reviewer_list = list ( itertools . chain ( * vacationer_list ) ) return [ review . strip ( ) for review in reviewer_list ] vacationer_list = get_vacationer_list ( ) reviewer_list = convert_reviewer ( vacationer_list ) project_list = [ “1” , “2” , “3” ] all_name_list = [ “리뷰어1” , “리뷰어2” , “리뷰어3” , “리뷰어4” , “리뷰어5” , “리뷰어6” , “리뷰어7” ] input_project = input ( “”” Pr프로젝트 입력하세요 : – 프로젝트 1 : 1 – 프로젝트 2 : 2 – 프로젝트 3 : 3 “”” ) if input_project not in project_list : sys . exit ( “잘못된 프로젝트 입력 입니다.” ) input_name = input ( f””” 이름을 입력하세요 : – 이름 리스트 : “리뷰어1”, “리뷰어2”, “리뷰어3”, “리뷰어4”, “리뷰어5”, “리뷰어6”, “리뷰어7” “”” ) if input_name not in all_name_list : sys . exit ( “잘못된 이름 입력 입니다.” ) first_approve_list = [ ] second_approve_list = [ ] if input_project == “1” : first_approve_list = [ “리뷰어1” , “리뷰어2” , “리뷰어3” ] elif input_project == “2” : first_approve_list = [ “리뷰어1” , “리뷰어4” ] else : first_approve_list = [ “리뷰어1” , “리뷰어3″ ] all_name_list = list ( set ( all_name_list ) – set ( reviewer_list ) ) first_approve_list = list ( set ( first_approve_list ) – set ( reviewer_list ) ) second_approve_list = list ( set ( all_name_list ) – set ( first_approve_list ) ) try : first_approve_list . remove ( input_name ) except ValueError : pass try : second_approve_list . remove ( input_name ) except ValueError : pass first_reviewer = None second_reviewer = None if first_approve_list : first_reviewer = random . choice ( first_approve_list ) second_reviewer = random . choice ( second_approve_list ) else : first_reviewer = random . choice ( second_approve_list ) second_approve_list . remove ( first_reviewer ) second_reviewer = random . choice ( second_approve_list ) print ( f”첫번째 승인자 : { first_reviewer } ” ) print ( f”두번째 승인자 : { second_reviewer } ” )

후기

처음엔 페이지를 크롤링해서 데이터를 얻으면 되지않을까 생각하고 검색해봤는데 마침 OpenAPI가 있어서 이용해보게 되었다.

원래 3시간이면 후다닥 끝나는 줄 알았으나…

현실은 이것저것 걸림돌이 꽤 있었다.

위 코드도 아직 모자란게 산더미이다.

1시간주기로 구글에서 제공해주는 token이 만료가되는데 이걸 계속해서 갱신해야하는 점도 아직 미해결로 남았고

반차나 반반차의 경우에는 시간을 지정하여 해당 시간만 제외하고는 리뷰어로 남을 수 있게 하는 기능도 아직이다.

삽질의 시간에 비해서 가성비는 좋지않다.

구글 콘솔에서부터 개인용도이외에 사용하기엔 무리(보안상 + 번거로움)라는 건 눈치챘으나 이왕 시작해서 끝까지 코딩은 해봤다.

구글 API를 이용하기 위해서는 보안관련해서 체크하고 넘어가는 것이 너무많고

단순 실행 스크립트인데 연동때문에 설치해야되는 패키지도 있는 점이 단점이다.

Information Technology WEBlog

구글 캘린더 API를 자바 기준으로 작성해보겠습니다.

목차

1. 구글캘린더 API 연동

2. Controller구현

3. 화면구현

4. 실행화면

1. 구글캘린더 API 연동

밑에 google API 콘솔로 들어갑니다

https://console.developers.google.com/?hl=ko

프로젝트 만들기 클릭

프로젝트를 만들어줍니다.

라이브러리 -> Calendar API 클릭

사용 설정 클릭

사용자 인증 정보 만들기 클릭

java로 구현하기때문에 웹서버 -> 애플리케이션 데이터 -> 아니요 -> 사용자 인정 정보 클릭

서비스 계정 이름은 아무거나 적고 -> 역할도 적당히 설정 -> 키 유형 JSON 체크 -> 계속

사용자 동의화면을 정해줍니다. -> 저장클릭

사용자 인증 정보 만들기 -> OAuth 클라이언트 ID 클릭

기타유형 -> 생성

접속정보 JSON을 다운 받습니다.

파일명을 변경

client_secret.json

src/main/resources 경로에 넣어줍니다.

dependency

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 com.google.api-client google-api-client 1.22.0 com.google.oauth-client google-oauth-client-jetty 1.22.0 com.google.apis google-api-services-calendar v3-rev235-1.22.0 Colored by Color Scripter cs

java로 접속할 객체를 만들어줍니다.

GoogleCalendarService.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 package com.t.hc.beans; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.List; import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.google.api.services.calendar.Calendar; import com.google.api.services.calendar.CalendarScopes; //import com.google.api.services.calendar.model.CalendarList; //import com.google.api.services.calendar.model.CalendarListEntry; public class GoogleCalendarService { private static final String APPLICATION_NAME = “Google Calendar API Java Quickstart”; private static final java.io.File DATA_STORE_DIR = new java.io.File( System.getProperty(“user.home”), “.credentials/calendar-java-quickstart”); private static FileDataStoreFactory DATA_STORE_FACTORY; private static final JsonFactory JSON_FACTORY = JacksonFactory .getDefaultInstance(); private static HttpTransport HTTP_TRANSPORT; private static final List SCOPES = Arrays .asList(CalendarScopes.CALENDAR); static { try { HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); } catch (Throwable t) { t.printStackTrace(); System.exit(1); } } public static Credential authorize() throws IOException { InputStream in = GoogleCalendarService.class .getResourceAsStream(“/client_secret.json”); GoogleClientSecrets clientSecrets = GoogleClientSecrets.load( JSON_FACTORY, new InputStreamReader(in)); GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) .setDataStoreFactory(DATA_STORE_FACTORY) .setAccessType(“offline”).build(); Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(“user”); System.out.println(“Credentials saved to ” + DATA_STORE_DIR.getAbsolutePath()); return credential; } public static Calendar getCalendarService() throws IOException { Credential credential = authorize(); return new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) .setApplicationName(APPLICATION_NAME).build(); } // public static void main(String[] args) throws IOException { // com.google.api.services.calendar.Calendar service = getCalendarService(); // // 캘린더 조회 // String pageToken = null; // do { // CalendarList calendarList = service.calendarList().list().setPageToken(pageToken).execute(); // List items1 = calendarList.getItems(); // // for (CalendarListEntry calendarListEntry : items1) { // System.out.println(calendarListEntry.getSummary()); // System.out.println(calendarListEntry.getId()); // } // pageToken = calendarList.getNextPageToken(); // } while (pageToken != null); // } } Colored by Color Scripter cs

접속 테스트를위해 main메소드를 돌려봅니다.

성공적으로 수행되면 최초호출시 권한요청 브라우저 창이 뜸니다.

성공적으로 calendar 목록데이터를 가져온걸 볼수있습니다.

CalendarDto.java 작성

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 package com.t.hc.dto; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class CalendarDto { private String summary; private String startDate; private String startTime; private String endDate; private String endTime; private String description; private String eventId; private String calendarId; { description = “”; } public CalendarDto() {} public Date getStartDateTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat(“yyyy-MM-ddHH:mm”); return format.parse(startDate+startTime); } public Date getEndDateTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat(“yyyy-MM-ddHH:mm”); return format.parse(endDate+endTime); } public String getSummary() { return summary; } public void setSummary(String summary) { this.summary = summary; } public String getStartDate() { return startDate; } public void setStartDate(String startDate) { this.startDate = startDate; } public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getEndDate() { return endDate; } public void setEndDate(String endDate) { this.endDate = endDate; } public String getEndTime() { return endTime; } public void setEndTime(String endTime) { this.endTime = endTime; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getEventId() { return eventId; } public void setEventId(String eventId) { this.eventId = eventId; } public String getCalendarId() { return calendarId; } public void setCalendarId(String calendarId) { this.calendarId = calendarId; } @Override public String toString() { return “GoogleCalendarDto [summary=” + summary + “, startDate=” + startDate + “, startTime=” + startTime + “, endDate=” + endDate + “, endTime=” + endTime + “, description=” + description + “, eventId=” + eventId + “, calendarId=” + calendarId + “]”; } } Colored by Color Scripter cs

2. Controller구현

캘린더 리스트 Controller 작성

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 package com.t.hc; import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.google.api.services.calendar.Calendar; import com.google.api.services.calendar.model.CalendarList; import com.google.api.services.calendar.model.CalendarListEntry; import com.t.hc.beans.GoogleCalendarService; import com.t.hc.dto.CalendarDto; @Controller public class HandcodingController { private Logger logger = LoggerFactory.getLogger(HandcodingController.class); // 캘린더리스트 @RequestMapping(value=”/coding.do”, method=RequestMethod.GET) public String coding(Model model) { logger.info(“calendarList”); try { Calendar service = GoogleCalendarService.getCalendarService(); CalendarList calendarList = service.calendarList().list().setPageToken(null).execute(); List items = calendarList.getItems(); model.addAttribute(“items”, items); } catch (IOException e) { e.printStackTrace(); } return “coding”; } // 캘린더 생성 처리 @RequestMapping(value=”/calendarAdd.do”, method=RequestMethod.POST) public String calendarAdd(CalendarDto calDto) { logger.info(“calendarAdd “+calDto.toString()); try { Calendar service = GoogleCalendarService.getCalendarService(); com.google.api.services.calendar.model.Calendar calendar = new com.google.api.services.calendar.model.Calendar(); calendar.setSummary(calDto.getSummary()); calendar.setTimeZone(“America/Los_Angeles”); service.calendars().insert(calendar).execute(); } catch (IOException e) { e.printStackTrace(); } return “redirect:/coding.do”; } // 캘린더 삭제 처리 @RequestMapping(value=”/calendarRemove.do”, method=RequestMethod.POST) public String calendarRemove(HttpServletRequest req) { logger.info(“calendarRemove”); String[] chkVal = req.getParameterValues(“chkVal”); try { Calendar service = GoogleCalendarService.getCalendarService(); for (String calendarId : chkVal) { service.calendars().delete(calendarId).execute(); } } catch (IOException e) { e.printStackTrace(); } return “redirect:/coding.do”; } // 캘린더 수정 처리 @RequestMapping(value=”/calendarModify.do”, method=RequestMethod.POST) public String calendarModify(CalendarDto calDto) { logger.info(“calendarModify “+calDto.toString()); try { Calendar service = GoogleCalendarService.getCalendarService(); com.google.api.services.calendar.model.Calendar calendar = service.calendars().get(calDto.getCalendarId()).execute(); calendar.setSummary(calDto.getSummary()); service.calendars().update(calendar.getId(), calendar).execute(); } catch (IOException e) { e.printStackTrace(); } return “redirect:/coding.do”; } // 캘린더 이동처리 @RequestMapping(value=”/schdule.do”, method=RequestMethod.GET) public String schdule(Model model, String calendarId, String title) { logger.info(“schdule”); model.addAttribute(“calendarId”, calendarId); model.addAttribute(“title”, title); return “schdule”; } } Colored by Color Scripter cs

일정이벤트 핸들링할 ajax컨트롤러 작성

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package com.t.hc; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.google.api.client.util.DateTime; import com.google.api.services.calendar.Calendar; import com.google.api.services.calendar.model.Event; import com.google.api.services.calendar.model.EventDateTime; import com.google.api.services.calendar.model.Events; import com.t.hc.beans.GoogleCalendarService; import com.t.hc.dto.CalendarDto; @RestController public class CalendarAjaxController { private Logger logger = LoggerFactory.getLogger(CalendarAjaxController.class); // 일정 데이터 처리 @RequestMapping(value=”/calendarEventList.do”, method=RequestMethod.POST) public List calendarEventList(CalendarDto calDto) { logger.info(“calendarEventList “+calDto.toString()); List items = new ArrayList(); try { com.google.api.services.calendar.Calendar service = GoogleCalendarService.getCalendarService(); Events events = service.events().list(calDto.getCalendarId()).setOrderBy(“startTime”).setSingleEvents(true).execute(); items = events.getItems(); } catch (IOException e) { e.printStackTrace(); } return items; } // 일정 저장 처리 @RequestMapping(value=”/calendarEventAdd.do”, method=RequestMethod.POST) public Map calendarEventAdd(CalendarDto calDto) { logger.info(“calendarEventAdd “+calDto.toString()); boolean isc = false; try { Calendar service = GoogleCalendarService.getCalendarService(); Event event = new Event().setSummary(calDto.getSummary()).setDescription(calDto.getDescription()); //시작일 DateTime startDateTime = new DateTime(calDto.getStartDateTime()); EventDateTime start = new EventDateTime().setDateTime(startDateTime).setTimeZone(“America/Los_Angeles”); event.setStart(start); //종료일 DateTime endDateTime = new DateTime(calDto.getEndDateTime()); EventDateTime end = new EventDateTime().setDateTime(endDateTime).setTimeZone(“America/Los_Angeles”); event.setEnd(end); event = service.events().insert(calDto.getCalendarId(), event).execute(); isc = true; } catch (IOException | ParseException e) { e.printStackTrace(); } Map map = new HashMap(); map.put(“isc”, isc); return map; } // 일정 삭제 @RequestMapping(value=”/calendarEventRemoveOne.do”, method=RequestMethod.POST) public Map calendarEventRemoveOne(CalendarDto calDto) { logger.info(“calendarEventRemoveOne “+calDto.toString()); boolean isc = false; try { Calendar service = GoogleCalendarService.getCalendarService(); service.events().delete(calDto.getCalendarId(), calDto.getEventId()).execute(); isc = true; } catch (IOException e) { e.printStackTrace(); } Map map = new HashMap(); map.put(“isc”, isc); return map; } // 일정 수정 @RequestMapping(value=”/calendarEventModify.do”, method=RequestMethod.POST) public Map calendarEventModify(CalendarDto calDto) { logger.info(“calendarEventModify “+calDto.toString()); boolean isc = false; try { Calendar service = GoogleCalendarService.getCalendarService(); Event event = service.events().get(calDto.getCalendarId(), calDto.getEventId()).execute(); event.setSummary(calDto.getSummary()).setDescription(calDto.getDescription()); service.events().update(calDto.getCalendarId(), event.getId(), event).execute(); isc = true; } catch (IOException e) { e.printStackTrace(); } Map map = new HashMap(); map.put(“isc”, isc); return map; } } Colored by Color Scripter cs

3. 화면구현

캘린더 리스트화면

coding.jsp

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 캘린더 관리

전체 캘린더이름 캘린더코드
${item.summary} ${item.id}

Colored by Color Scripter cs

캘린더 일정화면

schdule.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 일정관리

${title}

Colored by Color Scripter cs

화면 라이브러리는 부트스트랩, jQuery, sweetalert을 씁니다.

기타 util javaScript

stringBuffer.js

1 2 3 4 5 6 7 8 9 10 // StringBuffer var StringBuffer = function() { this.buffer = new Array(); }; StringBuffer.prototype.append = function(str) { this.buffer[this.buffer.length] = str; }; StringBuffer.prototype.toString = function() { return this.buffer.join(“”); }; Colored by Color Scripter cs

달력연산객체를 하나 만들어줍니다.

calendar.js

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 // 캘린더 객체 var calendar = { LEAF : [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], //윤년 PLAIN : [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], //평년 iscLeafCheck : //윤년 판단 function(year) { var isc = false; if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { // 윤년이면 isc = true; } return isc; }, daysY : //년도에 따른 일수 누적 function(year) { var daySum = 0; for (var i = 1; i < year; i++) { if (this.iscLeafCheck(i)) { daySum += 366; } else { daySum += 365; } } return daySum; }, daysM : //년도누적 + 월 일수 누적 function(year, month) { var daySum = this.daysY(year); for (var i = 1; i < month; i++) { daySum += this.PLAIN[i - 1]; } if (month >= 2 && this.iscLeafCheck(year)) { daySum++; } return daySum; }, daysD : //년도누적 + 월 누적 + 일수 누적 function(year, month, day) { return this.daysM(year, month) + day; }, lastDay : // 구하고자 하는 년월의 최대 일수 function(year, month) { var last_day = 0; if (this.iscLeafCheck(year)) { last_day = this.LEAF[month – 1]; } else { last_day = this.PLAIN[month – 1]; } return last_day; }, isBeforeDays : // 앞의 달에 년도 분기 function(year, month) { var days = 0; if (month == 1) { days = this.lastDay(year – 1, 12); } else { days = this.lastDay(year, month – 1); } return days; }, make : // 해당달력을 배열로 반환 function(year, month) { var dateOfWeek = (this.daysD(year, month, 1)) % 7; var beforeLastDay = this.isBeforeDays(year, month); var startLastDay = beforeLastDay – dateOfWeek + 1; var last_day = this.lastDay(year, month); // 구하고자 하는 년월의 최대 일수 var lastWeekDays = (7 – (dateOfWeek + last_day) % 7) % 7; if (this.iscLeafCheck(year)) { startLastDay++; lastWeekDays++; } var dayArray = new Array(); var cnt = 0; for (var i = startLastDay; i <= beforeLastDay; i++, cnt++) { dayArray[cnt] = i; } for (var i = 1; i <= last_day; i++, cnt++) { dayArray[cnt] = i; } for (var i = 1; i <= lastWeekDays; i++, cnt++) { dayArray[cnt] = i; } return dayArray; }, makeOne : // 달력 한개만 function(year, month){ var last_day = this.lastDay(year, month); // 구하고자 하는 년월의 최대 일수 var dayArray = new Array(); var cnt = 0; for (var i = 1; i <= last_day; i++, cnt++) { dayArray[cnt] = i; } return dayArray; } } Colored by Color Scripter cs 캘린더 리스트 화면을 핸들링할 javaScript calendarList.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 // 캘린더 생성폼 호출 function calendarAddForm() { $('#calendarAddForm').modal(); } // 캘린더 생성 처리 function calendarAdd() { var summary = $('#summary').val(); if(summary.trim() == '' || summary.trim().length == 0) { swal('이름','입력해주세요'); return false; } $('#frmCalendarAdd').submit(); } //전체체크 function checkAllDel(bool) { var chkVal = document.getElementsByName("chkVal"); for (var i = 0; i < chkVal.length; i++) { chkVal[i].checked = bool; } } //캘린더 삭제 function calendarRemove() { var chkVal = document.getElementsByName("chkVal"); var n = 0; for (var i = 0; i < chkVal.length; i++) { if(chkVal[i].checked == true){ n++; } } if(n>0){ $(‘#frmCalendarRemove’).submit(); }else { swal(“캘린더 삭제”, ‘선택해주세요’); } } // 캘린더 수정 호출 function calendarModifyForm() { var chkVal = document.getElementsByName(“chkVal”); var summarys = document.getElementsByName(“summarys”); var n = 0; var calendarId = ”; var summary = ”; for (var i = 0; i < chkVal.length; i++) { if(chkVal[i].checked == true){ n++; calendarId = chkVal[i].value; summary = summarys[i].value; } } if(n==1) { $('#frmCalendarModify').find('#summaryModify').val(summary); $('#frmCalendarModify').find('#calendarIdModify').val(calendarId); }else if(n>1) { swal(“캘린더 수정”, ‘1개만 선택해주세요’); return false; }else { swal(“캘린더 수정”, ‘선택해주세요’); return false; } $(‘#calendarModifyForm’).modal(); } // 캘린더 수정 처리 function calendarModify() { $(‘#frmCalendarModify’).submit(); } Colored by Color Scripter cs

일정을 핸들링할 js

calendarSchdule.js

var data = {} // List var locationMonth = 0; // 현재 달력위치 var locationYear = 0; // 현재 년도위치 var locationWeek = 0; // 현재 주차위치 // 날짜 테그를 만들어준다 function dayTagFormat(year, month, day) { var tag = new StringBuffer(); tag.append(“

“); tag.append(““+numFormat(day)+”“); tag.append(“

“); return tag.toString(); } //숫자 5 -> 05 변경 function numFormat(num) { var str = ”+num; if(num<10 && str.indexOf('0') == -1 || str.length == 1) { str = '0'+num; } return str; } // 시간을 리턴한다 function getTime(item) { return numFormat(item.getHours()) + ":" + numFormat(item.getMinutes()); } // 일정추가 폼 function schduleAdd(year, month, day) { $('.startDate').val(year + "-" + numFormat(month) + "-" + numFormat(day)); $('#summary').val(''); $('#startTime').val(''); $('#endTime').val(''); $('#description').val(''); $('#schduleForm').modal(); } // 유효성 검사 일정 저장처리 function calendarSchduleAdd() { var summary = $('#summary').val(); var startTime = $('#startTime').val().split(":"); var endTime = $('#endTime').val().split(":"); if(summary.trim() == '' || summary.trim().length == 0) { swal('제목','입력해주세요'); return false; }else if($('#startTime').val() == '') { swal('시작시간','입력해주세요'); return false; }else if($('#endTime').val() == '') { swal('종료시간','입력해주세요'); return false; }else if(new Date(0,0,0,endTime[0],endTime[1]).getTime() - new Date(0,0,0,startTime[0],startTime[1]).getTime() < 0) { swal('시간','종료시간이 시작시간보다 늦습니다'); return false; }else if($('#endDate').val() == '') { swal('종료날짜','입력해주세요'); return false; }else if(new Date($('#endDate').val()).getTime() - new Date($('#startDate').val()).getTime() < 0) { swal('날짜','종료일이 시작일보다 늦습니다'); return false; } $("#schduleForm").modal('hide'); swal('calendar', 'google토큰이 필요합니다.'); $.ajax({ url: './calendarEventAdd.do', type: 'post', async: false, data : $('#frmSchdule').serialize(), success: function(msg) { if(msg.isc) { swal('저장', '성공하였습니다'); }else { swal('저장', '실패하였습니다'); } } }); calendarEventList(); screenWriteMonth(); } //달력의 해당 날짜의 요일을 구하기위해 현재위치 반환 function monthDayIndex(month, day) { for(var i=0; i‘); } if(i

‘); } } $(‘#tbody’).html(tag.toString()); $(‘#yearMonth’).text(year + “년 ” + numFormat(months[1]) + “월”); if(data.chk) { for(var i=0; i“); tag.append(‘‘); tag.append(‘

‘); if(description == null) { tag.append(‘

내용이 없습니다

‘); }else { tag.append(‘

‘+description+’

‘); } tag.append(‘

‘); tag.append(‘

‘); tag.append(‘

‘); tag.append(“

“); return tag.toString(); } // collapse 처리 function collapse(eventId) { $(‘.collapse’).not(‘#collapseExample’+eventId).each(function(){ $(this).attr(‘class’, ‘collapse collapse’); }); } // 일정수정 modal function modifyEventModal(title, eventId, description) { $(‘#modifySummary’).val(title); if(description != ‘undefined’) { $(‘#modifyDescription’).val(description); }else { $(‘#modifyDescription’).val(”); } $(‘#modifyEventId’).val(eventId); $(‘#schduleFormModify’).modal(); } // 일정수정 처리 function modifyEvent() { var summary = $(‘#modifySummary’).val(); if(summary.trim() == ” || summary.trim().length == 0) { swal(‘제목’,’입력해주세요’); return false; } $(“#schduleFormModify”).modal(‘hide’); $.ajax({ url: ‘./calendarEventModify.do’, type: ‘post’, async: false, data: $(‘#frmSchduleModify’).serialize(), success: function(msg) { if(msg.isc) { swal(‘수정’, ‘성공하였습니다’); }else { swal(‘수정’, ‘실패하였습니다’); } } }); calendarEventList(); if($(‘#chk’).val() == ‘1’) { screenWriteWeek(); }else { screenWriteMonth(); } } // 일정삭제 function removeEventOne(eventId) { $.ajax({ url: ‘./calendarEventRemoveOne.do’, type: ‘post’, async: false, data : { “eventId” : eventId, “calendarId” : $(‘#calendarId’).val() }, success: function(msg) { if(msg.isc) { swal(‘삭제’, ‘성공하였습니다’); }else { swal(‘삭제’, ‘실패하였습니다’); } } }); calendarEventList(); if($(‘#chk’).val() == ‘1’) { screenWriteWeek(); }else { screenWriteMonth(); } } // ajax로 이벤트 데이터를 받는다 function calendarEventList() { $.ajax({ url: ‘./calendarEventList.do’, type: ‘post’, data: { “calendarId” : $(‘#calendarId’).val() }, async: false, success: function(lists) { if(lists.length != 0) { data.chk = true; data.cnt = lists.length; data.title = new Array(); data.description = new Array(); data.start = new Array(); data.end = new Array(); data.eventId = new Array(); $.each(lists, function(i, item){ data.title[i] = item.summary; data.description[i] = item.description; data.start[i] = new Date(item.start.dateTime.value); data.end[i] = new Date(item.end.dateTime.value); data.eventId[i] = item.id; }); }else { data.chk = false; } } }); } // 주단위로 화면에 그린다 function screenWriteWeek() { var date = new Date(); var month = date.getMonth()+1+locationMonth; if(month == 0) { locationYear–; locationMonth = 12 – Math.abs(locationMonth); month = date.getMonth()+1+locationMonth; }else if(month == 13) { locationYear++; locationMonth = locationMonth – 12; month = date.getMonth()+1+locationMonth; } var year = date.getFullYear()+locationYear; if(locationWeek < 0) { locationMonth--; month = date.getMonth()+1+locationMonth; if(month == 0) { locationYear--; locationMonth = 12 - Math.abs(locationMonth); month = date.getMonth()+1+locationMonth; year = date.getFullYear()+locationYear; } if(new Date(year, month-1, calendar.lastDay(year, month)).getDay() == 6) { locationWeek = calendar.make(year, month).length/7-1; }else { locationWeek = calendar.make(year, month).length/7-2; } }else if(locationWeek > calendar.make(year, month).length/7-2) { locationMonth++; month = date.getMonth()+1+locationMonth; if(month == 13) { locationYear++; locationMonth = locationMonth – 12; month = date.getMonth()+1+locationMonth; year = date.getFullYear()+locationYear; } locationWeek = 0; } var months = [month-1, month, month+1]; if(month == 1) { months = [12, month, month+1]; }else if(month == 12) { months = [month-1, month, 1]; } var monthDay = calendar.make(year, months[1]); var start = 0+locationWeek*7; var last = 6+locationWeek*7; var startIndex = monthDayIndex(monthDay, 1); var lastIndex = monthDayIndex(calendar.makeOne(year, months[1]), calendar.lastDay(year, months[1])) + startIndex; for(var i=start; i<=last; i++) { if(i‘); j++; } if(j%2 == 1) { if(i%8 == 0) { tag.append(‘

‘+numFormat(k++)+’:00

‘); }else { tag.append(‘

‘); } }else { if(i%8 < 7) { tag.append('

‘); } } if(i%8 == 7) { tag.append(‘

‘); } } $(‘#tbody’).html(tag.toString()); // 캘린더 날짜정보 처리 고민필요 지금은 귀찮으니 대충 작성 if(data.chk) { for(var i=start; i<=last; i++) { for(var j=0; j= 30)) { if(monthDay[i] == data.end[j].getDate() && months[1] == data.end[j].getMonth()+1 && year == data.end[j].getFullYear()) { if(data.end[j].getMinutes() < 30) { $('.'+(data.end[j].getHours()*2+1)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); }else { $('.'+(data.end[j].getHours()*2+2)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); } } } }else { weekStartTimeAppend(i, j, monthDay, months, year, 1); weekEndTimeAppend(i, j, monthDay, months, year, 1); } } } } } // startTime Tag append function weekStartTimeAppend(i, j, monthDay, months, year, num) { if(monthDay[i] == data.start[j].getDate() && months[0] == data.start[j].getMonth()+1) { if(months[0] == 12 && year+num == data.start[j].getFullYear()) { if(data.start[j].getMinutes() < 30) { $('.'+(data.start[j].getHours()*2+1)).eq(i%7).html(eventTagFormat(getTime(data.start[j]), data.title[j], data.eventId[j], data.description[j])); }else { $('.'+(data.start[j].getHours()*2+2)).eq(i%7).html(eventTagFormat(getTime(data.start[j]), data.title[j], data.eventId[j], data.description[j])); } }else if(year == data.start[j].getFullYear()) { if(data.start[j].getMinutes() < 30) { $('.'+(data.start[j].getHours()*2+1)).eq(i%7).html(eventTagFormat(getTime(data.start[j]), data.title[j], data.eventId[j], data.description[j])); }else { $('.'+(data.start[j].getHours()*2+2)).eq(i%7).html(eventTagFormat(getTime(data.start[j]), data.title[j], data.eventId[j], data.description[j])); } } } } // endTime Tag append function weekEndTimeAppend(i, j, monthDay, months, year, num) { if(data.start[j].getHours() != data.end[j].getHours() || (data.start[j].getMinutes() < 30 && data.end[j].getMinutes() >= 30)) { if(monthDay[i] == data.end[j].getDate() && months[2] == data.end[j].getMonth()+1) { if(months[2] == 1 && year+num == data.end[j].getFullYear()) { if(data.end[j].getMinutes() < 30) { $('.'+(data.end[j].getHours()*2+1)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); }else { $('.'+(data.end[j].getHours()*2+2)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); } }else if(year == data.end[j].getFullYear()) { if(data.end[j].getMinutes() < 30) { $('.'+(data.end[j].getHours()*2+1)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); }else { $('.'+(data.end[j].getHours()*2+2)).eq(i%7).html(eventTagFormatEnd(getTime(data.end[j]), data.title[j], data.eventId[j], data.description[j])); } } } } } //일정 종료 태그를 만들어 준다 function eventTagFormatEnd(time, title, eventId, description) { var tag = new StringBuffer(); tag.append("

“); tag.append(‘‘); tag.append(“

“); return tag.toString(); } // 이전 주 이동 function moveWeekPre() { locationWeek–; screenWriteWeek(); } // 다음 주 이동 function moveWeekNext() { locationWeek++; screenWriteWeek(); } //이전 달 주 이동 function moveFastWeekPre() { locationMonth–; screenWriteWeek(); } // 다음 달 주 이동 function moveFastWeekNext() { locationMonth++; screenWriteWeek(); } // 주단위로 바꾼다 function tabWeek() { $(‘#movePre’).attr(‘onclick’, ‘moveWeekPre()’); $(‘#moveNext’).attr(‘onclick’, ‘moveWeekNext()’); $(‘#moveFastPre’).attr(‘onclick’, ‘moveFastWeekPre()’); $(‘#moveFastNext’).attr(‘onclick’, ‘moveFastWeekNext()’); if($(‘#chk’).val() != ‘1’) { $(‘#thead tr:eq(0) td:eq(0)’).attr(‘colspan’, ‘8’); $(‘#thead tr:eq(1)’).prepend(‘

시간

‘); $(‘#chk’).val(‘1’); } screenWriteWeek(); } // 월단위로 바꾼다 function tabMonth() { $(‘#movePre’).attr(‘onclick’, ‘moveMonthPre()’); $(‘#moveNext’).attr(‘onclick’, ‘moveMonthNext()’); $(‘#moveFastPre’).attr(‘onclick’, ‘moveFastMonthPre()’); $(‘#moveFastNext’).attr(‘onclick’, ‘moveFastMonthNext()’); if($(‘#chk’).val() != ‘0’) { $(‘#thead tr:eq(0) td:eq(0)’).attr(‘colspan’, ‘7’); $(‘#thead tr:eq(1) td:eq(0)’).remove(); $(‘.week’).text(”); $(‘#chk’).val(‘0’); } screenWriteMonth(); } $(document).ready(function(){ calendarEventList(); screenWriteMonth(); }); Colored by Color Scripter cs

4. 실행화면

캘린더 리스트 화면

캘린더 생성시 modal처리 화면

캘린더 수정시 modal처리 화면

캘린더 삭제시 sweetalert처리 화면

일정 월 처리화면

일정 주 처리화면

일정 상세보기 화면

일정등록 modal처리 화면

일정 수정처리 modal처리 화면

일정 삭제시 sweetalert처리 화면

일정 주 상세보기 화면

이상으로 google calendar API 구현이였는데요

저는 java로 구현했기때문에

만약 배포시 권한동의화면을 띄워야하는데 전혀 써먹지 못합니다.(java코드에서 브라우저를 실행시키기때문에 ㅋㅋ)

소감으로는 API를 쓰는데 생각보다 많은 노력이 필요하고 그 시간에 DB구축하고도 남아돌기 때문에 추천하지 않습니다.

만약 만든다면 배포할때를 위해 javaScript로 구현하시기 바랍니다.

참고 API문서

연동 : https://developers.google.com/google-apps/calendar/quickstart/js

CRUD 코드 : https://developers.google.com/google-apps/calendar/v3/reference/events/get

Data속성 : https://developers.google.com/google-apps/calendar/v3/reference/events

GoogleCalendarAPI.zip

출처 : https://handcoding.tistory.com/20

react-google-calendar-api

An api to manage your google calendar

Install

Npm

npm install –save react-google-calendar-api

yarn

yarn add react-google-calendar-api

Use (Javascript / Typescript)

You will need to enable the “Google Calendar API”(https://console.developers.google.com/flows/enableapi?apiid=calendar.) You will need a clientId and ApiKey from Google(https://developers.google.com/workspace/guides/create-credentials)

import ApiCalendar from ‘react-google-calendar-api’ ; const config = { “clientId” : “” , “apiKey” : “” , “scope” : “https://www.googleapis.com/auth/calendar” , “discoveryDocs” : [ “https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest” ] } const apiCalendar = new ApiCalendar ( config )

Setup

/** * Sign in with a Google account. * @returns { any } A Promise that is fulfilled with the GoogleUser instance when the user successfully authenticates and grants the requested scopes, or rejected with an object containing an error property if an error happened */ public handleAuthClick ( ) : void

/** * Sign out user google account */ public handleSignoutClick ( ) : void

Example

import React , { ReactNode , SyntheticEvent } from ‘react’ ; import ApiCalendar from ‘react-google-calendar-api’ ; const config = { “clientId” : “” , “apiKey” : “” , “scope” : “https://www.googleapis.com/auth/calendar” , “discoveryDocs” : [ “https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest” ] } const apiCalendar = new ApiCalendar ( config ) export default class DoubleButton extends React . Component { constructor ( props ) { super ( props ) ; this . handleItemClick = this . handleItemClick . bind ( this ) ; } public handleItemClick ( event : SyntheticEvent < any > , name : string ) : void { if ( name === ‘sign-in’ ) { apiCalendar . handleAuthClick ( ) } else if ( name === ‘sign-out’ ) { apiCalendar . handleSignoutClick ( ) ; } } render ( ) : ReactNode { return ( < button onClick = { ( e ) => this . handleItemClick ( e , ‘sign-in’ ) } > sign-in < / button > < button onClick = { ( e ) => this . handleItemClick ( e , ‘sign-out’ ) } > sign – out < / button> ) ; } }

/** * Set the default attribute calendar * @param { string } newCalendar ID. */ public setCalendar ( newCalendar : string ) : void

Manage Event

You need to be registered with handleAuthClick.

Create Event:

/** * Create calendar event * @param { string } CalendarId for the event by default use ‘primary’. * @param { object } Event with start and end dateTime * @param { string } sendUpdates Acceptable values are: “all”, “externalOnly”, “none” * @returns { any } Promise on the event. */ public createEvent ( event : object , calendarId : string = this . calendar , sendUpdates : string = ‘none’ , ) : any {

Create Event From Now:

/** * Create an event from the current time for a certain period. * @param { number } Time in minutes for the event * @param { string } Summary(Title) of the event * @param { string } Description of the event (optional) * @param { string } CalendarId by default calendar set by setCalendar. * @param { string } timeZone The time zone in which the time is specified. (Formatted as an IANA Time Zone Database name, e.g. “Europe/Zurich”.) * @returns { any } Promise on the event. */ public createEventFromNow ( { time , summary , description = ” } : any , calendarId : string = this . calendar , timeZone : string = “Europe/Paris” ) : any

Example

import ApiCalendar from ‘react-google-calendar-api’ ; const config = { “clientId” : “” , “apiKey” : “” , “scope” : “https://www.googleapis.com/auth/calendar” , “discoveryDocs” : [ “https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest” ] } const apiCalendar = new ApiCalendar ( config ) const eventFromNow : object = { summary : ‘Poc Dev From Now’ , time : 480 , } ; apiCalendar . createEventFromNow ( eventFromNow ) . then ( ( result : object ) => { console . log ( result ) ; } ) . catch ( ( error : any ) => { console . log ( error ) ; } ) ;

List All Upcoming Events:

/** * List all events in the calendar * @param { number } maxResults to see * @param { string } calendarId to see by default use the calendar attribute * @returns { any } Promise with the result. */ public listUpcomingEvents ( maxResults : number , calendarId : string = this . calendar ) : any

Example

// The user need to signIn with Handle AuthClick before apiCalendar . listUpcomingEvents ( 10 ) . then ( ( { result } : any ) => { console . log ( result . items ) ;

List All Events:

/** * List all events in the calendar queried by custom query options * See all available options here https://developers.google.com/calendar/v3/reference/events/list * @param { object } queryOptions to see * @param { string } calendarId to see by default use the calendar attribute * @returns { any } */ public listEvents ( queryOptions , calendarId = this . calendar ) : any

Example

// The user need to signIn with Handle AuthClick before apiCalendar . listEvents ( { timeMin : new Date ( ) . . toISOString ( ) , timeMax : new Date ( ) . addDays ( 10 ) . toISOString ( ) , showDeleted : true , maxResults : 10 , orderBy : ‘updated’ } ) . then ( ( { result } : any ) => { console . log ( result . items ) ; } ) ;

Update Event

/** * Update Calendar event * @param { string } calendarId for the event. * @param { string } eventId of the event. * @param { object } event with details to update, e.g. summary * @param { string } sendUpdates Acceptable values are: “all”, “externalOnly”, “none” * @returns { any } Promise object with result */ public updateEvent ( event : object , eventId : string , calendarId : string = this . calendar , sendUpdates : string = ‘none’ ) : any

Example

const event = { summary : ‘New Event Title’ , } ; apiCalendar . updateEvent ( event , ‘2eo85lmjkkd2i63uo3lhi8a2cq’ ) . then ( console . log ) ;

Delete Event

/** * Delete an event in the calendar. * @param { string } eventId of the event to delete. * @param { string } calendarId where the event is. * @returns { any } Promise resolved when the event is deleted. */ public deleteEvent ( eventId : string , calendarId : string = this . calendar ) : any

Example

apiCalendar . deleteEvent ( ‘2eo85lmjkkd2i63uo3lhi8a2cq’ ) . then ( console . log ) ;

Get Event

/** * Get Calendar event * @param { string } calendarId for the event. * @param { string } eventId specifies individual event * @returns { any } */ public getEvent ( eventId : string , calendarId : string = this . calendar ) : any

Example

Python) Google Calendar API 사용 방법

728×90

Python에서 Google Calendar API를 사용하여 내 계정의 이벤트를 가져오는 것을 해보고자 한다.

일단 구글 캘린더 API를 사용하기 위해서는 Open API를 인증받아야 한다.

일단 다른 글들을 따라가면서 순서대로 캡처한 것을 보여주면서 진행하려고 한다.

그래서 뭔가 중간 중간에 보안적인 문제가 있을 수 있으니 주의하시길 바란다.

API 인증 받기

1. 로그인 및 프로젝트 생성

https://console.cloud.google.com/?pli=1

위의 URL로 들어가서 구글 로그인을 하고 하나의 프로젝트를 생성하자.

이름은 아무렇게나 하면 된다.

[프로젝트 선택] -> [새 프로젝트]

2. 프로젝트 생성

프로젝트 이름을 설정하고 만들기를 누른다.

3. 프로젝트 확인

그러면 이렇게 ‘AUTOMATING CALENCAR’라는 프로젝트가 생긴다.

4. 검색창에 calendar API 찾고 눌러주기

상단에 검색창에서 calendar라고 검색하면 아래에 Google Calendar API가 나온다.

그러면 그걸 클릭하자.

[검색] -> [Google Calendar API] -> [클릭]

5. Google Calendar API 사용 버튼 누르기

해당 프로젝트에서 사용하기 버튼을 누르자.

6. 사용자 인증 정보 만들기

[사용자 인증 정보] -> [+ 사용자 인증 정보 만들기] -> [OAuth 클라이언트 ID] 클릭

그러면 Google Calendar API에서 사용자 인증 정보를 만들어보자.

application 유형을 [데스크톱 앱]으로 선택

[이름] 설정

7. OAuth 동의 하기

[OAuth 동의 화면] -> [User Type] 선택-> [만들기]

일단 조직을 선택을 안 해서 그런지 내부는 안되기 때문에 외부를 선택했다.

8. OAuth 동의 하기 화면 1 (범위 추가) Calendar API

[범위 추가 또는 삭제] -> [Google Calendar API] 선택

Google Calendar API를 보면 여러 개가 있는데, 다양한 것이 있지만, 일단 모든 권환이 있는 것을 선택한다. (사용자 패턴에 맞게 바꾸기?)

9. 클라이언트 다운로드하기 (보안 주의)

우리가 만든 calendar automation 맨 오른쪽에 다운로드를 클릭합니다.

그러면 아래와 같은 화면이 나옵니다.

그러면 여기서 JSON 다운로드를 클릭하고 이상한 이름이 나올 텐데, 이것을 일단 credentials.json입니다.

해당 파일은 다른 사람들과 공유하지 마세요.

자 여기까지 하면 생성이 된 것을 알 수 있다.

10. Python API

check_google_calendar.ipynb를 확인해보면 된다.

https://github.com/sungreong/PyKorAnniversary

11. Traffic 확인

10번)에서 Python API를 이용해서 하면 다음과 같이 트래픽이 나오는 것을 알 수 있다.

참고

https://karenapp.io/articles/how-to-automate-google-calendar-with-python-using-the-calendar-api/

Google Calendar API 이용하기 (2/3) – Python 예제

728×90

키워드에 대한 정보 구글 캘린더 api

다음은 Bing에서 구글 캘린더 api 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!)

  • fullcalendar
  • 달력
  • 일정
  • 일정관리
  • 구글 캘린더
  • Google Calendar API
  • Goolge open API
  • 구글 캘린더 API
  • 자바스크립트
  • 코딩
  • 프로그래밍

달력(fullcalendar)과 #구글 #캘린더 #API #연동 #(30분만에 #관리형 #달력 #완성!)


YouTube에서 구글 캘린더 api 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 달력(fullcalendar)과 구글 캘린더 API 연동 (30분만에 관리형 달력 완성!) | 구글 캘린더 api, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

Leave a Comment