from flask import current_app from flask_wtf import FlaskForm from wtforms import (StringField, PasswordField, BooleanField, SubmitField, EmailField, IntegerField, DateField, SelectField, SelectMultipleField, FieldList, FormField, FloatField, TextAreaField) from wtforms.validators import DataRequired, Length, Email, NumberRange, Optional, ValidationError import pytz from common.models.user import Role from config.type_defs.service_types import SERVICE_TYPES class TenantForm(FlaskForm): name = StringField('Name', validators=[DataRequired(), Length(max=80)]) type = SelectField('Tenant Type', validators=[Optional()], default='Active') website = StringField('Website', validators=[DataRequired(), Length(max=255)]) # language fields default_language = SelectField('Default Language', choices=[], validators=[DataRequired()]) allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[DataRequired()]) # invoicing fields currency = SelectField('Currency', choices=[], validators=[DataRequired()]) # Timezone timezone = SelectField('Timezone', choices=[], validators=[DataRequired()]) # LLM fields embedding_model = SelectField('Embedding Model', choices=[], validators=[DataRequired()]) llm_model = SelectField('Large Language Model', choices=[], validators=[DataRequired()]) # Embedding variables submit = SubmitField('Submit') def __init__(self, *args, **kwargs): super(TenantForm, self).__init__(*args, **kwargs) # initialise language fields self.default_language.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']] self.allowed_languages.choices = [(lang, lang.lower()) for lang in current_app.config['SUPPORTED_LANGUAGES']] # initialise currency field self.currency.choices = [(curr, curr) for curr in current_app.config['SUPPORTED_CURRENCIES']] # initialise timezone self.timezone.choices = [(tz, tz) for tz in pytz.all_timezones] # initialise LLM fields self.embedding_model.choices = [(model, model) for model in current_app.config['SUPPORTED_EMBEDDINGS']] self.llm_model.choices = [(model, model) for model in current_app.config['SUPPORTED_LLMS']] # Initialize fallback algorithms self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']] class BaseUserForm(FlaskForm): user_name = StringField('Name', validators=[DataRequired(), Length(max=80)]) email = EmailField('Email', validators=[DataRequired(), Email()]) first_name = StringField('First Name', validators=[DataRequired(), Length(max=80)]) last_name = StringField('Last Name', validators=[DataRequired(), Length(max=80)]) valid_to = DateField('Valid to', id='form-control datepicker', validators=[Optional()]) tenant_id = IntegerField('Tenant ID', validators=[NumberRange(min=0)]) roles = SelectMultipleField('Roles', coerce=int) is_primary_contact = BooleanField('Primary Contact') is_financial_contact = BooleanField('Financial Contact') def __init__(self, *args, **kwargs): super(BaseUserForm, self).__init__(*args, **kwargs) self.roles.choices = [(role.id, role.name) for role in Role.query.all()] class CreateUserForm(BaseUserForm): submit = SubmitField('Create User') class EditUserForm(BaseUserForm): # Some R/O informational fields confirmed_at = DateField('Confirmed At', id='form-control datepicker', validators=[Optional()], render_kw={'readonly': True}) last_login_at = DateField('Last Login At', id='form-control datepicker', validators=[Optional()], render_kw={'readonly': True}) login_count = IntegerField('Login Count', validators=[Optional()], render_kw={'readonly': True}) submit = SubmitField('Save User') class RoleForm(FlaskForm): # This subform will represent a single checkbox for each role role_id = StringField('Role ID') checked = BooleanField('Assigned') class UserRoleForm(FlaskForm): email = EmailField('Email', validators=[DataRequired(), Email()]) roles = FieldList(FormField(RoleForm), min_entries=1) submit = SubmitField('Update Roles') class TenantDomainForm(FlaskForm): domain = StringField('Domain', validators=[DataRequired(), Length(max=80)]) valid_to = DateField('Valid to', id='form-control datepicker', validators=[Optional()]) submit = SubmitField('Add Domain') class TenantSelectionForm(FlaskForm): types = SelectMultipleField('Tenant Types', choices=[], validators=[Optional()]) search = StringField('Search', validators=[Optional()]) submit = SubmitField('Filter') def __init__(self, *args, **kwargs): super(TenantSelectionForm, self).__init__(*args, **kwargs) self.types.choices = [(t, t) for t in current_app.config['TENANT_TYPES']] class TenantProjectForm(FlaskForm): name = StringField('Name', validators=[DataRequired(), Length(max=50)]) description = TextAreaField('Description', validators=[Optional()]) services = SelectMultipleField('Allowed Services', choices=[], validators=[DataRequired()]) unencrypted_api_key = StringField('Unencrypted API Key', validators=[DataRequired()], render_kw={'readonly': True}) visual_api_key = StringField('Visual API Key', validators=[DataRequired()], render_kw={'readonly': True}) active = BooleanField('Active', validators=[DataRequired()], default=True) responsible_email = EmailField('Responsible Email', validators=[Optional(), Email()]) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize choices for the services field self.services.choices = [(key, value['description']) for key, value in SERVICE_TYPES.items()] class EditTenantProjectForm(FlaskForm): name = StringField('Name', validators=[DataRequired(), Length(max=50)]) description = TextAreaField('Description', validators=[Optional()]) services = SelectMultipleField('Allowed Services', choices=[], validators=[DataRequired()]) visual_api_key = StringField('Visual API Key', validators=[DataRequired()], render_kw={'readonly': True}) active = BooleanField('Active', validators=[DataRequired()], default=True) responsible_email = EmailField('Responsible Email', validators=[Optional(), Email()]) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize choices for the services field self.services.choices = [(key, value['description']) for key, value in SERVICE_TYPES.items()]