class User(UserMixin, db.Model, BaseModel): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.String(255), unique=True, nullable=False) first_name = db.Column(db.String, nullable=True) last_name = db.Column(db.String, nullable=True) full_name = db.Column(db.String, nullable=True) avatar_url = db.Column(db.String, nullable=True) is_active = db.Column(db.Boolean, nullable=False, default=True) # password_hash = db.Column(db.String(255), nullable=False) registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow()) # admin = db.Column(db.Boolean, nullable=False, default=False) roles = db.relationship('UserRole', secondary='users_user_roles', lazy='dynamic', backref=db.backref('users', lazy=True)) symbols = db.relationship('CurrencyPair', secondary=symbol_subscribers, lazy='subquery', backref=db.backref('users', lazy=True)) buy_percentage = db.Column(db.Float, nullable=True, default=0.5) sell_percentage = db.Column(db.Float, nullable=True, default=0.5) close_bet_interval_in_minutes = db.Column(db.Float, nullable=True, default=10) def __repr__(self): return '<User {0}>'.format(self.email) def add_role(self, role_name): try: role = UserRole.query.filter_by(role_name=role_name).first() if role not in self.roles: return self.roles.append(role) else: return self.roles except exc.IdentifierError: pass def get_full_name(self): return "{0} {1}".format(self.first_name, self.last_name) @property def get_user_roles_names_list(self): return [each.role_name for each in self.roles]
class Task(db.Model): __tablename__ = 'tasks' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(250), unique=True, nullable=False) description = db.Column(db.String) creation_date = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False) status = db.Column(db.Integer, nullable=False, default=0) # Relationships users = db.relationship('User', secondary=task_users, backref=db.backref('tasks')) @hybrid_property def nr_users(self): return len(self.annotations) def update_users(self, user_ids): new_users = db.session.query(User).filter(User.id.in_(user_ids)).all() self.users = new_users db.session.commit() def __init__(self, name, status=0): self.name = name self.status = status
class Post(ResourceMixin, db.Model): __tablename__ = 'posts' # Relationships comments = db.relationship('Comment', backref=db.backref('post', uselist=False), passive_deletes=True, lazy='dynamic') # Properties id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), index=True, unique=True, nullable=False) body = db.Column(db.ARRAY(db.String), nullable=False) summary = db.Column(db.String(250), nullable=False) img_src = db.Column(db.String(200)) thumbnail_src = db.Column(db.String(200)) view_count = db.Column(db.Integer, server_default='0') # Foreign Keys author_id = db.Column(db.Integer, db.ForeignKey('staff.id')) practice_area_id = db.Column(db.Integer, db.ForeignKey('practice_areas.id')) def __init__(self, **kwargs): # Call Flask-SQLAlchemy's constructor. super(Post, self).__init__(**kwargs) @hybrid_property def slug(self): return slugify(self.title) @classmethod def find_by_title(cls, title): """ Find client by user ID. :param user_id: user ID :type title: str :return: Client instance """ return cls.query.filter(cls.title == title).first() def to_json(self): return { 'id': self.id, 'title': self.title, 'author': self.author.user.first_last_name, 'body': self.body, 'summary': self.summary, 'practiceArea': self.practice_area.area, 'imgSrc': self.img_src, 'thumbnailSrc': self.thumbnail_src, 'created': self.created_on, 'updated': self.updated_on, 'views': self.view_count, 'authorPhoto': self.author.user.photo, 'slug': self.slug }
class UserUserRole(db.Model, BaseModel): __tablename__ = 'users_user_roles' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) product_id = db.Column(db.Integer, db.ForeignKey('user_roles.id')) creation_date = db.Column(db.DateTime, default=datetime.utcnow) user = db.relationship(User, lazy='subquery', backref=db.backref("users_user_roles", cascade="all, delete-orphan", lazy=True)) user_role = db.relationship(UserRole, lazy='subquery', backref=db.backref( "users_user_roles", cascade="all, delete-orphan", lazy=True))
class UserRole(db.Model, BaseModel): """This model created for custom permission role_name: is the permissions' name. It can be "owner" or screens' name ("order history") for which user has permission""" __tablename__ = 'user_roles' id = db.Column(db.Integer, primary_key=True, autoincrement=True) role_name = db.Column(db.String, unique=True, nullable=False) roles = db.relationship('User', secondary='users_user_roles', lazy='dynamic', backref=db.backref('user_roles', lazy=True)) def __repr__(self): return '<Role {0}>'.format(self.role_name)
class StockMarket(db.Model, BaseModel): __tablename__ = 'stock_market' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), unique=True, nullable=False) web_address = db.Column(db.String(200), unique=True, nullable=True) currencies = db.relationship('Currency', secondary=market_currencies, lazy='subquery', backref=db.backref('stock_markets', lazy=True)) leverage = db.Column(db.Integer, default=1) max_leverage = db.Column(db.Integer, default=leverage) balance_percentage = db.Column(db.Integer, default=0) transaction_fee = db.Column(db.Float, nullable=True, default=0.001) is_available = db.Column(db.Boolean, nullable=True, default=True) is_trading_active = db.Column(db.Boolean, default=False) is_terminate_all_required = db.Column(db.Boolean, default=False) def to_json(self, currencies=False): result = { "id": self.id, "name": self.name, "web_address": self.web_address, "leverage": self.leverage, "balance_percentage": self.balance_percentage } if currencies: result["currencies"] = [currency.to_json() for currency in self.currencies] return result def __repr__(self): return "<id: {}>, <name: {}>".format(self.id, self.name) @staticmethod def get_by_name(market_name): market = StockMarket.query.filter_by(name=market_name).first() if not market: raise NoMarketByNameException("No market by name: {}".format(market_name)) return market
class Picture(db.Model): """ Picture database """ __table__name = 'picture' id = Column('Id', db.Integer, primary_key=True, autoincrement=True) data = Column('data', db.LargeBinary, nullable=False) author_id = Column( 'AuthorID', db.String(STRING_LEN), db.ForeignKey('user.Id', ondelete='SET NULL', onupdate='CASCADE')) author = db.relationship("User", backref=db.backref("pictures", lazy='dynamic'), lazy=True) def __init__(self): pass def set_data(self, data, author_id): self.data = data self.author_id = author_id def add_picture(self): try: Picture.query.filter_by(id=self.id).one() return False except NoResultFound: try: db.session.add(self) db.session.commit() return True except IntegrityError: db.session.rollback() return False except Exception as e: db.session.rollback() raise e
class PracticeArea(ResourceMixin, db.Model): __tablename__ = 'practice_areas' # Relationships posts = db.relationship('Post', backref=db.backref('practice_area', lazy="joined"), lazy='dynamic') matters = db.relationship('Matter', backref='practice_areas', secondary=practice_area_matter) # Properties id = db.Column(db.Integer, primary_key=True) area = db.Column(db.String(128), nullable=False, unique=True, index=True) img_src = db.Column(db.String(200)) thumbnail_src = db.Column(db.String(200)) description = db.Column(db.ARRAY(db.String), nullable=False) slug = db.Column(db.String(128), nullable=False, unique=True, index=True) @classmethod def get_by_slug(cls, slug): return PracticeArea.query.filter(PracticeArea.slug == slug).first() def to_json_short(self): return { 'id': self.id, 'area': self.area } def to_json(self): return { 'id': self.id, 'area': self.area, 'imgSrc': self.img_src, 'thumbnailSrc': self.thumbnail_src, 'posts': [post.id for post in self.posts], 'matters': [matter.id for matter in self.matters], 'staff': [staff_member.id for staff_member in self.staff], 'description': self.description, 'slug': self.slug }
class User(UserMixin, ResourceMixin, db.Model): ROLE = OrderedDict([('admin', 'Admin'), ('client', 'Client'), ('staff', 'Staff'), ('public', 'Public')]) __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) # Relationships client = db.relationship(Client, backref=db.backref('user', uselist=False), uselist=False, cascade="all, delete-orphan") staff = db.relationship(Staff, backref=db.backref('user', uselist=False), uselist=False, cascade="all, delete-orphan") comments = db.relationship(Comment, backref=db.backref('author', uselist=False), lazy='dynamic') appointments = db.relationship(Appointment, backref='user', lazy='dynamic') # Properties. role = db.Column(db.Enum(*ROLE, name='role_types', native_enum=False), index=True, nullable=False, server_default='public') active = db.Column('is_active', db.Boolean(), nullable=False, server_default='1') username = db.Column(db.String(24), unique=True, index=True, nullable=False) email = db.Column(db.String(255), unique=True, index=True, nullable=False, server_default='') password = db.Column(db.String(128), nullable=False, server_default='') first_name = db.Column(db.String(256), nullable=False) middle_name = db.Column(db.String(256)) last_name = db.Column(db.String(256), index=True, nullable=False) unit_number = db.Column(db.String(128)) street_address = db.Column(db.String(128)) suburb = db.Column(db.String(128)) postcode = db.Column(db.String(4)) state = db.Column(db.String(128)) country = db.Column(db.String(128)) phone_number = db.Column(db.String(128), nullable=False) photo = db.Column(db.String(256)) # Activity tracking. sign_in_count = db.Column(db.Integer, nullable=False, default=0) current_sign_in_on = db.Column(AwareDateTime()) current_sign_in_ip = db.Column(db.String(45)) last_sign_in_on = db.Column(AwareDateTime()) last_sign_in_ip = db.Column(db.String(45)) # Additional settings. locale = db.Column(db.String(5), nullable=False, server_default='en') def __init__(self, **kwargs): # Call Flask-SQLAlchemy's constructor. super(User, self).__init__(**kwargs) self.password = User.encrypt_password(kwargs.get('password', '')) @hybrid_property def full_name(self): if self.middle_name: return self.last_name.upper( ) + ', ' + self.first_name + ' ' + self.middle_name else: return self.last_name.upper() + ', ' + self.first_name @hybrid_property def first_last_name(self): return self.first_name + ' ' + self.last_name @hybrid_property def full_address(self): street_address = self.unit_number + "/" + self.street_address if self.unit_number and self.street_address else self.street_address address_elements = [ street_address, self.suburb, self.postcode, self.state, self.country ] return ", ".join( address_elements) if None not in address_elements else None @classmethod def find_by_identity(cls, identity): """ Find user by e-mail or username. :param identity: Email or username :type identity: str :return: User instance """ return User.query.filter((User.email == identity) | (User.username == identity)).first() @classmethod def encrypt_password(cls, plaintext_password): """ Hash password using Bcrypt. :param plaintext_password: Password in plain text :type plaintext_password: str :return: str """ if plaintext_password: return hashpw(plaintext_password, gensalt()) return None @classmethod def deserialize_token(cls, token): """ Obtain user from de-serializing token. :param token: Signed token. :type token: str :return: User instance or None """ private_key = TimedJSONWebSignatureSerializer( current_app.config['SECRET_KEY']) try: decoded_payload = private_key.loads(token) return User.find_by_identity(decoded_payload.get('user_email')) except Exception: return None @classmethod def initialize_password_reset(cls, identity): """ Generate token to reset the password for a specific user. :param identity: User e-mail address or username :type identity: str :return: User instance """ u = User.find_by_identity(identity) reset_token = u.serialize_token() # This prevents circular imports. from server.blueprints.user.tasks import (deliver_password_reset_email) deliver_password_reset_email.delay(u.id, reset_token) return u @classmethod def search(cls, query): """ Search using ILIKE (case-insensitive) expression. :param query: Search query :type query: str :return: SQLAlchemy filter """ if not query: return '' search_query = '%{0}%'.format(query) search_chain = (User.email.ilike(search_query), User.username.ilike(search_query)) return or_(*search_chain) @classmethod def is_last_admin(cls, user, new_role, new_active): """ Return whether user is last admin account. :param user: User being tested :type user: User :param new_role: New role being set :type new_role: str :param new_active: New active status being set :type new_active: bool :return: bool """ is_changing_roles = user.role == 'admin' and new_role != 'admin' is_changing_active = user.active is True and new_active is None if is_changing_roles or is_changing_active: admin_count = User.query.filter(User.role == 'admin').count() active_count = User.query.filter(User.is_active is True).count() if admin_count == 1 or active_count == 1: return True return False def is_active(self): """ Return whether user account is active (overrides Flask-Login default). :return: bool """ return self.active def get_auth_token(self): """ Return user's auth token. :return: str """ private_key = current_app.config['SECRET_KEY'] serializer = URLSafeTimedSerializer(private_key) data = [str(self.id), md5(self.password.encode('utf-8')).hexdigest()] return serializer.dumps(data) def authenticated(self, with_password=True, password=''): """ Ensure user authenticated. :param with_password: Optionally check password :type with_password: bool :param password: Password to verify :type password: str :return: bool """ if with_password: return checkpw(password.encode('utf-8'), self.password.encode('utf-8')) return True def serialize_token(self, expiration=3600): """ Serialize token for resetting passwords, etc. :param expiration: Seconds until it expires, defaults to 1 hour :type expiration: int :return: JSON """ private_key = current_app.config['SECRET_KEY'] serializer = TimedJSONWebSignatureSerializer(private_key, expiration) return serializer.dumps({'user_email': self.email}).decode('utf-8') def update_activity_tracking(self, ip_address): """ Update user's meta data. :param ip_address: IP address :type ip_address: str :return: SQLAlchemy commit results """ self.sign_in_count += 1 self.last_sign_in_on = self.current_sign_in_on self.last_sign_in_ip = self.current_sign_in_ip self.current_sign_in_on = datetime.datetime.now(pytz.utc) self.current_sign_in_ip = ip_address return self.save() def to_json(self): active = "Active" if self.active == True else "Disabled" json_data = { 'id': self.id, 'created': self.created_on, 'updated': self.updated_on, 'active': active, 'firstLastName': self.first_last_name, 'firstName': self.first_name, 'middleName': self.middle_name, 'lastName': self.last_name.upper(), 'fullName': self.full_name, 'username': self.username, 'email': self.email, 'phoneNumber': self.phone_number, 'unitNumber': self.unit_number, 'streetAddress': self.street_address, 'suburb': self.suburb, 'postcode': self.postcode, 'state': self.state, 'country': self.country, 'fullAddress': self.full_address, 'role': self.role, 'photo': self.photo, } return json_data
class Staff(ResourceMixin, db.Model): __tablename__ = 'staff' # Relationships posts_authored = db.relationship(Post, backref=db.backref('author', lazy="joined"), lazy='dynamic') matters_handled = db.relationship(Matter, backref='staff', secondary=staff_matter) appointments = db.relationship(Appointment, backref='staff', secondary=staff_appointment) practice_areas = db.relationship(PracticeArea, backref='staff', secondary=staff_practice_area) id = db.Column(db.Integer, primary_key=True) dated_joined = db.Column(AwareDateTime(), default=tzaware_datetime) position = db.Column(db.String(128)) description = db.Column(db.ARRAY(db.String)) # Foreign Keys user_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True, unique=True, nullable=False) @classmethod def find_by_user_id(cls, user_id): """ Find staff by user ID. :param user_id: user ID :type title: str :return: Staff instance """ return cls.query.filter(cls.user_id == user_id).first() def to_json(self): matters_handled = [matter.id for matter in self.matters_handled] posts_authored = [post.id for post in self.posts_authored] practice_areas = [ practice_area.id for practice_area in self.practice_areas ] return { 'id': self.id, 'name': self.user.first_last_name, 'dateJoined': self.dated_joined, 'position': self.position, 'photo': self.user.photo, 'posts': self.posts_authored.count(), 'description': self.description, 'userId': self.user_id, 'mattersHandled': matters_handled, 'postsAuthored': posts_authored, 'practiceAreas': practice_areas }