Adjust the directory structure to prepare for merging into Master.

This commit is contained in:
Liu Zhicong
2023-09-27 11:40:46 -07:00
parent 5146bc1871
commit 030e4c4f52
115 changed files with 413 additions and 160 deletions
@@ -0,0 +1,7 @@
# OpenDAN Plugin Schedule Assistant
## Run
```
python -m uvicorn main:app
```
@@ -0,0 +1 @@
SCOPES = ["https://www.googleapis.com/auth/calendar"]
@@ -0,0 +1,165 @@
import datetime
from typing import Optional
from response import *
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from .oauth import auth
class Event(BaseModel):
id: str
summary: str = ""
description: str = ""
start_time: int = -1 # Second
end_time: int = -1 # Second
def convert_to_timestamp(time: str):
return int(datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%SZ').timestamp())
def convert_to_time(timestamp: int):
return datetime.datetime.fromtimestamp(timestamp).isoformat() + "Z"
def convert_to_event(e: Dict):
event = Event(**e)
start_time = e["start"].get("dateTime", e["start"].get("date"))
end_time = e["end"].get("dateTime", e["end"].get("date"))
event.start_time = convert_to_timestamp(start_time)
event.end_time = convert_to_timestamp(end_time)
return event
def get_events():
creds = auth()
if not creds:
return build_failure_response(RESPONSE_UNAUTHORIZED, [])
try:
service = build("calendar", "v3", credentials=creds)
# Call the Calendar API
now = datetime.datetime.utcnow().isoformat() + "Z" # 'Z' indicates UTC time
events_result = (
service.events()
.list(
calendarId="primary",
timeMin=now,
singleEvents=True,
orderBy="startTime",
timeZone="UTC"
)
.execute()
)
events = events_result.get("items", [])
if not events:
result = build_success_response([])
else:
o_events = []
for event in events:
o_events.append(convert_to_event(event))
result = build_success_response(o_events)
except HttpError as error:
print("An error occurred: %s" % error)
result = build_failure_response(RESPONSE_UNKNOWN_ERROR[0], error.reason, [])
return result
def get_event(event_id: str):
creds = auth()
if not creds:
return build_failure_response(RESPONSE_UNAUTHORIZED, {})
try:
service = build("calendar", "v3", credentials=creds)
# Call the Calendar API
event = (
service.events()
.get(
calendarId="primary",
eventId=event_id,
timeZone="UTC"
)
.execute()
)
if not event:
result = build_failure_response(RESPONSE_TASK_NOT_FOUND, {})
else:
result = build_success_response(convert_to_event(event).dict())
except HttpError as error:
print("An error occurred: %s" % error)
result = build_failure_response(RESPONSE_UNKNOWN_ERROR[0], error.reason, {})
return result
def add_event(start_time: int, end_time: int, summary: Optional[str], description: Optional[str]):
start = convert_to_time(start_time)
end = convert_to_time(end_time)
event = {
'summary': summary,
'description': description,
'start': {
'dateTime': start,
'timeZone': 'UTC',
},
'end': {
'dateTime': end,
'timeZone': 'UTC',
},
}
creds = auth()
if not creds:
return build_failure_response(RESPONSE_UNAUTHORIZED, [])
try:
service = build("calendar", "v3", credentials=creds)
event = service.events().insert(calendarId='primary', body=event).execute()
result = build_success_response({
"id": event["id"]
})
except HttpError as error:
print("An error occurred: %s" % error)
result = build_failure_response(RESPONSE_UNKNOWN_ERROR[0], error.reason, [])
return result
def delete_event(event_id: str):
creds = auth()
if not creds:
return build_failure_response(RESPONSE_UNAUTHORIZED, [])
try:
service = build("calendar", "v3", credentials=creds)
service.events().delete(calendarId='primary', eventId=event_id).execute()
result = build_success_response({})
except HttpError as error:
print("An error occurred: %s" % error)
result = build_failure_response(RESPONSE_UNKNOWN_ERROR[0], error.reason, [])
return result
@@ -0,0 +1,26 @@
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from .config import SCOPES
def auth():
creds = None
if os.path.exists("token.json"):
creds = Credentials.from_authorized_user_file("token.json", SCOPES)
# If there are no (valid) credentials available, let the user log in.
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("credentials.json", SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open("token.json", "w") as token:
token.write(creds.to_json())
return creds
@@ -0,0 +1,48 @@
from fastapi import FastAPI
from response import *
from google_calendar.event import *
app = FastAPI(
title="OpenDAN Schedule Assistant API",
description="",
version="0.1.0",
)
@app.get("/tasks", response_model=Response, summary="Get all the tasks", description="", tags=['TASK'])
async def tasks():
return get_events()
class AddTaskParams(BaseModel):
start_time: int
end_time: int
summary: Union[str, None] = None
description: Union[str, None] = None
@app.post("/task/add", response_model=Response, summary="Add a task", description="", tags=['TASK'])
async def add_task(params: AddTaskParams):
return add_event(params.start_time, params.end_time, params.summary, params.description)
@app.post(
"/task/delete/{task_id}",
response_model=Response,
summary="Delete task with TaskId",
description="",
tags=['TASK']
)
async def delete_task(task_id: str):
return delete_event(task_id)
@app.get(
"/task/{task_id}",
response_model=Response,
summary="Get task details",
description="",
tags=['TASK']
)
async def get_task(task_id: str):
return get_event(task_id)
@@ -0,0 +1,5 @@
from enum import Enum
class Provider(str, Enum):
GOOGLE_CALENDAR = "google"
@@ -0,0 +1,34 @@
from typing import Union, Tuple, Dict, List
from pydantic import BaseModel
class Response(BaseModel):
code: int
message: str
data: Union[Dict, List]
def build_success_response(data: Union[Dict, List]):
return {
"code": RESPONSE_SUCCESS[0],
"message": RESPONSE_SUCCESS[1],
"data": data
}
def build_failure_response(result_tuple: Tuple, data: Union[Dict, List]):
return build_failure_response(result_tuple[0], result_tuple[1], data)
def build_failure_response(code: int, message: str, data: Union[Dict, List]):
return {
"code": code,
"message": message,
"data": data
}
RESPONSE_SUCCESS = 200, "SUCCESS"
RESPONSE_UNKNOWN_ERROR = 100001, "UNKNOWN ERROR"
RESPONSE_UNAUTHORIZED = 100002, "UNAUTHORIZED"
RESPONSE_TASK_NOT_FOUND = 100003, "TASK NOT FOUND"