calendar test

This commit is contained in:
quaduzi 2023-06-29 20:39:56 +07:00
parent 35d7cffa9a
commit 9243eeb536
7 changed files with 492 additions and 24 deletions

View File

@ -12,18 +12,18 @@ services:
- "8000:8000"
volumes:
- .:/backend_labs
depends_on:
- postgres
postgres:
image: postgres:15.3
container_name: postgres
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- .env
ports:
- "5432:5432"
volumes:
postgres_data:
# depends_on:
# - postgres
#
# postgres:
# image: postgres:15.3
# container_name: postgres
# volumes:
# - postgres_data:/var/lib/postgresql/data/
# env_file:
# - .env
# ports:
# - "5432:5432"
#
#volumes:
# postgres_data:

251
poetry.lock generated
View File

@ -77,6 +77,18 @@ files = [
tests = ["pytest (>=3.2.1,!=3.3.0)"]
typecheck = ["mypy"]
[[package]]
name = "cachetools"
version = "5.3.1"
description = "Extensible memoizing collections and decorators"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"},
{file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"},
]
[[package]]
name = "certifi"
version = "2023.5.7"
@ -257,6 +269,127 @@ dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"]
test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
[[package]]
name = "google-api-core"
version = "2.11.1"
description = "Google API client core library"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "google-api-core-2.11.1.tar.gz", hash = "sha256:25d29e05a0058ed5f19c61c0a78b1b53adea4d9364b464d014fbda941f6d1c9a"},
{file = "google_api_core-2.11.1-py3-none-any.whl", hash = "sha256:d92a5a92dc36dd4f4b9ee4e55528a90e432b059f93aee6ad857f9de8cc7ae94a"},
]
[package.dependencies]
google-auth = ">=2.14.1,<3.0.dev0"
googleapis-common-protos = ">=1.56.2,<2.0.dev0"
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0"
requests = ">=2.18.0,<3.0.0.dev0"
[package.extras]
grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"]
grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
[[package]]
name = "google-api-python-client"
version = "2.90.0"
description = "Google API Client Library for Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "google-api-python-client-2.90.0.tar.gz", hash = "sha256:cbcb3ba8be37c6806676a49df16ac412077e5e5dc7fa967941eff977b31fba03"},
{file = "google_api_python_client-2.90.0-py2.py3-none-any.whl", hash = "sha256:4a41ffb7797d4f28e44635fb1e7076240b741c6493e7c3233c0e4421cec7c913"},
]
[package.dependencies]
google-api-core = ">=1.31.5,<2.0.0 || >2.3.0,<3.0.0.dev0"
google-auth = ">=1.19.0,<3.0.0.dev0"
google-auth-httplib2 = ">=0.1.0"
httplib2 = ">=0.15.0,<1.dev0"
uritemplate = ">=3.0.1,<5"
[[package]]
name = "google-auth"
version = "2.17.3"
description = "Google Authentication Library"
category = "main"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
files = [
{file = "google-auth-2.17.3.tar.gz", hash = "sha256:ce311e2bc58b130fddf316df57c9b3943c2a7b4f6ec31de9663a9333e4064efc"},
{file = "google_auth-2.17.3-py2.py3-none-any.whl", hash = "sha256:f586b274d3eb7bd932ea424b1c702a30e0393a2e2bc4ca3eae8263ffd8be229f"},
]
[package.dependencies]
cachetools = ">=2.0.0,<6.0"
pyasn1-modules = ">=0.2.1"
rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""}
six = ">=1.9.0"
[package.extras]
aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"]
enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"]
pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"]
reauth = ["pyu2f (>=0.1.5)"]
requests = ["requests (>=2.20.0,<3.0.0dev)"]
[[package]]
name = "google-auth-httplib2"
version = "0.1.0"
description = "Google Authentication Library: httplib2 transport"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"},
{file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"},
]
[package.dependencies]
google-auth = "*"
httplib2 = ">=0.15.0"
six = "*"
[[package]]
name = "google-auth-oauthlib"
version = "1.0.0"
description = "Google Authentication Library"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"},
{file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"},
]
[package.dependencies]
google-auth = ">=2.15.0"
requests-oauthlib = ">=0.7.0"
[package.extras]
tool = ["click (>=6.0.0)"]
[[package]]
name = "googleapis-common-protos"
version = "1.59.1"
description = "Common protobufs used in Google APIs"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "googleapis-common-protos-1.59.1.tar.gz", hash = "sha256:b35d530fe825fb4227857bc47ad84c33c809ac96f312e13182bdeaa2abe1178a"},
{file = "googleapis_common_protos-1.59.1-py2.py3-none-any.whl", hash = "sha256:0cbedb6fb68f1c07e18eb4c48256320777707e7d0c55063ae56c15db3224a61e"},
]
[package.dependencies]
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0"
[package.extras]
grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"]
[[package]]
name = "greenlet"
version = "2.0.2"
@ -364,6 +497,21 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
[[package]]
name = "httplib2"
version = "0.22.0"
description = "A comprehensive HTTP client library."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"},
{file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"},
]
[package.dependencies]
pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""}
[[package]]
name = "idna"
version = "3.4"
@ -474,6 +622,23 @@ files = [
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
]
[[package]]
name = "oauthlib"
version = "3.2.2"
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"},
{file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"},
]
[package.extras]
rsa = ["cryptography (>=3.0.0)"]
signals = ["blinker (>=1.4.0)"]
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
[[package]]
name = "passlib"
version = "1.7.4"
@ -495,6 +660,29 @@ bcrypt = ["bcrypt (>=3.1.0)"]
build-docs = ["cloud-sptheme (>=1.10.1)", "sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)"]
totp = ["cryptography"]
[[package]]
name = "protobuf"
version = "4.23.3"
description = ""
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "protobuf-4.23.3-cp310-abi3-win32.whl", hash = "sha256:514b6bbd54a41ca50c86dd5ad6488afe9505901b3557c5e0f7823a0cf67106fb"},
{file = "protobuf-4.23.3-cp310-abi3-win_amd64.whl", hash = "sha256:cc14358a8742c4e06b1bfe4be1afbdf5c9f6bd094dff3e14edb78a1513893ff5"},
{file = "protobuf-4.23.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2991f5e7690dab569f8f81702e6700e7364cc3b5e572725098215d3da5ccc6ac"},
{file = "protobuf-4.23.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:08fe19d267608d438aa37019236db02b306e33f6b9902c3163838b8e75970223"},
{file = "protobuf-4.23.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3b01a5274ac920feb75d0b372d901524f7e3ad39c63b1a2d55043f3887afe0c1"},
{file = "protobuf-4.23.3-cp37-cp37m-win32.whl", hash = "sha256:aca6e86a08c5c5962f55eac9b5bd6fce6ed98645d77e8bfc2b952ecd4a8e4f6a"},
{file = "protobuf-4.23.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0149053336a466e3e0b040e54d0b615fc71de86da66791c592cc3c8d18150bf8"},
{file = "protobuf-4.23.3-cp38-cp38-win32.whl", hash = "sha256:84ea0bd90c2fdd70ddd9f3d3fc0197cc24ecec1345856c2b5ba70e4d99815359"},
{file = "protobuf-4.23.3-cp38-cp38-win_amd64.whl", hash = "sha256:3bcbeb2bf4bb61fe960dd6e005801a23a43578200ea8ceb726d1f6bd0e562ba1"},
{file = "protobuf-4.23.3-cp39-cp39-win32.whl", hash = "sha256:5cb9e41188737f321f4fce9a4337bf40a5414b8d03227e1d9fbc59bc3a216e35"},
{file = "protobuf-4.23.3-cp39-cp39-win_amd64.whl", hash = "sha256:29660574cd769f2324a57fb78127cda59327eb6664381ecfe1c69731b83e8288"},
{file = "protobuf-4.23.3-py3-none-any.whl", hash = "sha256:447b9786ac8e50ae72cae7a2eec5c5df6a9dbf9aa6f908f1b8bda6032644ea62"},
{file = "protobuf-4.23.3.tar.gz", hash = "sha256:7a92beb30600332a52cdadbedb40d33fd7c8a0d7f549c440347bc606fb3fe34b"},
]
[[package]]
name = "psycopg2"
version = "2.9.6"
@ -530,6 +718,21 @@ files = [
{file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"},
]
[[package]]
name = "pyasn1-modules"
version = "0.3.0"
description = "A collection of ASN.1-based protocols modules"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
{file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"},
{file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"},
]
[package.dependencies]
pyasn1 = ">=0.4.6,<0.6.0"
[[package]]
name = "pydantic"
version = "1.10.9"
@ -583,6 +786,21 @@ typing-extensions = ">=4.2.0"
dotenv = ["python-dotenv (>=0.10.4)"]
email = ["email-validator (>=1.0.3)"]
[[package]]
name = "pyparsing"
version = "3.1.0"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
optional = false
python-versions = ">=3.6.8"
files = [
{file = "pyparsing-3.1.0-py3-none-any.whl", hash = "sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1"},
{file = "pyparsing-3.1.0.tar.gz", hash = "sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea"},
]
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "python-jose"
version = "3.3.0"
@ -642,6 +860,25 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "requests-oauthlib"
version = "1.3.1"
description = "OAuthlib authentication support for Requests."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"},
{file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"},
]
[package.dependencies]
oauthlib = ">=3.0.0"
requests = ">=2.0.0"
[package.extras]
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
[[package]]
name = "rsa"
version = "4.9"
@ -835,6 +1072,18 @@ files = [
{file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"},
]
[[package]]
name = "uritemplate"
version = "4.1.1"
description = "Implementation of RFC 6570 URI Templates"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"},
{file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"},
]
[[package]]
name = "urllib3"
version = "2.0.3"
@ -875,4 +1124,4 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "c9c66d7cf4eb31fdb3b4bb60c157739e9cd4c6f71511a9398705943e5a63fe3c"
content-hash = "f97783e2d795f0b96d6b8d2085f4b8871bc30363f47d22cc659a9108181b4910"

View File

@ -24,6 +24,9 @@ psycopg2 = "^2.9.6"
python-multipart = "^0.0.6"
python-jose = "^3.3.0"
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
google-api-python-client = "^2.90.0"
google-auth-httplib2 = "^0.1.0"
google-auth-oauthlib = "^1.0.0"
[build-system]

View File

@ -2,13 +2,13 @@ import os
from sqlmodel import SQLModel, create_engine, Session
# db_string = "sqlite:///database.sqlite"
db_string = "sqlite:///database.sqlite"
db_string = os.environ.get("DB_OVERRIDES_STRING")
if not db_string:
db_string = f'{os.environ.get("DB_CONNECTION")}://' \
f'{os.environ.get("DB_USERNAME")}:{os.environ.get("DB_PASSWORD", default="")}@' \
f'{os.environ.get("DB_HOST")}:{os.environ.get("DB_PORT")}/{os.environ.get("DB_DATABASE")}'
# db_string = os.environ.get("DB_OVERRIDES_STRING")
# if not db_string:
# db_string = f'{os.environ.get("DB_CONNECTION")}://' \
# f'{os.environ.get("DB_USERNAME")}:{os.environ.get("DB_PASSWORD", default="")}@' \
# f'{os.environ.get("DB_HOST")}:{os.environ.get("DB_PORT")}/{os.environ.get("DB_DATABASE")}'
connect_args = {"check_same_thread": False} if "sqlite" in db_string else {}

View File

@ -1,9 +1,21 @@
from fastapi import FastAPI
from datetime import datetime, timedelta
from typing import List, Optional
from fastapi import FastAPI, Query, Depends, HTTPException, status
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from sqlmodel import SQLModel
from pydantic import BaseModel, Field
from routes import main_router
from google.auth.transport.requests import Request
from google.oauth2 import service_account
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build, Resource
app = FastAPI()
origins = ["*"]
@ -19,3 +31,194 @@ app.add_middleware(
app.mount("/static", StaticFiles(directory="static"), name="static")
app.include_router(router=main_router)
SCOPES = ['https://www.googleapis.com/auth/calendar']
FILE_PATH = 'token.json'
CALENDAR_ID = '926affbbac4e8e6701060f1fec6189162b0b6d246db13d84682749d647af9a1f@group.calendar.google.com'
creds = service_account.Credentials.from_service_account_file(filename=FILE_PATH, scopes=SCOPES)
TITLE_FREE = 'Запись свободна'
COLOR_FREE = '10'
TITLE_BUSY = 'Занято'
COLOR_BUSY = '6'
def get_calendar_service():
with build('calendar', 'v3', credentials=creds) as service:
print("Service created")
yield service
class CalendarDate(SQLModel):
dateTime: str = Field(alias="dateTime")
timeZone: str = Field(alias="timeZone")
date: str | None
class CalendarAttendees(SQLModel):
email: str
response_status: str | None = Field(default=None, alias="responseStatus")
class CalendarEvent(SQLModel):
id: str | None = None
start: CalendarDate
end: CalendarDate
colorId: str | None = None
summary: str | None = None
description: str | None = None
status: str | None = None
attendees: List[CalendarAttendees] | None = None
@app.get('/calendar_events', response_model=List[CalendarEvent])
def get_calendar_events(
lower_bound: datetime = None,
upper_bound: datetime = None,
service: Resource = Depends(get_calendar_service)
):
if lower_bound and upper_bound:
events_result = service.events().list(
calendarId=CALENDAR_ID,
orderBy="startTime",
singleEvents=True,
timeMin=lower_bound.isoformat(),
timeMax=upper_bound.isoformat()
).execute()
elif lower_bound:
events_result = service.events().list(
calendarId=CALENDAR_ID,
orderBy="startTime",
singleEvents=True,
timeMin=lower_bound.isoformat()
).execute()
elif upper_bound:
events_result = service.events().list(
calendarId=CALENDAR_ID,
orderBy="startTime",
singleEvents=True,
timeMax=upper_bound.isoformat()
).execute()
else:
events_result = service.events().list(
calendarId=CALENDAR_ID,
orderBy="startTime",
singleEvents=True
).execute()
events = events_result.get('items', [])
return events
@app.post('/calendar_events')
def create_calendar_event(calendar_event: CalendarEvent, service: Resource = Depends(get_calendar_service)):
# Call the Calendar API
now = datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
print(calendar_event.dict(exclude_unset=True))
events_result = service.events().insert(calendarId=CALENDAR_ID, body=calendar_event.dict(exclude_unset=True)).execute()
return calendar_event
@app.post('/calendar_events/create_slots', response_model=List[CalendarEvent])
def create_calendar_slots(datetime_start: datetime, timezone: str, slot_length_minutes: int, count: int, service: Resource = Depends(get_calendar_service)):
# Call the Calendar API
events = []
batch = service.new_batch_http_request()
for i in range(count):
event = (CalendarEvent(
start=CalendarDate(
dateTime=(datetime_start + timedelta(minutes=slot_length_minutes*i)).isoformat(),
timeZone=timezone
),
end=CalendarDate(
dateTime=(datetime_start + timedelta(minutes=slot_length_minutes * i) + timedelta(minutes=slot_length_minutes)).isoformat(),
timeZone=timezone
),
colorId='10',
summary='Запись свободна'
))
batch.add(service.events().insert(calendarId=CALENDAR_ID, body=event.dict(exclude_unset=True)))
events.append(event)
# events_result = service.events().insert(calendarId=CALENDAR_ID, body=event.dict(exclude_unset=True)).execute()
batch.execute()
return events
@app.post('/calendar_events/mark_busy', response_model=CalendarEvent)
def mark_busy_calendar_slot(
description: str | None = None,
lower_bound: datetime = None,
upper_bound: datetime = None,
service: Resource = Depends(get_calendar_service)
):
events_dict = get_calendar_events(lower_bound=lower_bound, upper_bound=upper_bound, service=service)
events = list(map(lambda x: CalendarEvent(**x), events_dict))
free_slots = list(filter(lambda x: x.summary == TITLE_FREE if x.summary else False, events))
if not free_slots:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Free slot not found")
event = free_slots[0]
event.summary = TITLE_BUSY
event.colorId = COLOR_BUSY
if description:
event.description = description
service.events().update(calendarId=CALENDAR_ID, eventId=event.id, body=event.dict(exclude_unset=True)).execute()
return event
@app.post('/calendar_events/mark_free', response_model=CalendarEvent)
def mark_free_calendar_slot(
lower_bound: datetime = None,
upper_bound: datetime = None,
service: Resource = Depends(get_calendar_service)
):
events_dict = get_calendar_events(lower_bound=lower_bound, upper_bound=upper_bound, service=service)
events = list(map(lambda x: CalendarEvent(**x), events_dict))
busy_slots = list(filter(lambda x: x.summary == TITLE_BUSY if x.summary else False, events))
if not busy_slots:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Busy slot not found")
event = busy_slots[0]
event.summary = TITLE_FREE
event.colorId = COLOR_FREE
service.events().update(calendarId=CALENDAR_ID, eventId=event.id, body=event.dict(exclude_unset=True)).execute()
return event
@app.post('/calendar_events/mark_free/batch', response_model=List[CalendarEvent])
def mark_free_calendar_slots(
lower_bound: datetime = None,
upper_bound: datetime = None,
service: Resource = Depends(get_calendar_service)
):
events_dict = get_calendar_events(lower_bound=lower_bound, upper_bound=upper_bound, service=service)
events = list(map(lambda x: CalendarEvent(**x), events_dict))
busy_slots = list(filter(lambda x: x.summary == TITLE_BUSY if x.summary else False, events))
if not busy_slots:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Busy slot not found")
batch = service.new_batch_http_request()
for event in busy_slots:
event.summary = TITLE_FREE
event.colorId = COLOR_FREE
event.description = ''
batch.add(service.events().update(calendarId=CALENDAR_ID, eventId=event.id, body=event.dict(exclude_unset=True)))
batch.execute()
return busy_slots

View File

@ -7,4 +7,4 @@ from blog.router import router as blog_router
main_router = APIRouter()
# main_router.include_router(router=users_router)
# main_router.include_router(router=products_router)
main_router.include_router(router=blog_router)
# main_router.include_router(router=blog_router)

13
src/token.json Normal file
View File

@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "calendar-test-390701",
"private_key_id": "0c0c4ccf5e4c772638d12d13e60b58538f3341ba",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCuhvclYmgqFCtV\n7ePXy/UrYeej4ny8ty7+iSXF29NRfNOzizdRZkpJuwr1E6PLM+u0SNGrWiHDtNGO\nryh+BaV4Go/+KnqjuH4Tf7ZV9OoySxEvm6dDXw2EXuQCSPTbdA8/WcN9y80mc7JW\nvQKRjcbN/JANq1EtgZGRQY4E4fUDvxezRBw8j7w1y6FmpAJQUl9RE/45L9w7cP1X\nhF2K5Vibgl7fn/oScaOJjxttoz7noLxC7HPxNfQharU9B3e7LBJ86rnDt7g+X2SJ\nrdW7DXLE54Oj4sgNPlCwAivxRkdQQbn8Q/STXd5LzSeVaAYj6Ykv87un60xfp+nn\n/87PXl7ZAgMBAAECggEAHGtDxqWjOpQ1iPTcxgtN1+DwZuz+zNKzZ0/j2Q0g+ELw\nTMCITcvvStmXQNhlh+A41bmJ0seGz1HGpzT5zf4+DImewDogkD+piqP1h+0CpGqO\n2NwVZ3th6G0fNF626HPvS6yNOxMQS95JFaYKILN1F55fGAAOju9rSbuNVFmK8S9M\nDcDEha/NAChT7xFkmv4BcCl79CFvlrImHd/HMIkyCPUyjh8OTaehcnJK/A5DuLn+\n+mcXKLlhkBST4Bq/2fLfWxSqO++O3L0Jc+3ErswQEjc5kqnDyZPPFwjkP8BvIsM4\nbOgIqpXL5EraOZ1DomMKBDKF9tE4JaqVGzDWQ+sKNQKBgQDjLbJJfxqQBGDxfmu+\nBhggryEfe0n9qnvvbZtxwb+IXKkmDDppRZHfK8qjct5FmO1QCpKyLOrGtC7YzxK7\nWOswtPEK70QBZCE5hER/lymq7aiqOoG/tO94WiB0O5xtCWICFv9LoSUc4hBJyBHl\ntneHtg6hHGaeE216ziPk2QLbSwKBgQDEq0KfKU2rr6+IXTiaOXPlMtGUM7SSPSWW\njZh8Nuk4XGvMBWgZJrzQIH2MLX/qYvpnkJJVONupr3SWZ+2GOXSHyt6VhflJ20LC\n5Q+zJ6+j5iKq5GKhCH24FRSdbS9gcwExsw6FAx1bXuiyjBNFpHemQdotS8ikUC1J\nHcM38pmT6wKBgQDgOL37ZIQnGOtF720QBJvTxoZ+uATzZU0lp50AziXoxOv+LZuJ\nQ60SA/rhEALp1mKD2auoSEUBEd4bB2aJmt2nGS+/hyAr71QLnMyu0dfCaQdL3Ksr\nN74Tn4Dgt+VQiS4+ucwILWif9U/2Qo3HmCypubr+sTVnV+16g/NRcA8tuQKBgQCE\nTZHr8KVHslCrs8q4NZ45ug4zXPVEy83VkjvalDYgrEv4XErDYMP0X2cWPiWnUB6U\nPTW0DyP26wnLhO7NNSmnkFpczFv/y3kGE4KUS0ZlRBReUnXnTwcEJ2pO3XzZrYRI\nIuTJpmbBaP+x3Xm5iALV3ccgYbMAls9gOJ1zrciTMQKBgQCHVOOFmhHSMTyqXdeM\nnjHGafUfJFHCDSt4+QPq2a2G59q1bEANTtvVuq+v0xgfvqImVXqtHKRUC5oP7wXk\nQcecRaLhjxNdXhaZwycNi5wggIy64PVF835isrdOQ3N6oJ3JqDRaBSa37xbyEj+H\ntlTKoos6HgXYuRRLoLdxtpyntw==\n-----END PRIVATE KEY-----\n",
"client_email": "calendar-app@calendar-test-390701.iam.gserviceaccount.com",
"client_id": "105991143927033285509",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/calendar-app%40calendar-test-390701.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}