Exemplo n.º 1
0
class RecipeCuisine(db.Model):
    """Association Table for many-to-many relationships for recipes and cuisines"""

    __tablename__ = "recipe_cuisines"
    __table_args__ = (db.UniqueConstraint("recipe_id",
                                          "cuisine_id",
                                          name="_recipe_cuisine_constraint"), )
    """Columns"""
    # Parent
    recipe_id = db.Column(db.Integer,
                          db.ForeignKey("recipes.id"),
                          primary_key=True,
                          nullable=False)
    # Child
    cuisine_id = db.Column(db.Integer,
                           db.ForeignKey("cuisines.id"),
                           primary_key=True,
                           nullable=False)
    """Relationships"""
    # Parent
    recipe = db.relationship("Recipe", back_populates="recipe_cuisines")
    # Child
    cuisine = db.relationship("Cuisine",
                              back_populates="recipes",
                              lazy="joined")

    def __init__(self, cuisine=None, recipe=None):
        """Called when appending Cuisine objects to Recipe objects, child used as first arg"""
        self.cuisine = cuisine
        self.recipe = recipe

    def __repr__(self):
        return f"<RecipeCuisine - {self.cuisine.name}/{self.recipe.name}>"
Exemplo n.º 2
0
class UserRole(db.Model):
    __tablename__ = "user_roles"
    __table_args__ = (db.UniqueConstraint("user_id",
                                          "role_id",
                                          name="_user_role_constraint"), )
    """Primary Keys"""
    # Parent
    user_id = db.Column(db.Integer,
                        db.ForeignKey("users.id"),
                        primary_key=True,
                        nullable=False)
    # Child
    role_id = db.Column(db.Integer,
                        db.ForeignKey("roles.id"),
                        primary_key=True,
                        nullable=False)
    """Relationships"""
    # Parent
    user = db.relationship("User", back_populates="user_roles")
    # Child
    role = db.relationship("Role", back_populates="users", lazy="joined")

    def __init__(self, role=None, user=None):
        self.role = role
        self.user = user

    def __repr__(self):
        return f"<UserRole - {self.user.username} has role {self.role.name}>"
Exemplo n.º 3
0
class RecipeDietType(db.Model):
    __tablename__ = "recipe_diet_types"
    __table_args__ = (db.UniqueConstraint(
        "recipe_id", "diet_type_id", name="_recipe_diet_type_constraint"), )
    """Primary Keys"""
    # Parent
    recipe_id = db.Column(db.Integer,
                          db.ForeignKey("recipes.id"),
                          primary_key=True,
                          nullable=False)
    # Child
    diet_type_id = db.Column(db.Integer,
                             db.ForeignKey("diet_types.id"),
                             primary_key=True,
                             nullable=False)
    """Relationships"""
    # Parent
    recipe = db.relationship("Recipe", back_populates="recipe_diet_types")
    # Child
    diet_type = db.relationship("DietType",
                                back_populates="recipes",
                                lazy="joined")

    def __init__(self, diet_type=None, recipe=None):
        """Called when appending DietType objects to Recipe objects, child used as first arg"""
        self.diet_type = diet_type
        self.recipe = recipe

    def __repr__(self):
        return f"<RecipeDietType - {self.recipe.name} / {self.diet_type.name}>"
Exemplo n.º 4
0
class RecipeTag(db.Model):
    __tablename__ = "recipe_tags"
    __table_args__ = (db.UniqueConstraint("recipe_id",
                                          "tag_id",
                                          name="_recipe_tag_constraint"), )
    """Columns"""
    recipe_id = db.Column(db.Integer,
                          db.ForeignKey("recipes.id"),
                          primary_key=True,
                          nullable=False)
    tag_id = db.Column(db.Integer,
                       db.ForeignKey("tags.id"),
                       primary_key=True,
                       nullable=False)
    """Relationships"""
    recipe = db.relationship("Recipe", back_populates="tags")
    tag = db.relationship("Tag", back_populates="recipes")

    def __repr__(self):
        return f"<RecipeTag {self.tag.name} on {self.recipe.name}>"
Exemplo n.º 5
0
class ShoppingList(db.Model):
    __tablename__ = "shopping_lists"
    """Primary Keys"""
    household_id = db.Column(db.Integer,
                             db.ForeignKey("households.id"),
                             primary_key=True,
                             nullable=False)
    ingredient_id = db.Column(db.Integer,
                              db.ForeignKey("ingredients.id"),
                              primary_key=True,
                              nullable=False)
    """Relationships"""
    ingredient = db.relationship("Ingredient", lazy="joined")
    household = db.relationship("Household",
                                back_populates="shopping_list_items")
    """Extra Data"""
    time_created = db.Column(db.DateTime,
                             default=func.now(),
                             server_default=func.now())
    time_updated = db.Column(db.DateTime, onupdate=func.now())
    time_removed = db.Column(db.DateTime)
    still_needed = db.Column(db.Boolean, default=True)

    def __init__(self, ingredient=None, household=None):
        self.ingredient = ingredient
        self.household = household
Exemplo n.º 6
0
class RecipeIngredient(db.Model):
    """Association object for recipe ingredients"""

    __tablename__ = "recipe_ingredients"

    """
    This constraint was causing issues on recipe import for recipes that had (for example) "lime" and "lime seasoning".
    Both were assigned the same Spoonacular ID, which caused db issues while assigning recipe ingredients. Removing for
    now.
    """
    # __table_args__ = (
    #     db.UniqueConstraint(
    #         "recipe_id",
    #         "ingredient_id",
    #         "original_string",
    #         name="_recipe_ingredient_uix",
    #     ),
    # )

    """Primary Keys"""
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    recipe_id = db.Column(
        db.Integer, db.ForeignKey("recipes.id"), primary_key=False, nullable=False
    )
    ingredient_id = db.Column(
        db.Integer, db.ForeignKey("ingredients.id"), primary_key=False, nullable=False
    )

    """Original Strings
    
    In the Spoonacular response, it grabs the original ingredient string from the recipe, which
    can contain special formatting. For display purposes, this is stored in this table
    """
    original_string = db.Column(db.String)

    """Quantities"""
    amount = db.Column(db.Float)
    unit = db.Column(db.String)
    us_amount = db.Column(db.Float)
    us_unit_short = db.Column(db.String)
    us_unit_long = db.Column(db.String)
    metric_amount = db.Column(db.Float)
    metric_unit_short = db.Column(db.String)
    metric_unit_long = db.Column(db.String)

    """Nutrition"""
    caffeine = db.Column(db.Float, default=0.0)
    calcium = db.Column(db.Float, default=0.0)
    calories = db.Column(db.Float, default=0.0)
    carbohydrates = db.Column(db.Float, default=0.0)
    cholesterol = db.Column(db.Float, default=0.0)
    choline = db.Column(db.Float, default=0.0)
    copper = db.Column(db.Float, default=0.0)
    fat = db.Column(db.Float, default=0.0)
    fiber = db.Column(db.Float, default=0.0)
    folate = db.Column(db.Float, default=0.0)
    folic_acid = db.Column(db.Float, default=0.0)
    iron = db.Column(db.Float, default=0.0)
    magnesium = db.Column(db.Float, default=0.0)
    manganese = db.Column(db.Float, default=0.0)
    mono_unsaturated_fat = db.Column(db.Float, default=0.0)
    net_carbohydrates = db.Column(db.Float, default=0.0)
    phosphorous = db.Column(db.Float, default=0.0)
    poly_unsaturated_fat = db.Column(db.Float, default=0.0)
    potassium = db.Column(db.Float, default=0.0)
    protein = db.Column(db.Float, default=0.0)
    saturated_fat = db.Column(db.Float, default=0.0)
    selenium = db.Column(db.Float, default=0.0)
    sodium = db.Column(db.Float, default=0.0)
    sugar = db.Column(db.Float, default=0.0)
    vitamin_a = db.Column(db.Float, default=0.0)
    vitamin_b1 = db.Column(db.Float, default=0.0)
    vitamin_b12 = db.Column(db.Float, default=0.0)
    vitamin_b2 = db.Column(db.Float, default=0.0)
    vitamin_b3 = db.Column(db.Float, default=0.0)
    vitamin_b5 = db.Column(db.Float, default=0.0)
    vitamin_b6 = db.Column(db.Float, default=0.0)
    vitamin_c = db.Column(db.Float, default=0.0)
    vitamin_d = db.Column(db.Float, default=0.0)
    vitamin_e = db.Column(db.Float, default=0.0)
    vitamin_k = db.Column(db.Float, default=0.0)
    zinc = db.Column(db.Float, default=0.0)

    """Glycemic Information"""
    glycemic_index = db.Column(db.Float, default=0.0)
    glycemic_load = db.Column(db.Float, default=0.0)

    """Cost Information"""
    estimated_cost_cents = db.Column(db.Float, default=0.0)

    """Relationships"""
    recipe = db.relationship("Recipe", back_populates="ingredients")
    ingredient = db.relationship("Ingredient", back_populates="recipes")

    def __repr__(self):
        return f"<RecipeIngredient {self.ingredient.name} in {self.recipe.name}>"

    def __setitem__(self, key, value):
        setattr(self, key, value)

    def __getitem__(self, key):
        return getattr(self, key)
Exemplo n.º 7
0
class User(PkModel, TimestampMixin, LookupByNameMixin):
    """Basic user model"""

    __tablename__ = "users"
    """Columns"""
    # id
    # time_created
    # time_updated
    username = db.Column(db.String, unique=True, nullable=False)
    email = db.Column(db.String, unique=True, nullable=False)
    _password = db.Column("password", db.String, nullable=False)
    active = db.Column(db.Boolean, default=True)
    first_name = db.Column(db.String)
    last_name = db.Column(db.String)
    birthday = db.Column(db.Date)
    height_inches = db.Column(db.Float)
    weight_lbs = db.Column(db.Float)
    gender = db.Column(db.Enum("male", "female", name="gender_enum"))
    """Relationships"""
    tags = relationship("Tag", back_populates="user")
    household = relationship("Household", back_populates="users")
    household_id = reference_col("households")

    user_roles = relationship("UserRole",
                              back_populates="user",
                              cascade="all, delete-orphan")
    roles = association_proxy("user_roles", "role")

    @hybrid_property
    def password(self):
        return self._password

    @password.setter
    def password(self, value):
        self._password = pwd_context.hash(value)

    # Register a callback function that takes whatever object is passed in as the
    # identity when creating JWTs and converts it to a JSON serializable format.
    @staticmethod
    @jwt_ext.user_identity_loader
    def user_identity_lookup(user):
        return {
            "id": user.id,
            "username": user.username,
            "email": user.email,
            "household_id": user.household_id,
        }

    # Register a callback function that loads a user from your database whenever
    # a protected route is accessed. This should return any python object on a
    # successful lookup, or None if the lookup failed for any reason (for example
    # if the user has been deleted from the database).
    @staticmethod
    @jwt_ext.user_lookup_loader
    def user_lookup_callback(_jwt_header, jwt_data):
        identity = jwt_data["sub"]
        return User.query.filter_by(id=identity["id"]).one_or_none()

    def has_role(self, role):
        return role in self.roles

    def __init__(self, *args, **kwargs):
        super().__init__(**kwargs)
        if len(self.roles) == 0:
            # TODO add default roles!
            pass

    def __repr__(self):
        return "<User %s>" % self.username

    def get_access_token(self):
        jwt = create_access_token(identity=self,
                                  additional_claims=self.additional_claims)
        return jwt

    def get_refresh_token(self):
        jwt = create_refresh_token(identity=self,
                                   additional_claims=self.additional_claims)
        return jwt

    @property
    def additional_claims(self):
        return {"roles": [r.name for r in self.roles]}

    @property
    def age(self) -> int:
        if self.birthday is None:
            return None
        today = date.today()
        age = (today.year - self.birthday.year -
               ((today.month, today.day) <
                (self.birthday.month, self.birthday.day)))
        return age

    def get_password_reset_token(self, expires_in: int = 3600):
        return encode_jwt(
            {
                "reset_password": self.id,
                "exp": time() + expires_in
            },
            current_app.config["SECRET_KEY"],
            algorithm=current_app.config["JWT_ALGORITHM"],
        )

    @classmethod
    def verify_password_reset_token(cls, token):
        user = None
        try:
            token_data = decode_jwt(
                token,
                current_app.config["SECRET_KEY"],
                algorithms=[current_app.config["JWT_ALGORITHM"]],
            )
            user_id = token_data["reset_password"]
            user = cls.get_by_id(user_id)
        except InvalidTokenError as ite:
            current_app.logger.error(
                f"Someone is trying to use an invalid token to reset a user password!\n{str(ite)}"
            )

        return user