from flask import current_app, session from flask_wtf import FlaskForm from wtforms import (StringField, BooleanField, SubmitField, EmailField, IntegerField, DateField, SelectField, SelectMultipleField, FieldList, FormField, TextAreaField) from wtforms.validators import DataRequired, Length, Email, NumberRange, Optional, ValidationError import pytz from flask_security import current_user from wtforms.widgets.core import HiddenInput from common.models.user import TenantMake from common.services.user import UserServices from config.type_defs.service_types import SERVICE_TYPES from eveai_app.views.dynamic_form_base import DynamicFormBase class TenantForm(FlaskForm): name = StringField('Name', validators=[DataRequired(), Length(max=80)]) code = StringField('Code', validators=[DataRequired()], render_kw={'readonly': True}) 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()]) # Default tenant make default_tenant_make_id = SelectField('Default Tenant Make', choices=[], validators=[Optional()]) # For Super Users only - Allow to assign the tenant to the partner assign_to_partner = BooleanField('Assign to Partner', default=False) # 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.common_timezones] # Initialize fallback algorithms self.type.choices = [(t, t) for t in current_app.config['TENANT_TYPES']] # Initialize default tenant make choices tenant_id = session.get('tenant', {}).get('id') if 'tenant' in session else None if tenant_id: tenant_makes = TenantMake.query.filter_by(tenant_id=tenant_id, active=True).all() self.default_tenant_make_id.choices = [(str(make.id), make.name) for make in tenant_makes] # Add empty choice self.default_tenant_make_id.choices.insert(0, ('', 'Geen')) # Show field only for Super Users with partner in session if not current_user.has_roles('Super User') or 'partner' not in session: self._fields.pop('assign_to_partner', None) 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 = UserServices.get_assignable_roles() 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=[Optional()], 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=[Optional()], 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()] def validate_make_name(form, field): # Controleer of een TenantMake met deze naam al bestaat existing_make = TenantMake.query.filter_by(name=field.data).first() # Als er een bestaande make is gevonden en we zijn niet in edit mode, # of als we wel in edit mode zijn maar het is een ander record (andere id) if existing_make and (not hasattr(form, 'id') or form.id.data != existing_make.id): raise ValidationError(f'A Make with name "{field.data}" already exists. Choose another name.') class TenantMakeForm(DynamicFormBase): id = IntegerField('ID', widget=HiddenInput()) name = StringField('Name', validators=[DataRequired(), Length(max=50), validate_make_name]) description = TextAreaField('Description', validators=[Optional()]) active = BooleanField('Active', validators=[Optional()], default=True) website = StringField('Website', validators=[DataRequired(), Length(max=255)]) logo_url = StringField('Logo URL', validators=[Optional(), Length(max=255)])