from flask_sqlalchemy import SQLAlchemy from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime from sqlalchemy import func db = SQLAlchemy() # Create the extension object class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) group_id = db.Column(db.Integer, default=0, nullable=False) name = db.Column(db.String(40), unique=True, nullable=False) password_hash = db.Column(db.String(256)) is_admin = db.Column(db.Boolean, default=False) is_approved = db.Column(db.Boolean, default=False) is_private = db.Column(db.Boolean, default=False) is_guest = db.Column(db.Boolean, default=False) def as_dict(self): result = {} for p in ['id','name','is_admin','is_approved','is_private','is_guest']: result[p] = getattr(self, p) return result def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def my_owned_lists(self, with_inactive=False): if with_inactive: return ListOfItems.query.filter_by(owner_user_id=self.id).all() return ListOfItems.query.filter_by(owner_user_id=self.id, is_active=True).all() def all_my_lists(self): result = self.my_owned_lists() for s in Shared.query.filter_by(user_id=self.id).all(): l = ListOfItems.query.filter_by(id=s.listofitem_id, is_active=True).first() if l: result.append(l) return result def all_my_lists_as_dict(self): result = [] for l in self.all_my_lists(): result.append(l.as_dict()) return result def shares_in_list(self, listofitem_id): shared = Shared.query.filter_by(user_id=self.id, listofitem_id=listofitem_id).first() return True if shared else False def owns_list(self, listofitem_id): return ListOfItems.query.filter_by(id=listofitem_id, owner_user_id=self.id).first() is not None def can_access_list(self, listofitem_id): listofitem = ListOfItems.query.filter_by(id=listofitem_id, is_active=True).first() if not listofitem: return False return listofitem.owner_user_id == self.id or self.shares_in_list(listofitem_id) def can_access_item(self, item_id): item = Item.query.get(item_id) return item is not None and self.can_access_list(item.listofitems_id) def set_group_id(self, secret): group = Group.query.filter_by(secret=secret).first() if group: return group.id else: return 0 class ListOfItems(db.Model): __table_args__ = ( db.UniqueConstraint("owner_user_id", "name", name="uq_list_owner_name"), ) id = db.Column(db.Integer, primary_key=True) updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) owner_user_id = db.Column(db.Integer, nullable=False) name = db.Column(db.String(40), nullable=False) is_active = db.Column(db.Boolean, default=False) @classmethod def name_exists_for_owner(cls, owner_user_id, name, exclude_id=None): query = cls.query.filter( cls.owner_user_id == owner_user_id, func.lower(cls.name) == name.strip().lower(), ) if exclude_id is not None: query = query.filter(cls.id != exclude_id) return query.first() is not None def as_dict(self): result = {} for p in ['id','name','owner_user_id','is_active']: result[p] = getattr(self, p) result["pending"] = self.items_left() result["total"] = self.items_total() return result def items_left(self): return len(Item.query.filter_by(listofitems_id=self.id, is_checked=False, is_suggestion=False).all()) def items_total(self): return len(Item.query.filter_by(listofitems_id=self.id, is_suggestion=False).all()) class Item(db.Model): id = db.Column(db.Integer, primary_key=True) updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) listofitems_id = db.Column(db.Integer, nullable=False) label = db.Column(db.String(40), nullable=False) quantity = db.Column(db.Integer, default=0) unit = db.Column(db.String(10)) label_alt1 = db.Column(db.String(40)) label_alt2 = db.Column(db.String(40)) is_checked = db.Column(db.Boolean, default=False) is_suggestion = db.Column(db.Boolean, default=False) category = db.Column(db.String(20)) def as_dict(self): result = {} for p in ['id','listofitems_id','label','quantity','unit','is_checked', 'is_suggestion', 'category']: result[p] = getattr(self, p) return result class Shared(db.Model): user_id = db.Column(db.Integer, primary_key=True) listofitem_id = db.Column(db.Integer, primary_key=True) class Group(db.Model): id = db.Column(db.Integer, primary_key=True) updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) secret = db.Column(db.String(128))