Remove submodule cic ussd
This commit is contained in:
47
apps/cic-ussd/cic_ussd/db/models/base.py
Normal file
47
apps/cic-ussd/cic_ussd/db/models/base.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# standard imports
|
||||
import datetime
|
||||
|
||||
# third-party imports
|
||||
from sqlalchemy import Column, Integer, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
Model = declarative_base(name='Model')
|
||||
|
||||
|
||||
class SessionBase(Model):
|
||||
__abstract__ = True
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
created = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
engine = None
|
||||
session = None
|
||||
query = None
|
||||
|
||||
@staticmethod
|
||||
def create_session():
|
||||
session = sessionmaker(bind=SessionBase.engine)
|
||||
return session()
|
||||
|
||||
@staticmethod
|
||||
def _set_engine(engine):
|
||||
SessionBase.engine = engine
|
||||
|
||||
@staticmethod
|
||||
def build():
|
||||
Model.metadata.create_all(bind=SessionBase.engine)
|
||||
|
||||
@staticmethod
|
||||
# https://docs.sqlalchemy.org/en/13/core/pooling.html#pool-disconnects
|
||||
def connect(data_source_name):
|
||||
engine = create_engine(data_source_name, pool_pre_ping=True)
|
||||
SessionBase._set_engine(engine)
|
||||
|
||||
@staticmethod
|
||||
def disconnect():
|
||||
SessionBase.engine.dispose()
|
||||
SessionBase.engine = None
|
||||
|
||||
19
apps/cic-ussd/cic_ussd/db/models/task_tracker.py
Normal file
19
apps/cic-ussd/cic_ussd/db/models/task_tracker.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# third-party imports
|
||||
from sqlalchemy import Column, String
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TaskTracker(SessionBase):
|
||||
__tablename__ = 'task_tracker'
|
||||
|
||||
def __init__(self, task_uuid):
|
||||
self.task_uuid = task_uuid
|
||||
|
||||
task_uuid = Column(String, nullable=False)
|
||||
90
apps/cic-ussd/cic_ussd/db/models/user.py
Normal file
90
apps/cic-ussd/cic_ussd/db/models/user.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# standard imports
|
||||
from enum import IntEnum
|
||||
|
||||
# third party imports
|
||||
from sqlalchemy import Column, Integer, String
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.encoder import check_password_hash, create_password_hash
|
||||
|
||||
|
||||
class AccountStatus(IntEnum):
|
||||
PENDING = 1
|
||||
ACTIVE = 2
|
||||
LOCKED = 3
|
||||
RESET = 4
|
||||
|
||||
|
||||
class User(SessionBase):
|
||||
"""
|
||||
This class defines a user record along with functions responsible for hashing the user's corresponding password and
|
||||
subsequently verifying a password's validity given an input to compare against the persisted hash.
|
||||
"""
|
||||
__tablename__ = 'user'
|
||||
|
||||
blockchain_address = Column(String)
|
||||
phone_number = Column(String)
|
||||
password_hash = Column(String)
|
||||
failed_pin_attempts = Column(Integer)
|
||||
account_status = Column(Integer)
|
||||
preferred_language = Column(String)
|
||||
|
||||
def __init__(self, blockchain_address, phone_number):
|
||||
self.blockchain_address = blockchain_address
|
||||
self.phone_number = phone_number
|
||||
self.password_hash = None
|
||||
self.failed_pin_attempts = 0
|
||||
self.account_status = AccountStatus.PENDING.value
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User: {self.blockchain_address}>'
|
||||
|
||||
def create_password(self, password):
|
||||
"""This method takes a password value and hashes the value before assigning it to the corresponding
|
||||
`hashed_password` attribute in the user record.
|
||||
:param password: A password value
|
||||
:type password: str
|
||||
"""
|
||||
self.password_hash = create_password_hash(password)
|
||||
|
||||
def verify_password(self, password):
|
||||
"""This method takes a password value and compares it to the user's corresponding `hashed_password` value to
|
||||
establish password validity.
|
||||
:param password: A password value
|
||||
:type password: str
|
||||
:return: Pin validity
|
||||
:rtype: boolean
|
||||
"""
|
||||
return check_password_hash(password, self.password_hash)
|
||||
|
||||
def reset_account_pin(self):
|
||||
"""This method is used to unlock a user's account."""
|
||||
self.failed_pin_attempts = 0
|
||||
self.account_status = AccountStatus.RESET.value
|
||||
|
||||
def get_account_status(self):
|
||||
"""This method checks whether the account is past the allowed number of failed pin attempts.
|
||||
If so, it changes the accounts status to Locked.
|
||||
:return: The account status for a user object
|
||||
:rtype: str
|
||||
"""
|
||||
if self.failed_pin_attempts > 2:
|
||||
self.account_status = AccountStatus.LOCKED.value
|
||||
return AccountStatus(self.account_status).name
|
||||
|
||||
def activate_account(self):
|
||||
"""This method is used to reset failed pin attempts and change account status to Active."""
|
||||
self.failed_pin_attempts = 0
|
||||
self.account_status = AccountStatus.ACTIVE.value
|
||||
|
||||
def has_valid_pin(self):
|
||||
"""This method checks whether the user's account status and if a pin hash is present which implies
|
||||
pin validity.
|
||||
:return: The presence of a valid pin and status of the account being active.
|
||||
:rtype: bool
|
||||
"""
|
||||
valid_pin = None
|
||||
if self.get_account_status() == 'ACTIVE' and self.password_hash is not None:
|
||||
valid_pin = True
|
||||
return valid_pin
|
||||
71
apps/cic-ussd/cic_ussd/db/models/ussd_session.py
Normal file
71
apps/cic-ussd/cic_ussd/db/models/ussd_session.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# third-party imports
|
||||
from sqlalchemy import Column, String, Integer
|
||||
from sqlalchemy.dialects.postgresql import JSON
|
||||
from sqlalchemy.orm.attributes import flag_modified
|
||||
|
||||
# local imports
|
||||
from cic_ussd.db.models.base import SessionBase
|
||||
from cic_ussd.error import VersionTooLowError
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UssdSession(SessionBase):
|
||||
__tablename__ = 'ussd_session'
|
||||
|
||||
external_session_id = Column(String, nullable=False, index=True, unique=True)
|
||||
service_code = Column(String, nullable=False)
|
||||
msisdn = Column(String, nullable=False)
|
||||
user_input = Column(String)
|
||||
state = Column(String, nullable=False)
|
||||
session_data = Column(JSON)
|
||||
version = Column(Integer, nullable=False)
|
||||
|
||||
def set_data(self, key, session, value):
|
||||
if self.session_data is None:
|
||||
self.session_data = {}
|
||||
self.session_data[key] = value
|
||||
|
||||
# https://stackoverflow.com/questions/42559434/updates-to-json-field-dont-persist-to-db
|
||||
flag_modified(self, "session_data")
|
||||
session.add(self)
|
||||
|
||||
def get_data(self, key):
|
||||
if self.session_data is not None:
|
||||
return self.session_data.get(key)
|
||||
else:
|
||||
return None
|
||||
|
||||
def check_version(self, new_version):
|
||||
if new_version <= self.version:
|
||||
raise VersionTooLowError('New session version number is not greater than last saved version!')
|
||||
|
||||
def update(self, user_input, state, version, session):
|
||||
self.check_version(version)
|
||||
self.user_input = user_input
|
||||
self.state = state
|
||||
self.version = version
|
||||
session.add(self)
|
||||
|
||||
@staticmethod
|
||||
def have_session_for_phone(phone):
|
||||
r = UssdSession.session.query(UssdSession).filter_by(msisdn=phone).first()
|
||||
return r is not None
|
||||
|
||||
def to_json(self):
|
||||
""" This function serializes the in db ussd session object to a JSON object
|
||||
:return: A JSON object of a ussd session in db
|
||||
:rtype: dict
|
||||
"""
|
||||
return {
|
||||
"external_session_id": self.external_session_id,
|
||||
"service_code": self.service_code,
|
||||
"msisdn": self.msisdn,
|
||||
"user_input": self.user_input,
|
||||
"state": self.state,
|
||||
"session_data": self.session_data,
|
||||
"version": self.version
|
||||
}
|
||||
Reference in New Issue
Block a user