From 8ee107d5a2b34b7bfe4645f1b65cd4fa3ddf85f5 Mon Sep 17 00:00:00 2001 From: Tom Bursch Date: Mon, 21 Oct 2024 19:07:09 +0200 Subject: [PATCH] chore: Improve type hints --- .../shoppinglist/shoppinglist_controller.py | 16 ++-- backend/app/helpers/db_list_type.py | 2 +- backend/app/helpers/db_model_mixin.py | 4 +- backend/app/helpers/timestamp_mixin.py | 14 +++- backend/app/helpers/validate_args.py | 3 +- backend/app/models/association.py | 21 +++--- backend/app/models/category.py | 23 +++--- backend/app/models/challenge_mail_verify.py | 11 +-- .../app/models/challenge_password_reset.py | 11 +-- backend/app/models/expense.py | 45 ++++++------ backend/app/models/expense_category.py | 19 ++--- backend/app/models/file.py | 21 +++--- backend/app/models/history.py | 20 ++--- backend/app/models/household.py | 65 +++++++++-------- backend/app/models/item.py | 29 ++++---- backend/app/models/oidc.py | 27 +++---- backend/app/models/planner.py | 17 +++-- backend/app/models/recipe.py | 73 ++++++++++--------- backend/app/models/recipe_history.py | 17 +++-- backend/app/models/settings.py | 7 +- backend/app/models/shoppinglist.py | 35 ++++----- backend/app/models/tag.py | 17 +++-- backend/app/models/token.py | 33 +++++---- backend/app/models/user.py | 43 +++++------ backend/migrations/versions/6c669d9ec3bd_.py | 2 +- 25 files changed, 301 insertions(+), 274 deletions(-) diff --git a/backend/app/controller/shoppinglist/shoppinglist_controller.py b/backend/app/controller/shoppinglist/shoppinglist_controller.py index 6c5287acd..b9e0616ee 100644 --- a/backend/app/controller/shoppinglist/shoppinglist_controller.py +++ b/backend/app/controller/shoppinglist/shoppinglist_controller.py @@ -115,7 +115,7 @@ def deleteShoppinglist(id): @shoppinglist.route("//item/", methods=["POST", "PUT"]) @jwt_required() @validate_args(UpdateDescription) -def updateItemDescription(args, id, item_id): +def updateItemDescription(args, id: int, item_id: int): con = ShoppinglistItems.find_by_ids(id, item_id) if not con: shoppinglist = Shoppinglist.find_by_id(id) @@ -305,13 +305,13 @@ def addShoppinglistItemByName(args, id): @shoppinglist.route("//item", methods=["DELETE"]) @jwt_required() @validate_args(RemoveItem) -def removeShoppinglistItem(args, id): +def removeShoppinglistItem(args, id: int): shoppinglist = Shoppinglist.find_by_id(id) if not shoppinglist: raise NotFoundRequest() shoppinglist.checkAuthorized() - con = removeShoppinglistItem( + con = removeShoppinglistItemFunc( shoppinglist, args["item_id"], args["removed_at"] if "removed_at" in args else None, @@ -332,14 +332,14 @@ def removeShoppinglistItem(args, id): @shoppinglist.route("//items", methods=["DELETE"]) @jwt_required() @validate_args(RemoveItems) -def removeShoppinglistItems(args, id): +def removeShoppinglistItems(args, id: int): shoppinglist = Shoppinglist.find_by_id(id) if not shoppinglist: raise NotFoundRequest() shoppinglist.checkAuthorized() for arg in args["items"]: - con = removeShoppinglistItem( + con = removeShoppinglistItemFunc( shoppinglist, arg["item_id"], arg["removed_at"] if "removed_at" in arg else None, @@ -357,9 +357,9 @@ def removeShoppinglistItems(args, id): return jsonify({"msg": "DONE"}) -def removeShoppinglistItem( - shoppinglist: Shoppinglist, item_id: int, removed_at: int = None -) -> ShoppinglistItems: +def removeShoppinglistItemFunc( + shoppinglist: Shoppinglist, item_id: int, removed_at: int | None = None +) -> ShoppinglistItems | None: item = Item.find_by_id(item_id) if not item: return None diff --git a/backend/app/helpers/db_list_type.py b/backend/app/helpers/db_list_type.py index 60e95cae0..cb1bd497a 100644 --- a/backend/app/helpers/db_list_type.py +++ b/backend/app/helpers/db_list_type.py @@ -12,7 +12,7 @@ def process_bind_param(self, value, dialect): else: return "[]" - def process_result_value(self, value, dialect) -> set: + def process_result_value(self, value, dialect) -> list: if type(value) is str: return json.loads(value) return list() diff --git a/backend/app/helpers/db_model_mixin.py b/backend/app/helpers/db_model_mixin.py index e3b0d4360..0cfb2f566 100644 --- a/backend/app/helpers/db_model_mixin.py +++ b/backend/app/helpers/db_model_mixin.py @@ -1,9 +1,9 @@ from __future__ import annotations from typing import Self from app import db +from app.helpers.timestamp_mixin import TimestampMixin - -class DbModelMixin(object): +class DbModelMixin(TimestampMixin): def save(self) -> Self: """ Persist changes to current instance in db diff --git a/backend/app/helpers/timestamp_mixin.py b/backend/app/helpers/timestamp_mixin.py index 0ffe4b847..c49fd57a6 100644 --- a/backend/app/helpers/timestamp_mixin.py +++ b/backend/app/helpers/timestamp_mixin.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone -from sqlalchemy import Column, DateTime +from sqlalchemy import DateTime +from sqlalchemy.orm import Mapped, mapped_column class TimestampMixin(object): @@ -8,11 +9,16 @@ class TimestampMixin(object): """ #: Timestamp for when this instance was created in UTC - created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) + created_at: Mapped[datetime] = mapped_column( + DateTime, default=lambda: datetime.now(timezone.utc), nullable=False + ) #: Timestamp for when this instance was last updated in UTC - updated_at = Column( - DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False + updated_at: Mapped[datetime] = mapped_column( + DateTime, + default=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + nullable=False, ) created_at._creation_order = 9998 diff --git a/backend/app/helpers/validate_args.py b/backend/app/helpers/validate_args.py index a5c42572c..f88c95227 100644 --- a/backend/app/helpers/validate_args.py +++ b/backend/app/helpers/validate_args.py @@ -1,10 +1,11 @@ +from marshmallow import Schema from marshmallow.exceptions import ValidationError from app.errors import InvalidUsage from flask import request from functools import wraps -def validate_args(schema_cls): +def validate_args(schema_cls: type[Schema]): def validate(func): @wraps(func) def func_wrapper(*args, **kwargs): diff --git a/backend/app/models/association.py b/backend/app/models/association.py index 6d9b3600d..b5ead8167 100644 --- a/backend/app/models/association.py +++ b/backend/app/models/association.py @@ -1,26 +1,27 @@ from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin +from sqlalchemy.orm import Mapped -class Association(db.Model, DbModelMixin, TimestampMixin): +class Association(db.Model , DbModelMixin): __tablename__ = "association" - id = db.Column(db.Integer, primary_key=True) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) - antecedent_id = db.Column(db.Integer, db.ForeignKey("item.id")) - consequent_id = db.Column(db.Integer, db.ForeignKey("item.id")) - support = db.Column(db.Float) - confidence = db.Column(db.Float) - lift = db.Column(db.Float) + antecedent_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("item.id")) + consequent_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("item.id")) + support: Mapped[float] = db.Column(db.Float) + confidence: Mapped[float] = db.Column(db.Float) + lift: Mapped[float] = db.Column(db.Float) - antecedent = db.relationship( + antecedent: Mapped["Item"] = db.relationship( "Item", uselist=False, foreign_keys=[antecedent_id], back_populates="antecedents", ) - consequent = db.relationship( + consequent: Mapped["Item"] = db.relationship( "Item", uselist=False, foreign_keys=[consequent_id], diff --git a/backend/app/models/category.py b/backend/app/models/category.py index 72ba7ba16..3bc5b4b17 100644 --- a/backend/app/models/category.py +++ b/backend/app/models/category.py @@ -1,23 +1,24 @@ from __future__ import annotations -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class Category(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Category(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "category" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - default = db.Column(db.Boolean, default=False) - default_key = db.Column(db.String(128)) - ordering = db.Column(db.Integer, default=0) - household_id = db.Column( + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + default: Mapped[bool] = db.Column(db.Boolean, default=False) + default_key: Mapped[str] = db.Column(db.String(128)) + ordering: Mapped[int] = db.Column(db.Integer, default=0) + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) - household = db.relationship("Household", uselist=False) - items = db.relationship("Item", back_populates="category") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + items: Mapped[List["Item"]] = db.relationship("Item", back_populates="category") def obj_to_full_dict(self) -> dict: res = super().obj_to_dict() diff --git a/backend/app/models/challenge_mail_verify.py b/backend/app/models/challenge_mail_verify.py index 64a99365e..6697e4e1f 100644 --- a/backend/app/models/challenge_mail_verify.py +++ b/backend/app/models/challenge_mail_verify.py @@ -3,15 +3,16 @@ from typing import Self import uuid from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from app.models.user import User +from sqlalchemy.orm import Mapped -class ChallengeMailVerify(db.Model, DbModelMixin, TimestampMixin): - challenge_hash = db.Column(db.String(256), primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) +class ChallengeMailVerify(db.Model , DbModelMixin): + challenge_hash: Mapped[str] = db.Column(db.String(256), primary_key=True) + user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) - user = db.relationship("User") + user: Mapped["User"] = db.relationship("User") @classmethod def find_by_challenge(cls, challenge: str) -> Self: diff --git a/backend/app/models/challenge_password_reset.py b/backend/app/models/challenge_password_reset.py index 8a4f585e4..506ef05ce 100644 --- a/backend/app/models/challenge_password_reset.py +++ b/backend/app/models/challenge_password_reset.py @@ -4,15 +4,16 @@ from typing import Self import uuid from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from app.models.user import User +from sqlalchemy.orm import Mapped -class ChallengePasswordReset(db.Model, DbModelMixin, TimestampMixin): - challenge_hash = db.Column(db.String(256), primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) +class ChallengePasswordReset(db.Model , DbModelMixin): + challenge_hash: Mapped[str] = db.Column(db.String(256), primary_key=True) + user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) - user = db.relationship("User") + user: Mapped["User"] = db.relationship("User") @classmethod def find_by_challenge(cls, challenge: str) -> Self: diff --git a/backend/app/models/expense.py b/backend/app/models/expense.py index 9132f7f45..c8d0de762 100644 --- a/backend/app/models/expense.py +++ b/backend/app/models/expense.py @@ -1,31 +1,32 @@ from datetime import datetime -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class Expense(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Expense(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "expense" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - amount = db.Column(db.Float()) - date = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) - category_id = db.Column(db.Integer, db.ForeignKey("expense_category.id")) - photo = db.Column(db.String(), db.ForeignKey("file.filename")) - paid_by_id = db.Column(db.Integer, db.ForeignKey("user.id")) - household_id = db.Column( + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + amount: Mapped[float] = db.Column(db.Float()) + date: Mapped[datetime] = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) + category_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("expense_category.id")) + photo: Mapped[str] = db.Column(db.String(), db.ForeignKey("file.filename")) + paid_by_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id")) + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) exclude_from_statistics = db.Column(db.Boolean, default=False, nullable=False) - household = db.relationship("Household", uselist=False) - category = db.relationship("ExpenseCategory") - paid_by = db.relationship("User") - paid_for = db.relationship( + household: Mapped["Household"] = db.relationship("Household", uselist=False) + category: Mapped["ExpenseCategory"] = db.relationship("ExpenseCategory") + paid_by: Mapped["User"] = db.relationship("User") + paid_for: Mapped[List["Household"]] = db.relationship( "ExpensePaidFor", back_populates="expense", cascade="all, delete-orphan" ) - photo_file = db.relationship("File", back_populates="expense", uselist=False) + photo_file: Mapped["File"] = db.relationship("File", back_populates="expense", uselist=False) def obj_to_dict(self) -> dict: res = super().obj_to_dict() @@ -72,15 +73,15 @@ def find_by_id(cls, id) -> Self: ) -class ExpensePaidFor(db.Model, DbModelMixin, TimestampMixin): +class ExpensePaidFor(db.Model , DbModelMixin): __tablename__ = "expense_paid_for" - expense_id = db.Column(db.Integer, db.ForeignKey("expense.id"), primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True) - factor = db.Column(db.Integer()) + expense_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("expense.id"), primary_key=True) + user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True) + factor: Mapped[int] = db.Column(db.Integer()) - expense = db.relationship("Expense", back_populates="paid_for") - user = db.relationship("User", back_populates="expenses_paid_for") + expense: Mapped["Expense"] = db.relationship("Expense", back_populates="paid_for") + user: Mapped["User"] = db.relationship("User", back_populates="expenses_paid_for") def obj_to_user_dict(self): res = self.user.obj_to_dict() diff --git a/backend/app/models/expense_category.py b/backend/app/models/expense_category.py index 7810897ee..e7ec9edf9 100644 --- a/backend/app/models/expense_category.py +++ b/backend/app/models/expense_category.py @@ -1,19 +1,20 @@ from __future__ import annotations -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class ExpenseCategory(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class ExpenseCategory(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "expense_category" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - color = db.Column(db.BigInteger) - household_id = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + color: Mapped[int] = db.Column(db.BigInteger) + household_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) - household = db.relationship("Household", uselist=False) - expenses = db.relationship("Expense", back_populates="category") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + expenses: Mapped[List["Household"]] = db.relationship("Expense", back_populates="category") def obj_to_full_dict(self) -> dict: res = super().obj_to_dict() diff --git a/backend/app/models/file.py b/backend/app/models/file.py index a8fd6d942..49f5b8e6a 100644 --- a/backend/app/models/file.py +++ b/backend/app/models/file.py @@ -5,24 +5,25 @@ from app import db from app.config import UPLOAD_FOLDER from app.errors import ForbiddenRequest -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin from app.models.user import User import os +from sqlalchemy.orm import Mapped -class File(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class File(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "file" - filename = db.Column(db.String(), primary_key=True) - blur_hash = db.Column(db.String(length=40), nullable=True) - created_by = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) + filename: Mapped[str] = db.Column(db.String(), primary_key=True) + blur_hash: Mapped[str] = db.Column(db.String(length=40), nullable=True) + created_by: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) - created_by_user = db.relationship("User", foreign_keys=[created_by], uselist=False) + created_by_user: Mapped["User"] = db.relationship("User", foreign_keys=[created_by], uselist=False) - household = db.relationship("Household", uselist=False) - recipe = db.relationship("Recipe", uselist=False) - expense = db.relationship("Expense", uselist=False) - profile_picture = db.relationship("User", foreign_keys=[User.photo], uselist=False) + household: Mapped["Household"] = db.relationship("Household", uselist=False) + recipe: Mapped["Recipe"] = db.relationship("Recipe", uselist=False) + expense: Mapped["Expense"] = db.relationship("Expense", uselist=False) + profile_picture: Mapped["User"] = db.relationship("User", foreign_keys=[User.photo], uselist=False) def delete(self): """ diff --git a/backend/app/models/history.py b/backend/app/models/history.py index 469237fd4..01526fa46 100644 --- a/backend/app/models/history.py +++ b/backend/app/models/history.py @@ -1,9 +1,9 @@ -from datetime import datetime from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from .shoppinglist import ShoppinglistItems from sqlalchemy import func +from sqlalchemy.orm import Mapped import enum @@ -13,21 +13,21 @@ class Status(enum.Enum): DROPPED = -1 -class History(db.Model, DbModelMixin, TimestampMixin): +class History(db.Model , DbModelMixin): __tablename__ = "history" - id = db.Column(db.Integer, primary_key=True) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) - shoppinglist_id = db.Column(db.Integer, db.ForeignKey("shoppinglist.id")) - item_id = db.Column(db.Integer, db.ForeignKey("item.id")) + shoppinglist_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("shoppinglist.id")) + item_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("item.id")) - item = db.relationship("Item", uselist=False, back_populates="history") - shoppinglist = db.relationship( + item: Mapped["Item"] = db.relationship("Item", uselist=False, back_populates="history") + shoppinglist: Mapped["Shoppinglist"] = db.relationship( "Shoppinglist", uselist=False, back_populates="history" ) - status = db.Column(db.Enum(Status)) - description = db.Column("description", db.String()) + status: Mapped[Status] = db.Column(db.Enum(Status)) + description: Mapped[str] = db.Column("description", db.String()) @classmethod def create_added_without_save(cls, shoppinglist, item, description="") -> Self: diff --git a/backend/app/models/household.py b/backend/app/models/household.py index e3785a9f5..e8e659f1f 100644 --- a/backend/app/models/household.py +++ b/backend/app/models/household.py @@ -1,43 +1,48 @@ -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from app.helpers.db_list_type import DbListType +from sqlalchemy.orm import Mapped -class Household(db.Model, DbModelMixin, TimestampMixin): +class Household(db.Model , DbModelMixin): __tablename__ = "household" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128), nullable=False) - photo = db.Column(db.String(), db.ForeignKey("file.filename")) - language = db.Column(db.String()) - planner_feature = db.Column(db.Boolean(), nullable=False, default=True) - expenses_feature = db.Column(db.Boolean(), nullable=False, default=True) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128), nullable=False) + photo: Mapped[str] = db.Column(db.String(), db.ForeignKey("file.filename")) + language: Mapped[str] = db.Column(db.String()) + planner_feature: Mapped[bool] = db.Column( + db.Boolean(), nullable=False, default=True + ) + expenses_feature: Mapped[bool] = db.Column( + db.Boolean(), nullable=False, default=True + ) - view_ordering = db.Column(DbListType(), default=list()) + view_ordering: Mapped[List] = db.Column(DbListType(), default=list()) - items = db.relationship( + items: Mapped[List["Item"]] = db.relationship( "Item", back_populates="household", cascade="all, delete-orphan" ) - shoppinglists = db.relationship( + shoppinglists: Mapped[List["Shoppinglist"]] = db.relationship( "Shoppinglist", back_populates="household", cascade="all, delete-orphan" ) - categories = db.relationship( + categories: Mapped[List["Category"]] = db.relationship( "Category", back_populates="household", cascade="all, delete-orphan" ) - recipes = db.relationship( + recipes: Mapped[List["Recipe"]] = db.relationship( "Recipe", back_populates="household", cascade="all, delete-orphan" ) - tags = db.relationship( + tags: Mapped[List["Tag"]] = db.relationship( "Tag", back_populates="household", cascade="all, delete-orphan" ) - expenses = db.relationship( + expenses: Mapped[List["Expense"]] = db.relationship( "Expense", back_populates="household", cascade="all, delete-orphan" ) - expenseCategories = db.relationship( + expenseCategories: Mapped[List["ExpenseCategory"]] = db.relationship( "ExpenseCategory", back_populates="household", cascade="all, delete-orphan" ) - member = db.relationship( + member: Mapped[List["HouseholdMember"]] = db.relationship( "HouseholdMember", back_populates="household", cascade="all, delete-orphan" ) photo_file = db.relationship("File", back_populates="household", uselist=False) @@ -49,7 +54,7 @@ def obj_to_dict(self) -> dict: if self.photo_file: res["photo_hash"] = self.photo_file.blur_hash return res - + def obj_to_public_dict(self) -> dict: res = super().obj_to_dict(include_columns=["id", "name", "photo", "language"]) if self.photo_file: @@ -71,21 +76,23 @@ def obj_to_export_dict(self) -> dict: } -class HouseholdMember(db.Model, DbModelMixin, TimestampMixin): +class HouseholdMember(db.Model , DbModelMixin): __tablename__ = "household_member" - household_id = db.Column( + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), primary_key=True ) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True) + user_id: Mapped[int] = db.Column( + db.Integer, db.ForeignKey("user.id"), primary_key=True + ) - owner = db.Column(db.Boolean(), default=False, nullable=False) - admin = db.Column(db.Boolean(), default=False, nullable=False) + owner: Mapped[bool] = db.Column(db.Boolean(), default=False, nullable=False) + admin: Mapped[bool] = db.Column(db.Boolean(), default=False, nullable=False) - expense_balance = db.Column(db.Float(), default=0, nullable=False) + expense_balance: Mapped[float] = db.Column(db.Float(), default=0, nullable=False) - household = db.relationship("Household", back_populates="member") - user = db.relationship("User", back_populates="households") + household: Mapped["Household"] = db.relationship("Household", back_populates="member") + user: Mapped["User"] = db.relationship("User", back_populates="households") def obj_to_user_dict(self) -> dict: res = self.user.obj_to_dict() @@ -121,7 +128,3 @@ def find_by_household(cls, household_id: int) -> list[Self]: @classmethod def find_by_user(cls, user_id: int) -> list[Self]: return cls.query.filter(cls.user_id == user_id).all() - - @classmethod - def find_by_household(cls, household_id: int) -> list[Self]: - return cls.query.filter(cls.household_id == household_id).all() diff --git a/backend/app/models/item.py b/backend/app/models/item.py index 494560e2f..cdc8d30c4 100644 --- a/backend/app/models/item.py +++ b/backend/app/models/item.py @@ -1,33 +1,34 @@ from __future__ import annotations -from typing import Self +from typing import Self, List from sqlalchemy import func from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin from app.models.category import Category from app.util import description_merger +from sqlalchemy.orm import Mapped -class Item(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Item(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "item" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - icon = db.Column(db.String(128), nullable=True) - category_id = db.Column(db.Integer, db.ForeignKey("category.id")) - default = db.Column(db.Boolean, default=False) - default_key = db.Column(db.String(128)) - household_id = db.Column( + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + icon: Mapped[str] = db.Column(db.String(128), nullable=True) + category_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("category.id")) + default: Mapped[bool] = db.Column(db.Boolean, default=False) + default_key: Mapped[str] = db.Column(db.String(128)) + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) - household = db.relationship("Household", uselist=False) - category = db.relationship("Category") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + category: Mapped["Category"] = db.relationship("Category") - recipes = db.relationship( + recipes: Mapped[List["RecipeItems"]] = db.relationship( "RecipeItems", back_populates="item", cascade="all, delete-orphan" ) - shoppinglists = db.relationship( + shoppinglists: Mapped[List["ShoppinglistItems"]] = db.relationship( "ShoppinglistItems", back_populates="item", cascade="all, delete-orphan" ) diff --git a/backend/app/models/oidc.py b/backend/app/models/oidc.py index 51bd23f48..81cf33af8 100644 --- a/backend/app/models/oidc.py +++ b/backend/app/models/oidc.py @@ -2,35 +2,36 @@ from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin +from sqlalchemy.orm import Mapped -class OIDCLink(db.Model, DbModelMixin, TimestampMixin): +class OIDCLink(db.Model , DbModelMixin): __tablename__ = "oidc_link" - sub = db.Column(db.String(256), primary_key=True) - provider = db.Column(db.String(24), primary_key=True) - user_id = db.Column( + sub: Mapped[str] = db.Column(db.String(256), primary_key=True) + provider: Mapped[str] = db.Column(db.String(24), primary_key=True) + user_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("user.id"), nullable=False, index=True ) - user = db.relationship("User", back_populates="oidc_links") + user: Mapped["User"] = db.relationship("User", back_populates="oidc_links") @classmethod def find_by_ids(cls, sub: str, provider: str) -> Self: return cls.query.filter(cls.sub == sub, cls.provider == provider).first() -class OIDCRequest(db.Model, DbModelMixin, TimestampMixin): +class OIDCRequest(db.Model , DbModelMixin): __tablename__ = "oidc_request" - state = db.Column(db.String(256), primary_key=True) - provider = db.Column(db.String(24), primary_key=True) - nonce = db.Column(db.String(256), nullable=False) - redirect_uri = db.Column(db.String(256), nullable=False) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) + state: Mapped[str] = db.Column(db.String(256), primary_key=True) + provider: Mapped[str] = db.Column(db.String(24), primary_key=True) + nonce: Mapped[str] = db.Column(db.String(256), nullable=False) + redirect_uri: Mapped[str] = db.Column(db.String(256), nullable=False) + user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) - user = db.relationship("User", back_populates="oidc_link_requests") + user: Mapped["User"] = db.relationship("User", back_populates="oidc_link_requests") @classmethod def find_by_state(cls, state: str) -> Self: diff --git a/backend/app/models/planner.py b/backend/app/models/planner.py index 0b9c10193..e7f5be499 100644 --- a/backend/app/models/planner.py +++ b/backend/app/models/planner.py @@ -1,21 +1,22 @@ from __future__ import annotations from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class Planner(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Planner(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "planner" - recipe_id = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) - day = db.Column(db.Integer, primary_key=True) - yields = db.Column(db.Integer) - household_id = db.Column( + recipe_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) + day: Mapped[int] = db.Column(db.Integer, primary_key=True) + yields: Mapped[int] = db.Column(db.Integer) + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) - household = db.relationship("Household", uselist=False) - recipe = db.relationship("Recipe", back_populates="plans") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + recipe: Mapped["Recipe"] = db.relationship("Recipe", back_populates="plans") def obj_to_full_dict(self) -> dict: res = self.obj_to_dict() diff --git a/backend/app/models/recipe.py b/backend/app/models/recipe.py index e6c2d87a1..9e404c0d1 100644 --- a/backend/app/models/recipe.py +++ b/backend/app/models/recipe.py @@ -1,46 +1,47 @@ from __future__ import annotations -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin from .item import Item from .tag import Tag from .planner import Planner from random import randint +from sqlalchemy.orm import Mapped -class Recipe(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Recipe(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "recipe" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - description = db.Column(db.String()) - photo = db.Column(db.String(), db.ForeignKey("file.filename")) - time = db.Column(db.Integer) - cook_time = db.Column(db.Integer) - prep_time = db.Column(db.Integer) - yields = db.Column(db.Integer) - source = db.Column(db.String()) - public = db.Column(db.Boolean(), nullable=False, default=False) - suggestion_score = db.Column(db.Integer, server_default="0") - suggestion_rank = db.Column(db.Integer, server_default="0") - household_id = db.Column( + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + description: Mapped[str] = db.Column(db.String()) + photo: Mapped[str] = db.Column(db.String(), db.ForeignKey("file.filename")) + time: Mapped[int] = db.Column(db.Integer) + cook_time: Mapped[int] = db.Column(db.Integer) + prep_time: Mapped[int] = db.Column(db.Integer) + yields: Mapped[int] = db.Column(db.Integer) + source: Mapped[str] = db.Column(db.String()) + public: Mapped[bool] = db.Column(db.Boolean(), nullable=False, default=False) + suggestion_score: Mapped[int] = db.Column(db.Integer, server_default="0") + suggestion_rank: Mapped[int] = db.Column(db.Integer, server_default="0") + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) - household = db.relationship("Household", uselist=False) - recipe_history = db.relationship( + household: Mapped["Household"] = db.relationship("Household", uselist=False) + recipe_history: Mapped[List["RecipeHistory"]] = db.relationship( "RecipeHistory", back_populates="recipe", cascade="all, delete-orphan" ) - items = db.relationship( + items: Mapped[List["RecipeItems"]] = db.relationship( "RecipeItems", back_populates="recipe", cascade="all, delete-orphan", lazy='selectin', order_by="RecipeItems._name", ) - tags = db.relationship( + tags: Mapped[List["RecipeTags"]] = db.relationship( "RecipeTags", back_populates="recipe", cascade="all, delete-orphan", lazy='selectin', order_by="RecipeTags._name", ) - plans = db.relationship( + plans: Mapped[List["Planner"]] = db.relationship( "Planner", back_populates="recipe", cascade="all, delete-orphan", lazy='selectin' ) - photo_file = db.relationship("File", back_populates="recipe", uselist=False, lazy='selectin') + photo_file: Mapped["File"] = db.relationship("File", back_populates="recipe", uselist=False, lazy='selectin') def obj_to_dict(self) -> dict: res = super().obj_to_dict() @@ -169,18 +170,18 @@ def all_by_name_with_filter( ) -class RecipeItems(db.Model, DbModelMixin, TimestampMixin): +class RecipeItems(db.Model , DbModelMixin): __tablename__ = "recipe_items" - recipe_id = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) - item_id = db.Column(db.Integer, db.ForeignKey("item.id"), primary_key=True) - description = db.Column("description", db.String()) - optional = db.Column("optional", db.Boolean) + recipe_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) + item_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("item.id"), primary_key=True) + description: Mapped[str] = db.Column("description", db.String()) + optional: Mapped[bool] = db.Column("optional", db.Boolean) - item = db.relationship("Item", back_populates="recipes", lazy="joined") - recipe = db.relationship("Recipe", back_populates="items") + item: Mapped["Item"] = db.relationship("Item", back_populates="recipes", lazy="joined") + recipe: Mapped["Recipe"] = db.relationship("Recipe", back_populates="items") - _name = db.column_property(db.select(Item.name).where(Item.id == item_id).scalar_subquery()) + _name: Mapped[str] = db.column_property(db.select(Item.name).where(Item.id == item_id).scalar_subquery()) def obj_to_item_dict(self) -> dict: res = self.item.obj_to_dict() @@ -208,16 +209,16 @@ def find_by_ids(cls, recipe_id: int, item_id: int) -> Self: ).first() -class RecipeTags(db.Model, DbModelMixin, TimestampMixin): +class RecipeTags(db.Model , DbModelMixin): __tablename__ = "recipe_tags" - recipe_id = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) - tag_id = db.Column(db.Integer, db.ForeignKey("tag.id"), primary_key=True) + recipe_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("recipe.id"), primary_key=True) + tag_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("tag.id"), primary_key=True) - tag = db.relationship("Tag", back_populates="recipes") - recipe = db.relationship("Recipe", back_populates="tags", lazy="joined") + tag: Mapped["Tag"] = db.relationship("Tag", back_populates="recipes") + recipe: Mapped["Recipe"] = db.relationship("Recipe", back_populates="tags", lazy="joined") - _name = db.column_property(db.select(Tag.name).where(Tag.id == tag_id).scalar_subquery()) + _name: Mapped[str] = db.column_property(db.select(Tag.name).where(Tag.id == tag_id).scalar_subquery()) def obj_to_item_dict(self) -> dict: res = self.tag.obj_to_dict() diff --git a/backend/app/models/recipe_history.py b/backend/app/models/recipe_history.py index 222313c91..802b4a18c 100644 --- a/backend/app/models/recipe_history.py +++ b/backend/app/models/recipe_history.py @@ -1,9 +1,10 @@ from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from .recipe import Recipe from .planner import Planner from sqlalchemy import func +from sqlalchemy.orm import Mapped import enum @@ -13,18 +14,18 @@ class Status(enum.Enum): DROPPED = -1 -class RecipeHistory(db.Model, DbModelMixin, TimestampMixin): +class RecipeHistory(db.Model , DbModelMixin): __tablename__ = "recipe_history" - id = db.Column(db.Integer, primary_key=True) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) - recipe_id = db.Column(db.Integer, db.ForeignKey("recipe.id")) - household_id = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) + recipe_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("recipe.id")) + household_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) - household = db.relationship("Household", uselist=False) - recipe = db.relationship("Recipe", uselist=False, back_populates="recipe_history") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + recipe: Mapped["Recipe"] = db.relationship("Recipe", uselist=False, back_populates="recipe_history") - status = db.Column(db.Enum(Status)) + status: Mapped[Status] = db.Column(db.Enum(Status)) @classmethod def create_added(cls, recipe: Recipe, household_id: int) -> Self: diff --git a/backend/app/models/settings.py b/backend/app/models/settings.py index f025e46af..96f3a5954 100644 --- a/backend/app/models/settings.py +++ b/backend/app/models/settings.py @@ -1,12 +1,13 @@ from typing import Self from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin +from sqlalchemy.orm import Mapped -class Settings(db.Model, DbModelMixin, TimestampMixin): +class Settings(db.Model , DbModelMixin): __tablename__ = "settings" - id = db.Column(db.Integer, primary_key=True, nullable=False) + id: Mapped[int] = db.Column(db.Integer, primary_key=True, nullable=False) @classmethod def get(cls) -> Self: diff --git a/backend/app/models/shoppinglist.py b/backend/app/models/shoppinglist.py index ad0b710a7..bd19bae60 100644 --- a/backend/app/models/shoppinglist.py +++ b/backend/app/models/shoppinglist.py @@ -1,22 +1,23 @@ -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class Shoppinglist(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Shoppinglist(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "shoppinglist" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) - household_id = db.Column( + household_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("household.id"), nullable=False, index=True ) - household = db.relationship("Household", uselist=False) - items = db.relationship("ShoppinglistItems", cascade="all, delete-orphan") + household: Mapped["Household"] = db.relationship("Household", uselist=False) + items: Mapped[List["ShoppinglistItems"]] = db.relationship("ShoppinglistItems", cascade="all, delete-orphan") - history = db.relationship( + history: Mapped[List["History"]] = db.relationship( "History", back_populates="shoppinglist", cascade="all, delete-orphan" ) @@ -30,19 +31,19 @@ def isDefault(self) -> bool: return self.id == self.getDefault(self.household_id).id -class ShoppinglistItems(db.Model, DbModelMixin, TimestampMixin): +class ShoppinglistItems(db.Model , DbModelMixin): __tablename__ = "shoppinglist_items" - shoppinglist_id = db.Column( + shoppinglist_id: Mapped[int] = db.Column( db.Integer, db.ForeignKey("shoppinglist.id"), primary_key=True ) - item_id = db.Column(db.Integer, db.ForeignKey("item.id"), primary_key=True) - description = db.Column("description", db.String()) - created_by = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) + item_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("item.id"), primary_key=True) + description: Mapped[str] = db.Column(db.String) + created_by: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) - item = db.relationship("Item", back_populates="shoppinglists") - shoppinglist = db.relationship("Shoppinglist", back_populates="items") - created_by_user = db.relationship("User", foreign_keys=[created_by], uselist=False) + item: Mapped["Item"] = db.relationship("Item", back_populates="shoppinglists") + shoppinglist: Mapped["Shoppinglist"] = db.relationship("Shoppinglist", back_populates="items") + created_by_user: Mapped["User"] = db.relationship("User", foreign_keys=[created_by], uselist=False) def obj_to_item_dict(self) -> dict: res = self.item.obj_to_dict() diff --git a/backend/app/models/tag.py b/backend/app/models/tag.py index 1601cdd57..c2ffb20db 100644 --- a/backend/app/models/tag.py +++ b/backend/app/models/tag.py @@ -1,18 +1,19 @@ -from typing import Self +from typing import Self, List from app import db -from app.helpers import DbModelMixin, TimestampMixin, DbModelAuthorizeMixin +from app.helpers import DbModelMixin, DbModelAuthorizeMixin +from sqlalchemy.orm import Mapped -class Tag(db.Model, DbModelMixin, TimestampMixin, DbModelAuthorizeMixin): +class Tag(db.Model , DbModelMixin, DbModelAuthorizeMixin): __tablename__ = "tag" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) - household_id = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) + household_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("household.id"), nullable=False) - household = db.relationship("Household", uselist=False) - recipes = db.relationship( + household: Mapped["Household"] = db.relationship("Household", uselist=False) + recipes: Mapped[List["RecipeTags"]] = db.relationship( "RecipeTags", back_populates="tag", cascade="all, delete-orphan" ) diff --git a/backend/app/models/token.py b/backend/app/models/token.py index 09a07096c..a33420433 100644 --- a/backend/app/models/token.py +++ b/backend/app/models/token.py @@ -1,32 +1,33 @@ from __future__ import annotations from datetime import datetime, timezone -from typing import Self, Tuple +from typing import Self, Tuple, List from flask import request from app import db from app.config import JWT_REFRESH_TOKEN_EXPIRES, JWT_ACCESS_TOKEN_EXPIRES from app.errors import UnauthorizedRequest -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from flask_jwt_extended import create_access_token, create_refresh_token, get_jti from app.models.user import User +from sqlalchemy.orm import Mapped -class Token(db.Model, DbModelMixin, TimestampMixin): +class Token(db.Model , DbModelMixin): __tablename__ = "token" - id = db.Column(db.Integer, primary_key=True) - jti = db.Column(db.String(36), nullable=False, index=True) - type = db.Column(db.String(16), nullable=False) - name = db.Column(db.String(), nullable=False) - last_used_at = db.Column(db.DateTime) - refresh_token_id = db.Column(db.Integer, db.ForeignKey("token.id"), nullable=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + jti: Mapped[str] = db.Column(db.String(36), nullable=False, index=True) + type: Mapped[str] = db.Column(db.String(16), nullable=False) + name: Mapped[str] = db.Column(db.String(), nullable=False) + last_used_at: Mapped[datetime] = db.Column(db.DateTime) + refresh_token_id: Mapped[int]= db.Column(db.Integer, db.ForeignKey("token.id"), nullable=True) + user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) - created_tokens = db.relationship( + created_tokens: Mapped[List["Token"]] = db.relationship( "Token", back_populates="refresh_token", cascade="all, delete-orphan" ) - refresh_token = db.relationship("Token", remote_side=[id]) - user = db.relationship("User") + refresh_token: Mapped["Token"] = db.relationship("Token", remote_side=[id]) + user: Mapped["User"] = db.relationship("User") def obj_to_dict(self, skip_columns=None, include_columns=None) -> dict: if skip_columns: @@ -98,7 +99,7 @@ def delete_created_access_tokens(self): @classmethod def create_access_token( cls, user: User, refreshTokenModel: Self - ) -> Tuple[any, Self]: + ) -> Tuple[str, Self]: accesssToken = create_access_token(identity=user) model = cls() model.jti = get_jti(accesssToken) @@ -111,8 +112,8 @@ def create_access_token( @classmethod def create_refresh_token( - cls, user: User, device: str = None, oldRefreshToken: Self = None - ) -> Tuple[any, Self]: + cls, user: User, device: str | None = None, oldRefreshToken: Self | None = None + ) -> Tuple[str, Self]: assert device or oldRefreshToken if oldRefreshToken and ( oldRefreshToken.type != "refresh" diff --git a/backend/app/models/user.py b/backend/app/models/user.py index 49c0dd656..e4f8824cb 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -1,52 +1,53 @@ -from typing import Self +from typing import Self, List from flask_jwt_extended import current_user from app import db -from app.helpers import DbModelMixin, TimestampMixin +from app.helpers import DbModelMixin from app.config import bcrypt +from sqlalchemy.orm import Mapped -class User(db.Model, DbModelMixin, TimestampMixin): +class User(db.Model , DbModelMixin): __tablename__ = "user" - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(128)) - username = db.Column(db.String(256), unique=True, nullable=False, index=True,) - email = db.Column(db.String(256), unique=True, nullable=True, index=True,) - password = db.Column(db.String(256), nullable=True) - photo = db.Column(db.String(), db.ForeignKey("file.filename", use_alter=True)) - admin = db.Column(db.Boolean(), default=False) - email_verified = db.Column(db.Boolean(), default=False) + id: Mapped[int] = db.Column(db.Integer, primary_key=True) + name: Mapped[str] = db.Column(db.String(128)) + username: Mapped[str] = db.Column(db.String(256), unique=True, nullable=False, index=True,) + email: Mapped[str] = db.Column(db.String(256), unique=True, nullable=True, index=True,) + password: Mapped[str] = db.Column(db.String(256), nullable=True) + photo: Mapped[str] = db.Column(db.String(), db.ForeignKey("file.filename", use_alter=True)) + admin: Mapped[bool] = db.Column(db.Boolean(), default=False) + email_verified: Mapped[bool] = db.Column(db.Boolean(), default=False) - tokens = db.relationship( + tokens: Mapped[List["Token"]] = db.relationship( "Token", back_populates="user", cascade="all, delete-orphan" ) - password_reset_challenge = db.relationship( + password_reset_challenge: Mapped[List["ChallengePasswordReset"]] = db.relationship( "ChallengePasswordReset", back_populates="user", cascade="all, delete-orphan" ) - verify_mail_challenge = db.relationship( + verify_mail_challenge: Mapped[List["ChallengeMailVerify"]] = db.relationship( "ChallengeMailVerify", back_populates="user", cascade="all, delete-orphan" ) - households = db.relationship( + households: Mapped[List["HouseholdMember"]] = db.relationship( "HouseholdMember", back_populates="user", cascade="all, delete-orphan" ) - expenses_paid = db.relationship( + expenses_paid: Mapped[List["Expense"]] = db.relationship( "Expense", back_populates="paid_by", cascade="all, delete-orphan" ) - expenses_paid_for = db.relationship( + expenses_paid_for: Mapped[List["ExpensePaidFor"]] = db.relationship( "ExpensePaidFor", back_populates="user", cascade="all, delete-orphan" ) - photo_file = db.relationship( + photo_file: Mapped["File"] = db.relationship( "File", back_populates="profile_picture", foreign_keys=[photo], uselist=False ) - oidc_links = db.relationship( + oidc_links: Mapped[List["OIDCLink"]] = db.relationship( "OIDCLink", back_populates="user", cascade="all, delete-orphan" ) - oidc_link_requests = db.relationship( + oidc_link_requests: Mapped[List["OIDCRequest"]] = db.relationship( "OIDCRequest", back_populates="user", cascade="all, delete-orphan" ) @@ -59,9 +60,9 @@ def set_password(self, password: str): def obj_to_dict( self, - include_email: bool = False, skip_columns: list[str] | None = None, include_columns: list[str] | None = None, + include_email: bool = False, ) -> dict: if skip_columns: skip_columns = skip_columns + ["password"] diff --git a/backend/migrations/versions/6c669d9ec3bd_.py b/backend/migrations/versions/6c669d9ec3bd_.py index 9079bdcc5..5f634220e 100644 --- a/backend/migrations/versions/6c669d9ec3bd_.py +++ b/backend/migrations/versions/6c669d9ec3bd_.py @@ -44,7 +44,7 @@ class Item(DeclarativeBase): class Planner(DeclarativeBase): __tablename__ = 'planner' recipe_id = sa.Column(sa.Integer, primary_key=True) - day = db.Column(db.Integer, primary_key=True) + day = sa.Column(db.Integer, primary_key=True) household_id = sa.Column(sa.Integer, sa.ForeignKey('household.id'), nullable=True) class Recipe(DeclarativeBase):