Files
eveAI/common/models/user.py

268 lines
11 KiB
Python

from datetime import date
from common.extensions import db
from flask_security import UserMixin, RoleMixin
from sqlalchemy.dialects.postgresql import ARRAY
import sqlalchemy as sa
from common.models.entitlements import License
class Tenant(db.Model):
"""Tenant model"""
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
# company Information
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(50), unique=True, nullable=True)
name = db.Column(db.String(80), unique=True, nullable=False)
website = db.Column(db.String(255), nullable=True)
timezone = db.Column(db.String(50), nullable=True, default='UTC')
rag_context = db.Column(db.Text, nullable=True)
type = db.Column(db.String(20), nullable=True, server_default='Active')
# language information
default_language = db.Column(db.String(2), nullable=True)
allowed_languages = db.Column(ARRAY(sa.String(2)), nullable=True)
# LLM specific choices
llm_model = db.Column(db.String(50), nullable=True)
# Entitlements
currency = db.Column(db.String(20), nullable=True)
storage_dirty = db.Column(db.Boolean, nullable=True, default=False)
# Relations
users = db.relationship('User', backref='tenant')
domains = db.relationship('TenantDomain', backref='tenant')
licenses = db.relationship('License', back_populates='tenant')
license_usages = db.relationship('LicenseUsage', backref='tenant')
@property
def current_license(self):
today = date.today()
return License.query.filter(
License.tenant_id == self.id,
License.start_date <= today,
(License.end_date.is_(None) | (License.end_date >= today))
).order_by(License.start_date.desc()).first()
def __repr__(self):
return f"<Tenant {self.id}: {self.name}>"
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'website': self.website,
'timezone': self.timezone,
'rag_context': self.rag_context,
'type': self.type,
'default_language': self.default_language,
'allowed_languages': self.allowed_languages,
'llm_model': self.llm_model,
'currency': self.currency,
}
class Role(db.Model, RoleMixin):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class RolesUsers(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
user_id = db.Column(db.Integer(), db.ForeignKey('public.user.id', ondelete='CASCADE'), primary_key=True)
role_id = db.Column(db.Integer(), db.ForeignKey('public.role.id', ondelete='CASCADE'), primary_key=True)
class User(db.Model, UserMixin):
"""User model"""
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
# User Information
id = db.Column(db.Integer, primary_key=True)
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False)
user_name = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=True)
first_name = db.Column(db.String(80), nullable=False)
last_name = db.Column(db.String(80), nullable=False)
active = db.Column(db.Boolean)
fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False)
confirmed_at = db.Column(db.DateTime, nullable=True)
valid_to = db.Column(db.Date, nullable=True)
is_primary_contact = db.Column(db.Boolean, nullable=True, default=False)
is_financial_contact = db.Column(db.Boolean, nullable=True, default=False)
# Security Trackable Information
last_login_at = db.Column(db.DateTime, nullable=True)
current_login_at = db.Column(db.DateTime, nullable=True)
last_login_ip = db.Column(db.String(255), nullable=True)
current_login_ip = db.Column(db.String(255), nullable=True)
login_count = db.Column(db.Integer, nullable=False, default=0)
# Relations
roles = db.relationship('Role', secondary=RolesUsers.__table__, backref=db.backref('users', lazy='dynamic'))
def __repr__(self):
return '<User %r>' % self.user_name
def has_roles(self, *args):
return any(role.name in args for role in self.roles)
class TenantDomain(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
id = db.Column(db.Integer, primary_key=True)
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False)
# Originally, domain was required to be unique.
# However, several tenants can run from the same domain (e.g. for demo purposes,
# but also internal and external chat clients.
domain = db.Column(db.String(255), nullable=False)
valid_to = db.Column(db.Date, nullable=True)
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
created_by = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False)
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
updated_by = db.Column(db.Integer, db.ForeignKey(User.id))
def __repr__(self):
return f"<TenantDomain {self.id}: {self.domain}>"
class TenantProject(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
id = db.Column(db.Integer, primary_key=True)
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False)
name = db.Column(db.String(50), nullable=False)
description = db.Column(db.Text, nullable=True)
services = db.Column(ARRAY(sa.String(50)), nullable=False)
encrypted_api_key = db.Column(db.String(500), nullable=True)
visual_api_key = db.Column(db.String(20), nullable=True)
active = db.Column(db.Boolean, nullable=False, default=True)
responsible_email = db.Column(db.String(255), nullable=True)
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
created_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'))
# Relations
tenant = db.relationship('Tenant', backref='projects')
def __repr__(self):
return f"<TenantProject {self.id}: {self.name}>"
class Partner(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
id = db.Column(db.Integer, primary_key=True)
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), nullable=False, unique=True)
code = db.Column(db.String(50), unique=True, nullable=False)
# Basic information
logo_url = db.Column(db.String(255), nullable=True)
active = db.Column(db.Boolean, default=True)
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
created_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
# Relationships
services = db.relationship('PartnerService', back_populates='partner')
tenant = db.relationship('Tenant', backref=db.backref('partner', uselist=False))
def to_dict(self):
return {
'id': self.id,
'tenant_id': self.tenant_id,
'code': self.code,
'logo_url': self.logo_url,
'active': self.active,
'name': self.tenant.name
}
class PartnerService(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
id = db.Column(db.Integer, primary_key=True)
partner_id = db.Column(db.Integer, db.ForeignKey('public.partner.id'), nullable=False)
# Basic info
name = db.Column(db.String(50), nullable=False)
description = db.Column(db.Text, nullable=True)
# Service type with versioning (similar to your specialist/retriever pattern)
type = db.Column(db.String(50), nullable=False) # REFERRAL, KNOWLEDGE, SPECIALIST, IMPLEMENTATION, WHITE_LABEL
type_version = db.Column(db.String(20), nullable=False, default="1.0.0")
# Status
active = db.Column(db.Boolean, default=True)
# Dynamic configuration specific to this service - using JSONB like your other models
configuration = db.Column(db.JSON, nullable=True)
# For services that need to track shared resources
system_metadata = db.Column(db.JSON, nullable=True)
user_metadata = db.Column(db.JSON, nullable=True)
# Relationships
partner = db.relationship('Partner', back_populates='services')
# Versioning Information
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
created_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
class PartnerTenant(db.Model):
__bind_key__ = 'public'
__table_args__ = {'schema': 'public'}
partner_service_id = db.Column(db.Integer, db.ForeignKey('public.partner_service.id'), primary_key=True)
tenant_id = db.Column(db.Integer, db.ForeignKey('public.tenant.id'), primary_key=True)
# Relationship type
relationship_type = db.Column(db.String(20), nullable=False) # REFERRED, MANAGED, WHITE_LABEL
# JSONB for flexible configuration specific to this relationship
configuration = db.Column(db.JSON, nullable=True)
# Tracking
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
created_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
updated_by = db.Column(db.Integer, db.ForeignKey('public.user.id'), nullable=True)