Files
eveAI/eveai_app/views/user_forms.py
Josako f10bb6f395 - TRA-99 Solved. Unable to create a new Tenant Make
- Generic improvement of initialisation of Dynamic Forms, ensuring correct form processing
2025-11-26 11:31:25 +01:00

234 lines
12 KiB
Python

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)])
# invoicing fields
currency = SelectField('Currency', choices=[], validators=[DataRequired()])
# Timezone
timezone = SelectField('Timezone', choices=[], validators=[DataRequired()])
# 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 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
# 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 EditTenantForm(FlaskForm):
id = IntegerField('ID', widget=HiddenInput())
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)])
# 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(EditTenantForm, self).__init__(*args, **kwargs)
# 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 = self.id.data
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):
# Check if tenant_make already exists in the database
existing_make = TenantMake.query.filter_by(name=field.data).first()
if existing_make:
if 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(FlaskForm):
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)])
allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[Optional()])
def __init__(self, *args, **kwargs):
super(TenantMakeForm, self).__init__(*args, **kwargs)
# Initialiseer de taalopties met taalcodes en vlaggen
lang_details = current_app.config['SUPPORTED_LANGUAGE_DETAILS']
self.allowed_languages.choices = [(details['iso 639-1'], f"{details['flag']} {details['iso 639-1']}")
for name, details in lang_details.items()]
class EditTenantMakeForm(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)])
default_language = SelectField('Default Language', choices=[], validators=[DataRequired()])
allowed_languages = SelectMultipleField('Allowed Languages', choices=[], validators=[Optional()])
def __init__(self, *args, **kwargs):
super(EditTenantMakeForm, self).__init__(*args, **kwargs)
# Initialiseer de taalopties met taalcodes en vlaggen
lang_details = current_app.config['SUPPORTED_LANGUAGE_DETAILS']
choices = [(details['iso 639-1'], f"{details['flag']} {details['iso 639-1']}")
for name, details in lang_details.items()]
self.allowed_languages.choices = choices
self.default_language.choices = choices
class ConsentVersionForm(FlaskForm):
consent_type = SelectField('Consent Type', choices=[], validators=[DataRequired()])
consent_version = StringField('Consent Version', validators=[DataRequired(), Length(max=20)])
consent_valid_from = DateField('Consent Valid From', id='form-control datepicker', validators=[DataRequired()])
consent_valid_to = DateField('Consent Valid To', id='form-control datepicker', validators=[Optional()])
def __init__(self, *args, **kwargs):
super(ConsentVersionForm, self).__init__(*args, **kwargs)
# Initialise consent types
self.consent_type.choices = [(t, t) for t in current_app.config['CONSENT_TYPES']]
class EditConsentVersionForm(FlaskForm):
consent_type = StringField('Consent Type', validators=[DataRequired()])
consent_version = StringField('Consent Version', validators=[DataRequired(), Length(max=20)])
consent_valid_from = DateField('Consent Valid From', id='form-control datepicker', validators=[DataRequired()])
consent_valid_to = DateField('Consent Valid To', id='form-control datepicker', validators=[Optional()])