calendar test
This commit is contained in:
parent
35d7cffa9a
commit
9243eeb536
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 {}
|
||||
|
||||
|
|
205
src/main.py
205
src/main.py
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
}
|
Loading…
Reference in New Issue