Initial commit.

This commit is contained in:
2025-06-21 17:51:07 +01:00
commit 6fd3a23aa7
296 changed files with 29154 additions and 0 deletions

0
forms/__init__.py Normal file
View File

37
forms/access_level.py Normal file
View File

@@ -0,0 +1,37 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Forms - Access Level Filters data input
Description:
Defines Flask-WTF forms for handling access level filter input.
"""
# internal
from business_objects.base import Base
from forms.base import Form_Base
import lib.argument_validation as av
# external
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
from flask_wtf.recaptcha import RecaptchaField
from abc import ABCMeta, abstractmethod
class Filters_Access_Level(Form_Base):
active = BooleanField("Active only?", default = True)
def __repr__(self):
return f'{self.__class__.__name__}(active={self.active.data})'
@classmethod
def from_json(cls, json):
form = Filters_Access_Level()
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], Base.FLAG_ACTIVE, f'{cls.__name__}.from_json')
return form
def to_json(self):
return {
Base.FLAG_ACTIVE: 1 if av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json') else 0,
}

78
forms/base.py Normal file
View File

@@ -0,0 +1,78 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Form Base and Meta Classes - data input
Description:
Defines Flask-WTF base forms for handling user input.
"""
# internal
# external
from flask_wtf import FlaskForm
from abc import ABCMeta, abstractmethod
class Form_Base_Meta(type(FlaskForm), ABCMeta):
pass
class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
"""
@classmethod
@abstractmethod
def from_filters(cls, filters):
pass
@abstractmethod
def __repr__(self):
pass
"""
def __repr__(self):
fields = ', '.join(
f"{name}={field.data}" for name, field in self._fields.items()
)
return f"{self.__class__.__name__}({fields})"
@classmethod
@abstractmethod
def from_json(cls, json):
pass
@classmethod
def get_default(cls):
return cls()
"""
@abstractmethod
def test_69(self):
pass
def get_Filters_Product_Category(data_request):
data_form = data_request[Model_View_Store_Product_Category.FLAG_FORM]
form_filters = Filters_Product_Category(**data_form)
form_filters.is_not_empty.data = av.input_bool(data_form['is_not_empty'], 'is_not_empty', 'filter_category')
form_filters.active.data = av.input_bool(data_form['active'], 'active', 'filter_category')
return form_filters
"""
@classmethod
def get_choices_blank(cls):
return [('', 'Select')]
@classmethod
def get_choice_all(cls):
return ('', 'All')
'''
class Filters_Stored_Procedure_Base(Form_Base):
"""
@abstractmethod
def __repr__(self):
pass
@classmethod
@abstractmethod
def from_json(cls, json):
pass
"""
@abstractmethod
def to_json(self):
pass
'''

100
forms/contact.py Normal file
View File

@@ -0,0 +1,100 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Contact Us Form
Description:
Defines Flask-WTF form for handling user input on Contact Us page.
"""
# IMPORTS
# internal
from business_objects.base import Base
from business_objects.project_hub.command import Command
# from models.model_view_store import Model_View_Store # circular
from models.model_view_base import Model_View_Base
from forms.base import Form_Base
# external
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, HiddenField, BooleanField, Field, EmailField
from wtforms.validators import DataRequired, Email, ValidationError
import markupsafe
from flask_wtf.recaptcha import RecaptchaField
from abc import ABCMeta, abstractmethod
import json
from altcha import verify_solution
import base64
class ALTCHAValidator:
def __init__(self, message=None):
self.message = message or 'ALTCHA verification failed'
def __call__(self, form, field):
altcha_data = field.data
if not altcha_data:
raise ValidationError(self.message)
try:
# The data is base64 encoded JSON
try:
# First try to decode it as JSON directly (if it's not base64 encoded)
altcha_payload = json.loads(altcha_data)
except json.JSONDecodeError:
# If direct JSON decoding fails, try base64 decoding first
decoded_data = base64.b64decode(altcha_data).decode('utf-8')
altcha_payload = json.loads(decoded_data)
ok, err = verify_solution(altcha_payload, current_app.app_config.ALTCHA_SECRET_KEY, check_expires=True)
if err or not ok:
raise ValidationError(self.message + ': ' + (err or 'Invalid solution'))
except Exception as e:
raise ValidationError(f'Invalid ALTCHA data: {str(e)}')
class ALTCHAField(Field):
def __init__(self, label='', validators=None, **kwargs):
validators = validators or []
validators.append(ALTCHAValidator())
super(ALTCHAField, self).__init__(label, validators, **kwargs)
def __call__(self, **kwargs):
html = f"""
<altcha-widget
challengeurl="/get-challenge"
auto="onload"
id="{self.id}"
name="{self.name}">
</altcha-widget>
"""
return markupsafe.Markup(html)
class Form_Contact(FlaskForm):
email = EmailField('Email')
contact_name = StringField('Name')
company_name = StringField('Company')
message = TextAreaField('Message')
receive_marketing = BooleanField('I would like to receive marketing emails.')
# recaptcha = RecaptchaField()
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
altcha = ALTCHAField('Verify you are human')
submit = SubmitField('Send Message')
def to_json(self):
return {
Base.FLAG_EMAIL: self.email.data
, Command.FLAG_NAME_CONTACT: self.contact_name.data
, Command.FLAG_NAME_COMPANY: self.company_name.data
, Command.FLAG_MESSAGE: self.message.data
, Command.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing.data
, Command.FLAG_ALTCHA: self.altcha.data
, Base.FLAG_ACTIVE: True
, Base.FLAG_CREATED_ON: None
}

134
forms/forms.py Normal file
View File

@@ -0,0 +1,134 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Forms - User data input
Description:
Defines Flask-WTF forms for handling user input.
"""
# IMPORTS
# internal
# from business_objects.store.product_category import Filters_Product_Category # circular
# from models.model_view_store import Model_View_Store # circular
from forms.base import Form_Base
# external
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
from flask_wtf.recaptcha import RecaptchaField
from abc import ABCMeta, abstractmethod
class Form_Contact(FlaskForm):
email = StringField('Email address')
CC = BooleanField('Would you like to receive a copy of this email request?') # not in use
name = StringField('Name')
message = TextAreaField('Message')
recaptcha = RecaptchaField()
submit = SubmitField('Submit')
class Form_Register(FlaskForm):
email = StringField('Email address')
CC = BooleanField('Would you like to receive a copy of this email request?') # not in use
name = StringField('Name')
message = TextAreaField('Message')
submit = SubmitField('Submit')
"""
class Form_Product(FlaskForm): # for basket, product tiles, product add
# PositiveIntegerField with validation constraints
quantity = IntegerField(
'Quantity',
validators=[
# InputRequired(message='Quantity'),
NumberRange(min=1, message='Please enter a positive integer')
],
default=1
)
"""
class Form_Basket_Add(FlaskForm): # for basket, product tiles, product add
# PositiveIntegerField with validation constraints
quantity = IntegerField(
'Quantity',
validators=[
# InputRequired(message='Quantity'),
NumberRange(min=1, message='Please enter a positive integer')
],
default=1
# render_kw={'id-product': ''} # {Model_View_Store.attr_id_product: ''}
)
submit = SubmitField('Add')
form_type = 'Form_Basket_Add'
class Form_Basket_Edit(FlaskForm): # for basket, product tiles, product add
# PositiveIntegerField with validation constraints
quantity = IntegerField(
'Quantity',
validators=[
# InputRequired(message='Quantity'),
NumberRange(min=1, message='Please enter a positive integer')
],
default=1
# render_kw={'id-product': ''} # {Model_View_Store.attr_id_product: ''}
)
submit = SubmitField('Update')
form_type = 'Form_Basket_Edit'
class Form_Billing(FlaskForm):
identical = BooleanField('Use delivery address')
region = SelectField('Country / region', choices=[('uk', 'UK'), ('international', 'International')], validators=[DataRequired()])
name_full = StringField('Full name')
phone_number = StringField('Phone number', validators=[Regexp(r'^\+?[0-9\s]{5,20}$', message='Only numbers, plus symbol, and space are allowed.'), DataRequired()])
postcode = StringField('Post code', validators=[DataRequired()])
address_1 = StringField('Address line 1', validators=[DataRequired()])
address_2 = StringField('Address line 2 (optional)')
city = StringField('City', validators=[DataRequired()])
county = StringField('County', validators=[DataRequired()])
submit = SubmitField('Submit')
form_type_billing_not_delivery = False
def output_id(self):
return 'formBilling' if self.form_type_billing_not_delivery else 'formDeliver'
class Form_Is_Included_VAT(FlaskForm):
is_included = BooleanField('Include VAT')
class Form_Delivery_Region(FlaskForm):
id_id_region_delivery = 'id_region_delivery'
id_region_delivery = SelectField('Region', id='id_region_delivery')
class Form_Currency(FlaskForm):
id_id_currency = 'id_currency'
id_currency = SelectField('Currency', id='id_currency')
# Store
class Form_Supplier(FlaskForm):
id_id_supplier = 'id_supplier'
id_supplier = SelectField('Supplier', id='id_supplier')
name_company = StringField('Company name')
name_contact = StringField('Contact name')
department_contact = StringField('Contact department')
id_address = SelectField('Address ID')
phone_number = StringField('Phone number')
email = StringField('Email address')
fax = StringField('Fax number')
website = StringField('Website')
id_currency = SelectField('Currency ID')
is_active = BooleanField('Active', default = True)
# class Form_Supplier_Purchase_Order(FlaskForm):
# User
class Form_Filters_User(FlaskForm):
active = BooleanField('Active only?', default = True)
id_user = SelectField('User ID', validators=[Optional()], choices=[])

42
forms/unit_measurement.py Normal file
View File

@@ -0,0 +1,42 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Forms - Unit of Measurement Filters data input
Description:
Defines Flask-WTF forms for handling unit of measurement filter input.
"""
# internal
from business_objects.base import Base
from forms.base import Form_Base
import lib.argument_validation as av
# external
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
from flask_wtf.recaptcha import RecaptchaField
from abc import ABCMeta, abstractmethod
class Filters_Unit_Measurement(Form_Base):
active = BooleanField("Active only?", default = True)
@classmethod
def from_filters(cls, filters):
form = Filters_Unit_Measurement()
form.active.data = filters.active
return form
def __repr__(self):
return f'Filters_Unit_Measurement(active={self.active.data})'
@classmethod
def from_json(cls, json):
form = Filters_Unit_Measurement()
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], 'active', 'Filters_Unit_Measurement')
return form
def to_json(self):
return {
Base.FLAG_ACTIVE: av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
}