class User(UserMixin, db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True, autoincrement=True) first_name = db.Column(db.String(128), nullable=False) last_name = db.Column(db.String(128), nullable=False) email = db.Column(db.String(128), nullable=False, unique=True) password = db.Column(db.String(128), nullable=False) image = db.Column(db.String(128), nullable=False) created_at = db.Column(db.DateTime, nullable=False) def __init__(self, first_name, last_name, email, password): self.first_name = first_name self.last_name = last_name self.email = email self.password = password self.image = "http://www.personalbrandingblog.com/wp-content/uploads/2017/08/blank-profile-picture-973460_640-300x300.png" self.created_at = datetime.datetime.utcnow() def save(self): """Add user to database""" db.session.add(self) db.session.commit() """ updates user's image """ def update_image(self, image): self.image = image db.session.add(self) db.session.commit() """ updates user's name """ def update_name(self, first_name, last_name): self.first_name = first_name self.last_name = last_name db.session.add(self) db.session.commit() """ Get all ingridients for an user Returns ------- List of ingridient object """ def get_ingridients(self): return Ingredient.query.filter_by(user_id=self.id) """ Add an ingridient Parameters ---------- item_name : Str Name of ingridient """ def add_ingridient(self, item_name): return Ingredient(name=item_name, user_id=self.id).save() """ Remove an ingridient Parameters ---------- item_name : Str Name of ingridient """ def remove_ingridient(self, item_name): Ingredient.query.filter_by(name=item_name, user_id=self.id).first().remove() """ Get all allergies for an user Returns ------- List of ingridient object """ def get_allergies(self): return Allergy.query.filter_by(user_id=self.id) """ Add an allergy Parameters ---------- item_name : Str Name of allergy """ def add_allergy(self, item_name): return Allergy(name=item_name, user_id=self.id).save() """ Add multiple allergies Parameters ---------- item_name : List of Str List of names of allergies """ def add_allergies(self, items_name): for item_name in items_name: self.add_allergy(item_name) """ Remove all allergy for an user """ def remove_all_allergies(self): for allergy in Allergy.query.filter_by(user_id=self.id): allergy.remove() """ Add pref """ def add_pref(self, diet_pref, personal_pref): for pref in Preference.query.filter_by(user_id=self.id): pref.remove() return Preference(diet_pref=diet_pref, personal_pref=personal_pref, user_id=self.id).save() """ Remove pref """ def get_pref(self): return Preference.query.filter_by(user_id=self.id) """ Check if the password given is correct or not Correct password is exactly same as the one that is stored in the database Parameters ---------- pswd : Str Password to be checked. e.q. String that user inputs in the log in page. Returns ------- Boolean True if the password is same. False if the password is NOT same. """ def is_password_correct(self, pswd): return self.password == pswd def tojson(self): """Represent user data as JSON object""" return json.dumps({ 'first_name': self.first_name, 'last_name': self.last_name, 'email': self.email, 'password': self.password }) """ Get one user based on the email Parameters ---------- email : Str User's email address that you are looking for Returns ------- User User object filtered by the email """ @staticmethod def get_one_user_by_email(email): return User.query.filter_by(email=email).first() # callback to reload the user object @login_manager.user_loader def load_user(id): return User.query.filter_by(id=id).first()
class TransferAccount(OneOrgBase, ModelBase): __tablename__ = 'transfer_account' name = db.Column(db.String()) _balance_wei = db.Column(db.Numeric(27), default=0) blockchain_address = db.Column(db.String()) is_approved = db.Column(db.Boolean, default=False) # These are different from the permissions on the user: # is_vendor determines whether the account is allowed to have cash out operations etc # is_beneficiary determines whether the account is included in disbursement lists etc is_vendor = db.Column(db.Boolean, default=False) is_beneficiary = db.Column(db.Boolean, default=False) is_ghost = db.Column(db.Boolean, default=False) account_type = db.Column(db.Enum(TransferAccountType)) payable_period_type = db.Column(db.String(), default='week') payable_period_length = db.Column(db.Integer, default=2) payable_epoch = db.Column(db.DateTime, default=datetime.datetime.utcnow) token_id = db.Column(db.Integer, db.ForeignKey("token.id")) exchange_contract_id = db.Column(db.Integer, db.ForeignKey(ExchangeContract.id)) transfer_card = db.relationship('TransferCard', backref='transfer_account', lazy=True, uselist=False) # users = db.relationship('User', backref='transfer_account', lazy=True) users = db.relationship( "User", secondary=user_transfer_account_association_table, back_populates="transfer_accounts", lazy='joined' ) credit_sends = db.relationship('CreditTransfer', backref='sender_transfer_account', foreign_keys='CreditTransfer.sender_transfer_account_id') credit_receives = db.relationship('CreditTransfer', backref='recipient_transfer_account', foreign_keys='CreditTransfer.recipient_transfer_account_id') spend_approvals_given = db.relationship('SpendApproval', backref='giving_transfer_account', foreign_keys='SpendApproval.giving_transfer_account_id') def get_float_transfer_account(self): for transfer_account in self.organisation.transfer_accounts: if transfer_account.account_type == 'FLOAT': return transfer_account float_wallet = TransferAccount.query.filter(TransferAccount.account_type == TransferAccountType.FLOAT).first() return float_wallet @property def balance(self): # division/multipication by int(1e16) occurs because # the db stores amounts in integer WEI: 1 BASE-UNIT (ETH/USD/ETC) * 10^18 # while the system passes around amounts in float CENTS: 1 BASE-UNIT (ETH/USD/ETC) * 10^2 # Therefore the conversion between db and system is 10^18/10^2c = 10^16 # We use cents for historical reasons, and to enable graceful degredation/rounding on # hardware that can only handle small ints (like the transfer cards and old android devices) # rounded to whole value of balance return float((self._balance_wei or 0) / int(1e16)) @balance.setter def balance(self, val): self._balance_wei = val * int(1e16) def decrement_balance(self, val): self.increment_balance(-1 * val) def increment_balance(self, val): # self.balance += val val_wei = val * int(1e16) if isinstance(val_wei, float): val_wei = Decimal(val_wei).quantize(Decimal('1')) self._balance_wei = (self._balance_wei or 0) + val_wei @hybrid_property def total_sent(self): return int( db.session.query(func.sum(server.models.credit_transfer.CreditTransfer.transfer_amount).label('total')).execution_options(show_all=True) .filter(server.models.credit_transfer.CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE) .filter(server.models.credit_transfer.CreditTransfer.sender_transfer_account_id == self.id).first().total or 0 ) @hybrid_property def total_received(self): return int( db.session.query(func.sum(server.models.credit_transfer.CreditTransfer.transfer_amount).label('total')).execution_options(show_all=True) .filter(server.models.credit_transfer.CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE) .filter(server.models.credit_transfer.CreditTransfer.recipient_transfer_account_id == self.id).first().total or 0 ) @hybrid_property def primary_user(self): if len(self.users) == 0: return None return self.users[0] # users = User.query.execution_options(show_all=True) \ # .filter(User.transfer_accounts.any(TransferAccount.id.in_([self.id]))).all() # if len(users) == 0: # # This only happens when we've unbound a user from a transfer account by manually editing the db # return None # # return sorted(users, key=lambda user: user.created)[0] @hybrid_property def primary_user_id(self): return self.primary_user.id # rounded balance @hybrid_property def rounded_account_balance(self): return (self._balance_wei or 0) / int(1e18) @hybrid_property def master_wallet_approval_status(self): if not current_app.config['USING_EXTERNAL_ERC20']: return 'NOT_REQUIRED' if not self.blockchain_address.encoded_private_key: return 'NOT_REQUIRED' base_query = ( BlockchainTransaction.query .filter(BlockchainTransaction.transaction_type == 'master wallet approval') .filter(BlockchainTransaction.credit_transfer.has(recipient_transfer_account_id=self.id)) ) successful_transactions = base_query.filter(BlockchainTransaction.status == 'SUCCESS').all() if len(successful_transactions) > 0: return 'APPROVED' requested_transactions = base_query.filter(BlockchainTransaction.status == 'PENDING').all() if len(requested_transactions) > 0: return 'REQUESTED' failed_transactions = base_query.filter(BlockchainTransaction.status == 'FAILED').all() if len(failed_transactions) > 0: return 'FAILED' return 'NO_REQUEST' def get_or_create_system_transfer_approval(self): sys_blockchain_address = self.organisation.system_blockchain_address approval = self.get_approval(sys_blockchain_address) if not approval: approval = self.give_approval_to_address(sys_blockchain_address) return approval def give_approval_to_address(self, address_getting_approved): approval = SpendApproval(transfer_account_giving_approval=self, address_getting_approved=address_getting_approved) db.session.add(approval) return approval def get_approval(self, receiving_address): for approval in self.spend_approvals_given: if approval.receiving_address == receiving_address: return approval return None def approve_and_disburse(self, initial_disbursement=None): from server.utils.access_control import AccessControl active_org = getattr(g, 'active_organisation', self.primary_user.default_organisation) admin = getattr(g, 'user', None) auto_resolve = initial_disbursement == active_org.default_disbursement if not self.is_approved and admin and AccessControl.has_sufficient_tier(admin.roles, 'ADMIN', 'admin'): self.is_approved = True if self.is_beneficiary: # TODO: make this more robust # approve_and_disburse might be called for a second time to disburse # so first check that no credit transfer have already been received if len(self.credit_receives) < 1: # make initial disbursement disbursement = self._make_initial_disbursement(initial_disbursement, auto_resolve) return disbursement elif len(self.credit_receives) == 1: # else likely initial disbursement received, check if DISBURSEMENT and PENDING and resolve if default disbursement = self.credit_receives[0] if disbursement.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT and disbursement.transfer_status == TransferStatusEnum.PENDING and auto_resolve: disbursement.resolve_as_completed() return disbursement def _make_initial_disbursement(self, initial_disbursement, auto_resolve=False): from server.utils.credit_transfer import make_payment_transfer active_org = getattr(g, 'active_organisation', Organisation.master_organisation()) initial_disbursement = initial_disbursement or active_org.default_disbursement if not initial_disbursement: return None user_id = get_authorising_user_id() if user_id is not None: sender = User.query.execution_options(show_all=True).get(user_id) else: sender = self.primary_user disbursement = make_payment_transfer( initial_disbursement, token=self.token, send_user=sender, receive_user=self.primary_user, transfer_subtype=TransferSubTypeEnum.DISBURSEMENT, is_ghost_transfer=False, require_sender_approved=False, require_recipient_approved=False, automatically_resolve_complete=auto_resolve) return disbursement def initialise_withdrawal(self, withdrawal_amount): from server.utils.credit_transfer import make_withdrawal_transfer withdrawal = make_withdrawal_transfer(withdrawal_amount, send_account=self, automatically_resolve_complete=False) return withdrawal def _bind_to_organisation(self, organisation): if not self.organisation: self.organisation = organisation if not self.token: self.token = organisation.token def __init__(self, blockchain_address: Optional[str]=None, bound_entity: Optional[Union[Organisation, User]]=None, account_type: Optional[TransferAccountType]=None, private_key: Optional[str] = None, **kwargs): super(TransferAccount, self).__init__(**kwargs) if bound_entity: bound_entity.transfer_accounts.append(self) if isinstance(bound_entity, Organisation): self.account_type = TransferAccountType.ORGANISATION self.blockchain_address = bound_entity.primary_blockchain_address self._bind_to_organisation(bound_entity) elif isinstance(bound_entity, User): self.account_type = TransferAccountType.USER self.blockchain_address = bound_entity.primary_blockchain_address if bound_entity.default_organisation: self._bind_to_organisation(bound_entity.default_organisation) elif isinstance(bound_entity, ExchangeContract): self.account_type = TransferAccountType.CONTRACT self.blockchain_address = bound_entity.blockchain_address self.is_public = True self.exchange_contact = self if not self.organisation: master_organisation = Organisation.master_organisation() if not master_organisation: raise Exception('master_organisation not found') self._bind_to_organisation(master_organisation) if blockchain_address: self.blockchain_address = blockchain_address if not self.blockchain_address: self.blockchain_address = bt.create_blockchain_wallet(private_key=private_key) if account_type: self.account_type = account_type
class System(db.Model): __tablename__ = 'system' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255)) address = db.Column(db.String(255)) owner = db.Column(db.String(255)) phone = db.Column(db.Integer) email = db.Column(db.String(255)) nit_1 = db.Column(db.Integer) nit_2 = db.Column(db.Integer) logo = db.Column(db.LargeBinary) sign = db.Column(db.LargeBinary) id_company_legal = db.Column(db.Integer, default=0) secuence_contract = db.Column(db.Integer, default=0) secuence_payroll = db.Column(db.Integer, default=0) secuence_vehicle = db.Column(db.Integer, default=0) def __init__(self, name=None, address=None, owner=None, phone=None, email=None, nit_1=None, nit_2=False, logo=None, sign=None, id_company_legal=None, secuence_contract=False, secuence_payroll=False, secuence_vehicle=False): if name: self.name = name.lower() if address: self.address = address.lower() if owner: self.owner = owner.lower() if phone: self.phone = phone if email: self.email = email.lower() if nit_1: self.nit_1 = nit_1 if nit_2: self.nit_2 = nit_2 if logo: self.logo = logo if sign: self.sign = sign if id_company_legal: self.id_company_legal = id_company_legal if secuence_contract: self.secuence_contract = secuence_contract if secuence_payroll: self.secuence_payroll = secuence_payroll if secuence_vehicle: self.secuence_vehicle = secuence_vehicle def get_json(self): return dict(name=self.name, address=self.address, owner=self.owner, phone=self.phone, email=self.email, nit_1=self.nit_1, nit_2=self.nit_2, logo=image_format(self.logo), sign=image_format(self.sign), id_company_legal=self.id_company_legal, secuence_contract=self.secuence_contract, secuence_payroll=self.secuence_payroll, secuence_vehicle=self.secuence_vehicle)
class Playlists(db.Model): id = db.Column(db.Integer, primary_key=True) # id of the playlist name = db.Column(db.String(80), unique=False, nullable=False, default="New playlist") creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) # Creation timestamp edit_date = db.Column(db.DateTime, default=datetime.utcnow) # Last time the playlist was edited (to update: datetime.datetime.utcnow()) version = db.Column(db.Integer, default=0) # Incremental version number: +1 every time the playlist is saved def save(self): self.edit_date = datetime.utcnow() self.version += 1 db.session.commit() def add_element(self, elements): if isinstance(elements, str): elements = json.loads(elements) if not isinstance(elements, list): elements = [elements] for i in elements: if "id" in i: # delete old ids to mantain the new sorting scheme (the elements list should be already ordered, for this reason we clear the elements and add them in the right order) del i["id"] if not isinstance(i, GenericPlaylistElement): i = GenericPlaylistElement.create_element_from_dict(i) i.save(self._ec()) db.session.commit() def clear_elements(self): return self._ec().clear_elements() def get_elements(self): els = self._ec().get_playlist_elements() res = [] for e in els: res.append(GenericPlaylistElement.create_element_from_db(e)) return res def get_elements_json(self): els = self.get_elements() return json.dumps([e.get_dict() for e in els]) def to_json(self): return json.dumps({ "name": self.name, "elements": self.get_elements_json(), "id": self.id, "version": self.version }) # returns the database table class for the elements of that playlist def _ec(self): if not hasattr(self, "_tc"): self._tc = get_playlist_table_class(self.id) return self._tc @classmethod def create_playlist(cls): item = Playlists() db.session.add(item) db.session.commit() create_playlist_table(item.id) return item @classmethod def get_playlist(cls, id): if id is None: raise ValueError("An id is necessary to select a playlist") try: return db.session.query(Playlists).filter(Playlists.id==id).one() # todo check if there is at leas one line (if the playlist exist) except: return Playlists.create_playlist() @classmethod def delete_playlist(cls, id): item = db.session.query(Playlists).filter_by(id=id).first() db.session.delete(item) db.session.commit() delete_playlist_table(id)
class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(255), unique=True) registration_datetime = db.Column(db.DateTime, default=datetime.datetime.utcnow())
class CreditTransfer(ManyOrgBase, BlockchainTaskableBase): __tablename__ = 'credit_transfer' uuid = db.Column(db.String, unique=True) resolved_date = db.Column(db.DateTime) _transfer_amount_wei = db.Column(db.Numeric(27), default=0) transfer_type = db.Column(db.Enum(TransferTypeEnum), index=True) transfer_subtype = db.Column(db.Enum(TransferSubTypeEnum)) transfer_status = db.Column(db.Enum(TransferStatusEnum), default=TransferStatusEnum.PENDING) transfer_mode = db.Column(db.Enum(TransferModeEnum)) transfer_use = db.Column(JSON) transfer_metadata = db.Column(JSONB) exclude_from_limit_calcs = db.Column(db.Boolean, default=False) resolution_message = db.Column(db.String()) token_id = db.Column(db.Integer, db.ForeignKey(Token.id)) sender_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) recipient_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) sender_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) recipient_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) sender_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True) recipient_user_id = db.Column(db.Integer, db.ForeignKey("user.id")) attached_images = db.relationship('UploadedResource', backref='credit_transfer', lazy=True) fiat_ramp = db.relationship('FiatRamp', backref='credit_transfer', lazy=True, uselist=False) __table_args__ = (Index('updated_index', "updated"), ) from_exchange = db.relationship('Exchange', backref='from_transfer', lazy=True, uselist=False, foreign_keys='Exchange.from_transfer_id') to_exchange = db.relationship('Exchange', backref='to_transfer', lazy=True, uselist=False, foreign_keys='Exchange.to_transfer_id') # TODO: Apply this to all transfer amounts/balances, work out the correct denominator size @hybrid_property def transfer_amount(self): return (self._transfer_amount_wei or 0) / int(1e16) @transfer_amount.setter def transfer_amount(self, val): self._transfer_amount_wei = val * int(1e16) def send_blockchain_payload_to_worker(self, is_retry=False, queue='high-priority'): sender_approval = self.sender_transfer_account.get_or_create_system_transfer_approval( ) recipient_approval = self.recipient_transfer_account.get_or_create_system_transfer_approval( ) self.blockchain_task_uuid = bt.make_token_transfer( signing_address=self.sender_transfer_account.organisation. system_blockchain_address, token=self.token, from_address=self.sender_transfer_account.blockchain_address, to_address=self.recipient_transfer_account.blockchain_address, amount=self.transfer_amount, prior_tasks=list( filter(lambda x: x is not None, [ sender_approval.eth_send_task_uuid, sender_approval.approval_task_uuid, recipient_approval.eth_send_task_uuid, recipient_approval.approval_task_uuid ])), queue=queue) def resolve_as_completed(self, existing_blockchain_txn=None, queue='high-priority'): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Transfer resolve function called multiple times for transaciton {self.id}' ) self.check_sender_transfer_limits() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.COMPLETE self.sender_transfer_account.decrement_balance(self.transfer_amount) self.recipient_transfer_account.increment_balance(self.transfer_amount) if self.transfer_type == TransferTypeEnum.PAYMENT and self.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT: if self.recipient_user and self.recipient_user.transfer_card: self.recipient_user.transfer_card.update_transfer_card() if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_completed() if not existing_blockchain_txn: self.send_blockchain_payload_to_worker(queue=queue) def resolve_as_rejected(self, message=None): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Transfer resolve function called multiple times for transaciton {self.id}' ) if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_rejected() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.REJECTED if message: self.resolution_message = message def get_transfer_limits(self): import server.utils.transfer_limits return server.utils.transfer_limits.get_transfer_limits(self) def check_sender_transfer_limits(self): if self.sender_user is None: # skip if there is no sender, which implies system send return relevant_transfer_limits = self.get_transfer_limits() for limit in relevant_transfer_limits: if limit.no_transfer_allowed: raise NoTransferAllowedLimitError(token=self.token.name) if limit.transfer_count is not None: # GE Limits transaction_count = limit.apply_all_filters( self, db.session.query( func.count(CreditTransfer.id).label('count')) ).execution_options(show_all=True).first().count if (transaction_count or 0) > limit.transfer_count: message = 'Account Limit "{}" reached. Allowed {} transaction per {} days'\ .format(limit.name, limit.transfer_count, limit.time_period_days) self.resolve_as_rejected(message=message) raise TransferCountLimitError( transfer_count_limit=limit.transfer_count, limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) if limit.transfer_balance_fraction is not None: allowed_transfer = limit.transfer_balance_fraction * self.sender_transfer_account.balance if self.transfer_amount > allowed_transfer: message = 'Account % Limit "{}" reached. {} available'.format( limit.name, max(allowed_transfer, 0)) self.resolve_as_rejected(message=message) raise TransferBalanceFractionLimitError( transfer_balance_fraction_limit=limit. transfer_balance_fraction, transfer_amount_avail=int(allowed_transfer), limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) if limit.total_amount is not None: # Sempo Compliance Account Limits transaction_volume = limit.apply_all_filters( self, db.session.query( func.sum(CreditTransfer.transfer_amount).label('total') )).execution_options(show_all=True).first().total or 0 if transaction_volume > limit.total_amount: # Don't include the current transaction when reporting amount available amount_avail = limit.total_amount - transaction_volume + int( self.transfer_amount) message = 'Account Limit "{}" reached. {} available'.format( limit.name, max(amount_avail, 0)) self.resolve_as_rejected(message=message) raise TransferAmountLimitError( transfer_amount_limit=limit.total_amount, transfer_amount_avail=amount_avail, limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) return relevant_transfer_limits def check_sender_has_sufficient_balance(self): return self.sender_user and self.sender_transfer_account.balance - self.transfer_amount >= 0 def check_sender_is_approved(self): return self.sender_user and self.sender_transfer_account.is_approved def check_recipient_is_approved(self): return self.recipient_user and self.recipient_transfer_account.is_approved def _select_transfer_account(self, token, user): if token is None: raise Exception("Token must be specified") return find_transfer_accounts_with_matching_token(user, token) def append_organisation_if_required(self, organisation): if organisation and organisation not in self.organisations: self.organisations.append(organisation) def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum = None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum = None, transfer_mode: TransferModeEnum = None, is_ghost_transfer=False): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp try: self.recipient_transfer_account = recipient_transfer_account or self._select_transfer_account( self.token, recipient_user) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer) db.session.add(self.recipient_transfer_account) if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.get_float_transfer_account( ) if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.get_float_transfer_account( ) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_mode = transfer_mode self.transfer_metadata = transfer_metadata if uuid is not None: self.uuid = uuid self.append_organisation_if_required( self.recipient_transfer_account.organisation) self.append_organisation_if_required( self.sender_transfer_account.organisation)
class Country(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), nullable=False) code = db.Column(db.String(3), nullable=False)
class Transaction(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id")) ticket_amount = db.Column(db.Integer) activity = db.Column(db.String(255)) datetime = db.Column(db.DateTime, default=datetime.datetime.utcnow())
class User(UserMixin, db.Model): __table_args__ = {'extend_existing': True} id = db.Column('id', db.Integer, primary_key=True) username = db.Column('username', db.String(), unique=False, index=True) email = db.Column('email', db.String(), unique=True, index=True) password = db.Column('password', db.String()) registered_on = db.Column('registered_on', db.DateTime(timezone=True), server_default=func.now()) notes = db.relationship('Notes', backref='author', lazy='dynamic', cascade="all, delete-orphan") trashed_notes = db.relationship('Trash', backref='author', lazy='dynamic', cascade="all, delete-orphan") def set_password(self, password): self.password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password, password) def generate_confirmation_token(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'], expiration) return s.dumps({'confirm': self.id}) def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except: return False if data.get('confirm') != self.id: return False self.confirmed = True db.session.add(self) return True def avatar(self, size=128): return 'https://www.gravatar.com/avatar/?d=monsterid&s={}'.format(size) @property def _links(self): return {'avatar': self.avatar(128)} def get_notes(self): notes = self.notes.limit(50).all() return notes def get_note(self, note_id): return self.notes.filter_by(id=note_id).first() def delete_note(self, note_id): note = self.notes.filter_by(id=note_id).first() if note: db.session.delete(note) def update_note(self, note_id, title=None, body=None, color=None, tags_string=None): return self.notes.filter_by(id=note_id).update({ Notes.title: title, Notes.body: body, Notes.color: color, Notes.tags_string: tags_string }) def move_note_to_trash(self, note): if note: trashed_note = Trash(user_id=self.id, title=note.title, body=note.body, color=note.color, tags_string=note.tags_string) db.session.add(trashed_note) self.delete_note(note.id) db.session.commit() return trashed_note return None def restore_from_trash(self, note_id): trashed_note = self.get_trashed_note(note_id) if trashed_note: note = Notes(user_id=self.id, title=trashed_note.title, body=trashed_note.body, color=trashed_note.color, tags_string=trashed_note.tags_string) db.session.add(note) self.delete_trashed_notes(note_id=note_id) db.session.commit() return note return None def get_trashed_notes(self): notes = self.trashed_notes.limit(50).all() return notes def get_trashed_note(self, note_id): return self.trashed_notes.filter_by(id=note_id).first() def delete_trashed_notes(self, note_id=None, all=False): if not note_id and not all: return None if note_id: self.trashed_notes.filter_by(id=note_id).delete() if all: self.trashed_notes.delete() db.session.commit() def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id def __repr__(self): return '<User %r>' % (self.username)
class Department(db.Model): departmentID = db.Column(db.Integer(), primary_key=True, unique=True, nullable=False) name = db.Column(db.String(32), nullable=False)
class Texte(db.Model): __tablename__ = 'Texte' __bind_key__ = 'plu' id_texte = db.Column('id_texte', db.Integer, primary_key=True) texte = db.Column('texte', db.String(1000))
class ExchangeContract(ModelBase): """ class for tracking contracts used for making on-chain exchanges of tokens (rather than using an internal sempo blockchain account that holds and swaps multiple tokens) currently only supports exchanges using liquid token contracts, though could be extended to support a constant-product market maker, continuous-double auction DEX etc. @:param blockchain_address: The address to which exchange requests should be sent. @:param contract_registry_blockchain_address: The contract registry is used to add new liquid token sub-exchanges. @:param subexchange_address_mapping: Exchanges made using a liquid token don't use a single on-chain contract, but rather a network of exchange-contracts, one for each token that can be exchanged, which we label 'sub-exchanges'. Each one of these sub-exchanges includes an internal reserve-token balance, and has parameters defined such as the reserve-ratio. @:param reserve_token: The stable token used as the reserve for liquid tokens. @:param exchangeable_tokens: The tokens that are exchangable using this contract @:param transfer_accounts: Accounts used for tracking the sends and receives of the various tokens exchangable by the exchange-network """ __tablename__ = 'exchange_contract' blockchain_address = db.Column(db.String(), index=True) contract_registry_blockchain_address = db.Column(db.String(), index=True) subexchange_address_mapping = db.Column(JSON) reserve_token_id = db.Column(db.Integer, db.ForeignKey("token.id")) exchangeable_tokens = db.relationship( "Token", secondary=exchange_contract_token_association_table, back_populates="exchange_contracts") transfer_accounts = db.relationship( 'TransferAccount', backref='exchange_contract', lazy=True, foreign_keys='TransferAccount.exchange_contract_id' ) def get_subexchange_details(self, token_address): if self.subexchange_address_mapping is None: raise SubexchangeNotFound details = self.subexchange_address_mapping.get(token_address, None) if not details: raise SubexchangeNotFound return details def _add_subexchange(self, token_address, subexchange_address, subexchange_reserve_ratio_ppm): if self.subexchange_address_mapping is None: self.subexchange_address_mapping = {} self.subexchange_address_mapping[token_address] = { 'subexchange_address': subexchange_address, 'subexchange_reserve_ratio_ppm': subexchange_reserve_ratio_ppm } if self.blockchain_address is None: self.blockchain_address = subexchange_address flag_modified(self, "subexchange_address_mapping") db.session.add(self) def add_reserve_token(self, reserve_token): self.reserve_token = reserve_token self.add_token(reserve_token, None, None) def add_token(self, token, subexchange_address, subexchange_reserve_ratio): exchange_transfer_account = (server.models.transfer_account.TransferAccount.query .filter_by(token=token) .filter_by(exchange_contract=self) .first()) if not exchange_transfer_account: exchange_transfer_account = server.models.transfer_account.TransferAccount( bound_entity=self, token=token, is_approved=True) db.session.add(exchange_transfer_account) if subexchange_address: self.exchangeable_tokens.append(token) self._add_subexchange(token.address, subexchange_address, subexchange_reserve_ratio) def __init__(self, **kwargs): super().__init__(**kwargs)
class User(db.Model): id = db.Column(db.String, primary_key=True, default=uuid.uuid4().hex) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(60), nullable=False) bio = db.Column(db.String(150)) image_file = db.Column(db.String(20),default='default.jpg') influence = db.Column(db.Integer, default=0) date = db.Column(db.String(10), nullable=False, default=datetime.utcnow) user_post = db.relationship("Post", backref="parent_post_user", lazy=True) user_comment = db.relationship("Comment", backref="parent_comment_user", lazy=True) user_postlike = db.relationship("PostLike", backref="parent_postlike_user", lazy=True) user_postdislike = db.relationship("PostDislike", backref="parent_postdislike_user", lazy=True) user_commentlike = db.relationship("CommentLike", backref="parent_commentlike_user", lazy=True) user_commentdislike = db.relationship("CommentDislike", backref="parent_commentdislike_user", lazy=True) def get_reset_token(self, expires_sec=1800): s = Serializer(current_app.config['SECRET_KEY'], expires_sec) return s.dumps({'user_id':self.id}).decode('utf-8') @staticmethod def verify_reset_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: user_id = s.loads(token)['user_id'] except: return None return User.query.get(user_id) def like_post(self, model, post): if not self.has_liked_post(model, post): like = model(username=self.username, post_id=post.id) db.session.add(like) def unlike_post(self, model,post): if self.has_liked_post(model, post): model.query.filter_by( username=self.username, post_id=post.id).delete() def has_liked_post(self, model, post): return model.query.filter( model.username == self.username, model.post_id == post.id).count() > 0 def like_comment(self, model, comment): if not self.has_liked_comment(model, comment): like = model(username=self.username, comment_id=comment.id) db.session.add(like) def unlike_comment(self, model,comment): if self.has_liked_comment(model, comment): model.query.filter_by( username=self.username, comment_id=comment.id).delete() def has_liked_comment(self, model, comment): return model.query.filter( model.username == self.username, model.comment_id == comment.id).count() > 0 def likes_recieved(self): posts = [z.to_json() for z in self.user_post] counter = 0 for post in posts: counter += post['likes'] return counter def to_json(self): return { "username": self.username, "email": self.email, "influence": self.influence, "date": self.date, "user_post": [z.to_json() for z in self.user_post], "user_comment": [z.to_json() for z in self.user_comment], "likes_recieved": self.likes_recieved(), "bio": self.bio } def user_post_to_json(self): return {"user_post" : [z.to_json() for z in self.user_post]} def __repr__(self): return f"User('{self.username}','{self.email}','{self.image_file}','{self.influence}', '{self.user_post}')"
class Asesi(db.Model): __tablename__ = 'Asesi' idAsesi = db.Column(db.Integer, primary_key=True, autoincrement=True) NamaLengkap = db.Column(db.String(64), nullable=False) TempatLahir = db.Column(db.String(255), nullable=False) JenisKelamin = db.Column(db.String(1), nullable=False) Kebangsaan = db.Column(db.String(64), nullable=False) Alamat = db.Column(db.String(255), nullable=False) KodePos = db.Column(db.String(8), nullable=False) NoHP = db.Column(db.String(13), nullable=False) NoHPRumah = db.Column(db.String(13)) NoHPKantor = db.Column(db.String(13)) Email = db.Column(db.String(64)) PendidikanTerakhir = db.Column(db.String(128)) StatusBekerja = db.Column(db.Boolean()) NamaPerusahaan = db.Column(db.String(128), nullable=False) Jabatan = db.Column(db.String(128)) AlamatPerusahaan = db.Column(db.String(255)) KodePosPerusahaan = db.Column(db.String(8)) NoTeleponPerusahaan = db.Column(db.String(13)) NoFaxPerusahaan = db.Column(db.String(32)) EmailPerusahaan = db.Column(db.String(64)) Skema = db.Column(db.Integer, db.ForeignKey('Skema.idSkema')) def __init__(self, nama, tempat, kelamin, bangsa, alamat, pos, nohp, rumah, kantor, email, pendidikan, statuskerja, pekerjaan, Skema): self.NamaLengkap = nama self.TempatLahir = tempat self.JenisKelamin = kelamin self.Kebangsaan = bangsa self.alamat = alamat self.KodePos = pos self.NoHP = nohp self.NoHPRumah = rumah self.NoHPKantor = kantor self.Email = email self.PendidikanTerakhir = pendidikan self.StatusKompeten = False self.StatusBekerja = statuskerja self.bekerja = pekerjaan self.Skema = Skema def __repr__(self): return self.NamaLengkap def cekKompeten(self): return self.StatusKompeten def setDataPerusahaan(self, nama, jabatan, alamat, pos, telepon, fax, email): self.NamaPerusahaan = nama self.Jabatan = jabatan self.AlamatPerusahaan = alamat self.KodePosPerusahaan = pos self.NoTeleponPerusahaan = telepon self.NoFaxPerusahaan = fax self.EmailPerusahaan = email
class Account(BaseModel, db.Model): """ Model for the account table """ __tablename__ = 'account' # The account id id = db.Column(UUID(as_uuid=True), server_default=db.text("uuid_generate_v4()"), unique=True, primary_key=True) # The user id user_id = db.Column(db.String(255), unique=True, nullable=False) # The password password = db.Column(db.String(255), nullable=False) # The ammount in his account balance = db.Column(db.Float, default=0.0, nullable=False) # The atual currency currency = db.Column(db.Enum(Currency), default=Currency.eur, nullable=False) # The state of the account : active or inactive state = db.Column(db.Boolean, default=True, nullable=False) # The date when the account was created created_at = db.Column(db.DateTime, nullable=False) # The date when the information account was updated updated_at = db.Column(db.DateTime, nullable=False) def __init__(self, user_id, password, currency): self.user_id = user_id self.password = bcrypt.generate_password_hash(password, app.config['BCRYPT_LOG_ROUNDS']).decode() self.balance = 0.0 self.currency = currency self.state = True self.created_at = self.updated_at = datetime.datetime.utcnow().isoformat() def __repr__(self): return '<user_id = '+str(self.user_id)+', password = '******'>' @classmethod def find_by_id(cls, user_id): return cls.query.filter_by(user_id=user_id).first() def save_to_db(self): db.session.add(self) db.session.commit() @staticmethod def encode_auth_token(user_id): """ Generates the Auth Token :return: string """ try: payload = { 'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1, seconds=3600), 'iat': datetime.datetime.utcnow(), 'sub': str(user_id) } return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256') except Exception as e: return e @staticmethod def decode_auth_token(auth_token): """ Validates the auth token :param auth_token: :return: integer|string """ try: payload = jwt.decode(auth_token, app.config['SECRET_KEY']) is_active_token = Active_Sessions.check_active_session(auth_token) if not is_active_token: return 'Token invalid.' else: return payload['sub'] except jwt.ExpiredSignatureError: return 'Signature expired. Please log in again.' except jwt.InvalidTokenError: return 'Invalid token. Please log in again.' def check_password_hash(hash, password): return bcrypt.check_password_hash(hash, password) def save_to_db(self): db.session.add(self) db.session.commit()
class CreditTransfer(ManyOrgBase, BlockchainTaskableBase): __tablename__ = 'credit_transfer' uuid = db.Column(db.String, unique=True) batch_uuid = db.Column(db.String) # override ModelBase deleted to add an index created = db.Column(db.DateTime, default=datetime.datetime.utcnow, index=True) resolved_date = db.Column(db.DateTime) _transfer_amount_wei = db.Column(db.Numeric(27), default=0) transfer_type = db.Column(db.Enum(TransferTypeEnum), index=True) transfer_subtype = db.Column(db.Enum(TransferSubTypeEnum)) transfer_status = db.Column(db.Enum(TransferStatusEnum), default=TransferStatusEnum.PENDING) transfer_mode = db.Column(db.Enum(TransferModeEnum), index=True) transfer_use = db.Column(JSON) # Deprecated transfer_usages = db.relationship( "TransferUsage", secondary=credit_transfer_transfer_usage_association_table, back_populates="credit_transfers", lazy='joined') transfer_metadata = db.Column(JSONB) exclude_from_limit_calcs = db.Column(db.Boolean, default=False) resolution_message = db.Column(db.String()) token_id = db.Column(db.Integer, db.ForeignKey(Token.id)) sender_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id"), index=True) sender_transfer_account = db.relationship( 'TransferAccount', foreign_keys=[sender_transfer_account_id], back_populates='credit_sends', lazy='joined') recipient_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id"), index=True) recipient_transfer_account = db.relationship( 'TransferAccount', foreign_keys=[recipient_transfer_account_id], back_populates='credit_receives', lazy='joined') sender_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id"), index=True) recipient_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id"), index=True) sender_transfer_card_id = db.Column(db.Integer, db.ForeignKey("transfer_card.id"), index=True) sender_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True) recipient_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True) is_initial_disbursement = db.Column(db.Boolean, default=False) attached_images = db.relationship('UploadedResource', backref='credit_transfer', lazy='joined') fiat_ramp = db.relationship('FiatRamp', backref='credit_transfer', lazy=True, uselist=False) __table_args__ = (Index('updated_index', "updated"), ) from_exchange = db.relationship('Exchange', backref='from_transfer', lazy='joined', uselist=False, foreign_keys='Exchange.from_transfer_id') to_exchange = db.relationship('Exchange', backref='to_transfer', lazy=True, uselist=False, foreign_keys='Exchange.to_transfer_id') def add_message(self, message): dated_message = f"[{datetime.datetime.utcnow()}:: {message}]" self.resolution_message = dated_message # TODO: Apply this to all transfer amounts/balances, work out the correct denominator size @hybrid_property def transfer_amount(self): return (self._transfer_amount_wei or 0) / int(1e16) @transfer_amount.setter def transfer_amount(self, val): self._transfer_amount_wei = val * int(1e16) @hybrid_property def rounded_transfer_amount(self): return (self._transfer_amount_wei or 0) / int(1e18) @hybrid_property def public_transfer_type(self): if self.transfer_type == TransferTypeEnum.PAYMENT: if self.transfer_subtype == TransferSubTypeEnum.STANDARD or None: return TransferTypeEnum.PAYMENT else: return self.transfer_subtype else: return self.transfer_type @public_transfer_type.expression def public_transfer_type(cls): from sqlalchemy import case, cast, String return case([ (cls.transfer_subtype == TransferSubTypeEnum.STANDARD, cast(cls.transfer_type, String)), (cls.transfer_type == TransferTypeEnum.PAYMENT, cast(cls.transfer_subtype, String)), ], else_=cast(cls.transfer_type, String)) def send_blockchain_payload_to_worker(self, is_retry=False, queue='high-priority'): sender_approval = self.sender_transfer_account.get_or_create_system_transfer_approval( ) recipient_approval = self.recipient_transfer_account.get_or_create_system_transfer_approval( ) # Approval is called so that the master account can make transactions on behalf of the transfer account. # Make sure this approval is done first before making a transaction approval_priors = list( filter(lambda x: x is not None, [ sender_approval.eth_send_task_uuid, sender_approval.approval_task_uuid, recipient_approval.eth_send_task_uuid, recipient_approval.approval_task_uuid ])) # Forces an order on transactions so that if there's an outage somewhere, transactions don't get confirmed # On chain in an order that leads to a unrecoverable state other_priors = [ t.blockchain_task_uuid for t in self._get_required_prior_tasks() ] all_priors = approval_priors + other_priors return bt.make_token_transfer( signing_address=self.sender_transfer_account.organisation. system_blockchain_address, token=self.token, from_address=self.sender_transfer_account.blockchain_address, to_address=self.recipient_transfer_account.blockchain_address, amount=self.transfer_amount, prior_tasks=all_priors, queue=queue, task_uuid=self.blockchain_task_uuid) def _get_required_prior_tasks(self): """ Get the tasks involving the sender's account that must complete prior to this task being submitted to chain To calculate the prior tasks for the sender Alice: - Find the most recent credit transfer where Alice was the sender, not including any transfers that have the same batch UUID as this transfer. Call this "most_recent_out_of_batch_send" - Find all credit transfers subsequent to "most_recent_out_of_batch_send" where Alice was the recipient. Call this "more_recent_receives" Required priors are all transfers in "more_recent_receives" and "most_recent_out_of_batch_send". For why this works, see https://github.com/teamsempo/SempoBlockchain/pull/262 """ # We're constantly querying complete transfers here. Lazy and DRY complete_transfer_base_query = (CreditTransfer.query.filter( CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE)) # Query for finding the most recent transfer sent by the sending account that isn't from the same batch uuid # that of the transfer in question most_recent_out_of_batch_send = ( complete_transfer_base_query.order_by( CreditTransfer.id.desc()).filter( CreditTransfer.sender_transfer_account == self.sender_transfer_account). filter(CreditTransfer.id != self.id).filter( or_( CreditTransfer.batch_uuid != self.batch_uuid, CreditTransfer.batch_uuid == None # Only exclude matching batch_uuids if they're not null )).first()) # Base query for finding more_recent_receives base_receives_query = (complete_transfer_base_query.filter( CreditTransfer.recipient_transfer_account == self.sender_transfer_account)) if most_recent_out_of_batch_send: # If most_recent_out_of_batch_send exists, find all receive transfers since it. more_recent_receives = base_receives_query.filter( CreditTransfer.id > most_recent_out_of_batch_send.id).all() # Required priors are then the out of batch send plus these receive transfers required_priors = more_recent_receives + [ most_recent_out_of_batch_send ] # Edge case handle: if most_recent_out_of_batch_send is a batch member, the whole batch are priors as well if most_recent_out_of_batch_send.batch_uuid is not None: same_batch_priors = complete_transfer_base_query.filter( CreditTransfer.batch_uuid == most_recent_out_of_batch_send.batch_uuid).all() required_priors = required_priors + same_batch_priors else: # Otherwise, return all receives, which are all our required priors required_priors = base_receives_query.all() # Filter out any transfers that we already know are complete - there's no reason to create an extra dep # We don't do this inside the Alchemy queries because we need the completed priors to calculate other priors required_priors = [ prior for prior in required_priors if prior.blockchain_status != BlockchainStatus.SUCCESS ] # Remove any possible duplicates return set(required_priors) def resolve_as_complete_with_existing_blockchain_transaction( self, transaction_hash): self.resolve_as_complete() self.blockchain_status = BlockchainStatus.SUCCESS self.blockchain_hash = transaction_hash def resolve_as_complete_and_trigger_blockchain( self, existing_blockchain_txn=None, queue='high-priority', batch_uuid: str = None): self.resolve_as_complete(batch_uuid) if not existing_blockchain_txn: self.blockchain_task_uuid = str(uuid4()) g.pending_transactions.append((self, queue)) def resolve_as_complete(self, batch_uuid=None): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Resolve called multiple times for transfer {self.id}') try: self.check_sender_transfer_limits() except TransferLimitError as e: # Sempo admins can always bypass limits, allowing for things like emergency moving of funds etc if hasattr(g, 'user') and AccessControl.has_suffient_role( g.user.roles, {'ADMIN': 'sempoadmin'}): self.add_message(f'Warning: {e}') else: raise e self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.COMPLETE self.update_balances() if self.transfer_type == TransferTypeEnum.PAYMENT and self.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT: if self.recipient_user and self.recipient_user.transfer_card: self.recipient_user.transfer_card.update_transfer_card() if batch_uuid: self.batch_uuid = batch_uuid if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_complete() def resolve_as_rejected(self, message=None): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Resolve called multiple times for transfer {self.id}') if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_rejected() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.REJECTED self.blockchain_status = BlockchainStatus.UNSTARTED self.update_balances() if message: self.add_message(message) def update_balances(self): self.sender_transfer_account.update_balance() self.recipient_transfer_account.update_balance() def get_transfer_limits(self): from server.utils.transfer_limits import ( LIMIT_IMPLEMENTATIONS, get_applicable_transfer_limits) return get_applicable_transfer_limits(LIMIT_IMPLEMENTATIONS, self) def check_sender_transfer_limits(self): if self.sender_user is None: # skip if there is no sender, which implies system send return relevant_transfer_limits = self.get_transfer_limits() for limit in relevant_transfer_limits: try: limit.validate_transfer(self) except (TransferAmountLimitError, TransferCountLimitError, TransferBalanceFractionLimitError, MaximumPerTransferLimitError, MinimumSentLimitError, NoTransferAllowedLimitError) as e: self.resolve_as_rejected(message=e.message) raise e return relevant_transfer_limits def check_sender_has_sufficient_balance(self): return self.sender_transfer_account.unrounded_balance - Decimal( self.transfer_amount) >= 0 def check_sender_is_approved(self): return self.sender_user and self.sender_transfer_account.is_approved def check_recipient_is_approved(self): return self.recipient_user and self.recipient_transfer_account.is_approved def _select_transfer_account(self, token, user): if token is None: raise Exception("Token must be specified") return find_transfer_accounts_with_matching_token(user, token) def append_organisation_if_required(self, organisation): if organisation and organisation not in self.organisations: self.organisations.append(organisation) def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum = None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum = None, transfer_mode: TransferModeEnum = None, transfer_card=None, is_ghost_transfer=False, require_sufficient_balance=True): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.token.float_account if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.token.float_account try: self.recipient_transfer_account = recipient_transfer_account or self.recipient_transfer_account or self._select_transfer_account( self.token, recipient_user) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer) db.session.add(self.recipient_transfer_account) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_mode = transfer_mode self.transfer_metadata = transfer_metadata self.transfer_card = transfer_card if uuid is not None: self.uuid = uuid self.append_organisation_if_required( self.recipient_transfer_account.organisation) self.append_organisation_if_required( self.sender_transfer_account.organisation) if require_sufficient_balance and not self.check_sender_has_sufficient_balance( ): message = "Sender {} has insufficient balance. Has {}, needs {}.".format( self.sender_transfer_account, self.sender_transfer_account.balance, self.transfer_amount) self.resolve_as_rejected(message) raise InsufficientBalanceError(message) self.update_balances()
class House(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) lianjiaId = db.Column(db.String(20), index=True) title = db.Column(db.String(50), index=True) follower_num = db.Column(db.Integer, index=True) total_price = db.Column(db.Integer, index=True) area = db.Column(db.Float, index=True) avg_price = db.Column(db.Integer, index=True) directions = db.Column(db.String(20), index=True) floor = db.Column(db.String(4), index=True) year = db.Column(db.Integer, index=True) decoration = db.Column(db.String(20), index=True) location = db.Column(db.String(300), index=True) school = db.Column(db.Integer, index=True) mall = db.Column(db.Integer, index=True) traffic = db.Column(db.Integer, index=True) medicine = db.Column(db.Integer, index=True) total_floor = db.Column(db.Integer, index=True) ring = db.Column(db.Integer, index=True) room = db.Column(db.Integer, index=True) parlor = db.Column(db.Integer, index=True) kitchen = db.Column(db.Integer, index=True) toilet = db.Column(db.Integer, index=True) district = db.Column(db.String(40), index=True) block = db.Column(db.String(40), index=True) name = db.Column(db.String(50), index=True) address = db.Column(db.String(50), index=True) des = db.Column(db.String(1000), index=True) community = db.Column(db.String(100), index=True) def __repr__(self): return '<House {}>'.format(self.lianjiaId) # 查询单条数据 def to_dict(self): return {c.name: getattr(self, c.name) for c in self.__table__.columns} # 查询多条数据 def dobule_to_dict(self): result = {} for key in self.__mapper__.c.keys(): if getattr(self, key) is not None: result[key] = str(getattr(self, key)) else: result[key] = getattr(self, key) return result #配合todict一起使用 def to_json(all_vendors): v = [ven.dobule_to_dict() for ven in all_vendors] return v def to_json(self): dict = self.__dict__ if "_sa_instance_state" in dict: del dict["_sa_instance_state"] return dict
class Users(db.Model): email = db.Column(db.String(120), primary_key=True) first_name = db.Column(db.String(120)) last_name = db.Column(db.String(120)) organization = db.Column(db.String(120), nullable=True) descr = db.Column(db.String(250), nullable=True) user_type = db.Column(db.String(120), nullable=True) gen_link_1 = db.Column(db.String(250), nullable=True) gen_link_2 = db.Column(db.String(250), nullable=True) gen_link_3 = db.Column(db.String(250), nullable=True) image = db.Column(db.String(250)) doc = db.Column(db.String(250), nullable=True) def __init__(self, e, fname, lname, org, des, u_type, gl1, gl2, gl3, img, d): self.email = e self.first_name = fname self.last_name = lname self.organization = org self.descr = des self.user_type = u_type self.gen_link_1 = gl1 self.gen_link_2 = gl2 self.gen_link_3 = gl3 self.image = img self.doc = d
class Fuec(db.Model): __table_args__ = {'extend_existing': True} __tablename__ = 'fuec' id = db.Column(db.Integer, primary_key=True) created_at = db.Column(db.DateTime, default=db.func.current_timestamp()) created_by = db.Column(db.Integer, db.ForeignKey('user.id')) no_fuec = db.Column(db.String(20)) social_object = db.Column(db.String(255), nullable=False) nit = db.Column(db.String(255)) no_agreement = db.Column(db.Integer) contractor = db.Column(db.String(255)) id_contractor = db.Column(db.Integer) object_agreement = db.Column(db.String(255)) origin_destination = db.Column(db.String(1000)) kind_hiring = db.Column(db.String(255)) kind_link = db.Column(db.String(255)) init_date = db.Column(db.String(255)) last_date = db.Column(db.String(255)) car_no = db.Column(db.Integer) car_license_plate = db.Column(db.String(255)) car_model = db.Column(db.String(255)) car_brand = db.Column(db.String(255)) car_class_car = db.Column(db.Integer) car_operation = db.Column(db.String(255)) data_driver_json = db.Column(db.String(1000)) contractor_owner = db.Column(db.String(1000)) file_pdf = db.Column(db.LargeBinary) def __init__(self, no_fuec, created_by, social_object, nit, no_agreement, contractor, id_contractor, object_agreement, origin_destination, kind_hiring, kind_link, init_date, last_date, car_no, car_license_plate, car_model, car_brand, car_class_car, car_operation, data_driver, contractor_owner, file_pdf): if no_fuec: self.no_fuec = no_fuec if created_by: self.created_by = created_by if social_object: self.social_object = social_object.lower() if nit: self.nit = nit if no_agreement: self.no_agreement = no_agreement if contractor: self.contractor = contractor if id_contractor: self.id_contractor = id_contractor if object_agreement: self.object_agreement = object_agreement if origin_destination: self.origin_destination = origin_destination if kind_hiring: self.kind_hiring = kind_hiring if kind_link: self.kind_link = kind_link if init_date: self.init_date = init_date if last_date: self.last_date = last_date if car_no: self.car_no = car_no if car_license_plate: self.car_license_plate = car_license_plate if car_model: self.car_model = car_model if car_brand: self.car_brand = car_brand if car_class_car: self.car_class_car = car_class_car if car_operation: self.car_operation = car_operation if data_driver: self.data_driver_json = data_driver if contractor_owner: self.contractor_owner = contractor_owner if file_pdf: self.file_pdf = file_pdf
class Data(db.Model): id = db.Column(db.Integer,primary_key=True,autoincrement=True) text = db.Column(db.String(500))
class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(30), nullable=False) password = db.Column(db.String(10), nullable=False) country = db.Column(db.String(10), nullable=True) gender = db.Column(db.String(1), nullable=False)
class User(db.Model): id = db.Column('user_id', db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) def __init__(self, name): self.name = name
class Login(db.Model): username = db.Column(db.String(255), primary_key=True) password = db.Column(db.String(255))
class Genre(db.Model): __tablename__ = 'Genre' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(), nullable=False)
class Course(db.Model): __tablename__ = 'COURSES' id = db.Column(db.Integer, primary_key=True, nullable=False) name = db.Column(db.String(10), nullable=False) session = db.Column(db.String(5), nullable=False)
class User(ManyOrgBase, ModelBase, SoftDelete): """Establishes the identity of a user for both making transactions and more general interactions. Admin users are created through the auth api by registering an account with an email that has been pre-approved on the whitelist. By default, admin users only have minimal access levels (view). Permissions must be elevated manually in the database. Transaction-capable users (vendors and beneficiaries) are created using the POST user API or the bulk upload function """ __tablename__ = 'user' first_name = db.Column(db.String()) last_name = db.Column(db.String()) preferred_language = db.Column(db.String()) primary_blockchain_address = db.Column(db.String()) _last_seen = db.Column(db.DateTime) email = db.Column(db.String()) _phone = db.Column(db.String(), unique=True, index=True) _public_serial_number = db.Column(db.String()) uuid = db.Column(db.String(), index=True) nfc_serial_number = db.Column(db.String()) password_hash = db.Column(db.String(200)) one_time_code = db.Column(db.String) secret = db.Column(db.String()) _TFA_secret = db.Column(db.String(128)) TFA_enabled = db.Column(db.Boolean, default=False) pin_hash = db.Column(db.String()) seen_latest_terms = db.Column(db.Boolean, default=False) failed_pin_attempts = db.Column(db.Integer, default=0) default_currency = db.Column(db.String()) _location = db.Column(db.String()) lat = db.Column(db.Float()) lng = db.Column(db.Float()) _held_roles = db.Column(JSONB) is_activated = db.Column(db.Boolean, default=False) is_disabled = db.Column(db.Boolean, default=False) is_phone_verified = db.Column(db.Boolean, default=False) is_self_sign_up = db.Column(db.Boolean, default=True) is_market_enabled = db.Column(db.Boolean, default=False) password_reset_tokens = db.Column(JSONB, default=[]) pin_reset_tokens = db.Column(JSONB, default=[]) terms_accepted = db.Column(db.Boolean, default=True) matched_profile_pictures = db.Column(JSON) business_usage_id = db.Column(db.Integer, db.ForeignKey(TransferUsage.id)) transfer_accounts = db.relationship( "TransferAccount", secondary=user_transfer_account_association_table, back_populates="users") default_transfer_account_id = db.Column( db.Integer, db.ForeignKey('transfer_account.id')) default_transfer_account = db.relationship( 'TransferAccount', primaryjoin='TransferAccount.id == User.default_transfer_account_id', lazy=True, uselist=False) default_organisation_id = db.Column(db.Integer, db.ForeignKey('organisation.id')) default_organisation = db.relationship( 'Organisation', primaryjoin=Organisation.id == default_organisation_id, lazy=True, uselist=False) # roles = db.relationship('UserRole', backref='user', lazy=True, # foreign_keys='UserRole.user_id') ussd_sessions = db.relationship('UssdSession', backref='user', lazy=True, foreign_keys='UssdSession.user_id') uploaded_images = db.relationship('UploadedResource', backref='user', lazy=True, foreign_keys='UploadedResource.user_id') kyc_applications = db.relationship('KycApplication', backref='user', lazy=True, foreign_keys='KycApplication.user_id') devices = db.relationship('DeviceInfo', backref='user', lazy=True) referrals = db.relationship( 'User', secondary=referrals, primaryjoin="User.id == referrals.c.referred_user_id", secondaryjoin="User.id == referrals.c.referrer_user_id", backref='referred_by') transfer_card = db.relationship('TransferCard', backref='user', lazy=True, uselist=False) credit_sends = db.relationship( 'CreditTransfer', backref='sender_user', lazy='dynamic', foreign_keys='CreditTransfer.sender_user_id') credit_receives = db.relationship( 'CreditTransfer', backref='recipient_user', lazy='dynamic', foreign_keys='CreditTransfer.recipient_user_id') ip_addresses = db.relationship('IpAddress', backref='user', lazy=True) feedback = db.relationship('Feedback', backref='user', lazy='dynamic', foreign_keys='Feedback.user_id') custom_attributes = db.relationship( "CustomAttributeUserStorage", backref='user', lazy='joined', foreign_keys='CustomAttributeUserStorage.user_id') exchanges = db.relationship("Exchange", backref="user") def delete_user_and_transfer_account(self): """ Soft deletes a User and default Transfer account if no other users associated to it. Removes User PII """ try: ta = self.default_transfer_account ta.delete_transfer_account_from_user(user=self) timenow = datetime.datetime.utcnow() self.deleted = timenow self.first_name = None self.last_name = None self.phone = None except (ResourceAlreadyDeletedError, TransferAccountDeletionError) as e: raise e @hybrid_property def cashout_authorised(self): # loop over all any_valid_token = [t.token for t in self.transfer_accounts] for token in any_valid_token: ct = server.models.credit_transfer example_transfer = ct.CreditTransfer( transfer_type=ct.TransferTypeEnum.PAYMENT, transfer_subtype=ct.TransferSubTypeEnum.AGENT_OUT, sender_user=self, recipient_user=self, token=token, amount=0) limits = example_transfer.get_transfer_limits() limit = limits[0] return limit.period_amount > 0 else: # default to false return False @hybrid_property def phone(self): return self._phone @phone.setter def phone(self, phone): self._phone = proccess_phone_number(phone) @hybrid_property def public_serial_number(self): return self._public_serial_number @public_serial_number.setter def public_serial_number(self, public_serial_number): self._public_serial_number = public_serial_number try: transfer_card = TransferCard.get_transfer_card( public_serial_number) if transfer_card.user_id is None and transfer_card.nfc_serial_number is not None: # Card hasn't been used before, and has a nfc number attached self.nfc_serial_number = transfer_card.nfc_serial_number self.transfer_card = transfer_card except NoTransferCardError: pass @hybrid_property def tfa_url(self): if not self._TFA_secret: self.set_TFA_secret() db.session.flush() secret_key = self.get_TFA_secret() return pyotp.totp.TOTP(secret_key).provisioning_uri( self.email, issuer_name='Sempo: {}'.format( current_app.config.get('DEPLOYMENT_NAME'))) @hybrid_property def location(self): return self._location @location.setter def location(self, location): self._location = location def attempt_update_gps_location(self): from server.utils.location import async_set_user_gps_from_location if self._location is not None and self._location is not '': # Delay execution until after request to avoid race condition with db # We still need to flush to get user id though db.session.flush() add_after_request_executor_job(async_set_user_gps_from_location, kwargs={ 'user_id': self.id, 'location': self._location }) @hybrid_property def roles(self): if self._held_roles is None: return {} return self._held_roles def remove_all_held_roles(self): self._held_roles = {} def set_held_role(self, role: str, tier: Union[str, None]): if role not in ACCESS_ROLES: raise RoleNotFoundException("Role '{}' not valid".format(role)) allowed_tiers = ACCESS_ROLES[role] if tier is not None and tier not in allowed_tiers: raise TierNotFoundException( "Tier {} not recognised for role {}".format(tier, role)) if self._held_roles is None: self._held_roles = {} if tier is None: self._held_roles.pop(role, None) else: self._held_roles[role] = tier flag_modified(self, '_held_roles') @hybrid_property def has_admin_role(self): return AccessControl.has_any_tier(self.roles, 'ADMIN') @has_admin_role.expression def has_admin_role(cls): return cls._held_roles.has_key('ADMIN') @hybrid_property def has_vendor_role(self): return AccessControl.has_any_tier(self.roles, 'VENDOR') @has_vendor_role.expression def has_vendor_role(cls): return cls._held_roles.has_key('VENDOR') @hybrid_property def has_beneficiary_role(self): return AccessControl.has_any_tier(self.roles, 'BENEFICIARY') @has_beneficiary_role.expression def has_beneficiary_role(cls): return cls._held_roles.has_key('BENEFICIARY') @hybrid_property def has_token_agent_role(self): return AccessControl.has_any_tier(self.roles, 'TOKEN_AGENT') @has_token_agent_role.expression def has_token_agent_role(cls): return cls._held_roles.has_key('TOKEN_AGENT') @hybrid_property def has_group_account_role(self): return AccessControl.has_any_tier(self.roles, 'GROUP_ACCOUNT') @has_group_account_role.expression def has_group_account_role(cls): return cls._held_roles.has_key('GROUP_ACCOUNT') @hybrid_property def admin_tier(self): return self._held_roles.get('ADMIN', None) @hybrid_property def vendor_tier(self): return self._held_roles.get('VENDOR', None) # todo: Refactor into above roles # These two are here to interface with the mobile API @hybrid_property def is_vendor(self): return AccessControl.has_sufficient_tier(self.roles, 'VENDOR', 'vendor') @hybrid_property def is_supervendor(self): return AccessControl.has_sufficient_tier(self.roles, 'VENDOR', 'supervendor') @hybrid_property def organisation_ids(self): return [organisation.id for organisation in self.organisations] @property def transfer_account(self): active_organisation = getattr( g, "active_organisation", None) or self.fallback_active_organisation() # TODO: Review if this could have a better concept of a default? return self.get_transfer_account_for_organisation(active_organisation) def get_transfer_account_for_organisation(self, organisation): for ta in self.transfer_accounts: if ta in organisation.transfer_accounts: return ta raise Exception( f"No matching transfer account for user {self}, token {organisation.token} and organsation {organisation}" ) def get_transfer_account_for_token(self, token): return find_transfer_accounts_with_matching_token(self, token) def fallback_active_organisation(self): if len(self.organisations) == 0: return None if len(self.organisations) > 1: return self.default_organisation return self.organisations[0] def update_last_seen_ts(self): cur_time = datetime.datetime.utcnow() if self._last_seen: # default to 1 minute intervals if cur_time - self._last_seen >= datetime.timedelta(minutes=1): self._last_seen = cur_time else: self._last_seen = cur_time @staticmethod def salt_hash_secret(password): f = Fernet(config.PASSWORD_PEPPER) return f.encrypt(bcrypt.hashpw(password.encode(), bcrypt.gensalt())).decode() @staticmethod def check_salt_hashed_secret(password, hashed_password): f = Fernet(config.PASSWORD_PEPPER) hashed_password = f.decrypt(hashed_password.encode()) return bcrypt.checkpw(password.encode(), hashed_password) def hash_password(self, password): self.password_hash = self.salt_hash_secret(password) def verify_password(self, password): return self.check_salt_hashed_secret(password, self.password_hash) def hash_pin(self, pin): self.pin_hash = self.salt_hash_secret(pin) def verify_pin(self, pin): return self.check_salt_hashed_secret(pin, self.pin_hash) def encode_TFA_token(self, valid_days=1): """ Generates the Auth Token for TFA :return: string """ try: payload = { 'exp': datetime.datetime.utcnow() + datetime.timedelta(days=valid_days, seconds=30), 'iat': datetime.datetime.utcnow(), 'id': self.id } return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256') except Exception as e: return e def encode_auth_token(self): """ Generates the Auth Token :return: string """ try: payload = { 'exp': datetime.datetime.utcnow() + datetime.timedelta( seconds=current_app.config['AUTH_TOKEN_EXPIRATION']), 'iat': datetime.datetime.utcnow(), 'id': self.id, 'roles': self.roles } return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256') except Exception as e: return e @staticmethod def decode_auth_token(auth_token, token_type='Auth'): """ Validates the auth token :param auth_token: :return: integer|string """ try: payload = jwt.decode(auth_token, current_app.config['SECRET_KEY'], algorithms='HS256', options={ 'verify_exp': current_app.config['VERIFY_JWT_EXPIRY'] }) is_blacklisted_token = BlacklistToken.check_blacklist(auth_token) if is_blacklisted_token: return 'Token blacklisted. Please log in again.' else: return payload except jwt.ExpiredSignatureError: return '{} Token Signature expired.'.format(token_type) except jwt.InvalidTokenError: return 'Invalid {} Token.'.format(token_type) def encode_single_use_JWS(self, token_type): s = TimedJSONWebSignatureSerializer( current_app.config['SECRET_KEY'], expires_in=current_app.config['SINGLE_USE_TOKEN_EXPIRATION']) return s.dumps({'id': self.id, 'type': token_type}).decode("utf-8") @classmethod def decode_single_use_JWS(cls, token, required_type): try: s = TimedJSONWebSignatureSerializer( current_app.config['SECRET_KEY']) data = s.loads(token.encode("utf-8")) user_id = data.get('id') token_type = data.get('type') if token_type != required_type: return { 'success': False, 'message': 'Wrong token type (needed %s)' % required_type } if not user_id: return {'success': False, 'message': 'No User ID provided'} user = cls.query.filter_by(id=user_id).execution_options( show_all=True).first() if not user: return {'success': False, 'message': 'User not found'} return {'success': True, 'user': user} except BadSignature: return {'success': False, 'message': 'Token signature not valid'} except SignatureExpired: return {'success': False, 'message': 'Token has expired'} except Exception as e: return {'success': False, 'message': e} def save_password_reset_token(self, password_reset_token): # make a "clone" of the existing token list self.clear_expired_password_reset_tokens() current_password_reset_tokens = self.password_reset_tokens[:] current_password_reset_tokens.append(password_reset_token) # set db value self.password_reset_tokens = current_password_reset_tokens def save_pin_reset_token(self, pin_reset_token): self.clear_expired_pin_reset_tokens() current_pin_reset_tokens = self.pin_reset_tokens[:] current_pin_reset_tokens.append(pin_reset_token) self.pin_reset_tokens = current_pin_reset_tokens def check_reset_token_already_used(self, password_reset_token): self.clear_expired_password_reset_tokens() is_valid = password_reset_token in self.password_reset_tokens return is_valid def delete_password_reset_tokens(self): self.password_reset_tokens = [] def delete_pin_reset_tokens(self): self.pin_reset_tokens = [] def clear_expired_reset_tokens(self, token_list): if token_list is None: token_list = [] valid_tokens = [] for token in token_list: validity_check = self.decode_single_use_JWS(token, 'R') if validity_check['success']: valid_tokens.append(token) return valid_tokens def clear_expired_password_reset_tokens(self): tokens = self.clear_expired_reset_tokens(self.password_reset_tokens) self.password_reset_tokens = tokens def clear_expired_pin_reset_tokens(self): tokens = self.clear_expired_reset_tokens(self.pin_reset_tokens) self.pin_reset_tokens = tokens def create_admin_auth(self, email, password, tier='view', organisation=None): self.email = email self.hash_password(password) self.set_held_role('ADMIN', tier) if organisation: self.add_user_to_organisation(organisation, is_admin=True) def add_user_to_organisation(self, organisation: Organisation, is_admin=False): if not self.default_organisation: self.default_organisation = organisation self.organisations.append(organisation) if is_admin and organisation.org_level_transfer_account_id: if organisation.org_level_transfer_account is None: organisation.org_level_transfer_account = (db.session.query( server.models.transfer_account.TransferAccount ).execution_options(show_all=True).get( organisation.org_level_transfer_account_id)) self.transfer_accounts.append( organisation.org_level_transfer_account) def is_TFA_required(self): for tier in current_app.config['TFA_REQUIRED_ROLES']: if AccessControl.has_exact_role(self.roles, 'ADMIN', tier): return True else: return False def is_TFA_secret_set(self): return bool(self._TFA_secret) def set_TFA_secret(self): secret = pyotp.random_base32() self._TFA_secret = encrypt_string(secret) def get_TFA_secret(self): return decrypt_string(self._TFA_secret) def validate_OTP(self, input_otp): secret = self.get_TFA_secret() server_otp = pyotp.TOTP(secret) ret = server_otp.verify(input_otp, valid_window=2) return ret def set_one_time_code(self, supplied_one_time_code): if supplied_one_time_code is None: self.one_time_code = str(random.randint(0, 9999)).zfill(4) else: self.one_time_code = supplied_one_time_code # pin as used in mobile. is set to password. we should probably change this to be same as ussd pin def set_pin(self, supplied_pin=None, is_activated=False): self.is_activated = is_activated if not is_activated: # Use a one time code, either generated or supplied. PIN will be set to random number for now self.set_one_time_code(supplied_one_time_code=supplied_pin) pin = str(random.randint(0, 9999)).zfill(4) else: pin = supplied_pin self.hash_password(pin) def has_valid_pin(self): # not in the process of resetting pin and has a pin self.clear_expired_pin_reset_tokens() not_resetting = len(self.pin_reset_tokens) == 0 return self.pin_hash is not None and not_resetting and self.failed_pin_attempts < 3 def user_details(self): # should drop the country code from phone number? return "{} {} {}".format(self.first_name, self.last_name, self.phone) def get_most_relevant_transfer_usages(self): '''Finds the transfer usage/business categories there are most relevant for the user based on the last number of send and completed credit transfers supplemented with the defaul business categories :return: list of most relevant transfer usage objects for the usage """ ''' sql = text(''' SELECT *, COUNT(*) FROM (SELECT c.transfer_use::text FROM credit_transfer c WHERE c.sender_user_id = {} AND c.transfer_status = 'COMPLETE' ORDER BY c.updated DESC LIMIT 20) C GROUP BY transfer_use ORDER BY count DESC '''.format(self.id)) result = db.session.execute(sql) most_common_uses = {} for row in result: if row[0] is not None: for use in json.loads(row[0]): most_common_uses[use] = row[1] return most_common_uses def get_reserve_token(self): # reserve token is master token for now return Organisation.master_organisation().token def __init__(self, blockchain_address=None, **kwargs): super(User, self).__init__(**kwargs) self.secret = ''.join( random.choices(string.ascii_letters + string.digits, k=16)) self.primary_blockchain_address = blockchain_address or bt.create_blockchain_wallet( ) def __repr__(self): if self.has_admin_role: return '<Admin {} {}>'.format(self.id, self.email) elif self.has_vendor_role: return '<Vendor {} {}>'.format(self.id, self.phone) else: return '<User {} {}>'.format(self.id, self.phone)
class Store(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255)) item_group = db.Column(db.Integer) price = db.Column(db.Integer) limit = db.Column(db.Integer)
class User(db.Model): __tablename__ = 'USER' __table_args__ = {'mysql_collate': 'utf8_general_ci'} user_idx = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(256), index=True, unique=True) user_id = db.Column(db.String(50), index=True, unique=True) password = db.Column(db.String(60)) user_nm = db.Column(db.String(50)) identity_num = db.Column(db.Integer, index=True, unique=True) admin_type = db.Column(db.String(10)) user_type = db.Column(db.String(1)) sex_gb = db.Column(db.String(1)) user_status = db.Column(db.String(1)) policy_yn = db.Column(db.String(1)) college_cd = db.Column(db.String(10)) dpt_cd = db.Column(db.String(10)) auth_email_yn = db.Column(db.String(1)) auth_token = db.Column(db.String(20)) user_profile = db.Column(db.String(100)) nick_nm = db.Column(db.String(50)) bamboo_stack = db.Column(db.Integer) links = db.Column(db.String(50)) reg_ip = db.Column(db.String(40)) reg_dt = db.Column(db.DateTime) upt_ip = db.Column(db.String(40)) upt_dt = db.Column(db.DateTime) log_ip = db.Column(db.String(40)) log_dt = db.Column(db.DateTime) def __init__(self, email, user_id, password, user_nm, identity_num, user_type, sex_gb, college_cd, dpt_cd, auth_token, nick_nm, reg_ip, reg_dt, upt_ip, upt_dt, log_ip, log_dt, admin_type='ORD', policy_yn='Y', user_status='Y', auth_email_yn='N', bamboo_stack=None, user_profile='', links=''): self.email = email self.user_id = user_id self.password = password self.user_nm = user_nm self.identity_num = identity_num self.user_type = user_type self.sex_gb = sex_gb self.user_status = user_status self.college_cd = college_cd self.dpt_cd = dpt_cd self.auth_token = auth_token self.nick_nm = nick_nm self.reg_dt = reg_dt self.reg_ip = reg_ip self.upt_dt = upt_dt self.upt_ip = upt_ip self.log_dt = log_dt self.log_ip = log_ip self.admin_type = admin_type self.policy_yn = policy_yn self.auth_email_yn = auth_email_yn self.bamboo_stack = bamboo_stack self.user_profile = user_profile self.links = links def __repr__(self): return '<User %r>' % self.user_nm def as_dict(self): return {x.name: getattr(self, x.name) for x in self.__table__.columns}
class TableName(db.Model): __table_args__ = (db.UniqueConstraint('uid', 'name'), ) id = db.Column(db.Integer, autoincrement=True, primary_key=True) uid = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) name = db.Column(db.String(80), nullable=False) tables = db.relationship('Table', backref='name', lazy=True)
class Regle(db.Model): __tablename__ = 'Regle' __bind_key__ = 'plu_tr' id_regle = db.Column('id_regle', db.Integer, primary_key=True) regle_brute = db.Column('regle_brute', db.String(200))