class Order(db.Model, JSONSerialize): __tablename__ = "ORDER" __public__ = ("oid", "uid", "pkg_name", "quantity", "currency", "status", "billing_id", "total_price", "total_charged", "order_date", "item", "billing") oid = db.Column(db.Integer, primary_key=True) uid = db.Column(db.Integer, db.ForeignKey("USER.uid", ondelete="CASCADE")) pkg_name = db.Column(db.String(200), db.ForeignKey("ITEM.pkg_name")) billing_id = db.Column(db.Integer, db.ForeignKey("BILLING_INFO.bid")) quantity = db.Column(db.Integer, default=1, nullable=False) currency = db.Column(db.String(3), default="USD", nullable=False) total_price = db.Column(db.Float) # If total_charged is NULL, then the order is not complete, user did't pay # or the payment failed status = db.Column(db.Integer, default=OrderStatus.OrderPlaced, nullable=False) total_charged = db.Column(db.Float, nullable=True) order_date = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) item = db.relationship(Item) billing = db.relationship(BillingInfo) def __repr__(self): return "<Order: UserID '%r' Item '%r' Quantity %r Total %r>" %\ (self.uid, self.pkg_name, self.quantity, self.total_price)
class Banner(db.Model, JSONSerialize): __tablename__ = 'BANNER' __public__ = ('banner_id', 'item', 'item_id', 'banner_assets_path') banner_id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True) item_id = db.Column(db.Integer, db.ForeignKey('ITEM.iid'), nullable=False) item = db.relationship(Item)
class VIPUsers(db.Model): __tablename__ = "VIPUSERS" __public__ = ('vip_email') vip_email = db.Column(db.String(), primary_key=True, unique=True, nullable=False)
class Review(db.Model, JSONSerialize): __tablename__ = "REVIEW" __public__ = ("rid", "uid", "iid", "title", "content", "rating", "add_date", "user.fullname", "item.display_name") rid = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True) uid = db.Column(db.Integer, db.ForeignKey("USER.uid")) iid = db.Column(db.Integer, db.ForeignKey("ITEM.iid")) rating = db.Column(db.Integer, nullable=False) title = db.Column(db.String(50), nullable=False) content = db.Column(db.String(500), nullable=False) add_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) user = db.relationship("User", back_populates="reviews") item = db.relationship("Item", back_populates="reviews") def __repr__(self): package_name = 'none' rating = 'none' if self != None and self.item != None and self.item.pkg_name != None: package_name = self.item.pkg_name if self != None and self.rating != None: rating = self.rating return "<Review of item '%r' rating %r>" % (package_name, rating)
class Category(db.Model, JSONSerialize): __tablename__ = "CATEGORY" __table_args = {"extend_existing": True} __public__ = ("cid", "parent_id", "name", "description", "items") reservedNames = ["featured"] cid = db.Column(db.Integer, primary_key=True, nullable=False) parent_id = db.Column(db.Integer, db.ForeignKey("CATEGORY.cid")) name = db.Column(db.String(100), nullable=False) description = db.Column(db.String(2000)) children = db.relationship( "Category", backref=db.backref("parent", remote_side=[cid]), ) items = db.relationship("Item", secondary=association_table, backref=db.backref('categories', lazy='dynamic'), lazy='dynamic') def __repr__(self): return "<Category '%r'>" % (self.name)
class Device(db.Model, JSONSerialize): __tablename__ = "DEVICE" __public__ = ("dev_id", "uid", "device_name", "IMEI", "UDID", "model") dev_id = db.Column(db.Integer, nullable=False, primary_key=True) uid = db.Column(db.Integer, db.ForeignKey('USER.uid', ondelete="CASCADE")) device_name = db.Column(db.String(200), nullable=False) IMEI = db.Column(db.String(100), nullable=False) UDID = db.Column(db.String(200), nullable=False) model = db.Column(db.String(100), nullable=False) def __repr__(self): return "<Device '%r': %r>" % (self.device_name, self.owner)
class User(db.Model, JSONSerialize): __tablename__ = 'USER' __public__ = ("uid", "email", "fullname", "age", "role", "author_identifier") uid = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True) email = db.Column(db.String(200), nullable=False, unique=True) password = db.Column(db.String(200), nullable=False) fullname = db.Column(db.String(200), nullable=False) age = db.Column(db.Integer, default=0, nullable=True) author_identifier = db.Column(db.String(100), nullable=True) # Account status,e.g. registered, activated, suspended etc status = db.Column(db.Integer, nullable=False, default=AccountStatus.PendingConfirmation) # The key for various encryption use # Account role/group for privilege checking role = db.Column(db.Integer, default=UserRole.User, nullable=False) private_key = db.Column(db.String(), nullable=False) # User profile image keypath profile_image_s3_keypath = db.Column(db.String(), nullable=True) secondary_email = db.Column(db.String(), nullable=True) summary = db.Column(db.String(), nullable=True) twitter = db.Column(db.String(), nullable=True) # The Stripe customer token for this user object stripe_customer_token = db.Column(db.String(100), nullable=True) # One to many relationship, if the user is deleted, all devices # registered under the account are deleted as well devices = db.relationship(Device, backref="owner", cascade="all,delete-orphan") billing_methods = db.relationship(BillingInfo, lazy="dynamic", backref="owner", cascade="all,delete-orphan") items = db.relationship(Item, backref="author", passive_deletes="all") orders = db.relationship(Order, lazy="dynamic", backref="user", cascade="all,delete-orphan") wishlist = db.relationship("WishList", lazy='dynamic') reviews = db.relationship(Review, back_populates="user") def __repr__(self): return "<User %r(%r uid=%r)>" % (self.fullname, self.email, self.uid) def get_or_create_stripe_customer_obj(self): stripe.api_key = app.config.get("STRIPE_API_KEY") try: return stripe.Customer.retrieve(self.stripe_customer_token) except Exception: # Stripe customer not found, create new customer stripe_customer_token = stripe.Customer.create( description=self.fullname, email=self.email) with db_scoped_session() as se: se.query(User).filter_by(uid=self.uid).update( {"stripe_customer_token": stripe_customer_token.id}) se.commit() return stripe_customer_token
from imods import db from imods.models.mixin import JSONSerialize association_table = db.Table( 'ITEM_CATEGORY_ASSOC', db.Column('category_id', db.Integer, db.ForeignKey('CATEGORY.cid')), db.Column('item_id', db.Integer, db.ForeignKey('ITEM.iid'))) class Category(db.Model, JSONSerialize): __tablename__ = "CATEGORY" __table_args = {"extend_existing": True} __public__ = ("cid", "parent_id", "name", "description", "items") reservedNames = ["featured"] cid = db.Column(db.Integer, primary_key=True, nullable=False) parent_id = db.Column(db.Integer, db.ForeignKey("CATEGORY.cid")) name = db.Column(db.String(100), nullable=False) description = db.Column(db.String(2000)) children = db.relationship( "Category", backref=db.backref("parent", remote_side=[cid]), ) items = db.relationship("Item", secondary=association_table, backref=db.backref('categories', lazy='dynamic'), lazy='dynamic')
class BillingInfo(db.Model, JSONSerialize): __tablename__ = "BILLING_INFO" __public__ = ("bid", "uid", "address", "zipcode", "city", "state", "country", "type_") bid = db.Column(db.Integer, primary_key=True, nullable=False) uid = db.Column(db.Integer, db.ForeignKey('USER.uid')) address = db.Column(db.String(200), nullable=False) zipcode = db.Column(db.Integer, nullable=False) city = db.Column(db.String(100), nullable=False) state = db.Column(db.String(100), nullable=False) country = db.Column(db.String(100), nullable=False) type_ = db.Column(db.String(200), default=BillingType.creditcard, nullable=False) cc_no = db.Column(db.String(100), nullable=True) cc_expr = db.Column(db.Date, nullable=True) cc_name = db.Column(db.String(200), nullable=True) stripe_card_token = db.Column(db.String(100), nullable=True) paypal_refresh_token = db.Column(db.String(), nullable=True) def __repr__(self): # Don't print out any information other than billing type return "<Billing Type:%r>" % (self.type_) def get_public(self, *args, **kwargs): result = super(BillingInfo, self).get_public(*args, **kwargs) if result.get('cc_no'): result['cc_no'] = self.cc_no[-4:] return result def get_or_create_stripe_card_obj(self, cvc=None): from imods.models import User stripe.api_key = app.config.get("STRIPE_API_KEY") user = User.query.get(self.uid) customer = user.get_or_create_stripe_customer_obj() try: return customer.cards.retrieve(self.stripe_card_token) except: stripe_card_token = customer.cards.create( card={ "number": self.cc_no, "exp_month": self.cc_expr.month, "exp_year": self.cc_expr.year, "cvc": cvc }) with db_scoped_session() as se: se.query(BillingInfo).filter_by(bid=self.bid).update( {"stripe_card_token": stripe_card_token.id}) se.commit() return stripe_card_token
class WishList(db.Model): __tablename__ = "WISHLIST" uid = db.Column(db.Integer, db.ForeignKey('USER.uid'), primary_key=True) iid = db.Column(db.Integer, db.ForeignKey('ITEM.iid'), primary_key=True) item = db.relationship("Item")
class Item(db.Model, JSONSerialize): __tablename__ = "ITEM" __public__ = ("iid", "category_id", "author_id", "pkg_name", "display_name", "pkg_version", "pkg_assets_path", "price", "summary", "description", "add_date", "last_update_date", "pkg_dependencies", "pkg_conflicts", "pkg_predepends", "type", "changelog") iid = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True) # author_id can be NULL because an item may be from a foreign source, # e.g. libc is standard c library and the author may not be present in # the database, so the author_id should be NULL # TODO: We may add a default author and assign all orhpan items to # that author author_id = db.Column(db.String(100), db.ForeignKey("USER.author_identifier"), unique=True) pkg_name = db.Column(db.String(200), unique=True, nullable=False) display_name = db.Column(db.String(100), nullable=False) pkg_version = db.Column(db.String(100), nullable=False) pkg_signature = db.Column(db.String()) pkg_path = db.Column(db.String()) pkg_assets_path = db.Column(db.String()) pkg_dependencies = db.Column(db.String()) pkg_conflicts = db.Column(db.String()) pkg_predepends = db.Column(db.String()) price = db.Column(db.Float(), default=0.0, nullable=False) summary = db.Column(db.String(500)) description = db.Column(db.String()) changelog = db.Column(db.String()) status = db.Column(db.Integer(), server_default=text('1')) type = db.Column(db.String()) downloads = db.Column(db.Integer(), server_default=text('0')) # The content of the control file of a debian package control = db.Column(db.String()) # Here we handle datetime at ORM level, because some databases don't handle # it well, and often cause problems. add_date = db.Column(db.Date(), default=datetime.utcnow, nullable=False) last_update_date = db.Column(db.Date(), default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) reviews = db.relationship(Review, back_populates="item", cascade="all, delete-orphan") def dependencies(self): return "<Dependencies: %r>" % (self.pkg_dependencies) def __repr__(self): return "<Item '%r'-%r by %r>" % (self.pkg_name, self.pkg_version, self.author_id) def __hash__(self): return self.iid