2016-01-28 11:42:13 +00:00
|
|
|
import uuid
|
|
|
|
|
|
2016-02-02 14:16:08 +00:00
|
|
|
from sqlalchemy import UniqueConstraint, Sequence
|
2016-01-07 17:31:17 +00:00
|
|
|
from . import db
|
2016-01-11 15:07:13 +00:00
|
|
|
import datetime
|
2016-02-19 14:47:45 +00:00
|
|
|
from sqlalchemy.dialects.postgresql import (UUID, ARRAY)
|
2016-01-19 11:38:29 +00:00
|
|
|
from app.encryption import (
|
|
|
|
|
hashpw,
|
|
|
|
|
check_hash
|
|
|
|
|
)
|
2016-01-15 11:12:05 +00:00
|
|
|
|
2016-01-07 17:31:17 +00:00
|
|
|
|
2016-01-08 17:51:46 +00:00
|
|
|
def filter_null_value_fields(obj):
|
|
|
|
|
return dict(
|
|
|
|
|
filter(lambda x: x[1] is not None, obj.items())
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2016-01-07 17:31:17 +00:00
|
|
|
class User(db.Model):
|
|
|
|
|
__tablename__ = 'users'
|
|
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
2016-01-19 11:38:29 +00:00
|
|
|
name = db.Column(db.String, nullable=False, index=True, unique=False)
|
2016-01-07 17:31:17 +00:00
|
|
|
email_address = db.Column(db.String(255), nullable=False, index=True, unique=True)
|
2016-01-11 15:07:13 +00:00
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
|
|
|
|
default=datetime.datetime.now)
|
|
|
|
|
updated_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True,
|
|
|
|
|
onupdate=datetime.datetime.now)
|
2016-01-19 11:38:29 +00:00
|
|
|
_password = db.Column(db.String, index=False, unique=False, nullable=False)
|
|
|
|
|
mobile_number = db.Column(db.String, index=False, unique=False, nullable=False)
|
|
|
|
|
password_changed_at = db.Column(db.DateTime, index=False, unique=False, nullable=True)
|
|
|
|
|
logged_in_at = db.Column(db.DateTime, nullable=True)
|
|
|
|
|
failed_login_count = db.Column(db.Integer, nullable=False, default=0)
|
|
|
|
|
state = db.Column(db.String, nullable=False, default='pending')
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def password(self):
|
|
|
|
|
raise AttributeError("Password not readable")
|
|
|
|
|
|
|
|
|
|
@password.setter
|
|
|
|
|
def password(self, password):
|
|
|
|
|
self._password = hashpw(password)
|
|
|
|
|
|
|
|
|
|
def check_password(self, password):
|
|
|
|
|
return check_hash(password, self._password)
|
2016-01-08 17:51:46 +00:00
|
|
|
|
2016-01-07 17:31:17 +00:00
|
|
|
|
|
|
|
|
user_to_service = db.Table(
|
|
|
|
|
'user_to_service',
|
|
|
|
|
db.Model.metadata,
|
|
|
|
|
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
|
2016-02-25 12:11:51 +00:00
|
|
|
db.Column('service_id', UUID(as_uuid=True), db.ForeignKey('services.id')),
|
|
|
|
|
|
|
|
|
|
UniqueConstraint('user_id', 'service_id', name='uix_user_to_service')
|
|
|
|
|
|
2016-01-07 17:31:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Service(db.Model):
|
|
|
|
|
__tablename__ = 'services'
|
|
|
|
|
|
2016-02-02 14:16:08 +00:00
|
|
|
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
|
|
|
old_id = db.Column(db.Integer, Sequence('services_id_seq'), nullable=False)
|
2016-02-19 15:52:19 +00:00
|
|
|
name = db.Column(db.String(255), nullable=False, unique=True)
|
2016-01-11 15:07:13 +00:00
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
|
|
|
|
default=datetime.datetime.now)
|
|
|
|
|
updated_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True,
|
|
|
|
|
onupdate=datetime.datetime.now)
|
2016-01-07 17:31:17 +00:00
|
|
|
active = db.Column(db.Boolean, index=False, unique=False, nullable=False)
|
|
|
|
|
limit = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
2016-01-11 15:07:13 +00:00
|
|
|
users = db.relationship(
|
|
|
|
|
'User',
|
|
|
|
|
secondary=user_to_service,
|
|
|
|
|
backref=db.backref('user_to_service', lazy='dynamic'))
|
2016-01-07 17:31:17 +00:00
|
|
|
restricted = db.Column(db.Boolean, index=False, unique=False, nullable=False)
|
2016-02-19 15:52:19 +00:00
|
|
|
email_from = db.Column(db.Text, index=False, unique=True, nullable=False)
|
2016-01-13 11:04:13 +00:00
|
|
|
|
2016-01-27 17:42:05 +00:00
|
|
|
|
2016-01-19 12:07:00 +00:00
|
|
|
class ApiKey(db.Model):
|
|
|
|
|
__tablename__ = 'api_key'
|
2016-01-13 09:25:46 +00:00
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
2016-01-19 12:07:00 +00:00
|
|
|
name = db.Column(db.String(255), nullable=False)
|
|
|
|
|
secret = db.Column(db.String(255), unique=True, nullable=False)
|
2016-02-02 14:16:08 +00:00
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, nullable=False)
|
2016-01-19 13:11:22 +00:00
|
|
|
service = db.relationship('Service', backref=db.backref('api_keys', lazy='dynamic'))
|
2016-01-13 09:25:46 +00:00
|
|
|
expiry_date = db.Column(db.DateTime)
|
|
|
|
|
|
2016-01-21 16:53:53 +00:00
|
|
|
__table_args__ = (
|
|
|
|
|
UniqueConstraint('service_id', 'name', name='uix_service_to_key_name'),
|
|
|
|
|
)
|
|
|
|
|
|
2016-01-13 09:25:46 +00:00
|
|
|
|
2016-03-08 16:34:03 +00:00
|
|
|
class NotificationStatistics(db.Model):
|
|
|
|
|
__tablename__ = 'notification_statistics'
|
2016-03-08 15:23:19 +00:00
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
|
day = db.Column(db.String(255), nullable=False)
|
|
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, nullable=False)
|
|
|
|
|
service = db.relationship('Service', backref=db.backref('service_notification_stats', lazy='dynamic'))
|
|
|
|
|
emails_requested = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
|
|
|
|
emails_delivered = db.Column(db.BigInteger, index=False, unique=False, nullable=True)
|
|
|
|
|
emails_error = db.Column(db.BigInteger, index=False, unique=False, nullable=True)
|
|
|
|
|
sms_requested = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
|
|
|
|
sms_delivered = db.Column(db.BigInteger, index=False, unique=False, nullable=True)
|
|
|
|
|
sms_error = db.Column(db.BigInteger, index=False, unique=False, nullable=True)
|
|
|
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
|
UniqueConstraint('service_id', 'day', name='uix_service_to_day'),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TEMPLATE_TYPE_SMS = 'sms'
|
|
|
|
|
TEMPLATE_TYPE_EMAIL = 'email'
|
|
|
|
|
TEMPLATE_TYPE_LETTER = 'letter'
|
|
|
|
|
|
|
|
|
|
TEMPLATE_TYPES = [TEMPLATE_TYPE_SMS, TEMPLATE_TYPE_EMAIL, TEMPLATE_TYPE_LETTER]
|
2016-01-13 11:04:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Template(db.Model):
|
|
|
|
|
__tablename__ = 'templates'
|
|
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
|
name = db.Column(db.String(255), nullable=False)
|
|
|
|
|
template_type = db.Column(db.Enum(*TEMPLATE_TYPES, name='template_type'), nullable=False)
|
|
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
|
|
|
|
default=datetime.datetime.now)
|
|
|
|
|
updated_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True,
|
2016-03-14 16:31:57 +00:00
|
|
|
onupdate=datetime.datetime.utcnow())
|
2016-01-13 11:04:13 +00:00
|
|
|
content = db.Column(db.Text, index=False, unique=False, nullable=False)
|
2016-02-02 14:16:08 +00:00
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=False)
|
2016-01-13 11:04:13 +00:00
|
|
|
service = db.relationship('Service', backref=db.backref('templates', lazy='dynamic'))
|
2016-02-19 15:52:19 +00:00
|
|
|
subject = db.Column(db.Text, index=False, unique=True, nullable=True)
|
2016-01-15 11:12:05 +00:00
|
|
|
|
|
|
|
|
|
2016-03-09 13:57:53 +00:00
|
|
|
JOB_STATUS_TYPES = ['pending', 'in progress', 'finished', 'sending limits exceeded']
|
2016-02-02 14:58:25 +00:00
|
|
|
|
|
|
|
|
|
2016-01-15 11:12:05 +00:00
|
|
|
class Job(db.Model):
|
|
|
|
|
__tablename__ = 'jobs'
|
|
|
|
|
|
|
|
|
|
id = db.Column(UUID(as_uuid=True), primary_key=True)
|
|
|
|
|
original_file_name = db.Column(db.String, nullable=False)
|
2016-01-16 10:14:48 +00:00
|
|
|
bucket_name = db.Column(db.String, nullable=False)
|
|
|
|
|
file_name = db.Column(db.String, nullable=False)
|
2016-02-02 14:16:08 +00:00
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=False)
|
2016-01-15 11:12:05 +00:00
|
|
|
service = db.relationship('Service', backref=db.backref('jobs', lazy='dynamic'))
|
|
|
|
|
template_id = db.Column(db.BigInteger, db.ForeignKey('templates.id'), index=True, unique=False)
|
2016-01-15 15:48:05 +00:00
|
|
|
template = db.relationship('Template', backref=db.backref('jobs', lazy='dynamic'))
|
2016-01-15 11:12:05 +00:00
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
2016-03-14 16:31:57 +00:00
|
|
|
default=datetime.datetime.utcnow())
|
2016-01-15 11:12:05 +00:00
|
|
|
updated_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True,
|
2016-03-14 16:31:57 +00:00
|
|
|
onupdate=datetime.datetime.utcnow())
|
2016-02-02 14:58:25 +00:00
|
|
|
status = db.Column(db.Enum(*JOB_STATUS_TYPES, name='job_status_types'), nullable=False, default='pending')
|
2016-02-22 14:56:09 +00:00
|
|
|
notification_count = db.Column(db.Integer, nullable=False)
|
2016-03-04 14:25:28 +00:00
|
|
|
notifications_sent = db.Column(db.Integer, nullable=False, default=0)
|
2016-02-25 09:59:50 +00:00
|
|
|
processing_started = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True)
|
|
|
|
|
processing_finished = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True)
|
2016-01-21 17:29:24 +00:00
|
|
|
|
|
|
|
|
|
2016-02-01 10:54:32 +00:00
|
|
|
VERIFY_CODE_TYPES = ['email', 'sms']
|
|
|
|
|
|
|
|
|
|
|
2016-01-21 17:29:24 +00:00
|
|
|
class VerifyCode(db.Model):
|
|
|
|
|
__tablename__ = 'verify_codes'
|
|
|
|
|
|
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
|
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True, nullable=False)
|
|
|
|
|
user = db.relationship('User', backref=db.backref('verify_codes', lazy='dynamic'))
|
|
|
|
|
_code = db.Column(db.String, nullable=False)
|
2016-02-01 10:54:32 +00:00
|
|
|
code_type = db.Column(db.Enum(*VERIFY_CODE_TYPES, name='verify_code_types'),
|
|
|
|
|
index=False, unique=False, nullable=False)
|
2016-01-21 17:29:24 +00:00
|
|
|
expiry_datetime = db.Column(db.DateTime, nullable=False)
|
|
|
|
|
code_used = db.Column(db.Boolean, default=False)
|
|
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
2016-03-14 16:31:57 +00:00
|
|
|
default=datetime.datetime.utcnow())
|
2016-01-21 17:29:24 +00:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def code(self):
|
|
|
|
|
raise AttributeError("Code not readable")
|
|
|
|
|
|
|
|
|
|
@code.setter
|
|
|
|
|
def code(self, cde):
|
|
|
|
|
self._code = hashpw(cde)
|
|
|
|
|
|
|
|
|
|
def check_code(self, cde):
|
|
|
|
|
return check_hash(cde, self._code)
|
2016-02-09 12:01:17 +00:00
|
|
|
|
|
|
|
|
|
2016-03-10 17:29:17 +00:00
|
|
|
NOTIFICATION_STATUS_TYPES = ['sent', 'delivered', 'failed', 'complaint', 'bounce']
|
2016-02-09 12:01:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Notification(db.Model):
|
|
|
|
|
|
|
|
|
|
__tablename__ = 'notifications'
|
|
|
|
|
|
2016-02-09 18:28:10 +00:00
|
|
|
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
2016-02-09 12:01:17 +00:00
|
|
|
to = db.Column(db.String, nullable=False)
|
2016-02-10 11:08:24 +00:00
|
|
|
job_id = db.Column(UUID(as_uuid=True), db.ForeignKey('jobs.id'), index=True, unique=False)
|
2016-02-09 12:01:17 +00:00
|
|
|
job = db.relationship('Job', backref=db.backref('notifications', lazy='dynamic'))
|
|
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False)
|
2016-02-09 12:48:27 +00:00
|
|
|
service = db.relationship('Service')
|
2016-02-09 12:01:17 +00:00
|
|
|
template_id = db.Column(db.BigInteger, db.ForeignKey('templates.id'), index=True, unique=False)
|
2016-02-09 12:48:27 +00:00
|
|
|
template = db.relationship('Template')
|
2016-02-09 12:01:17 +00:00
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
2016-02-25 09:59:50 +00:00
|
|
|
nullable=False)
|
|
|
|
|
sent_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True)
|
|
|
|
|
sent_by = db.Column(db.String, nullable=True)
|
2016-02-09 12:01:17 +00:00
|
|
|
updated_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=True,
|
2016-03-14 16:31:57 +00:00
|
|
|
onupdate=datetime.datetime.utcnow())
|
2016-02-09 12:01:17 +00:00
|
|
|
status = db.Column(
|
|
|
|
|
db.Enum(*NOTIFICATION_STATUS_TYPES, name='notification_status_types'), nullable=False, default='sent')
|
2016-03-11 09:40:35 +00:00
|
|
|
reference = db.Column(db.String, nullable=True, index=True)
|
2016-02-23 16:21:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
INVITED_USER_STATUS_TYPES = ['pending', 'accepted', 'cancelled']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvitedUser(db.Model):
|
|
|
|
|
|
|
|
|
|
__tablename__ = 'invited_users'
|
|
|
|
|
|
|
|
|
|
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
|
|
|
email_address = db.Column(db.String(255), nullable=False)
|
|
|
|
|
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True, nullable=False)
|
|
|
|
|
from_user = db.relationship('User')
|
|
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False)
|
|
|
|
|
service = db.relationship('Service')
|
|
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
2016-03-14 16:31:57 +00:00
|
|
|
default=datetime.datetime.utcnow())
|
2016-02-23 16:21:47 +00:00
|
|
|
status = db.Column(
|
2016-02-24 14:01:19 +00:00
|
|
|
db.Enum(*INVITED_USER_STATUS_TYPES, name='invited_users_status_types'), nullable=False, default='pending')
|
2016-02-29 09:49:12 +00:00
|
|
|
permissions = db.Column(db.String, nullable=False)
|
|
|
|
|
|
|
|
|
|
# would like to have used properties for this but haven't found a way to make them
|
|
|
|
|
# play nice with marshmallow yet
|
|
|
|
|
def get_permissions(self):
|
|
|
|
|
return self.permissions.split(',')
|
2016-02-26 12:00:16 +00:00
|
|
|
|
|
|
|
|
|
2016-03-01 14:21:28 +00:00
|
|
|
# Service Permissions
|
2016-03-02 15:34:26 +00:00
|
|
|
MANAGE_USERS = 'manage_users'
|
2016-03-01 14:21:28 +00:00
|
|
|
MANAGE_TEMPLATES = 'manage_templates'
|
2016-03-02 15:34:26 +00:00
|
|
|
MANAGE_SETTINGS = 'manage_settings'
|
|
|
|
|
SEND_TEXTS = 'send_texts'
|
|
|
|
|
SEND_EMAILS = 'send_emails'
|
|
|
|
|
SEND_LETTERS = 'send_letters'
|
|
|
|
|
MANAGE_API_KEYS = 'manage_api_keys'
|
|
|
|
|
ACCESS_DEVELOPER_DOCS = 'access_developer_docs'
|
2016-03-01 14:21:28 +00:00
|
|
|
|
|
|
|
|
# List of permissions
|
|
|
|
|
PERMISSION_LIST = [
|
2016-03-02 15:34:26 +00:00
|
|
|
MANAGE_USERS,
|
2016-03-01 17:18:46 +00:00
|
|
|
MANAGE_TEMPLATES,
|
2016-03-02 15:34:26 +00:00
|
|
|
MANAGE_SETTINGS,
|
|
|
|
|
SEND_TEXTS,
|
|
|
|
|
SEND_EMAILS,
|
|
|
|
|
SEND_LETTERS,
|
|
|
|
|
MANAGE_API_KEYS,
|
|
|
|
|
ACCESS_DEVELOPER_DOCS]
|
2016-03-01 14:21:28 +00:00
|
|
|
|
|
|
|
|
|
2016-02-26 12:00:16 +00:00
|
|
|
class Permission(db.Model):
|
|
|
|
|
__tablename__ = 'permissions'
|
|
|
|
|
|
|
|
|
|
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
|
|
|
# Service id is optional, if the service is omitted we will assume the permission is not service specific.
|
|
|
|
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=True)
|
|
|
|
|
service = db.relationship('Service')
|
|
|
|
|
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True, nullable=False)
|
|
|
|
|
user = db.relationship('User')
|
2016-03-01 17:18:46 +00:00
|
|
|
permission = db.Column(
|
|
|
|
|
db.Enum(*PERMISSION_LIST, name='permission_types'),
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False)
|
2016-02-26 12:00:16 +00:00
|
|
|
created_at = db.Column(
|
|
|
|
|
db.DateTime,
|
|
|
|
|
index=False,
|
|
|
|
|
unique=False,
|
|
|
|
|
nullable=False,
|
2016-03-14 16:31:57 +00:00
|
|
|
default=datetime.datetime.utcnow())
|
2016-02-26 12:00:16 +00:00
|
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
|
UniqueConstraint('service_id', 'user_id', 'permission', name='uix_service_user_permission'),
|
|
|
|
|
)
|