Update FastAPI to 0.98.0 #16

Merged
profitroll merged 3 commits from dev into master 2023-06-23 12:32:47 +03:00
9 changed files with 110 additions and 124 deletions
Showing only changes of commit d688d766da - Show all commits

View File

@ -1,5 +1,6 @@
import re
from os import makedirs, path, rename
from os import makedirs, rename
from pathlib import Path
from shutil import rmtree
from typing import Union
@ -49,9 +50,7 @@ async def album_create(
if col_albums.find_one({"name": name}) is not None:
raise AlbumAlreadyExistsError(name)
makedirs(
path.join("data", "users", current_user.user, "albums", name), exist_ok=True
)
makedirs(Path(f"data/users/{current_user.user}/albums/{name}"), exist_ok=True)
uploaded = col_albums.insert_one(
{"user": current_user.user, "name": name, "title": title, "cover": None}
@ -123,8 +122,8 @@ async def album_patch(
if 2 > len(name) > 20:
raise AlbumIncorrectError("name", "must be >2 and <20 characters.")
rename(
path.join("data", "users", current_user.user, "albums", album["name"]),
path.join("data", "users", current_user.user, "albums", name),
Path(f"data/users/{current_user.user}/albums/{album['name']}"),
Path(f"data/users/{current_user.user}/albums/{name}"),
)
col_photos.update_many(
{"user": current_user.user, "album": album["name"]},
@ -186,8 +185,8 @@ async def album_put(
cover = image["_id"].__str__() if image is not None else None # type: ignore
rename(
path.join("data", "users", current_user.user, "albums", album["name"]),
path.join("data", "users", current_user.user, "albums", name),
Path(f"data/users/{current_user.user}/albums/{album['name']}"),
Path(f"data/users/{current_user.user}/albums/{name}"),
)
col_photos.update_many(
@ -222,6 +221,6 @@ async def album_delete(
col_photos.delete_many({"album": album["name"]})
rmtree(path.join("data", "users", current_user.user, "albums", album["name"]))
rmtree(Path(f"data/users/{current_user.user}/albums/{album['name']}"))
return Response(status_code=HTTP_204_NO_CONTENT)

View File

@ -1,4 +1,4 @@
from os import path
from pathlib import Path
import aiofiles
from fastapi.responses import HTMLResponse, Response
@ -8,27 +8,21 @@ from modules.app import app
@app.get("/pages/matter.css", include_in_schema=False)
async def page_matter():
async with aiofiles.open(
path.join("pages", "matter.css"), "r", encoding="utf-8"
) as f:
async with aiofiles.open(Path("pages/matter.css"), "r", encoding="utf-8") as f:
output = await f.read()
return Response(content=output)
@app.get("/pages/{page}/{file}", include_in_schema=False)
async def page_assets(page: str, file: str):
async with aiofiles.open(
path.join("pages", page, file), "r", encoding="utf-8"
) as f:
async with aiofiles.open(Path(f"pages/{page}/{file}"), "r", encoding="utf-8") as f:
output = await f.read()
return Response(content=output)
@app.get("/", include_in_schema=False)
async def page_home():
async with aiofiles.open(
path.join("pages", "home", "index.html"), "r", encoding="utf-8"
) as f:
async with aiofiles.open(Path("pages/home/index.html"), "r", encoding="utf-8") as f:
output = await f.read()
return HTMLResponse(content=output)
@ -36,7 +30,7 @@ async def page_home():
@app.get("/register", include_in_schema=False)
async def page_register():
async with aiofiles.open(
path.join("pages", "register", "index.html"), "r", encoding="utf-8"
Path("pages/register/index.html"), "r", encoding="utf-8"
) as f:
output = await f.read()
return HTMLResponse(content=output)

View File

@ -1,6 +1,8 @@
import logging
import re
from datetime import datetime, timedelta, timezone
from os import makedirs, path, remove, system
from pathlib import Path
from secrets import token_urlsafe
from shutil import move
from threading import Thread
@ -42,14 +44,18 @@ from modules.security import (
get_current_active_user,
get_user,
)
from modules.utils import configGet, logWrite
from modules.utils import configGet
logger = logging.getLogger(__name__)
async def compress_image(image_path: str):
image_type = Magic(mime=True).from_file(image_path)
if image_type not in ["image/jpeg", "image/png"]:
logWrite(f"Not compressing {image_path} because its mime is '{image_type}'")
logger.info(
"Not compressing %s because its mime is '%s'", image_path, image_type
)
return
size_before = path.getsize(image_path) / 1024
@ -65,12 +71,15 @@ async def compress_image(image_path: str):
return
task.start()
logWrite(f"Compressing '{path.split(image_path)[-1]}'...")
logger.info("Compressing '%s'...", Path(image_path).name)
task.join()
size_after = path.getsize(image_path) / 1024
logWrite(
f"Compressed '{path.split(image_path)[-1]}' from {size_before} Kb to {size_after} Kb"
logger.info(
"Compressed '%s' from %s Kb to %s Kb",
Path(image_path).name,
size_before,
size_after,
)
@ -109,15 +118,11 @@ async def photo_upload(
if col_albums.find_one({"user": current_user.user, "name": album}) is None:
raise AlbumNameNotFoundError(album)
makedirs(
path.join("data", "users", current_user.user, "albums", album), exist_ok=True
)
makedirs(Path(f"data/users/{current_user.user}/albums/{album}"), exist_ok=True)
filename = file.filename
if path.exists(
path.join("data", "users", current_user.user, "albums", album, file.filename)
):
if Path(f"data/users/{current_user.user}/albums/{album}/{file.filename}").exists():
base_name = file.filename.split(".")[:-1]
extension = file.filename.split(".")[-1]
filename = (
@ -125,12 +130,12 @@ async def photo_upload(
)
async with aiofiles.open(
path.join("data", "users", current_user.user, "albums", album, filename), "wb"
Path(f"data/users/{current_user.user}/albums/{album}/{filename}"), "wb"
) as f:
f.write(await file.read())
await f.write(await file.read())
file_hash = await get_phash(
path.join("data", "users", current_user.user, "albums", album, filename)
Path(f"data/users/{current_user.user}/albums/{album}/{filename}")
)
duplicates = await get_duplicates(file_hash, album)
@ -168,7 +173,7 @@ async def photo_upload(
try:
coords = extract_location(
path.join("data", "users", current_user.user, "albums", album, filename)
Path(f"data/users/{current_user.user}/albums/{album}/{filename}")
)
except (UnpackError, ValueError):
coords = {"lng": 0.0, "lat": 0.0, "alt": 0.0}
@ -193,9 +198,7 @@ async def photo_upload(
compress_image,
trigger="date",
run_date=datetime.now() + timedelta(seconds=1),
args=[
path.join("data", "users", current_user.user, "albums", album, filename)
],
args=[Path(f"data/users/{current_user.user}/albums/{album}/{filename}")],
)
return UJSONResponse(
@ -254,8 +257,8 @@ if configGet("media_token_access") is True:
except InvalidId:
raise PhotoNotFoundError(id)
image_path = path.join(
"data", "users", user.user, "albums", image["album"], image["filename"]
image_path = Path(
f"data/users/{user.user}/albums/{image['album']}/{image['filename']}"
)
mime = Magic(mime=True).from_file(image_path)
@ -299,8 +302,8 @@ async def photo_get(
except InvalidId:
raise PhotoNotFoundError(id)
image_path = path.join(
"data", "users", current_user.user, "albums", image["album"], image["filename"]
image_path = Path(
f"data/users/{current_user.user}/albums/{image['album']}/{image['filename']}"
)
mime = Magic(mime=True).from_file(image_path)
@ -335,11 +338,9 @@ async def photo_move(
if col_albums.find_one({"user": current_user.user, "name": album}) is None:
raise AlbumNameNotFoundError(album)
if path.exists(
path.join(
"data", "users", current_user.user, "albums", album, image["filename"]
)
):
if Path(
f"data/users/{current_user.user}/albums/{album}/{image['filename']}"
).exists():
base_name = image["filename"].split(".")[:-1]
extension = image["filename"].split(".")[-1]
filename = (
@ -360,15 +361,10 @@ async def photo_move(
)
move(
path.join(
"data",
"users",
current_user.user,
"albums",
image["album"],
image["filename"],
Path(
f"data/users/{current_user.user}/albums/{image['album']}/{image['filename']}"
),
path.join("data", "users", current_user.user, "albums", album, filename),
Path(f"data/users/{current_user.user}/albums/{album}/{filename}"),
)
return UJSONResponse(
@ -441,13 +437,8 @@ async def photo_delete(
col_albums.update_one({"name": image["album"]}, {"$set": {"cover": None}})
remove(
path.join(
"data",
"users",
current_user.user,
"albums",
image["album"],
image["filename"],
Path(
f"data/users/{current_user.user}/albums/{image['album']}/{image['filename']}"
)
)

View File

@ -1,3 +1,4 @@
import logging
from datetime import datetime, timedelta
from uuid import uuid1
@ -21,7 +22,9 @@ from modules.security import (
get_user,
verify_password,
)
from modules.utils import configGet, logWrite
from modules.utils import configGet
logger = logging.getLogger(__name__)
async def send_confirmation(user: str, email: str):
@ -41,9 +44,11 @@ async def send_confirmation(user: str, email: str):
col_emails.insert_one(
{"user": user, "email": email, "used": False, "code": confirmation_code}
)
logWrite(f"Sent confirmation email to '{email}' with code {confirmation_code}")
logger.info(
"Sent confirmation email to '%s' with code %s", email, confirmation_code
)
except Exception as exp:
logWrite(f"Could not send confirmation email to '{email}' due to: {exp}")
logger.error("Could not send confirmation email to '%s' due to: %s", email, exp)
@app.get("/users/me/", response_model=User)

View File

@ -1,6 +1,7 @@
import re
from datetime import datetime, timezone
from os import makedirs, path, remove
from os import makedirs, remove
from pathlib import Path
from secrets import token_urlsafe
from shutil import move
from typing import Union
@ -45,15 +46,11 @@ async def video_upload(
if col_albums.find_one({"user": current_user.user, "name": album}) is None:
raise AlbumNameNotFoundError(album)
makedirs(
path.join("data", "users", current_user.user, "albums", album), exist_ok=True
)
makedirs(Path(f"data/users/{current_user.user}/albums/{album}"), exist_ok=True)
filename = file.filename
if path.exists(
path.join("data", "users", current_user.user, "albums", album, file.filename)
):
if Path(f"data/users/{current_user.user}/albums/{album}/{file.filename}").exists():
base_name = file.filename.split(".")[:-1]
extension = file.filename.split(".")[-1]
filename = (
@ -61,7 +58,7 @@ async def video_upload(
)
async with aiofiles.open(
path.join("data", "users", current_user.user, "albums", album, filename), "wb"
Path(f"data/users/{current_user.user}/albums/{album}/{filename}"), "wb"
) as f:
await f.write(await file.read())
@ -125,8 +122,8 @@ async def video_get(
except InvalidId:
raise VideoNotFoundError(id)
video_path = path.join(
"data", "users", current_user.user, "albums", video["album"], video["filename"]
video_path = Path(
f"data/users/{current_user.user}/albums/{video['album']}/{video['filename']}"
)
mime = Magic(mime=True).from_file(video_path)
@ -161,11 +158,9 @@ async def video_move(
if col_albums.find_one({"user": current_user.user, "name": album}) is None:
raise AlbumNameNotFoundError(album)
if path.exists(
path.join(
"data", "users", current_user.user, "albums", album, video["filename"]
)
):
if Path(
f"data/users/{current_user.user}/albums/{album}/{video['filename']}"
).exists():
base_name = video["filename"].split(".")[:-1]
extension = video["filename"].split(".")[-1]
filename = (
@ -186,15 +181,10 @@ async def video_move(
)
move(
path.join(
"data",
"users",
current_user.user,
"albums",
video["album"],
video["filename"],
Path(
f"data/users/{current_user.user}/albums/{video['album']}/{video['filename']}"
),
path.join("data", "users", current_user.user, "albums", album, filename),
Path(f"data/users/{current_user.user}/albums/{album}/{filename}"),
)
return UJSONResponse(
@ -264,13 +254,8 @@ async def video_delete(
album = col_albums.find_one({"name": video["album"]})
remove(
path.join(
"data",
"users",
current_user.user,
"albums",
video["album"],
video["filename"],
Path(
f"data/users/{current_user.user}/albums/{video['album']}/{video['filename']}"
)
)

View File

@ -1,5 +1,6 @@
from importlib.util import module_from_spec, spec_from_file_location
from os import getcwd, path, walk
from pathlib import Path
# =================================================================================
@ -12,7 +13,7 @@ def get_py_files(src):
for root, dirs, files in walk(src):
for file in files:
if file.endswith(".py"):
py_files.append(path.join(cwd, root, file))
py_files.append(Path(f"{cwd}/{root}/{file}"))
return py_files
@ -36,7 +37,7 @@ def dynamic_import(module_name, py_path):
def dynamic_import_from_src(src, star_import=False):
my_py_files = get_py_files(src)
for py_file in my_py_files:
module_name = path.split(py_file)[-1][:-3]
module_name = Path(py_file).stem
print(f"Importing {module_name} extension...", flush=True)
imported_module = dynamic_import(module_name, py_file)
if imported_module != None:

View File

@ -1,8 +1,11 @@
import logging
from smtplib import SMTP, SMTP_SSL
from ssl import create_default_context
from traceback import print_exc
from modules.utils import configGet, logWrite
from modules.utils import configGet
logger = logging.getLogger(__name__)
try:
if configGet("use_ssl", "mailer", "smtp") is True:
@ -10,7 +13,7 @@ try:
configGet("host", "mailer", "smtp"),
configGet("port", "mailer", "smtp"),
)
logWrite(f"Initialized SMTP SSL connection")
logger.info("Initialized SMTP SSL connection")
elif configGet("use_tls", "mailer", "smtp") is True:
mail_sender = SMTP(
configGet("host", "mailer", "smtp"),
@ -18,21 +21,21 @@ try:
)
mail_sender.starttls(context=create_default_context())
mail_sender.ehlo()
logWrite(f"Initialized SMTP TLS connection")
logger.info("Initialized SMTP TLS connection")
else:
mail_sender = SMTP(
configGet("host", "mailer", "smtp"), configGet("port", "mailer", "smtp")
)
mail_sender.ehlo()
logWrite(f"Initialized SMTP connection")
logger.info("Initialized SMTP connection")
except Exception as exp:
logWrite(f"Could not initialize SMTP connection to: {exp}")
logger.error("Could not initialize SMTP connection to: %s", exp)
print_exc()
try:
mail_sender.login(
configGet("login", "mailer", "smtp"), configGet("password", "mailer", "smtp")
)
logWrite(f"Successfully initialized mailer")
logger.info("Successfully initialized mailer")
except Exception as exp:
logWrite(f"Could not login into provided SMTP account due to: {exp}")
logger.error("Could not login into provided SMTP account due to: %s", exp)

View File

@ -1,21 +1,18 @@
from traceback import print_exc
import logging
from pathlib import Path
from traceback import format_exc
from typing import Any, Union
from ujson import JSONDecodeError, dumps, loads
# Print to stdout and then to log
def logWrite(message: str, debug: bool = False) -> None:
# save to log file and rotation is to be done
# logAppend(f'{message}', debug=debug)
print(f"{message}", flush=True)
logger = logging.getLogger(__name__)
def jsonLoad(filepath: str) -> Any:
def jsonLoad(filepath: Union[str, Path]) -> Any:
"""Load json file
### Args:
* filepath (`str`): Path to input file
* filepath (`Union[str, Path]`): Path to input file
### Returns:
* `Any`: Some json deserializable
@ -24,32 +21,36 @@ def jsonLoad(filepath: str) -> Any:
try:
output = loads(file.read())
except JSONDecodeError:
logWrite(
f"Could not load json file {filepath}: file seems to be incorrect!\n{print_exc()}"
logger.error(
"Could not load json file %s: file seems to be incorrect!\n%s",
filepath,
format_exc(),
)
raise
except FileNotFoundError:
logWrite(
f"Could not load json file {filepath}: file does not seem to exist!\n{print_exc()}"
logger.error(
"Could not load json file %s: file does not seem to exist!\n%s",
filepath,
format_exc(),
)
raise
file.close()
return output
def jsonSave(contents: Union[list, dict], filepath: str) -> None:
def jsonSave(contents: Union[list, dict], filepath: Union[str, Path]) -> None:
"""Save contents into json file
### Args:
* contents (`Union[list, dict]`): Some json serializable
* filepath (`str`): Path to output file
* filepath (`Union[str, Path]`): Path to output file
"""
try:
with open(filepath, "w", encoding="utf8") as file:
file.write(dumps(contents, ensure_ascii=False, indent=4))
file.close()
except Exception as exp:
logWrite(f"Could not save json file {filepath}: {exp}\n{print_exc()}")
logger.error("Could not save json file %s: %s\n%s", filepath, exp, format_exc())
return
@ -63,7 +64,7 @@ def configGet(key: str, *args: str) -> Any:
### Returns:
* `Any`: Value of provided key
"""
this_dict = jsonLoad("config.json")
this_dict = jsonLoad(Path("config.json"))
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]

View File

@ -1,13 +1,20 @@
from os import makedirs, path
import logging
from os import makedirs
from pathlib import Path
from fastapi.responses import FileResponse
from modules.app import app
from modules.extensions_loader import dynamic_import_from_src
from modules.scheduler import scheduler
from modules.utils import *
makedirs(path.join("data", "users"), exist_ok=True)
makedirs(Path("data/users"), exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="%(name)s.%(funcName)s | %(levelname)s | %(message)s",
datefmt="[%X]",
)
@app.get("/favicon.ico", response_class=FileResponse, include_in_schema=False)