Merge pull request #68 from Dayanfreitas/main
Feat: add cookbook google calendar
This commit is contained in:
commit
1fc2f66127
|
|
@ -0,0 +1,6 @@
|
|||
# Google Calendar API Configuration
|
||||
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com
|
||||
GOOGLE_APPLICATION_CREDENTIALS=credentials.json
|
||||
|
||||
# Application Configuration
|
||||
TIMEZONE=America/Sao_Paulo # or your preferred timezone
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.env
|
||||
Pipfile.lock
|
||||
credentials.json
|
||||
token.pickle
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
python-dotenv = ">=0.19.0"
|
||||
pocketflow = ">=0.0.2"
|
||||
google-auth-oauthlib = ">=1.0.0"
|
||||
google-auth-httplib2 = ">=0.1.0"
|
||||
google-api-python-client = ">=2.0.0"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.13"
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
# Pocket Google Calendar
|
||||
|
||||
An application based on the Pocket Flow framework for Google Calendar integration.
|
||||
|
||||
## 📋 Description
|
||||
|
||||
This project implements a Google Calendar integration using the Pocket Flow framework, allowing efficient management of events and appointments through a simple and intuitive interface.
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- Google Calendar API Integration
|
||||
- Event Management
|
||||
- Appointment Viewing
|
||||
- Flow-based Interface using Pocket Flow
|
||||
|
||||
## 🛠️ Technologies Used
|
||||
|
||||
- Python
|
||||
- Pocket Flow Framework
|
||||
- Google Calendar API
|
||||
- Pipenv for dependency management
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone [REPOSITORY_URL]
|
||||
cd pocket-google-calendar
|
||||
```
|
||||
|
||||
2. Install dependencies using Pipenv:
|
||||
```bash
|
||||
pipenv install
|
||||
```
|
||||
|
||||
## 🔑 Credentials Setup
|
||||
|
||||
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project or select an existing one
|
||||
3. Enable the Google Calendar API for your project
|
||||
4. Create credentials:
|
||||
- Go to "APIs & Services" > "Credentials"
|
||||
- Click "Create Credentials" > "OAuth client ID"
|
||||
- Choose "Desktop application" as the application type
|
||||
- Download the credentials file
|
||||
- Rename it to `credentials.json`
|
||||
- Place it in the root directory of the project
|
||||
|
||||
## 🌍 Environment Variables
|
||||
|
||||
Create a `.env` file in the root directory with the following variables:
|
||||
|
||||
```env
|
||||
# Google Calendar API Configuration
|
||||
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com
|
||||
GOOGLE_APPLICATION_CREDENTIALS=credentials.json
|
||||
|
||||
# Application Configuration
|
||||
TIMEZONE=America/Sao_Paulo # or your preferred timezone
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
1. Activate the virtual environment:
|
||||
```bash
|
||||
pipenv shell
|
||||
```
|
||||
|
||||
2. Run the application:
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
When running the example, you'll see an output similar to this:
|
||||
|
||||
```
|
||||
=== Listing your calendars ===
|
||||
- Primary Calendar
|
||||
- Work
|
||||
- Personal
|
||||
|
||||
=== Creating an example event ===
|
||||
Event created successfully!
|
||||
Event ID: abc123xyz
|
||||
```
|
||||
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
pocket-google-calendar/
|
||||
├── main.py # Application entry point
|
||||
├── nodes.py # Pocket Flow node definitions
|
||||
├── utils/ # Utilities and helper functions
|
||||
├── Pipfile # Pipenv configuration
|
||||
├── credentials.json # Google Calendar API credentials
|
||||
├── .env # Environment variables
|
||||
└── token.pickle # Google Calendar authentication token
|
||||
```
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
1. Fork the project
|
||||
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## 📝 License
|
||||
|
||||
This project is under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
||||
|
||||
## ✨ Acknowledgments
|
||||
|
||||
- [Pocket Flow](https://github.com/the-pocket/PocketFlow) - Framework used
|
||||
- [Google Calendar API](https://developers.google.com/calendar) - Integration API
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
from pocketflow import Flow
|
||||
from nodes import CreateCalendarEventNode, ListCalendarEventsNode, ListCalendarsNode
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
def create_calendar_flow():
|
||||
"""Creates a flow to manage calendar events."""
|
||||
# Create nodes
|
||||
create_event_node = CreateCalendarEventNode()
|
||||
list_events_node = ListCalendarEventsNode()
|
||||
|
||||
# Connect nodes
|
||||
create_event_node - "success" >> list_events_node
|
||||
create_event_node - "error" >> None
|
||||
|
||||
# Create flow
|
||||
return Flow(start=create_event_node)
|
||||
|
||||
def list_calendars_flow():
|
||||
"""Creates a flow to list all user calendars."""
|
||||
list_calendars_node = ListCalendarsNode()
|
||||
return Flow(start=list_calendars_node)
|
||||
|
||||
def main():
|
||||
# Example: List all calendars
|
||||
print("=== Listing your calendars ===")
|
||||
flow = list_calendars_flow()
|
||||
shared = {}
|
||||
flow.run(shared)
|
||||
|
||||
if 'available_calendars' in shared:
|
||||
for cal in shared['available_calendars']:
|
||||
print(f"- {cal.get('summary')}")
|
||||
|
||||
# Example: Create a simple event
|
||||
print("\n=== Creating an example event ===")
|
||||
flow = create_calendar_flow()
|
||||
|
||||
shared = {
|
||||
'event_summary': 'Example Meeting',
|
||||
'event_description': 'An example meeting created by PocketFlow',
|
||||
'event_start_time': datetime.now() + timedelta(days=1),
|
||||
'event_end_time': datetime.now() + timedelta(days=1, hours=1),
|
||||
'days_to_list': 7
|
||||
}
|
||||
|
||||
flow.run(shared)
|
||||
|
||||
if 'last_created_event' in shared:
|
||||
print("Event created successfully!")
|
||||
print(f"Event ID: {shared['last_created_event']['id']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
from pocketflow import Node
|
||||
from utils.google_calendar import create_event, list_events, list_calendar_lists
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
class CreateCalendarEventNode(Node):
|
||||
def prep(self, shared):
|
||||
"""Prepares the necessary data to create an event."""
|
||||
return {
|
||||
'summary': shared.get('event_summary'),
|
||||
'description': shared.get('event_description'),
|
||||
'start_time': shared.get('event_start_time'),
|
||||
'end_time': shared.get('event_end_time')
|
||||
}
|
||||
|
||||
def exec(self, event_data):
|
||||
"""Creates a new calendar event."""
|
||||
try:
|
||||
event = create_event(
|
||||
summary=event_data['summary'],
|
||||
description=event_data['description'],
|
||||
start_time=event_data['start_time'],
|
||||
end_time=event_data['end_time']
|
||||
)
|
||||
return {'success': True, 'event': event}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def post(self, shared, prep_res, exec_res):
|
||||
"""Stores the event creation result."""
|
||||
if exec_res['success']:
|
||||
shared['last_created_event'] = exec_res['event']
|
||||
return 'success'
|
||||
else:
|
||||
shared['error'] = exec_res['error']
|
||||
return 'error'
|
||||
|
||||
class ListCalendarEventsNode(Node):
|
||||
def prep(self, shared):
|
||||
"""Prepares parameters to list events."""
|
||||
return {
|
||||
'days': shared.get('days_to_list', 7)
|
||||
}
|
||||
|
||||
def exec(self, params):
|
||||
"""Lists calendar events."""
|
||||
try:
|
||||
events = list_events(days=params['days'])
|
||||
return {'success': True, 'events': events}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def post(self, shared, prep_res, exec_res):
|
||||
"""Stores the list of events."""
|
||||
if exec_res['success']:
|
||||
shared['calendar_events'] = exec_res['events']
|
||||
return 'success'
|
||||
else:
|
||||
shared['error'] = exec_res['error']
|
||||
return 'error'
|
||||
|
||||
class ListCalendarsNode(Node):
|
||||
def prep(self, shared):
|
||||
"""No special preparation needed to list calendars."""
|
||||
return {}
|
||||
|
||||
def exec(self, params):
|
||||
"""Lists all available calendars for the user."""
|
||||
try:
|
||||
calendars = list_calendar_lists()
|
||||
return {'success': True, 'calendars': calendars}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def post(self, shared, prep_res, exec_res):
|
||||
"""Stores the list of calendars in the shared store."""
|
||||
if exec_res['success']:
|
||||
shared['available_calendars'] = exec_res['calendars']
|
||||
return 'success'
|
||||
else:
|
||||
shared['error'] = exec_res['error']
|
||||
return 'error'
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
from google.oauth2.credentials import Credentials
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from googleapiclient.discovery import build
|
||||
import os.path
|
||||
import os
|
||||
import pickle
|
||||
from datetime import datetime, timedelta
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
CALENDAR_ID = os.getenv('GOOGLE_CALENDAR_ID')
|
||||
GOOGLE_APPLICATION_CREDENTIALS = os.getenv('GOOGLE_APPLICATION_CREDENTIALS')
|
||||
TIMEZONE = os.getenv('TIMEZONE')
|
||||
|
||||
SCOPES = ['https://www.googleapis.com/auth/calendar']
|
||||
|
||||
def get_calendar_service():
|
||||
"""Gets the authenticated Google Calendar service."""
|
||||
creds = None
|
||||
if os.path.exists('token.pickle'):
|
||||
with open('token.pickle', 'rb') as token:
|
||||
creds = pickle.load(token)
|
||||
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
GOOGLE_APPLICATION_CREDENTIALS, SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
with open('token.pickle', 'wb') as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
return build('calendar', 'v3', credentials=creds)
|
||||
|
||||
def create_event(summary, description, start_time, end_time, timezone=TIMEZONE):
|
||||
"""Creates a new event in Google Calendar."""
|
||||
service = get_calendar_service()
|
||||
|
||||
event = {
|
||||
'summary': summary,
|
||||
'description': description,
|
||||
'start': {
|
||||
'dateTime': start_time.isoformat(),
|
||||
'timeZone': timezone,
|
||||
},
|
||||
'end': {
|
||||
'dateTime': end_time.isoformat(),
|
||||
'timeZone': timezone,
|
||||
},
|
||||
}
|
||||
|
||||
event = service.events().insert(calendarId=CALENDAR_ID, body=event).execute()
|
||||
return event
|
||||
|
||||
def list_events(days=7):
|
||||
"""Lists events for the next X days."""
|
||||
service = get_calendar_service()
|
||||
|
||||
now = datetime.utcnow()
|
||||
time_min = now.isoformat() + 'Z'
|
||||
time_max = (now + timedelta(days=days)).isoformat() + 'Z'
|
||||
|
||||
events_result = service.events().list(
|
||||
calendarId=CALENDAR_ID,
|
||||
timeMin=time_min,
|
||||
timeMax=time_max,
|
||||
singleEvents=True,
|
||||
orderBy='startTime'
|
||||
).execute()
|
||||
|
||||
return events_result.get('items', [])
|
||||
|
||||
def create_custom_calendar(calendar_name, description=""):
|
||||
"""Creates a new custom calendar in Google Calendar."""
|
||||
service = get_calendar_service()
|
||||
|
||||
calendar = {
|
||||
'summary': calendar_name,
|
||||
'description': description,
|
||||
'timeZone': TIMEZONE
|
||||
}
|
||||
|
||||
created_calendar = service.calendars().insert(body=calendar).execute()
|
||||
return created_calendar
|
||||
|
||||
def list_calendar_lists():
|
||||
"""Lists all available calendars for the user."""
|
||||
service = get_calendar_service()
|
||||
|
||||
calendar_list = service.calendarList().list().execute()
|
||||
return calendar_list.get('items', [])
|
||||
Loading…
Reference in New Issue