Feat(SQL, UI): Redesign database with much more detailed command response quality analysis and created successfully loading Dog Command Links page
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
"""
|
||||
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,
|
||||
}
|
||||
@@ -11,9 +11,12 @@ Defines Flask-WTF base forms for handling user input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from dog_training.helpers.helper_app import Helper_App
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from wtforms import SelectField, BooleanField, SubmitField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
|
||||
|
||||
class Form_Base_Meta(type(FlaskForm), ABCMeta):
|
||||
@@ -21,45 +24,30 @@ class Form_Base_Meta(type(FlaskForm), ABCMeta):
|
||||
|
||||
|
||||
class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_filters(cls, filters):
|
||||
pass
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
"""
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'Error: Parent classes of {cls.__qualname__} must define cls.from_json')
|
||||
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls()
|
||||
@classmethod
|
||||
def get_select_option_blank(cls):
|
||||
return (cls.get_select_option_default_value(), 'Select')
|
||||
@classmethod
|
||||
def get_select_option_all(cls):
|
||||
return (cls.get_select_option_default_value(), 'All')
|
||||
|
||||
@staticmethod
|
||||
def get_select_option_default_value():
|
||||
return ''
|
||||
|
||||
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):
|
||||
@@ -75,4 +63,10 @@ class Filters_Stored_Procedure_Base(Form_Base):
|
||||
@abstractmethod
|
||||
def to_json(self):
|
||||
pass
|
||||
'''
|
||||
'''
|
||||
|
||||
|
||||
|
||||
class Form_Filters_User(FlaskForm):
|
||||
active = BooleanField('Active only?', default = True)
|
||||
id_user = SelectField('User ID', validators=[Optional()], choices=[])
|
||||
100
forms/contact.py
100
forms/contact.py
@@ -1,100 +0,0 @@
|
||||
"""
|
||||
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
|
||||
}
|
||||
0
forms/dog/__init__.py
Normal file
0
forms/dog/__init__.py
Normal file
64
forms/dog/dog_command_link.py
Normal file
64
forms/dog/dog_command_link.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
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 dog_training.business_objects.base import Base
|
||||
from dog_training.business_objects.dog.command import Command
|
||||
from dog_training.business_objects.dog.dog import Dog
|
||||
from dog_training.business_objects.dog.obedience_level import Obedience_Level
|
||||
# from dog_training.models.model_view_store import Model_View_Store # circular
|
||||
# from dog_training.models.model_view_base import Model_View_Base
|
||||
from dog_training.forms.base import Form_Base
|
||||
import dog_training.lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import SelectField, BooleanField, SubmitField
|
||||
from wtforms.validators import DataRequired, Email, ValidationError
|
||||
import markupsafe
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import json
|
||||
|
||||
class Filters_Dog_Command_Link(Form_Base):
|
||||
id_dog = SelectField(
|
||||
'Dog'
|
||||
, choices = [Form_Base.get_select_option_all()]
|
||||
, default = Form_Base.get_select_option_default_value()
|
||||
)
|
||||
id_command = SelectField(
|
||||
'Command'
|
||||
, choices = [Form_Base.get_select_option_all()]
|
||||
, default = Form_Base.get_select_option_default_value()
|
||||
)
|
||||
active_only = BooleanField(
|
||||
'Active'
|
||||
, default = True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
filters = cls()
|
||||
filters.id_dog.choices = [(json[Dog.ATTR_ID_DOG], json[Dog.ATTR_ID_DOG])]
|
||||
filters.id_dog.data = json[Dog.ATTR_ID_DOG]
|
||||
filters.id_command.choices = [(json[Command.ATTR_ID_COMMAND], json[Command.ATTR_ID_COMMAND])]
|
||||
filters.id_command.data = json[Command.ATTR_ID_COMMAND]
|
||||
filters.active_only.data = av.input_bool(json[Base.FLAG_ACTIVE], Base.FLAG_ACTIVE, f'{cls.__name__}.from_json')
|
||||
return filters
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
Dog.FLAG_DOG: self.id_dog.data
|
||||
, Command.FLAG_COMMAND: self.id_command.data
|
||||
, Base.FLAG_ACTIVE: self.active_only.data
|
||||
}
|
||||
134
forms/forms.py
134
forms/forms.py
@@ -1,134 +0,0 @@
|
||||
"""
|
||||
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=[])
|
||||
@@ -1,42 +0,0 @@
|
||||
"""
|
||||
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'),
|
||||
}
|
||||
Reference in New Issue
Block a user