class CampaignGoal(common.ConfigurationModel, common.ActiveMixin, common.MetadataMixin): __tablename__ = 'campaign_goal' predecessor_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign_goal.id'), nullable=True) predecessor = db.relationship('CampaignGoal', uselist=False, backref=db.backref( 'descendant', remote_side="CampaignGoal.id")) campaign = db.relationship('Campaign', backref='goals', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=False) type = db.Column( db.Enum('petition', 'project', 'purchase', name='campaign_goal_type_enum')) purchase = db.relationship('Purchase', backref='campaign_goal', uselist=False, lazy='select') purchase_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('purchase.id'), nullable=True)
class CampaignGoalAssociation(db.Model, common.TrackIPMixin, common.TrackTimeMixin, common.EnabledMixin, common.FieldUpdateMixin): __tablename__ = 'campaign_goal_association' user = db.relationship('User', backref='goals', lazy='select') user_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('user.id'), nullable=False, primary_key=True) campaign = db.relationship('Campaign', backref='goal_associations', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=False, primary_key=True) campaign_goal = db.relationship('CampaignGoal', backref='participants', lazy='select') campaign_goal_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign_goal.id'), nullable=False, primary_key=True) participation = db.Column( db.Enum('opted-in', 'opted-out', 'participating', 'nonparticipating', name='participation_enum')) pledge = db.Column(db.DECIMAL(precision=24, scale=4), nullable=True) __table_args__ = (db.UniqueConstraint(user_id, campaign_id, campaign_goal_id), {})
class User(common.Model, common.IDMixin, common.NullNameMixin, common.EnabledMixin, common.VerifiedMixin, common.SerializationMixin, common.BalanceMixin, common.MetadataMixin): username = db.Column(db.String(40), unique=True, nullable=False) _password = db.Column('password', db.String(64), nullable=False) purchases = db.relationship('Purchase', secondary=UserPurchase, backref='purchasing_user') @property def password(self): return self._password @password.setter def password(self, password): self._password = generate_password_hash(password) @hybrid_property def display_name(self): return self.name or self.username def __init__(self, *args, **kw): super(User, self).__init__(*args, **kw) self.update_field('username', kw.get('username')) password = kw.get('password') if password is not None: self.password = password def is_password(self, password): return check_password_hash(self.password, password) def is_anonymous(self): return False def is_authenticated(self): return True def is_active(self): return self.enabled def get_id(self): return unicode(self.id) @property def primary_email(self): emails = [e.address for e in self.emails if e.primary] if not emails: return return emails[0] def to_dict(self, fields=None): fields = fields or ['username', 'display_name', 'about', 'created', 'modified', 'enabled'] return super(User, self).to_dict(fields=fields)
class Transaction(common.LedgerModel): balance = db.relationship('Balance', backref='transactions', lazy='select') balance_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('balance.id'), nullable=False) campaign_goal = db.relationship('CampaignGoal', backref='purchased_goals', lazy='select') campaign_goal_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign_goal.id'), nullable=True)
class Fee(common.ConfigurationModel): fractional_pct = db.Column(db.DECIMAL(precision=5, scale=4), nullable=False, default=0) flat = db.Column(db.DECIMAL(precision=8, scale=4), nullable=False, default=0) @property def percentage(self): return self.fractional_pct * Decimal('100.0000')
class Invitee(common.UUIDMixin, common.EnabledMixin, common.Model): email = db.Column(db.String(255), nullable=False, index=True) accepted = db.Column(DateTimeTZ, nullable=True) campaign = db.relationship('Campaign', backref='invitees', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=False) user = db.relationship('User', backref='invitations', lazy='select') user_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('user.id'), nullable=True) __table_args__ = (db.UniqueConstraint(campaign_id, email), {})
class CampaignMeta(common.Model, common.EnabledMixin, common.KeyValueMixin): __tablename__ = 'campaign_meta' campaign = db.relationship('Campaign', backref='metadata', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=False)
class ExternalLedger(common.LedgerModel): __tablename__ = 'external_ledger' record_id = db.Column(UUID) record_table = db.Column(db.Enum('transaction', 'exchange', 'transfer', name='record_table_enum'), nullable=False, index=True) processor = db.Column(db.String(255), nullable=False, index=True) reference_number = db.Column(db.String(255), nullable=False, index=True) currency_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('currency.id'), nullable=False) currency = db.relationship('Currency', backref='external_ledger_entries', lazy='select') fee_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('fee.id'), nullable=True) fee = db.relationship('Fee', backref='external_ledger_entries', lazy='select') full_name = db.Column(db.String(255), nullable=True)
class UserMeta(common.Model, common.IDMixin, common.KeyValueMixin): __tablename__ = 'user_meta' user = db.relationship('User', backref='metadata', lazy='select') user_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('user.id'), nullable=False)
class CampaignGoalLedger(common.LedgerModel): __tablename__ = 'campaign_goal_ledger' campaign = db.relationship('Campaign', backref='goals_ledger', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=False) campaign_goal = db.relationship('CampaignGoal', backref='ledger', lazy='select') campaign_goal_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign_goal.id'), nullable=False) party_id = db.Column(db.BigInteger(unsigned=True)) party_type = db.Column(db.Enum( 'user', 'campaign', name='campaign_goal_ledger_target_type_enum'), nullable=False, index=True)
class Exchange(common.LedgerModel): debit_currency_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('currency.id'), nullable=False) debit_currency = db.relationship('Currency', backref='debit_exchanges', lazy='select', primaryjoin="Exchange.debit_currency_id==Currency.id") credit_currency_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('currency.id'), nullable=False) credit_currency = db.relationship('Currency', backref='credit_exchanges', lazy='select', primaryjoin="Exchange.credit_currency_id==Currency.id") exchange_rate = db.Column(db.DECIMAL(precision=24, scale=4), nullable=False) balance = db.relationship('Balance', backref='exchanges', lazy='select') balance_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('balance.id'), nullable=False)
class Currency(common.DisabledMixin, common.Model): title = db.Column(db.String(128)) code = db.Column(db.String(4), index=True) number = db.Column(db.SmallInteger(unsigned=True), index=True) unit = db.Column(db.String(32)) unit_plural = db.Column(db.String(32)) sign = db.Column(db.String(1)) @classmethod def get(cls, code): return cls.query.filter_by(code=code).first() def __repr__(self): return '<Currency %r>' % self.code or self.title
class SlugMixin(object): slug = db.Column(db.String(255), nullable=False, unique=True, index=True)
class UUIDMixin(object): id = db.Column(UUID, primary_key=True, default=uuid)
class NameMixin(object): name = db.Column(db.String(255), nullable=False)
from sqlalchemy.ext.hybrid import hybrid_property from werkzeug.security import generate_password_hash, check_password_hash from pooldlib.postgresql import db, common UserPurchase = db.Table('user_purchase', db.metadata, db.Column('id', db.BigInteger(unsigned=True), primary_key=True), db.Column('user_id', db.BigInteger(unsigned=True), db.ForeignKey('user.id'), nullable=False), db.Column('purchase_id', db.BigInteger(unsigned=True), db.ForeignKey('purchase.id'), nullable=False)) class User(common.Model, common.IDMixin, common.NullNameMixin, common.EnabledMixin, common.VerifiedMixin, common.SerializationMixin, common.BalanceMixin, common.MetadataMixin): username = db.Column(db.String(40), unique=True, nullable=False) _password = db.Column('password', db.String(64), nullable=False) purchases = db.relationship('Purchase', secondary=UserPurchase, backref='purchasing_user') @property def password(self): return self._password @password.setter
class ActiveMixin(EnabledMixin): start = db.Column(DateTimeTZ, index=True) end = db.Column(DateTimeTZ, index=True) @hybrid_property def status(self): if not self.enabled: return 'disabled' now = datetime.utcnow() if self.active_start and self.active_start > now: return 'pending' if self.active_end and self.active_end < now: return 'finished' return 'live' @hybrid_property def is_live(self): return self.status == 'live' @hybrid_property def is_disabled(self): return self.status == 'disabled' @hybrid_property def is_pending(self): return self.status == 'pending' @hybrid_property def is_finished(self): return self.status == 'finished' @classmethod def filter_live(cls, now=None): if now is None: now = datetime.utcnow() query = cls.filter_by(enabled=True) query = query.filter(cls.active_start < now) query = query.filter(cls.active_end > now) return query.order_by(cls.active_start, cls.active_end) @classmethod def filter_finished(cls, now=None): if now is None: now = datetime.utcnow() query = cls.query.filter(cls.active_start < now) query = query.filter(cls.active_end < now) return query.order_by(cls.active_end.desc(), cls.active_start) @classmethod def first_live(cls, *args, **kw): return cls.filter_live(*args, **kw).first() @classmethod def first_finished(cls, *args, **kw): return cls.filter_finished(*args, **kw).first()
class EnabledMixin(object): enabled = db.Column(db.Boolean, nullable=False, default=True)
class NullNameMixin(object): name = db.Column(db.String(255))
class VerifiedMixin(object): verified = db.Column(db.Boolean, nullable=False, default=False)
class Balance(common.Model, common.EnabledMixin): currency_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('currency.id'), nullable=False) currency = db.relationship('Currency', backref='balances') amount = db.Column(db.DECIMAL(precision=24, scale=4), nullable=False, default=0) user_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('user.id'), nullable=True) user = db.relationship('User', backref='balances', lazy='select') campaign_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('campaign.id'), nullable=True) campaign = db.relationship('Campaign', backref='balances', lazy='select') type = db.Column(db.Enum('user', 'campaign', name='balance_type_enum')) @classmethod def filter_by(cls, currency=None, query=None): from pooldlib.postgresql import Currency if hasattr(currency, 'id'): currency = currency.id if not query: query = cls.query if currency and isinstance(currency, basestring): query = query.join(Currency) return query.filter(Currency.code == currency) if currency: return query.filter(cls.currency_id == currency) return query @classmethod def first(cls, *args, **kw): return cls.filter_by(*args, **kw).first() @classmethod def filter_by_user(cls, user=None, currency=None): if hasattr(user, 'id'): user = user.id if not user: return query = cls.query.filter(cls.user_id == user) return super(Balance, cls).filter_by(currency=currency, query=query) @classmethod def filter_by_campaign(cls, campaign=None, currency=None): if hasattr(campaign, 'id'): campaign = campaign.id if not campaign: return query = cls.query.filter(cls.campaign_id == campaign) return super(Balance, cls).filter_by(currency=currency, query=query)
class Purchase(common.NameMixin, common.DescriptionMixin, common.Model): purchase_ledger_id = db.Column(UUID, db.ForeignKey('external_ledger.id'), nullable=False) purchase_ledger = db.relationship('ExternalLedger', backref='purchase', uselist=False, lazy='select', primaryjoin='Purchase.purchase_ledger_id==ExternalLedger.id') fulfilled = db.Column(db.Boolean, default=False) refunded = db.Column(db.Boolean, default=False) refund_ledger_id = db.Column(UUID, db.ForeignKey('external_ledger.id'), nullable=False) refund_ledger = db.relationship('ExternalLedger', backref='refund', uselist=False, lazy='select', primaryjoin='Purchase.refund_ledger_id==ExternalLedger.id') # These should be migrated to a hstore address_one = db.Column(db.String(255)) address_two = db.Column(db.String(255)) city = db.Column(db.String(255)) state = db.Column(db.String(4)) zip = db.Column(db.String(32)) country = db.Column(db.String(255)) email = db.Column(db.String(255), index=True, nullable=False)
class LedgerMixin(object): created = db.Column(DateTimeTZ, default=datetime.utcnow) debit = db.Column(db.DECIMAL(precision=24, scale=4), nullable=True) credit = db.Column(db.DECIMAL(precision=24, scale=4), nullable=True)
class KeyValueMixin(object): key = db.Column(db.String(64), nullable=False, index=True) value = db.Column(db.Text, nullable=False)
class IDMixin(object): id = db.Column(db.BigInteger(unsigned=True), primary_key=True)
class DescriptionMixin(object): description = db.Column(db.Text)
class Transfer(common.LedgerModel): record_id = db.Column(UUID, unique=False, index=True) balance = db.relationship('Balance', backref='transfers', lazy='select') balance_id = db.Column(db.BigInteger(unsigned=True), db.ForeignKey('balance.id'), nullable=False)