Feat: Multiplayer sessions added using CRUD database.
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.env
|
||||||
|
|
||||||
|
*.log
|
||||||
|
*.log.*
|
||||||
|
|
||||||
|
env_tcg/
|
||||||
|
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
40
README.md
Normal file
40
README.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
Magic: The Gathering trading card game commander life tracking tool.
|
||||||
|
|
||||||
|
Powered by flask
|
||||||
|
|
||||||
|
enter virtual environment:
|
||||||
|
python -m venv VIRTUAL_ENVIRONMENT_NAME
|
||||||
|
|
||||||
|
run module bundler:
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
host for machine:
|
||||||
|
python -m flask run
|
||||||
|
|
||||||
|
host for local network:
|
||||||
|
python -m flask run --host=0.0.0.0
|
||||||
|
|
||||||
|
|
||||||
|
files dedicated to each page:
|
||||||
|
CSS
|
||||||
|
page
|
||||||
|
HTML
|
||||||
|
page
|
||||||
|
row
|
||||||
|
JavaScript
|
||||||
|
page
|
||||||
|
api
|
||||||
|
router
|
||||||
|
base - navigation buttons
|
||||||
|
PostgreSQL
|
||||||
|
get
|
||||||
|
save
|
||||||
|
table
|
||||||
|
staging table
|
||||||
|
audit table
|
||||||
|
Python
|
||||||
|
business object
|
||||||
|
controller
|
||||||
|
datastore
|
||||||
|
form
|
||||||
|
model
|
||||||
20
__init__.py
Normal file
20
__init__.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Backend
|
||||||
|
Feature: Initialisation
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises the Flask application.
|
||||||
|
Initialises any extensions used in the project.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object('config')
|
||||||
|
|
||||||
|
# from app import routes
|
||||||
|
# import business_objects, lib, models
|
||||||
135
app.py
Normal file
135
app.py
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: App General
|
||||||
|
Feature: App
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# VARIABLE INSTANTIATION
|
||||||
|
# METHODS
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
from config import app_config, Config
|
||||||
|
from controllers.legal.legal import routes_legal
|
||||||
|
from controllers.tcg.mtg_game import routes_mtg_game
|
||||||
|
from controllers.user.user import routes_user
|
||||||
|
from extensions import db, csrf, mail, oauth
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||||
|
# from flask_appconfig import AppConfig
|
||||||
|
from flask_cors import CORS
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_mail import Mail, Message
|
||||||
|
from flask_wtf.csrf import CSRFProtect
|
||||||
|
from werkzeug.exceptions import HTTPException
|
||||||
|
from authlib.integrations.flask_client import OAuth
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__)) # Todo: why?
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.secret_key = os.getenv('KEY_SECRET_FLASK')
|
||||||
|
|
||||||
|
# AppConfig(app)
|
||||||
|
app.config.from_object(app_config) # for db init with required keys
|
||||||
|
app.app_config = app_config
|
||||||
|
# app.config["config"] = app_config()
|
||||||
|
|
||||||
|
# logging
|
||||||
|
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)
|
||||||
|
handler.setLevel(logging.DEBUG)
|
||||||
|
app.logger.addHandler(handler)
|
||||||
|
|
||||||
|
@app.errorhandler(Exception)
|
||||||
|
def internal_server_error(error):
|
||||||
|
if isinstance(error, HTTPException) and error.code == 404:
|
||||||
|
return "Not Found", 404
|
||||||
|
|
||||||
|
app.logger.error('Server Error: %s', (error))
|
||||||
|
app.logger.error('Request: %s %s %s %s %s',
|
||||||
|
request.remote_addr,
|
||||||
|
request.method,
|
||||||
|
request.scheme,
|
||||||
|
request.full_path,
|
||||||
|
request.headers)
|
||||||
|
app.logger.error('Request data: %s', request.get_data())
|
||||||
|
app.logger.error('Traceback: %s', traceback.format_exc())
|
||||||
|
return "Internal Server Error", 500
|
||||||
|
|
||||||
|
"""
|
||||||
|
@app.before_first_request
|
||||||
|
def clear_session():
|
||||||
|
session.clear()
|
||||||
|
"""
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def make_session_permanent():
|
||||||
|
session.permanent = True
|
||||||
|
|
||||||
|
csrf = CSRFProtect()
|
||||||
|
cors = CORS(app, resources={
|
||||||
|
r"/static/*": {
|
||||||
|
"origins": [app.config["URL_HOST"]],
|
||||||
|
"methods": ["GET"],
|
||||||
|
"max_age": 3600
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
csrf.init_app(app)
|
||||||
|
cors.init_app(app)
|
||||||
|
db.init_app(app)
|
||||||
|
mail.init_app(app)
|
||||||
|
oauth.init_app(app)
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
# config = app.config["config"]
|
||||||
|
db.create_all()
|
||||||
|
db.engine.url = app.config['SQLALCHEMY_DATABASE_URI']
|
||||||
|
|
||||||
|
oauth.register(
|
||||||
|
"auth0",
|
||||||
|
client_id = app.config['ID_AUTH0_CLIENT'],
|
||||||
|
client_secret = app.config['ID_AUTH0_CLIENT_SECRET'],
|
||||||
|
client_kwargs={
|
||||||
|
"scope": "openid profile email",
|
||||||
|
},
|
||||||
|
server_metadata_url=f'https://{app.config["DOMAIN_AUTH0"]}/.well-known/openid-configuration',
|
||||||
|
api_base_url = f'https://{app.config["DOMAIN_AUTH0"]}',
|
||||||
|
authorize_url = f'https://{app.config["DOMAIN_AUTH0"]}/authorize',
|
||||||
|
access_token_url = f'https://{app.config["DOMAIN_AUTH0"]}/oauth/token',
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Registered clients: {list(oauth._clients.keys())}")
|
||||||
|
|
||||||
|
app.register_blueprint(routes_legal)
|
||||||
|
app.register_blueprint(routes_user)
|
||||||
|
app.register_blueprint(routes_mtg_game)
|
||||||
|
|
||||||
|
|
||||||
|
@app.template_filter('console_log')
|
||||||
|
def console_log(value):
|
||||||
|
Helper_App.console_log(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def add_cache_headers(response):
|
||||||
|
if request.path.startswith('/static/'):
|
||||||
|
# Cache static assets
|
||||||
|
response.headers['Cache-Control'] = 'public, max-age=31536000'
|
||||||
|
else:
|
||||||
|
# No caching for dynamic content
|
||||||
|
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||||
|
return response
|
||||||
11
business_objects/__init__.py
Normal file
11
business_objects/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Module Initialisation
|
||||||
|
Feature: Business Objects
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises business objects module.
|
||||||
|
"""
|
||||||
32
business_objects/api.py
Normal file
32
business_objects/api.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: Base Business Object
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Abstract business object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from extensions import db
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from typing import ClassVar
|
||||||
|
from flask import jsonify
|
||||||
|
|
||||||
|
|
||||||
|
class API():
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_standard_response(success: bool, status_code: int, message: str, data: any, errors: list, meta: dict):
|
||||||
|
return jsonify({
|
||||||
|
"success": success,
|
||||||
|
"status_code": status_code,
|
||||||
|
"message": message,
|
||||||
|
"data": data,
|
||||||
|
"errors": errors,
|
||||||
|
"meta": meta
|
||||||
|
})
|
||||||
102
business_objects/base.py
Normal file
102
business_objects/base.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: Base Business Object
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Abstract base class for all business objects in app
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from extensions import db
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class Base():
|
||||||
|
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
|
||||||
|
ATTR_ID_ADDRESS: ClassVar[str] = 'id_address'
|
||||||
|
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
|
||||||
|
ATTR_ID_MSG_ERROR_TYPE: ClassVar[str] = 'id_type'
|
||||||
|
ATTR_ID_REGION: ClassVar[str] = 'id_region'
|
||||||
|
ATTR_USER_ID: ClassVar[str] = 'user_id'
|
||||||
|
ATTR_USER_ID_MANAGER: ClassVar[str] = 'user_id_manager'
|
||||||
|
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
|
||||||
|
FLAG_ACTIVE: ClassVar[str] = 'active'
|
||||||
|
FLAG_ACTIVE_ONLY: ClassVar[str] = 'active_only'
|
||||||
|
FLAG_ADDRESS: ClassVar[str] = 'address'
|
||||||
|
FLAG_ADDRESS_LINE_1: ClassVar[str] = 'address_line_1'
|
||||||
|
FLAG_ADDRESS_LINE_2: ClassVar[str] = 'address_line_2'
|
||||||
|
FLAG_BACKGROUND_COLOUR: ClassVar[str] = 'background_colour'
|
||||||
|
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
|
||||||
|
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
|
||||||
|
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
|
||||||
|
FLAG_CITY: ClassVar[str] = 'city'
|
||||||
|
FLAG_CODE: ClassVar[str] = 'code'
|
||||||
|
FLAG_COUNTY: ClassVar[str] = 'county'
|
||||||
|
FLAG_CREATED_BY: ClassVar[str] = 'created_by'
|
||||||
|
FLAG_CREATED_ON: ClassVar[str] = 'created_on'
|
||||||
|
FLAG_CURRENCY: ClassVar[str] = 'currency'
|
||||||
|
FLAG_CURRENCY_COST: ClassVar[str] = 'currency_cost'
|
||||||
|
FLAG_DATE_FROM: ClassVar[str] = 'date_from'
|
||||||
|
FLAG_DATE_TO: ClassVar[str] = 'date_to'
|
||||||
|
FLAG_DESCRIPTION: ClassVar[str] = 'description'
|
||||||
|
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||||
|
FLAG_EDIT: ClassVar[str] = 'edit'
|
||||||
|
FLAG_EMAIL: ClassVar[str] = 'email'
|
||||||
|
FLAG_END_ON: ClassVar[str] = 'end_on'
|
||||||
|
FLAG_FAX: ClassVar[str] = 'fax'
|
||||||
|
FLAG_FIRSTNAME: ClassVar[str] = 'firstname'
|
||||||
|
FLAG_GUID: ClassVar[str] = 'guid'
|
||||||
|
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
|
||||||
|
# FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
|
||||||
|
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||||
|
FLAG_NAME: ClassVar[str] = 'name'
|
||||||
|
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'NAME_ATTR_OPTION_TEXT'
|
||||||
|
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'NAME_ATTR_OPTION_VALUE'
|
||||||
|
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
|
||||||
|
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
|
||||||
|
FLAG_NOTES: ClassVar[str] = "notes"
|
||||||
|
FLAG_PATH: ClassVar[str] = 'path'
|
||||||
|
FLAG_PHONE_NUMBER: ClassVar[str] = 'phone_number'
|
||||||
|
FLAG_POSTCODE: ClassVar[str] = 'postcode'
|
||||||
|
FLAG_PRICE: ClassVar[str] = 'price'
|
||||||
|
FLAG_PRIORITY: ClassVar[str] = 'priority'
|
||||||
|
FLAG_QUANTITY: ClassVar[str] = 'quantity'
|
||||||
|
FLAG_REGION: ClassVar[str] = 'region'
|
||||||
|
FLAG_ROWS: ClassVar[str] = 'rows'
|
||||||
|
FLAG_SEARCH: ClassVar[str] = 'search'
|
||||||
|
FLAG_START_ON: ClassVar[str] = 'start_on'
|
||||||
|
FLAG_SURNAME: ClassVar[str] = 'surname'
|
||||||
|
FLAG_SYMBOL: ClassVar[str] = 'symbol'
|
||||||
|
FLAG_TEXT_COLOUR: ClassVar[str] = 'text_colour'
|
||||||
|
FLAG_URL: ClassVar[str] = 'url'
|
||||||
|
FLAG_USER: ClassVar[str] = 'authorisedUser' # 'user' already used
|
||||||
|
FLAG_VALUE_LOCAL_VAT_EXCL: ClassVar[str] = 'value_local_vat_excl'
|
||||||
|
FLAG_VALUE_LOCAL_VAT_INCL: ClassVar[str] = 'value_local_vat_incl'
|
||||||
|
FLAG_WEBSITE: ClassVar[str] = 'website'
|
||||||
|
USER_ID_GUEST: ClassVar[int] = 7
|
||||||
|
"""
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'name-attribute-option-text'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'name-attribute-option-value'
|
||||||
|
"""
|
||||||
|
def __repr__(self):
|
||||||
|
attrs = '\n'.join(f'{k}={v!r}' for k, v in self.__dict__.items())
|
||||||
|
return f'<{self.__class__.__name__}(\n{attrs}\n)>'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def output_bool(cls, value):
|
||||||
|
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_list_options(objects):
|
||||||
|
return [object.to_json_option() for object in objects]
|
||||||
|
@classmethod
|
||||||
|
def get_shared_json_attributes(cls, object):
|
||||||
|
return {
|
||||||
|
cls.FLAG_NAME_ATTR_OPTION_TEXT: object.NAME_ATTR_OPTION_TEXT
|
||||||
|
, cls.FLAG_NAME_ATTR_OPTION_VALUE: object.NAME_ATTR_OPTION_VALUE
|
||||||
|
}
|
||||||
65
business_objects/db_base.py
Normal file
65
business_objects/db_base.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: Database Base Business Objects
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Abstract base class for database objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||||
|
from extensions import db
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from typing import ClassVar
|
||||||
|
from abc import abstractmethod, ABCMeta
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from sqlalchemy.ext.declarative import DeclarativeMeta
|
||||||
|
# from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SQLAlchemy_ABCMeta(db.Model.__class__, ABCMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SQLAlchemy_ABC(db.Model, metaclass=SQLAlchemy_ABCMeta):
|
||||||
|
__abstract__ = True
|
||||||
|
# id = db.Column(db.Integer, primary_key=True)
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def __repr__(self):
|
||||||
|
pass
|
||||||
|
def to_json(self):
|
||||||
|
pass
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
pass
|
||||||
|
def to_temporary_record(self):
|
||||||
|
pass
|
||||||
|
def to_object_with_missing_attributes(self, excluded_attributes):
|
||||||
|
return {
|
||||||
|
column.name: getattr(self, column.name)
|
||||||
|
for column in self.__table__.columns
|
||||||
|
if column.name not in excluded_attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Get_Many_Parameters_Base(BaseModel, metaclass=ABCMeta):
|
||||||
|
# a_user_id: int
|
||||||
|
def __init__(self, **kwargs): # , a_user_id
|
||||||
|
super().__init__(**kwargs) # a_user_id=a_user_id,
|
||||||
|
@classmethod
|
||||||
|
@abstractmethod
|
||||||
|
def get_default(cls): # , user_id
|
||||||
|
pass
|
||||||
|
@classmethod
|
||||||
|
@abstractmethod
|
||||||
|
def from_json(self):
|
||||||
|
pass
|
||||||
|
@abstractmethod
|
||||||
|
def to_json(self):
|
||||||
|
pass # return self.dict()
|
||||||
147
business_objects/sql_error.py
Normal file
147
business_objects/sql_error.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: SQL Error Business Object
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Business object for SQL errors returned by Get Many Stored Procedures
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from lib import data_types
|
||||||
|
# external
|
||||||
|
from enum import Enum
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import locale
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from sqlalchemy import Uuid
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
# db = SQLAlchemy()
|
||||||
|
|
||||||
|
|
||||||
|
class SQL_Error(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_ERROR_ID: ClassVar[str] = 'error_id'
|
||||||
|
FLAG_IS_BREAKING_ERROR: ClassVar[str] = 'is_breaking_error'
|
||||||
|
|
||||||
|
__tablename__ = 'error'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
error_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
guid = db.Column(Uuid)
|
||||||
|
id_type = db.Column(db.Integer)
|
||||||
|
code_type = db.Column(db.Text)
|
||||||
|
name_type = db.Column(db.Text)
|
||||||
|
msg = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.error_id = 0
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_error(cls, record):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_error'
|
||||||
|
Helper_App.console_log(_m)
|
||||||
|
Helper_App.console_log(f'record: {record}')
|
||||||
|
error = cls()
|
||||||
|
error.error_id = record[0]
|
||||||
|
error.guid = record[1]
|
||||||
|
error.id_type = record[2]
|
||||||
|
error.code_type = record[3]
|
||||||
|
error.name_type = record[4]
|
||||||
|
error.msg = record[5]
|
||||||
|
error.display_order = record[6]
|
||||||
|
error.active = av.input_bool(record[7], "active", _m)
|
||||||
|
return error
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_exception(cls, exception: Exception, is_breaking: bool = True):
|
||||||
|
_m = f'{cls.__qualname__}.from_exception'
|
||||||
|
Helper_App.console_log(_m)
|
||||||
|
error = cls()
|
||||||
|
error.error_id = -1
|
||||||
|
error.id_type = -1
|
||||||
|
error.code_type = type(exception).__name__
|
||||||
|
error.name_type = type(exception).__name__
|
||||||
|
error.msg = str(exception)
|
||||||
|
Helper_App.console_log(f'Error: {error}')
|
||||||
|
return error
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
error = cls()
|
||||||
|
if json is None: return error
|
||||||
|
"""
|
||||||
|
# Helper_App.console_log(f'{_m}\njson: {json}')
|
||||||
|
error.error_id = json.get(cls.ATTR_ERROR_ID, -1)
|
||||||
|
error.id_type = json.get()
|
||||||
|
error.name = json[cls.FLAG_NAME]
|
||||||
|
error.code = json.get(cls.FLAG_CODE, error.name.upper().replace(" ", "_"))
|
||||||
|
error.active = av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, _m)
|
||||||
|
# Helper_App.console_log(f'Error: {error}')
|
||||||
|
return error
|
||||||
|
"""
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
self.ATTR_ERROR_ID: self.error_id
|
||||||
|
, Base.FLAG_GUID: self.guid
|
||||||
|
, Base.ATTR_ID_MSG_ERROR_TYPE: self.id_type
|
||||||
|
, Base.FLAG_CODE: self.code_type
|
||||||
|
, Base.FLAG_NAME: self.name_type
|
||||||
|
, Base.FLAG_MESSAGE: self.msg
|
||||||
|
, Base.FLAG_DISPLAY_ORDER: self.display_order
|
||||||
|
, Base.FLAG_ACTIVE: self.active
|
||||||
|
}
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
# Helper_App.console_log(f'{cls.__qualname__}.__repr__')
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_ERROR_ID}: {self.error_id}
|
||||||
|
{Base.ATTR_ID_MSG_ERROR_TYPE}: {self.id_type}
|
||||||
|
{Base.FLAG_CODE}: {self.code_type}
|
||||||
|
{Base.FLAG_NAME}: {self.name_type}
|
||||||
|
{Base.FLAG_MESSAGE}: {self.msg}
|
||||||
|
{Base.FLAG_DISPLAY_ORDER}: {self.display_order}
|
||||||
|
{Base.FLAG_ACTIVE}: {self.active}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
class Parameters_SQL_Error(Get_Many_Parameters_Base):
|
||||||
|
guid: str # UUID stored as string for Pydantic compatibility
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, guid):
|
||||||
|
return cls(
|
||||||
|
guid = guid
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
guid = json.get('a_guid', None)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_guid': self.guid
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_guid': Uuid
|
||||||
|
}
|
||||||
1
business_objects/tcg/__init__.py
Normal file
1
business_objects/tcg/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
172
business_objects/tcg/mtg_deck.py
Normal file
172
business_objects/tcg/mtg_deck.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Deck Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
|
||||||
|
|
||||||
|
class MTG_Deck(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_DECK_ID: ClassVar[str] = 'deck_id'
|
||||||
|
ATTR_COMMANDER_BRACKET_ID: ClassVar[str] = 'commander_bracket_id'
|
||||||
|
FLAG_DECK: ClassVar[str] = 'deck'
|
||||||
|
FLAG_IS_COMMANDER: ClassVar[str] = 'is_commander'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_DECK_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_deck'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
deck_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.Text)
|
||||||
|
is_commander = db.Column(db.Boolean)
|
||||||
|
commander_bracket_id = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.deck_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_deck(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_deck'
|
||||||
|
deck = cls()
|
||||||
|
deck.deck_id = query_row[0]
|
||||||
|
deck.name = query_row[1]
|
||||||
|
deck.is_commander = av.input_bool(query_row[2], cls.FLAG_IS_COMMANDER, _m)
|
||||||
|
deck.commander_bracket_id = query_row[3]
|
||||||
|
deck.active = av.input_bool(query_row[4], cls.FLAG_ACTIVE, _m)
|
||||||
|
deck.created_on = query_row[5]
|
||||||
|
deck.created_by_user_id = query_row[6]
|
||||||
|
return deck
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
deck = cls()
|
||||||
|
if json is None: return deck
|
||||||
|
deck.deck_id = json.get(cls.ATTR_DECK_ID, -1)
|
||||||
|
deck.name = json.get(cls.FLAG_NAME, None)
|
||||||
|
deck.is_commander = av.input_bool(json.get(cls.FLAG_IS_COMMANDER, True), cls.FLAG_IS_COMMANDER, _m)
|
||||||
|
deck.commander_bracket_id = json.get(cls.ATTR_COMMANDER_BRACKET_ID, None)
|
||||||
|
deck.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
deck.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
deck.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return deck
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_DECK_ID: self.deck_id
|
||||||
|
, self.FLAG_NAME: self.name
|
||||||
|
, self.FLAG_IS_COMMANDER: self.is_commander
|
||||||
|
, self.ATTR_COMMANDER_BRACKET_ID: self.commander_bracket_id
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
, Base.ATTR_USER_ID: self.created_by_user_id
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_DECK_ID}: {self.deck_id}
|
||||||
|
{self.FLAG_NAME}: {self.name}
|
||||||
|
{self.FLAG_IS_COMMANDER}: {self.is_commander}
|
||||||
|
{self.ATTR_COMMANDER_BRACKET_ID}: {self.commander_bracket_id}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
{Base.ATTR_USER_ID}: {self.created_by_user_id}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_MTG_Deck(Get_Many_Parameters_Base):
|
||||||
|
get_all_deck: bool
|
||||||
|
get_inactive_deck: bool
|
||||||
|
deck_ids: str
|
||||||
|
deck_names: str
|
||||||
|
commander_bracket_ids: str
|
||||||
|
include_commander_option: bool
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
require_all_non_id_filters_met: bool
|
||||||
|
require_any_non_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls):
|
||||||
|
return cls(
|
||||||
|
get_all_deck = True
|
||||||
|
, get_inactive_deck = False
|
||||||
|
, deck_ids = ''
|
||||||
|
, deck_names = ''
|
||||||
|
, commander_bracket_ids = ''
|
||||||
|
, include_commander_option = True
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
, require_all_non_id_filters_met = False
|
||||||
|
, require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_deck = json.get('a_get_all_deck', False)
|
||||||
|
, get_inactive_deck = json.get('a_get_inactive_deck', False)
|
||||||
|
, deck_ids = json.get('a_deck_ids', '')
|
||||||
|
, deck_names = json.get('a_deck_names', '')
|
||||||
|
, commander_bracket_ids = json.get('a_commander_bracket_ids', '')
|
||||||
|
, include_commander_option = json.get('a_include_commander_option', True)
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
, require_all_non_id_filters_met = json.get('a_require_all_non_id_filters_met', False)
|
||||||
|
, require_any_non_id_filters_met = json.get('a_require_any_non_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_deck': self.get_all_deck
|
||||||
|
, 'a_get_inactive_deck': self.get_inactive_deck
|
||||||
|
, 'a_deck_ids': self.deck_ids
|
||||||
|
, 'a_deck_names': self.deck_names
|
||||||
|
, 'a_commander_bracket_ids': self.commander_bracket_ids
|
||||||
|
, 'a_include_commander_option': self.include_commander_option
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
, 'a_require_all_non_id_filters_met': self.require_all_non_id_filters_met
|
||||||
|
, 'a_require_any_non_id_filters_met': self.require_any_non_id_filters_met
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_deck': Boolean
|
||||||
|
, 'a_get_inactive_deck': Boolean
|
||||||
|
, 'a_deck_ids': Text
|
||||||
|
, 'a_deck_names': Text
|
||||||
|
, 'a_commander_bracket_ids': Text
|
||||||
|
, 'a_include_commander_option': Boolean
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
, 'a_require_all_non_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_non_id_filters_met': Boolean
|
||||||
|
}
|
||||||
152
business_objects/tcg/mtg_deck_commander_bracket.py
Normal file
152
business_objects/tcg/mtg_deck_commander_bracket.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Deck Commander Bracket Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class MTG_Deck_Commander_Bracket(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_COMMANDER_BRACKET_ID: ClassVar[str] = 'commander_bracket_id'
|
||||||
|
FLAG_COMMANDER_BRACKET: ClassVar[str] = 'commander_bracket'
|
||||||
|
FLAG_DESCRIPTION: ClassVar[str] = 'description'
|
||||||
|
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_COMMANDER_BRACKET_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_deck_commander_bracket'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
commander_bracket_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.Text)
|
||||||
|
description = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.commander_bracket_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_deck_commander_bracket(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_deck_commander_bracket'
|
||||||
|
bracket = cls()
|
||||||
|
bracket.commander_bracket_id = query_row[0]
|
||||||
|
bracket.name = query_row[1]
|
||||||
|
bracket.description = query_row[2]
|
||||||
|
bracket.display_order = query_row[3]
|
||||||
|
bracket.active = av.input_bool(query_row[4], cls.FLAG_ACTIVE, _m)
|
||||||
|
bracket.created_on = query_row[5]
|
||||||
|
bracket.created_by_user_id = query_row[6]
|
||||||
|
return bracket
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
bracket = cls()
|
||||||
|
if json is None: return bracket
|
||||||
|
bracket.commander_bracket_id = json.get(cls.ATTR_COMMANDER_BRACKET_ID, -1)
|
||||||
|
bracket.name = json.get(cls.FLAG_NAME, None)
|
||||||
|
bracket.description = json.get(cls.FLAG_DESCRIPTION, None)
|
||||||
|
bracket.display_order = json.get(cls.FLAG_DISPLAY_ORDER, 0)
|
||||||
|
bracket.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
bracket.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
bracket.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return bracket
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_COMMANDER_BRACKET_ID: self.commander_bracket_id
|
||||||
|
, self.FLAG_NAME: self.name
|
||||||
|
, self.FLAG_DESCRIPTION: self.description
|
||||||
|
, self.FLAG_DISPLAY_ORDER: self.display_order
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
, Base.ATTR_USER_ID: self.created_by_user_id
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_COMMANDER_BRACKET_ID}: {self.commander_bracket_id}
|
||||||
|
{self.FLAG_NAME}: {self.name}
|
||||||
|
{self.FLAG_DESCRIPTION}: {self.description}
|
||||||
|
{self.FLAG_DISPLAY_ORDER}: {self.display_order}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
{Base.ATTR_USER_ID}: {self.created_by_user_id}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_MTG_Deck_Commander_Bracket(Get_Many_Parameters_Base):
|
||||||
|
get_all_commander_bracket: bool
|
||||||
|
get_inactive_commander_bracket: bool
|
||||||
|
commander_bracket_ids: str
|
||||||
|
commander_bracket_names: str
|
||||||
|
user_ids: str
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
require_all_non_id_filters_met: bool
|
||||||
|
require_any_non_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, user_id_session):
|
||||||
|
return cls(
|
||||||
|
get_all_commander_bracket = True
|
||||||
|
, get_inactive_commander_bracket = False
|
||||||
|
, commander_bracket_ids = ''
|
||||||
|
, commander_bracket_names = ''
|
||||||
|
, user_ids = str(user_id_session)
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
, require_all_non_id_filters_met = False
|
||||||
|
, require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_commander_bracket = json.get('a_get_all_commander_bracket', False)
|
||||||
|
, get_inactive_commander_bracket = json.get('a_get_inactive_commander_bracket', False)
|
||||||
|
, commander_bracket_ids = json.get('a_commander_bracket_ids', '')
|
||||||
|
, commander_bracket_names = json.get('a_commander_bracket_names', '')
|
||||||
|
, user_ids = json.get('a_user_ids', '')
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
, require_all_non_id_filters_met = json.get('a_require_all_non_id_filters_met', False)
|
||||||
|
, require_any_non_id_filters_met = json.get('a_require_any_non_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_commander_bracket': self.get_all_commander_bracket
|
||||||
|
, 'a_get_inactive_commander_bracket': self.get_inactive_commander_bracket
|
||||||
|
, 'a_commander_bracket_ids': self.commander_bracket_ids
|
||||||
|
, 'a_commander_bracket_names': self.commander_bracket_names
|
||||||
|
, 'a_user_ids': self.user_ids
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
, 'a_require_all_non_id_filters_met': self.require_all_non_id_filters_met
|
||||||
|
, 'a_require_any_non_id_filters_met': self.require_any_non_id_filters_met
|
||||||
|
}
|
||||||
192
business_objects/tcg/mtg_game.py
Normal file
192
business_objects/tcg/mtg_game.py
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Game Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from sqlalchemy import bindparam
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
|
||||||
|
|
||||||
|
class MTG_Game(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_GAME_ID: ClassVar[str] = 'game_id'
|
||||||
|
FLAG_END_ON: ClassVar[str] = 'end_on'
|
||||||
|
FLAG_GAME: ClassVar[str] = 'game'
|
||||||
|
FLAG_IS_COMMANDER: ClassVar[str] = 'is_commander'
|
||||||
|
FLAG_IS_DRAFT: ClassVar[str] = 'is_draft'
|
||||||
|
FLAG_IS_SEALED: ClassVar[str] = 'is_sealed'
|
||||||
|
FLAG_LOCATION_NAME: ClassVar[str] = 'location_name'
|
||||||
|
FLAG_NOTES: ClassVar[str] = 'notes'
|
||||||
|
FLAG_START_ON: ClassVar[str] = 'start_on'
|
||||||
|
FLAG_STARTING_LIFE: ClassVar[str] = 'starting_life'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_GAME_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = FLAG_START_ON
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_game'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
game_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
notes = db.Column(db.Text)
|
||||||
|
is_commander = db.Column(db.Boolean)
|
||||||
|
is_draft = db.Column(db.Boolean)
|
||||||
|
is_sealed = db.Column(db.Boolean)
|
||||||
|
location_name = db.Column(db.Text)
|
||||||
|
start_on = db.Column(db.DateTime)
|
||||||
|
end_on = db.Column(db.DateTime)
|
||||||
|
starting_life = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.game_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_game(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_game'
|
||||||
|
game = cls()
|
||||||
|
game.game_id = query_row[0]
|
||||||
|
game.notes = query_row[1]
|
||||||
|
game.is_commander = av.input_bool(query_row[2], cls.FLAG_IS_COMMANDER, _m)
|
||||||
|
game.is_draft = av.input_bool(query_row[3], cls.FLAG_IS_DRAFT, _m)
|
||||||
|
game.is_sealed = av.input_bool(query_row[4], cls.FLAG_IS_SEALED, _m)
|
||||||
|
game.location_name = query_row[5]
|
||||||
|
game.start_on = query_row[6]
|
||||||
|
game.end_on = query_row[7]
|
||||||
|
game.starting_life = query_row[8]
|
||||||
|
game.active = av.input_bool(query_row[9], cls.FLAG_ACTIVE, _m)
|
||||||
|
game.created_on = query_row[10]
|
||||||
|
game.created_by_user_id = query_row[11]
|
||||||
|
return game
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
game = cls()
|
||||||
|
if json is None: return game
|
||||||
|
game.game_id = json.get(cls.ATTR_GAME_ID, -1)
|
||||||
|
game.notes = json.get(cls.FLAG_NOTES, None)
|
||||||
|
game.is_commander = av.input_bool(json.get(cls.FLAG_IS_COMMANDER, True), cls.FLAG_IS_COMMANDER, _m)
|
||||||
|
game.is_draft = av.input_bool(json.get(cls.FLAG_IS_DRAFT, False), cls.FLAG_IS_DRAFT, _m)
|
||||||
|
game.is_sealed = av.input_bool(json.get(cls.FLAG_IS_SEALED, False), cls.FLAG_IS_SEALED, _m)
|
||||||
|
game.location_name = json.get(cls.FLAG_LOCATION_NAME, None)
|
||||||
|
game.start_on = json.get(cls.FLAG_START_ON, None)
|
||||||
|
game.starting_life = json.get(cls.FLAG_STARTING_LIFE, 40)
|
||||||
|
game.end_on = json.get(cls.FLAG_END_ON, None)
|
||||||
|
game.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
game.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
game.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return game
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_GAME_ID: self.game_id
|
||||||
|
, self.FLAG_NOTES: self.notes
|
||||||
|
, self.FLAG_IS_COMMANDER: self.is_commander
|
||||||
|
, self.FLAG_IS_DRAFT: self.is_draft
|
||||||
|
, self.FLAG_IS_SEALED: self.is_sealed
|
||||||
|
, self.FLAG_LOCATION_NAME: self.location_name
|
||||||
|
, self.FLAG_START_ON: self.start_on
|
||||||
|
, self.FLAG_STARTING_LIFE: self.starting_life
|
||||||
|
, self.FLAG_END_ON: self.end_on
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
, Base.ATTR_USER_ID: self.created_by_user_id
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_GAME_ID}: {self.game_id}
|
||||||
|
{self.FLAG_NOTES}: {self.notes}
|
||||||
|
{self.FLAG_IS_COMMANDER}: {self.is_commander}
|
||||||
|
{self.FLAG_IS_DRAFT}: {self.is_draft}
|
||||||
|
{self.FLAG_IS_SEALED}: {self.is_sealed}
|
||||||
|
{self.FLAG_LOCATION_NAME}: {self.location_name}
|
||||||
|
{self.FLAG_START_ON}: {self.start_on}
|
||||||
|
{self.FLAG_END_ON}: {self.end_on}
|
||||||
|
{self.FLAG_STARTING_LIFE}: {self.starting_life}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
{Base.ATTR_USER_ID}: {self.created_by_user_id}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
class Parameters_MTG_Game(Get_Many_Parameters_Base):
|
||||||
|
get_all_game: bool
|
||||||
|
get_inactive_game: bool
|
||||||
|
game_ids: str
|
||||||
|
get_all_user: bool
|
||||||
|
get_inactive_user: bool
|
||||||
|
user_ids: str
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, user_id_session):
|
||||||
|
return cls(
|
||||||
|
get_all_game = True
|
||||||
|
, get_inactive_game = False
|
||||||
|
, game_ids = ''
|
||||||
|
, get_all_user = False
|
||||||
|
, get_inactive_user = False
|
||||||
|
, user_ids = '' if user_id_session is None else f'{user_id_session}'
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_game = json.get('a_get_all_game', False)
|
||||||
|
, get_inactive_game = json.get('a_get_inactive_game', False)
|
||||||
|
, game_ids = json.get('a_game_ids', '')
|
||||||
|
, get_all_user = json.get('a_get_all_user', False)
|
||||||
|
, get_inactive_user = json.get('a_get_inactive_user', False)
|
||||||
|
, user_ids = json.get('a_user_ids', '')
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_game': self.get_all_game
|
||||||
|
, 'a_get_inactive_game': self.get_inactive_game
|
||||||
|
, 'a_game_ids': str(self.game_ids)
|
||||||
|
, 'a_get_all_user': self.get_all_user
|
||||||
|
, 'a_get_inactive_user': self.get_inactive_user
|
||||||
|
, 'a_user_ids': str(self.user_ids)
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
}
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_game': Boolean
|
||||||
|
, 'a_get_inactive_game': Boolean
|
||||||
|
, 'a_game_ids': Text
|
||||||
|
, 'a_get_all_user': Boolean
|
||||||
|
, 'a_get_inactive_user': Boolean
|
||||||
|
, 'a_user_ids': Text
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
}
|
||||||
197
business_objects/tcg/mtg_game_player.py
Normal file
197
business_objects/tcg/mtg_game_player.py
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Game Player Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from sqlalchemy import Uuid
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
# import uuid
|
||||||
|
|
||||||
|
class MTG_Game_Player(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_PLAYER_ID: ClassVar[str] = 'player_id'
|
||||||
|
ATTR_GAME_ID: ClassVar[str] = 'game_id'
|
||||||
|
ATTR_DECK_ID: ClassVar[str] = 'deck_id'
|
||||||
|
FLAG_PLAYER: ClassVar[str] = 'player'
|
||||||
|
FLAG_NOTES: ClassVar[str] = 'notes'
|
||||||
|
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_PLAYER_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_game_player'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
player_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
game_id = db.Column(db.Integer)
|
||||||
|
user_id = db.Column(db.Integer)
|
||||||
|
deck_id = db.Column(db.Integer)
|
||||||
|
name = db.Column(db.Text)
|
||||||
|
notes = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.player_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_game_player(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_game_player'
|
||||||
|
player = cls()
|
||||||
|
player.player_id = query_row[0]
|
||||||
|
player.game_id = query_row[1]
|
||||||
|
player.user_id = query_row[2]
|
||||||
|
player.deck_id = query_row[3]
|
||||||
|
player.name = query_row[4]
|
||||||
|
player.notes = query_row[5]
|
||||||
|
player.display_order = query_row[6]
|
||||||
|
player.active = av.input_bool(query_row[7], cls.FLAG_ACTIVE, _m)
|
||||||
|
player.created_on = query_row[8]
|
||||||
|
player.created_by_user_id = query_row[9]
|
||||||
|
return player
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
player = cls()
|
||||||
|
if json is None: return player
|
||||||
|
player.player_id = json.get(cls.ATTR_PLAYER_ID, -1)
|
||||||
|
player.game_id = json.get(cls.ATTR_GAME_ID, None)
|
||||||
|
player.user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
player.deck_id = json.get(cls.ATTR_DECK_ID, None)
|
||||||
|
player.name = json.get(cls.FLAG_NAME, None)
|
||||||
|
player.notes = json.get(cls.FLAG_NOTES, None)
|
||||||
|
player.display_order = json.get(cls.FLAG_DISPLAY_ORDER, 0)
|
||||||
|
player.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
player.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
player.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return player
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_PLAYER_ID: self.player_id
|
||||||
|
, self.ATTR_GAME_ID: self.game_id
|
||||||
|
, Base.ATTR_USER_ID: self.user_id
|
||||||
|
, self.ATTR_DECK_ID: self.deck_id
|
||||||
|
, self.FLAG_NAME: self.name
|
||||||
|
, self.FLAG_NOTES: self.notes
|
||||||
|
, self.FLAG_DISPLAY_ORDER: self.display_order
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_PLAYER_ID}: {self.player_id}
|
||||||
|
{self.ATTR_GAME_ID}: {self.game_id}
|
||||||
|
{Base.ATTR_USER_ID}: {self.user_id}
|
||||||
|
{self.ATTR_DECK_ID}: {self.deck_id}
|
||||||
|
{self.FLAG_NAME}: {self.name}
|
||||||
|
{self.FLAG_NOTES}: {self.notes}
|
||||||
|
{self.FLAG_DISPLAY_ORDER}: {self.display_order}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
class MTG_Game_Player_Temp(db.Model, Base):
|
||||||
|
__tablename__ = 'tcg_mtg_game_player_temp'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
temp_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
player_id = db.Column(db.Integer)
|
||||||
|
game_id = db.Column(db.Integer)
|
||||||
|
user_id = db.Column(db.Integer)
|
||||||
|
deck_id = db.Column(db.Integer)
|
||||||
|
name = db.Column(db.Text)
|
||||||
|
notes = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
guid = db.Column(Uuid) #, default = uuid.uuid4)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_player(cls, player, guid):
|
||||||
|
_m = 'MTG_Game_Player_Temp.from_player'
|
||||||
|
temp = cls()
|
||||||
|
temp.player_id = player.player_id
|
||||||
|
temp.game_id = player.game_id
|
||||||
|
temp.user_id = player.user_id
|
||||||
|
temp.deck_id = player.deck_id
|
||||||
|
temp.name = player.name
|
||||||
|
temp.notes = player.notes
|
||||||
|
temp.display_order = player.display_order
|
||||||
|
temp.active = player.active
|
||||||
|
temp.created_on = player.created_on
|
||||||
|
temp.guid = guid
|
||||||
|
return temp
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_MTG_Game_Player(Get_Many_Parameters_Base):
|
||||||
|
get_all_game: bool
|
||||||
|
get_inactive_game: bool
|
||||||
|
game_ids: str
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, user_id_session):
|
||||||
|
return cls(
|
||||||
|
get_all_game = True
|
||||||
|
, get_inactive_game = False
|
||||||
|
, game_ids = ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_game = json.get('a_get_all_game', False)
|
||||||
|
, get_inactive_game = json.get('a_get_inactive_game', False)
|
||||||
|
, game_ids = json.get('a_game_ids', '')
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_game': self.get_all_game
|
||||||
|
, 'a_get_inactive_game': self.get_inactive_game
|
||||||
|
, 'a_game_ids': self.game_ids
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_game': Boolean
|
||||||
|
, 'a_get_inactive_game': Boolean
|
||||||
|
, 'a_game_ids': Text
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
}
|
||||||
176
business_objects/tcg/mtg_game_round.py
Normal file
176
business_objects/tcg/mtg_game_round.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Game Round Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from sqlalchemy import Uuid
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
|
||||||
|
|
||||||
|
class MTG_Game_Round(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_ROUND_ID: ClassVar[str] = 'round_id'
|
||||||
|
ATTR_GAME_ID: ClassVar[str] = 'game_id'
|
||||||
|
FLAG_ROUND: ClassVar[str] = 'round'
|
||||||
|
FLAG_NOTES: ClassVar[str] = 'notes'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_ROUND_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = ATTR_ROUND_ID
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_game_round'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
round_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
game_id = db.Column(db.Integer)
|
||||||
|
notes = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.round_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_game_round(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_game_round'
|
||||||
|
round = cls()
|
||||||
|
round.round_id = query_row[0]
|
||||||
|
round.game_id = query_row[1]
|
||||||
|
round.notes = query_row[2]
|
||||||
|
round.display_order = query_row[3]
|
||||||
|
round.active = av.input_bool(query_row[4], cls.FLAG_ACTIVE, _m)
|
||||||
|
round.created_on = query_row[5]
|
||||||
|
round.created_by_user_id = query_row[6]
|
||||||
|
return round
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
round = cls()
|
||||||
|
if json is None: return round
|
||||||
|
round.round_id = json.get(cls.ATTR_ROUND_ID, -1)
|
||||||
|
round.game_id = json.get(cls.ATTR_GAME_ID, None)
|
||||||
|
round.notes = json.get(cls.FLAG_NOTES, None)
|
||||||
|
round.display_order = json.get(cls.FLAG_DISPLAY_ORDER, -1)
|
||||||
|
round.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
round.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
round.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return round
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_ROUND_ID: self.round_id
|
||||||
|
, self.ATTR_GAME_ID: self.game_id
|
||||||
|
, self.FLAG_NOTES: self.notes
|
||||||
|
, self.FLAG_DISPLAY_ORDER: self.display_order
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
, Base.ATTR_USER_ID: self.created_by_user_id
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_ROUND_ID}: {self.round_id}
|
||||||
|
{self.ATTR_GAME_ID}: {self.game_id}
|
||||||
|
{self.FLAG_NOTES}: {self.notes}
|
||||||
|
{self.FLAG_DISPLAY_ORDER}: {self.display_order}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
{Base.ATTR_USER_ID}: {self.created_by_user_id}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
class MTG_Game_Round_Temp(db.Model, Base):
|
||||||
|
__tablename__ = 'tcg_mtg_game_round_temp'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
temp_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
round_id = db.Column(db.Integer)
|
||||||
|
game_id = db.Column(db.Integer)
|
||||||
|
notes = db.Column(db.Text)
|
||||||
|
display_order = db.Column(db.Integer)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
guid = db.Column(Uuid)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_round(cls, round, guid):
|
||||||
|
_m = 'MTG_Game_Round_Temp.from_round'
|
||||||
|
temp = cls()
|
||||||
|
temp.round_id = round.round_id
|
||||||
|
temp.game_id = round.game_id
|
||||||
|
temp.notes = round.notes
|
||||||
|
temp.display_order = round.display_order
|
||||||
|
temp.active = round.active
|
||||||
|
temp.created_on = round.created_on
|
||||||
|
temp.guid = guid
|
||||||
|
return temp
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_MTG_Game_Round(Get_Many_Parameters_Base):
|
||||||
|
get_all_game: bool
|
||||||
|
get_inactive_game: bool
|
||||||
|
game_ids: str
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, user_id_session):
|
||||||
|
return cls(
|
||||||
|
get_all_game = True
|
||||||
|
, get_inactive_game = False
|
||||||
|
, game_ids = ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_game = json.get('a_get_all_game', False)
|
||||||
|
, get_inactive_game = json.get('a_get_inactive_game', False)
|
||||||
|
, game_ids = json.get('a_game_ids', '')
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_game': self.get_all_game
|
||||||
|
, 'a_get_inactive_game': self.get_inactive_game
|
||||||
|
, 'a_game_ids': self.game_ids
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_game': Boolean
|
||||||
|
, 'a_get_inactive_game': Boolean
|
||||||
|
, 'a_game_ids': Text
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
}
|
||||||
201
business_objects/tcg/mtg_game_round_player_damage.py
Normal file
201
business_objects/tcg/mtg_game_round_player_damage.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: MTG Game Round Player Damage Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from sqlalchemy import Uuid
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
|
||||||
|
|
||||||
|
class MTG_Game_Round_Player_Damage(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_DAMAGE_ID: ClassVar[str] = 'damage_id'
|
||||||
|
ATTR_PLAYER_ID: ClassVar[str] = 'player_id'
|
||||||
|
ATTR_ROUND_ID: ClassVar[str] = 'round_id'
|
||||||
|
ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID: ClassVar[str] = 'received_from_commander_player_id'
|
||||||
|
FLAG_COMMANDER_DEATHS: ClassVar[str] = 'commander_deaths'
|
||||||
|
FLAG_DAMAGE: ClassVar[str] = 'damage'
|
||||||
|
FLAG_HEALTH_CHANGE: ClassVar[str] = 'health_change'
|
||||||
|
FLAG_IS_ELIMINATED: ClassVar[str] = 'is_eliminated'
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_DAMAGE_ID
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = ATTR_DAMAGE_ID
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_mtg_game_round_player_damage'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
damage_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
round_id = db.Column(db.Integer)
|
||||||
|
player_id = db.Column(db.Integer)
|
||||||
|
received_from_commander_player_id = db.Column(db.Integer)
|
||||||
|
health_change = db.Column(db.Integer)
|
||||||
|
commander_deaths = db.Column(db.Integer)
|
||||||
|
is_eliminated = db.Column(db.Boolean)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
created_by_user_id = db.Column(db.Integer)
|
||||||
|
updated_last_on = db.Column(db.DateTime)
|
||||||
|
updated_last_by_user_id = db.Column(db.Integer)
|
||||||
|
change_set_id = db.Column(db.Integer)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.damage_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_mtg_game_round_player_damage(cls, query_row):
|
||||||
|
_m = f'{cls.__qualname__}.from_db_mtg_game_round_player_damage'
|
||||||
|
damage = cls()
|
||||||
|
damage.damage_id = query_row[0]
|
||||||
|
damage.round_id = query_row[1]
|
||||||
|
damage.player_id = query_row[2]
|
||||||
|
damage.received_from_commander_player_id = query_row[3]
|
||||||
|
damage.health_change = query_row[4]
|
||||||
|
damage.commander_deaths = query_row[5]
|
||||||
|
damage.is_eliminated = av.input_bool(query_row[6], cls.FLAG_IS_ELIMINATED, _m)
|
||||||
|
damage.active = av.input_bool(query_row[7], cls.FLAG_ACTIVE, _m)
|
||||||
|
damage.created_on = query_row[8]
|
||||||
|
damage.created_by_user_id = query_row[9]
|
||||||
|
return damage
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
damage = cls()
|
||||||
|
if json is None: return damage
|
||||||
|
damage.damage_id = json.get(cls.ATTR_DAMAGE_ID, -1)
|
||||||
|
damage.round_id = json.get(cls.ATTR_ROUND_ID, None)
|
||||||
|
damage.player_id = json.get(cls.ATTR_PLAYER_ID, None)
|
||||||
|
damage.received_from_commander_player_id = json.get(cls.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID, None)
|
||||||
|
damage.health_change = json.get(cls.FLAG_HEALTH_CHANGE, 0)
|
||||||
|
damage.commander_deaths = json.get(cls.FLAG_COMMANDER_DEATHS, 0)
|
||||||
|
damage.is_eliminated = json.get(cls.FLAG_IS_ELIMINATED, False)
|
||||||
|
damage.active = av.input_bool(json.get(cls.FLAG_ACTIVE, True), cls.FLAG_ACTIVE, _m)
|
||||||
|
damage.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||||
|
damage.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
|
||||||
|
return damage
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_DAMAGE_ID: self.damage_id
|
||||||
|
, self.ATTR_ROUND_ID: self.round_id
|
||||||
|
, self.ATTR_PLAYER_ID: self.player_id
|
||||||
|
, self.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID: self.received_from_commander_player_id
|
||||||
|
, self.FLAG_HEALTH_CHANGE: self.health_change
|
||||||
|
, self.FLAG_COMMANDER_DEATHS: self.commander_deaths
|
||||||
|
, self.FLAG_IS_ELIMINATED: self.is_eliminated
|
||||||
|
, self.FLAG_ACTIVE: self.active
|
||||||
|
, self.FLAG_CREATED_ON: self.created_on
|
||||||
|
, Base.ATTR_USER_ID: self.created_by_user_id
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
{self.__class__.__name__}(
|
||||||
|
{self.ATTR_DAMAGE_ID}: {self.damage_id}
|
||||||
|
{self.ATTR_ROUND_ID}: {self.round_id}
|
||||||
|
{self.ATTR_PLAYER_ID}: {self.player_id}
|
||||||
|
{self.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID}: {self.received_from_commander_player_id}
|
||||||
|
{self.FLAG_HEALTH_CHANGE}: {self.health_change}
|
||||||
|
{self.FLAG_COMMANDER_DEATHS}: {self.commander_deaths}
|
||||||
|
{self.FLAG_IS_ELIMINATED}: {self.is_eliminated}
|
||||||
|
{self.FLAG_ACTIVE}: {self.active}
|
||||||
|
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||||
|
{Base.ATTR_USER_ID}: {self.created_by_user_id}
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
class MTG_Game_Round_Player_Damage_Temp(db.Model, Base):
|
||||||
|
__tablename__ = 'tcg_mtg_game_round_player_damage_temp'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
temp_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
damage_id = db.Column(db.Integer)
|
||||||
|
round_id = db.Column(db.Integer)
|
||||||
|
player_id = db.Column(db.Integer)
|
||||||
|
received_from_commander_player_id = db.Column(db.Integer)
|
||||||
|
health_change = db.Column(db.Integer)
|
||||||
|
commander_deaths = db.Column(db.Integer)
|
||||||
|
is_eliminated = db.Column(db.Boolean)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
created_on = db.Column(db.DateTime)
|
||||||
|
guid = db.Column(Uuid)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_damage(cls, damage, guid):
|
||||||
|
_m = 'MTG_Game_Round_Player_Damage_Temp.from_damage'
|
||||||
|
temp = cls()
|
||||||
|
temp.damage_id = damage.damage_id
|
||||||
|
temp.round_id = damage.round_id
|
||||||
|
temp.player_id = damage.player_id
|
||||||
|
temp.received_from_commander_player_id = damage.received_from_commander_player_id
|
||||||
|
temp.health_change = damage.health_change
|
||||||
|
temp.commander_deaths = damage.commander_deaths
|
||||||
|
temp.is_eliminated = damage.is_eliminated
|
||||||
|
temp.active = damage.active
|
||||||
|
temp.created_on = damage.created_on
|
||||||
|
temp.guid = guid
|
||||||
|
return temp
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_MTG_Game_Round_Player_Damage(Get_Many_Parameters_Base):
|
||||||
|
get_all_game: bool
|
||||||
|
get_inactive_game: bool
|
||||||
|
game_ids: str
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls, user_id_session):
|
||||||
|
return cls(
|
||||||
|
get_all_game = True
|
||||||
|
, get_inactive_game = False
|
||||||
|
, game_ids = ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
get_all_game = json.get('a_get_all_game', False)
|
||||||
|
, get_inactive_game = json.get('a_get_inactive_game', False)
|
||||||
|
, game_ids = json.get('a_game_ids', '')
|
||||||
|
, require_all_id_filters_met = json.get('a_require_all_id_filters_met', True)
|
||||||
|
, require_any_id_filters_met = json.get('a_require_any_id_filters_met', True)
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'a_get_all_game': self.get_all_game
|
||||||
|
, 'a_get_inactive_game': self.get_inactive_game
|
||||||
|
, 'a_game_ids': self.game_ids
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_game': Boolean
|
||||||
|
, 'a_get_inactive_game': Boolean
|
||||||
|
, 'a_game_ids': Text
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
}
|
||||||
229
business_objects/tcg/user.py
Normal file
229
business_objects/tcg/user.py
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Business Objects
|
||||||
|
Feature: User Business Object
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from extensions import db
|
||||||
|
from mtg_commander_life_tracker.forms.tcg.user import Filters_User
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar, Optional
|
||||||
|
from sqlalchemy.types import Text, Boolean
|
||||||
|
|
||||||
|
|
||||||
|
class User(SQLAlchemy_ABC, Base):
|
||||||
|
ATTR_USER_AUTH0_ID: ClassVar[str] = 'user_auth0_id'
|
||||||
|
FLAG_IS_EMAIL_VERIFIED: ClassVar[str] = 'is_email_verified'
|
||||||
|
FLAG_IS_SUPER_USER: ClassVar[str] = 'is_super_user'
|
||||||
|
FLAG_PRIORITY_ACCESS_LEVEL: ClassVar[str] = 'priority_access_level'
|
||||||
|
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||||
|
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_USER_ID
|
||||||
|
|
||||||
|
__tablename__ = 'tcg_user'
|
||||||
|
__table_args__ = { 'extend_existing': True }
|
||||||
|
|
||||||
|
user_id = db.Column(db.Integer, primary_key=True)
|
||||||
|
user_auth0_id = db.Column(db.String(250))
|
||||||
|
firstname = db.Column(db.Text)
|
||||||
|
surname = db.Column(db.Text)
|
||||||
|
email = db.Column(db.String(256))
|
||||||
|
is_email_verified = db.Column(db.Boolean)
|
||||||
|
is_super_user = db.Column(db.Boolean)
|
||||||
|
priority_access_level = db.Column(db.Integer)
|
||||||
|
is_new = db.Column(db.Boolean)
|
||||||
|
active = db.Column(db.Boolean)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.user_id = 0
|
||||||
|
self.is_new = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db_user(cls, query_row):
|
||||||
|
"""Map from PostgreSQL FN_TCG_User_Get_Many result columns:
|
||||||
|
user_id, user_auth0_id, firstname, surname, email, is_email_verified,
|
||||||
|
is_super_user, active, created_on, created_by_user_id, updated_last_on,
|
||||||
|
updated_last_by_user_id, change_set_id
|
||||||
|
"""
|
||||||
|
_m = f'{cls.__qualname__}.from_db_user'
|
||||||
|
Helper_App.console_log(f'user record: {query_row}')
|
||||||
|
user = cls()
|
||||||
|
user.user_id = query_row[0]
|
||||||
|
user.user_auth0_id = query_row[1]
|
||||||
|
user.firstname = query_row[2]
|
||||||
|
user.surname = query_row[3]
|
||||||
|
user.email = query_row[4]
|
||||||
|
user.is_email_verified = av.input_bool(query_row[5], cls.FLAG_IS_EMAIL_VERIFIED, _m)
|
||||||
|
user.is_super_user = av.input_bool(query_row[6], cls.FLAG_IS_SUPER_USER, _m)
|
||||||
|
user.active = av.input_bool(query_row[7], 'active', _m)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
user = cls()
|
||||||
|
if json is None: return user
|
||||||
|
Helper_App.console_log(f'{_m}/n{json}')
|
||||||
|
user.user_id = json[cls.ATTR_USER_ID]
|
||||||
|
user.user_auth0_id = json[cls.ATTR_USER_AUTH0_ID]
|
||||||
|
user.firstname = json[cls.FLAG_FIRSTNAME]
|
||||||
|
user.surname = json[cls.FLAG_SURNAME]
|
||||||
|
user.email = json[cls.FLAG_EMAIL]
|
||||||
|
user.is_email_verified = av.input_bool(json[cls.FLAG_IS_EMAIL_VERIFIED], cls.FLAG_IS_EMAIL_VERIFIED, _m)
|
||||||
|
user.is_super_user = av.input_bool(json[cls.FLAG_IS_SUPER_USER], cls.FLAG_IS_SUPER_USER, _m)
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json_auth0(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json_auth0'
|
||||||
|
Helper_App.console_log(_m)
|
||||||
|
Helper_App.console_log(f'JSON: {json}')
|
||||||
|
user = cls()
|
||||||
|
if json is None: return user
|
||||||
|
user_info = json['userinfo']
|
||||||
|
Helper_App.console_log(f'user_info: {user_info}')
|
||||||
|
user.user_id = None
|
||||||
|
user.user_auth0_id = user_info['sub']
|
||||||
|
user.firstname = None
|
||||||
|
user.surname = None
|
||||||
|
user.email = user_info[cls.FLAG_EMAIL]
|
||||||
|
user.is_email_verified = av.input_bool(user_info['email_verified'], cls.FLAG_IS_EMAIL_VERIFIED, _m)
|
||||||
|
user.is_super_user = None
|
||||||
|
return user
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
as_json = {
|
||||||
|
**self.get_shared_json_attributes(self)
|
||||||
|
, self.ATTR_USER_ID: self.user_id
|
||||||
|
, self.ATTR_USER_AUTH0_ID: self.user_auth0_id
|
||||||
|
, self.FLAG_FIRSTNAME: self.firstname
|
||||||
|
, self.FLAG_SURNAME: self.surname
|
||||||
|
, self.FLAG_NAME: self.get_name()
|
||||||
|
, self.FLAG_EMAIL: self.email
|
||||||
|
, self.FLAG_IS_EMAIL_VERIFIED: self.is_email_verified
|
||||||
|
, self.FLAG_IS_SUPER_USER: self.is_super_user
|
||||||
|
, self.FLAG_PRIORITY_ACCESS_LEVEL: self.priority_access_level
|
||||||
|
}
|
||||||
|
return as_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'''
|
||||||
|
User (
|
||||||
|
{self.ATTR_USER_ID}: {self.user_id}
|
||||||
|
, {self.ATTR_USER_AUTH0_ID}: {self.user_auth0_id}
|
||||||
|
, {self.FLAG_FIRSTNAME}: {self.firstname}
|
||||||
|
, {self.FLAG_SURNAME}: {self.surname}
|
||||||
|
, {self.FLAG_NAME}: {self.get_name()}
|
||||||
|
, {self.FLAG_EMAIL}: {self.email}
|
||||||
|
, {self.FLAG_IS_EMAIL_VERIFIED}: {self.is_email_verified}
|
||||||
|
, {self.FLAG_IS_SUPER_USER}: {self.is_super_user}
|
||||||
|
, {self.FLAG_PRIORITY_ACCESS_LEVEL}: {self.priority_access_level}
|
||||||
|
) '''
|
||||||
|
|
||||||
|
def get_is_logged_in(self):
|
||||||
|
return (self.user_id is not None and self.user_id > 0 and self.user_id != Base.USER_ID_GUEST)
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return f'{"" if self.firstname is None else self.firstname} {"" if self.surname is None else self.surname}'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Parameters_User(Get_Many_Parameters_Base):
|
||||||
|
# user_id: Optional[int]
|
||||||
|
# auth0_user_id: str
|
||||||
|
get_all_user: bool
|
||||||
|
get_inactive_user: bool
|
||||||
|
user_ids: str
|
||||||
|
"""
|
||||||
|
user_auth0_ids: str
|
||||||
|
names_user: str
|
||||||
|
emails_user: str
|
||||||
|
"""
|
||||||
|
require_all_id_filters_met: bool
|
||||||
|
require_any_id_filters_met: bool
|
||||||
|
# require_all_non_id_filters_met: bool
|
||||||
|
# require_any_non_id_filters_met: bool
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_form_filters_user(cls, form):
|
||||||
|
_m = f'{cls.__qualname__}.from_form_filters_user'
|
||||||
|
av.val_instance(form, 'form', _m, Filters_User)
|
||||||
|
get_inactive = not av.input_bool(form.active_only.data, "active", _m)
|
||||||
|
# user_id = '' if form.user_id.data is None else form.user_id.data
|
||||||
|
filters = cls.get_default()
|
||||||
|
filters.get_all_user = True # (user_id == '')
|
||||||
|
filters.get_inactive_user = get_inactive
|
||||||
|
filters.user_ids = '' # user_id
|
||||||
|
# filters.user_auth0_ids = ''
|
||||||
|
filters.require_all_id_filters_met = True
|
||||||
|
filters.require_any_id_filters_met = True
|
||||||
|
# filters.require_all_non_id_filters_met = False
|
||||||
|
# filters.require_any_non_id_filters_met = True
|
||||||
|
return filters
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_user(cls, user):
|
||||||
|
av.val_instance(user, 'user', 'Parameters_User.from_user', User)
|
||||||
|
filters = cls.get_default()
|
||||||
|
filters.get_all_user = ((user.user_id is None or user.user_id == 0) and user.user_auth0_id is None)
|
||||||
|
filters.get_inactive_user = False
|
||||||
|
filters.user_ids = '' if user.user_id is None else str(user.user_id)
|
||||||
|
# filters.user_auth0_ids = user.user_auth0_id
|
||||||
|
# filters.names_user = user.get_name()
|
||||||
|
# filters.emails_user = user.email
|
||||||
|
return filters
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default(cls):
|
||||||
|
return cls(
|
||||||
|
# user_id = None
|
||||||
|
# , auth0_user_id = ''
|
||||||
|
get_all_user = False
|
||||||
|
, get_inactive_user = False
|
||||||
|
, user_ids = ''
|
||||||
|
# , user_auth0_ids = ''
|
||||||
|
# , names_user = ''
|
||||||
|
# , emails_user = ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
# , require_all_non_id_filters_met = False
|
||||||
|
# , require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(self):
|
||||||
|
pass
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
# 'a_user_id': self.user_id
|
||||||
|
# , 'a_auth0_user_id': self.auth0_user_id
|
||||||
|
'a_get_all_user': self.get_all_user
|
||||||
|
, 'a_get_inactive_user': self.get_inactive_user
|
||||||
|
, 'a_user_ids': self.user_ids
|
||||||
|
# , 'a_user_auth0_ids': self.user_auth0_ids
|
||||||
|
# , 'a_names_user': self.names_user
|
||||||
|
# , 'a_emails_user': self.emails_user
|
||||||
|
, 'a_require_all_id_filters_met': self.require_all_id_filters_met
|
||||||
|
, 'a_require_any_id_filters_met': self.require_any_id_filters_met
|
||||||
|
# , 'a_require_all_non_id_filters_met': self.require_all_non_id_filters_met
|
||||||
|
# , 'a_require_any_non_id_filters_met': self.require_any_non_id_filters_met
|
||||||
|
}
|
||||||
|
@staticmethod
|
||||||
|
def get_type_hints():
|
||||||
|
return {
|
||||||
|
'a_get_all_user': Boolean
|
||||||
|
, 'a_get_inactive_user': Boolean
|
||||||
|
, 'a_user_ids': Text
|
||||||
|
, 'a_require_all_id_filters_met': Boolean
|
||||||
|
, 'a_require_any_id_filters_met': Boolean
|
||||||
|
}
|
||||||
132
config.py
Normal file
132
config.py
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Backend
|
||||||
|
Feature: Configuration
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Configuration variables
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv, find_dotenv
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
load_dotenv(find_dotenv())
|
||||||
|
|
||||||
|
# CLASSES
|
||||||
|
class Config:
|
||||||
|
is_development = False
|
||||||
|
is_production = False
|
||||||
|
# Miscellaneous
|
||||||
|
DEBUG = False # av.input_bool(os.getenv('DEBUG'), 'DEBUG', 'Config')
|
||||||
|
TESTING = False
|
||||||
|
URL_HOST = os.getenv('URL_HOST')
|
||||||
|
SECRET_KEY = os.getenv('KEY_SECRET_FLASK') # gen cmd: openssl rand -hex 32
|
||||||
|
# Add other configuration variables as needed
|
||||||
|
# MySQL
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
||||||
|
'pool_size': 10,
|
||||||
|
'pool_recycle': 280,
|
||||||
|
'pool_pre_ping': True,
|
||||||
|
'pool_timeout': 30,
|
||||||
|
}
|
||||||
|
# Auth0
|
||||||
|
SESSION_COOKIE_SECURE = True # depends on is_producction
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
SESSION_COOKIE_SAMESITE = 'None' # depends on is_producction
|
||||||
|
REMEMBER_COOKIE_SECURE = True
|
||||||
|
WTF_CSRF_ENABLED = True
|
||||||
|
# WTF_CSRF_CHECK_DEFAULT = False # We'll check it manually for API routes
|
||||||
|
# WTF_CSRF_HEADERS = ['X-CSRFToken'] # Accept CSRF token from this header
|
||||||
|
WTF_CSRF_TIME_LIMIT = None
|
||||||
|
WTF_CSRF_SSL_STRICT = False # Allows testing without HTTPS
|
||||||
|
ID_AUTH0_CLIENT = os.getenv('ID_AUTH0_CLIENT')
|
||||||
|
ID_AUTH0_CLIENT_SECRET = os.getenv('ID_AUTH0_CLIENT_SECRET')
|
||||||
|
DOMAIN_AUTH0 = os.getenv('DOMAIN_AUTH0')
|
||||||
|
ID_TOKEN_USER = 'user'
|
||||||
|
# PostgreSQL
|
||||||
|
DB_NAME = os.getenv('DB_NAME')
|
||||||
|
DB_USER = os.getenv('DB_USER')
|
||||||
|
DB_PASSWORD = os.getenv('DB_PASSWORD')
|
||||||
|
DB_HOST = os.getenv('DB_HOST')
|
||||||
|
# DB_PORT = os.getenv('DB_PORT')
|
||||||
|
# Store
|
||||||
|
# is_included_VAT = True
|
||||||
|
"""
|
||||||
|
KEY_IS_INCLUDED_VAT = 'is_included_VAT'
|
||||||
|
code_currency = 1
|
||||||
|
KEY_CODE_CURRENCY = 'id_currency'
|
||||||
|
code_region_delivery = 1
|
||||||
|
KEY_CODE_REGION_DELIVERY = 'id_region_delivery'
|
||||||
|
KEY_ID_CURRENCY = 'id_currency'
|
||||||
|
KEY_ID_REGION_DELIVERY = 'id_region_delivery'
|
||||||
|
"""
|
||||||
|
# id_currency = 1
|
||||||
|
# id_region_delivery = 1
|
||||||
|
# Mail
|
||||||
|
MAIL_DEBUG = False # av.input_bool(os.getenv('DEBUG'), 'DEBUG', 'Config')
|
||||||
|
MAIL_SERVER = 'mail.partsltd.co.uk' # 'smtp.gmail.com'
|
||||||
|
MAIL_PORT = 465 # 587
|
||||||
|
MAIL_USE_TLS = False
|
||||||
|
MAIL_USE_SSL = True
|
||||||
|
MAIL_USERNAME = os.getenv('MAIL_DEFAULT_SENDER')
|
||||||
|
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
||||||
|
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
||||||
|
MAIL_CONTACT_PUBLIC = os.getenv('MAIL_CONTACT_PUBLIC')
|
||||||
|
"""
|
||||||
|
# Recaptcha
|
||||||
|
RECAPTCHA_PUBLIC_KEY = os.getenv('RECAPTCHA_PUBLIC_KEY')
|
||||||
|
RECAPTCHA_PRIVATE_KEY = os.getenv('RECAPTCHA_PRIVATE_KEY')
|
||||||
|
"""
|
||||||
|
# ALTCHA
|
||||||
|
ALTCHA_API_KEY = os.getenv('ALTCHA_API_KEY')
|
||||||
|
ALTCHA_SECRET_KEY = os.getenv('ALTCHA_SECRET_KEY')
|
||||||
|
ALTCHA_REGION = 'eu'
|
||||||
|
|
||||||
|
class DevelopmentConfig(Config):
|
||||||
|
is_development = True
|
||||||
|
# Add development-specific configuration variables
|
||||||
|
DEBUG = True
|
||||||
|
MAIL_DEBUG = True
|
||||||
|
SESSION_COOKIE_SECURE = True # False
|
||||||
|
SESSION_COOKIE_SAMESITE = 'None' # 'Lax' # depends on is_producction
|
||||||
|
|
||||||
|
class ProductionConfig(Config):
|
||||||
|
is_production = True
|
||||||
|
# Add production-specific configuration variables
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Set the configuration class based on the environment
|
||||||
|
# You can change 'development' to 'production' when deploying
|
||||||
|
config_env = os.getenv('FLASK_ENV', "development")
|
||||||
|
with open('app.log', 'a') as f:
|
||||||
|
print(f'config_env: {config_env}')
|
||||||
|
f.write(f'config_env: {config_env}\n')
|
||||||
|
# current_app.logger.error(f'config_env: {config_env}') # logger not yet initialised
|
||||||
|
if config_env == 'development':
|
||||||
|
app_config = DevelopmentConfig
|
||||||
|
elif config_env == 'production':
|
||||||
|
app_config = ProductionConfig
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid configuration environment")
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
"""
|
||||||
|
SET KEY_SECRET_FLASK=nips
|
||||||
|
SET ID_AUTH0_CLIENT=
|
||||||
|
SET ID_AUTH0_CLIENT_SECRET=
|
||||||
|
SET DOMAIN_AUTH0=
|
||||||
|
SET MAIL_PASSWORD=
|
||||||
|
SET RECAPTCHA_PUBLIC_KEY=
|
||||||
|
SET RECAPTCHA_PRIVATE_KEY=
|
||||||
|
SET SQLALCHEMY_DATABASE_URI=
|
||||||
|
SET URL_HOST=
|
||||||
|
"""
|
||||||
|
# SET SQLALCHEMY_DATABASE_URI = mysql://username:password@localhost/dbname
|
||||||
|
# Replace 'username', 'password', 'localhost', and 'dbname' with your actual database credentials
|
||||||
0
controllers/__init__.py
Normal file
0
controllers/__init__.py
Normal file
0
controllers/core/__init__.py
Normal file
0
controllers/core/__init__.py
Normal file
0
controllers/legal/__init__.py
Normal file
0
controllers/legal/__init__.py
Normal file
78
controllers/legal/legal.py
Normal file
78
controllers/legal/legal.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: App Routing
|
||||||
|
Feature: Legal Routes
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Legal Section Controller.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
# from models.model_view_home import Model_View_Home
|
||||||
|
from models.model_view_license import Model_View_License
|
||||||
|
from models.model_view_privacy_policy import Model_View_Privacy_Policy
|
||||||
|
from models.model_view_accessibility_report import Model_View_Accessibility_Report
|
||||||
|
from models.model_view_accessibility_statement import Model_View_Accessibility_Statement
|
||||||
|
from models.model_view_retention_schedule import Model_View_Retention_Schedule
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from flask import render_template, Blueprint, send_from_directory
|
||||||
|
|
||||||
|
|
||||||
|
routes_legal = Blueprint('routes_legal', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
# snore
|
||||||
|
@routes_legal.route('/license', methods=['GET'])
|
||||||
|
def license():
|
||||||
|
try:
|
||||||
|
model = Model_View_License()
|
||||||
|
html_body = render_template('pages/legal/_license.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
@routes_legal.route('/accessibility-statement', methods=['GET'])
|
||||||
|
def accessibility_statement():
|
||||||
|
try:
|
||||||
|
model = Model_View_Accessibility_Statement()
|
||||||
|
html_body = render_template('pages/legal/_accessibility_statement.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
@routes_legal.route('/accessibility-report', methods=['GET'])
|
||||||
|
def accessibility_report():
|
||||||
|
try:
|
||||||
|
model = Model_View_Accessibility_Report()
|
||||||
|
html_body = render_template('pages/legal/_accessibility_report.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
@routes_legal.route('/retention-schedule', methods=['GET'])
|
||||||
|
def retention_schedule():
|
||||||
|
try:
|
||||||
|
model = Model_View_Retention_Schedule()
|
||||||
|
html_body = render_template('pages/legal/_retention_schedule.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
@routes_legal.route('/privacy-policy', methods=['GET'])
|
||||||
|
def privacy_policy():
|
||||||
|
try:
|
||||||
|
model = Model_View_Privacy_Policy()
|
||||||
|
html_body = render_template('pages/legal/_privacy_policy.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
@routes_legal.route('/robots.txt', methods=['GET'])
|
||||||
|
def robots_txt():
|
||||||
|
return send_from_directory('static', 'docs/robots.txt')
|
||||||
|
@routes_legal.route('/favicon.ico', methods=['GET'])
|
||||||
|
def favicon_ico():
|
||||||
|
return send_from_directory('static', 'images/logo.ico', mimetype='image/vnd.microsoft.icon') # -and-company-name-curved-0.5
|
||||||
|
@routes_legal.route('/sitemap.xml', methods=['GET'])
|
||||||
|
def sitemap_xml():
|
||||||
|
return send_from_directory('static', 'docs/sitemap.xml')
|
||||||
0
controllers/tcg/__init__.py
Normal file
0
controllers/tcg/__init__.py
Normal file
378
controllers/tcg/mtg_game.py
Normal file
378
controllers/tcg/mtg_game.py
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: App Routing
|
||||||
|
Feature: TCG - MTG Game Routes
|
||||||
|
|
||||||
|
Description:
|
||||||
|
MTG Game Page Controller.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
from business_objects.api import API
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game
|
||||||
|
from business_objects.tcg.mtg_game_player import MTG_Game_Player, Parameters_MTG_Game_Player
|
||||||
|
from business_objects.tcg.mtg_game_round import MTG_Game_Round, Parameters_MTG_Game_Round
|
||||||
|
from business_objects.tcg.mtg_game_round_player_damage import MTG_Game_Round_Player_Damage, Parameters_MTG_Game_Round_Player_Damage
|
||||||
|
from business_objects.tcg.mtg_deck import MTG_Deck, Parameters_MTG_Deck
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_mtg import DataStore_MTG
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from forms.tcg.game import Filters_MTG_Game
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
from models.model_view_mtg_base import Model_View_MTG_Base
|
||||||
|
from models.model_view_mtg_game import Model_View_MTG_Game
|
||||||
|
from models.model_view_mtg_games import Model_View_MTG_Games
|
||||||
|
from models.model_view_mtg_home import Model_View_MTG_Home
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app, flash, Response
|
||||||
|
from flask_mail import Mail, Message
|
||||||
|
from extensions import db, oauth, mail
|
||||||
|
from urllib.parse import quote_plus, urlencode
|
||||||
|
from authlib.integrations.flask_client import OAuth
|
||||||
|
from authlib.integrations.base_client import OAuthError
|
||||||
|
from urllib.parse import quote, urlparse, parse_qs
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
routes_mtg_game = Blueprint('routes_mtg_game', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_PAGE_MTG_GAMES, methods=['GET'])
|
||||||
|
def games():
|
||||||
|
Helper_App.console_log('mtg games')
|
||||||
|
Helper_App.console_log(f'request_args: {request.args}')
|
||||||
|
try:
|
||||||
|
form_filters = Filters_MTG_Game.from_json(request.args)
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {e}')
|
||||||
|
form_filters = Filters_MTG_Game()
|
||||||
|
Helper_App.console_log(f'form_filters={form_filters}')
|
||||||
|
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
|
||||||
|
parameters_game = form_filters.to_parameters(user_id_session = user_session.user_id)
|
||||||
|
|
||||||
|
model = Model_View_MTG_Games(parameters_game = parameters_game)
|
||||||
|
model.form_filters = form_filters
|
||||||
|
Helper_App.console_log(f'form_filters={form_filters}')
|
||||||
|
return render_template('pages/tcg/mtg/_games.html', model=model)
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(f'{Model_View_MTG_Base.HASH_PAGE_MTG_GAME}/<int:game_id>', methods=['GET'])
|
||||||
|
def game_detail(game_id):
|
||||||
|
Helper_App.console_log(f'mtg game detail: {game_id}')
|
||||||
|
model = Model_View_MTG_Game(game_id=game_id)
|
||||||
|
if not model.is_user_logged_in:
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
if model.game is None:
|
||||||
|
flash('Game not found', 'error')
|
||||||
|
return redirect(url_for('routes_mtg_game.games'))
|
||||||
|
return render_template('pages/tcg/mtg/_game.html', model=model)
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_SAVE_MTG_GAME, methods=['POST'])
|
||||||
|
def save_game():
|
||||||
|
_m = 'routes_mtg_game.save_game'
|
||||||
|
data = Helper_App.get_request_data(request)
|
||||||
|
Helper_App.console_log(f'{_m}\n{data}')
|
||||||
|
try:
|
||||||
|
"""
|
||||||
|
form_filters = Filters_MTG_Game.from_json(data.get(Model_View_MTG_Base.FLAG_FORM_FILTERS, {}))
|
||||||
|
if not form_filters.validate_on_submit():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||||
|
})
|
||||||
|
form_filters = Filters_MTG_Game.get_default()
|
||||||
|
"""
|
||||||
|
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
raise Exception('User not logged in')
|
||||||
|
|
||||||
|
games = data.get(Model_View_MTG_Base.FLAG_GAME, [])
|
||||||
|
if len(games) == 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'No games to save.'
|
||||||
|
})
|
||||||
|
Helper_App.console_log(f"Games to save: {games}")
|
||||||
|
|
||||||
|
obj_game = MTG_Game.from_json(games[0])
|
||||||
|
Helper_App.console_log(f'obj_game={obj_game}')
|
||||||
|
|
||||||
|
game_id, errors = DataStore_MTG.save_mtg_game(obj_game)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error saving games.\n{Model_View_MTG_Game.convert_list_objects_to_json(errors)}'
|
||||||
|
})
|
||||||
|
"""
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: Model_View_MTG_Base.convert_list_objects_to_json(model_return.games)
|
||||||
|
})
|
||||||
|
"""
|
||||||
|
return redirect(url_for('routes_mtg_game.game_detail', game_id = game_id))
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_PAGE_MTG_HOME, methods=['GET'])
|
||||||
|
def home():
|
||||||
|
model = Model_View_MTG_Home()
|
||||||
|
if model.user.get_is_logged_in():
|
||||||
|
return redirect(url_for('routes_mtg_game.games'))
|
||||||
|
return render_template('pages/tcg/mtg/_home.html', model=model)
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_PAGE_MTG_TRIAL_GAME, methods=['GET'])
|
||||||
|
def trial_game():
|
||||||
|
return send_from_directory('templates/pages/tcg/mtg', 'trial_game.html')
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route('/mtg/api/game/<int:game_id>/players', methods=['GET'])
|
||||||
|
def get_game_players(game_id):
|
||||||
|
"""Get players for a game with enriched user and deck information."""
|
||||||
|
_m = 'routes_mtg_game.get_game_players'
|
||||||
|
Helper_App.console_log(f'{_m}: game_id={game_id}')
|
||||||
|
try:
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
datastore_user = DataStore_User()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'User not logged in'
|
||||||
|
}), 401
|
||||||
|
|
||||||
|
# Get players for this game
|
||||||
|
parameters_player = Parameters_MTG_Game_Player.get_default(user_session.user_id)
|
||||||
|
parameters_player.game_ids = str(game_id)
|
||||||
|
parameters_player.get_all_game = False
|
||||||
|
players, errors = datastore.get_many_mtg_game_player(parameters_player)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error fetching players: {errors}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
players_json = [p.to_json() for p in players]
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: players_json
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'{_m} Error: {str(e)}')
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route('/mtg/api/game/<int:game_id>/rounds', methods=['GET'])
|
||||||
|
def get_many_game_round(game_id):
|
||||||
|
"""Get rounds for a game."""
|
||||||
|
_m = 'routes_mtg_game.get_many_game_round'
|
||||||
|
Helper_App.console_log(f'{_m}: game_id={game_id}')
|
||||||
|
try:
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'User not logged in'
|
||||||
|
}), 401
|
||||||
|
|
||||||
|
# Get rounds for this game
|
||||||
|
parameters_round = Parameters_MTG_Game_Round.get_default(user_session.user_id)
|
||||||
|
parameters_round.game_ids = str(game_id)
|
||||||
|
parameters_round.get_all_game = False
|
||||||
|
rounds, errors = datastore.get_many_mtg_game_round(parameters_round)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error fetching rounds: {errors}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
rounds_json = [r.to_json() for r in rounds]
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: rounds_json
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'{_m} Error: {str(e)}')
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route('/mtg/api/game/<int:game_id>/damage-records', methods=['GET'])
|
||||||
|
def get_many_game_player_damage(game_id):
|
||||||
|
"""Get damage records for a game."""
|
||||||
|
_m = 'routes_mtg_game.get_many_game_player_damage'
|
||||||
|
Helper_App.console_log(f'{_m}: game_id={game_id}')
|
||||||
|
try:
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'User not logged in'
|
||||||
|
}), 401
|
||||||
|
|
||||||
|
parameters_damage = Parameters_MTG_Game_Round_Player_Damage.get_default(user_session.user_id)
|
||||||
|
parameters_damage.game_ids = str(game_id)
|
||||||
|
parameters_damage.get_all_game = False
|
||||||
|
damages, errors = datastore.get_many_mtg_game_round_player_damage(parameters_damage)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error fetching damage records: {errors}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
damage_records = [d.to_json() for d in damages]
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: damage_records
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'{_m} Error: {str(e)}')
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_SAVE_MTG_GAME_PLAYER, methods=['POST'])
|
||||||
|
def save_game_player():
|
||||||
|
_m = 'routes_mtg_game.save_game_player'
|
||||||
|
data = Helper_App.get_request_data(request)
|
||||||
|
Helper_App.console_log(f'{_m}\n{data}')
|
||||||
|
try:
|
||||||
|
"""
|
||||||
|
form_filters = Filters_MTG_Game.from_json(data.get(Model_View_MTG_Base.FLAG_FORM_FILTERS, {}))
|
||||||
|
if not form_filters.validate_on_submit():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||||
|
})
|
||||||
|
form_filters = Filters_MTG_Game.get_default()
|
||||||
|
"""
|
||||||
|
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
raise Exception('User not logged in')
|
||||||
|
|
||||||
|
players = data.get(Model_View_MTG_Base.FLAG_PLAYER, [])
|
||||||
|
if len(players) == 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'No players to save.'
|
||||||
|
})
|
||||||
|
|
||||||
|
objs_player = []
|
||||||
|
for player in players:
|
||||||
|
obj_player = MTG_Game_Player.from_json(player)
|
||||||
|
Helper_App.console_log(f'obj_player = {obj_player}')
|
||||||
|
objs_player.append(obj_player)
|
||||||
|
success, errors = DataStore_MTG.save_mtg_game_player(objs_player)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error saving players.\n{Model_View_MTG_Game.convert_list_objects_to_json(errors)}'
|
||||||
|
})
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS if success else Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: None
|
||||||
|
})
|
||||||
|
# return redirect(url_for('routes_mtg_game.game_detail', game_id = game_id))
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||||
|
})
|
||||||
|
|
||||||
|
@routes_mtg_game.route(Model_View_MTG_Base.HASH_SAVE_MTG_GAME_ROUND_PLAYER_DAMAGE, methods=['POST'])
|
||||||
|
def save_game_round_player_damage():
|
||||||
|
_m = 'routes_mtg_game.save_game_round_player_damage'
|
||||||
|
data = Helper_App.get_request_data(request)
|
||||||
|
Helper_App.console_log(f'{_m}\n{data}')
|
||||||
|
try:
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
raise Exception('User not logged in')
|
||||||
|
|
||||||
|
rounds = data.get(Model_View_MTG_Base.FLAG_ROUND, [])
|
||||||
|
if len(rounds) == 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'No rounds to save.'
|
||||||
|
})
|
||||||
|
|
||||||
|
objs_round = []
|
||||||
|
for round in rounds:
|
||||||
|
obj_round = MTG_Game_Round.from_json(round)
|
||||||
|
Helper_App.console_log(f'obj_round = {obj_round}')
|
||||||
|
objs_round.append(obj_round)
|
||||||
|
|
||||||
|
damages = data.get(Model_View_MTG_Base.FLAG_DAMAGE, [])
|
||||||
|
if len(damages) == 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: 'No damages to save.'
|
||||||
|
})
|
||||||
|
|
||||||
|
objs_damage = []
|
||||||
|
for damage in damages:
|
||||||
|
obj_damage = MTG_Game_Round_Player_Damage.from_json(damage)
|
||||||
|
Helper_App.console_log(f'obj_damage = {obj_damage}')
|
||||||
|
objs_damage.append(obj_damage)
|
||||||
|
|
||||||
|
success, errors = DataStore_MTG.save_mtg_game_round_player_damage(objs_round, objs_damage)
|
||||||
|
|
||||||
|
if len(errors) > 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Error saving round player damages.\n{Model_View_MTG_Game.convert_list_objects_to_json(errors)}'
|
||||||
|
})
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS if success else Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_DATA: None
|
||||||
|
})
|
||||||
|
# return redirect(url_for('routes_mtg_game.game_detail', game_id = game_id))
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE,
|
||||||
|
Model_View_MTG_Base.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||||
|
})
|
||||||
255
controllers/user/user.py
Normal file
255
controllers/user/user.py
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: App Routing
|
||||||
|
Feature: User Routes
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
from models.model_view_user import Model_View_User
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from mtg_commander_life_tracker.forms.tcg.user import Filters_User
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from sqlalchemy import exc
|
||||||
|
from flask_wtf.csrf import generate_csrf
|
||||||
|
from werkzeug.exceptions import BadRequest
|
||||||
|
from extensions import oauth # db,
|
||||||
|
from urllib.parse import quote_plus, urlencode
|
||||||
|
from authlib.integrations.flask_client import OAuth
|
||||||
|
from authlib.integrations.base_client import OAuthError
|
||||||
|
from urllib.parse import quote, urlparse, parse_qs
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
routes_user = Blueprint('routes_user', __name__)
|
||||||
|
|
||||||
|
def handle_db_disconnect(f):
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except exc.OperationalError as e:
|
||||||
|
if "MySQL server has gone away" in str(e):
|
||||||
|
# Close the session and create a new connection
|
||||||
|
db.session.remove()
|
||||||
|
db.session.rollback()
|
||||||
|
# Retry the operation
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
raise
|
||||||
|
return decorated_function
|
||||||
|
|
||||||
|
# User authentication
|
||||||
|
@routes_user.route("/login", methods=['POST', 'OPTIONS']) # required endpoint for Auth0
|
||||||
|
def login():
|
||||||
|
oauth = current_app.extensions['authlib.integrations.flask_client']
|
||||||
|
try:
|
||||||
|
# Helper_App.console_log('login')
|
||||||
|
# Helper_App.console_log(f'method={request.method}')
|
||||||
|
try:
|
||||||
|
data = request.json
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
except:
|
||||||
|
data = {}
|
||||||
|
except:
|
||||||
|
data = {}
|
||||||
|
# Helper_App.console_log(f'data={data}')
|
||||||
|
hash_callback = data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_MTG_HOME)
|
||||||
|
# Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||||
|
|
||||||
|
uri_redirect = url_for('routes_user.login_callback', _external=True)
|
||||||
|
# Helper_App.console_log(f'redirect uri: {uri_redirect}')
|
||||||
|
|
||||||
|
# Helper_App.console_log(f'Before red')
|
||||||
|
# Helper_App.console_log(f"Registered clients: {list(oauth._clients.keys())}")
|
||||||
|
try:
|
||||||
|
with current_app.app_context():
|
||||||
|
red = oauth.auth0.authorize_redirect(
|
||||||
|
redirect_uri = uri_redirect
|
||||||
|
, state = quote(hash_callback)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f"Error: {str(e)}")
|
||||||
|
# Helper_App.console_log(f'redirect: {red}')
|
||||||
|
headers = red.headers['Location']
|
||||||
|
# Helper_App.console_log(f'headers: {headers}')
|
||||||
|
parsed_url = urlparse(headers)
|
||||||
|
query_params = parse_qs(parsed_url.query)
|
||||||
|
Helper_App.console_log(f"""
|
||||||
|
OAuth Authorize Redirect URL:
|
||||||
|
|
||||||
|
Base URL: {parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}
|
||||||
|
{parsed_url}
|
||||||
|
|
||||||
|
Query Parameters: {query_params}
|
||||||
|
""")
|
||||||
|
return jsonify({'Success': True, Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS, f'{Model_View_Base.FLAG_CALLBACK}': headers})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'status': 'error', 'message': str(e)}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@routes_user.route("/login_callback")
|
||||||
|
@handle_db_disconnect
|
||||||
|
def login_callback():
|
||||||
|
oauth = current_app.extensions['authlib.integrations.flask_client']
|
||||||
|
# Helper_App.console_log('login_callback')
|
||||||
|
try:
|
||||||
|
# Helper_App.console_log(f'Redceived state: {request.args.get("state")}')
|
||||||
|
token = None
|
||||||
|
try:
|
||||||
|
token = oauth.auth0.authorize_access_token()
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f"Error: {str(e)}")
|
||||||
|
session[current_app.config['ID_TOKEN_USER']] = token
|
||||||
|
|
||||||
|
try:
|
||||||
|
hash_callback = token.get('hash_callback')
|
||||||
|
if hash_callback is None:
|
||||||
|
Helper_App.console_log('hash is none')
|
||||||
|
state = request.args.get('state')
|
||||||
|
Helper_App.console_log(f'state: {state}')
|
||||||
|
hash_callback = state
|
||||||
|
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||||
|
except:
|
||||||
|
Helper_App.console_log("get hash callback failed")
|
||||||
|
|
||||||
|
error_state = request.args.get(Model_View_User.FLAG_ERROR_OAUTH)
|
||||||
|
has_error = error_state is not None
|
||||||
|
if has_error:
|
||||||
|
error_description = request.args.get(Model_View_User.FLAG_ERROR_DESCRIPTION_OAUTH)
|
||||||
|
error_text = f'Error: {error_state}: {error_description}'
|
||||||
|
Helper_App.console_log(error_text)
|
||||||
|
return redirect(f"{current_app.config['URL_HOST']}{hash_callback}") # login()
|
||||||
|
|
||||||
|
user = User.from_json_auth0(token)
|
||||||
|
Helper_App.console_log(f'user: {user}')
|
||||||
|
"""
|
||||||
|
session[Model_View_Base.FLAG_USER] = user.to_json()
|
||||||
|
Helper_App.console_log(f'user stored on session')
|
||||||
|
"""
|
||||||
|
|
||||||
|
datastore_user = DataStore_User()
|
||||||
|
try:
|
||||||
|
saved_user, errors = datastore_user.login_user(user)
|
||||||
|
if (len(errors) > 0): raise ValueError(f'Database errors: {errors}')
|
||||||
|
Helper_App.console_log('User logged in')
|
||||||
|
Helper_App.console_log(f'user ({str(type(saved_user))}): {saved_user}')
|
||||||
|
Helper_App.console_log(f'user key: {Model_View_Base.FLAG_USER}')
|
||||||
|
saved_user_json = saved_user.to_json()
|
||||||
|
Helper_App.console_log(f'User JSON: {saved_user_json}')
|
||||||
|
session[Model_View_Base.FLAG_USER] = saved_user_json
|
||||||
|
Helper_App.console_log(f'user stored on session')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'User not found: {saved_user}\nDatabase query error: {errors}')
|
||||||
|
|
||||||
|
|
||||||
|
Helper_App.console_log(f'user session: {session.get(Model_View_Base.FLAG_USER, "(Key not found)")}')
|
||||||
|
return redirect(f"{current_app.config['URL_HOST']}{hash_callback}")
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Controller error.\n{e}'})
|
||||||
|
|
||||||
|
@routes_user.route("/logout")
|
||||||
|
def logout():
|
||||||
|
session.clear()
|
||||||
|
url_logout = f"https://{current_app.config['DOMAIN_AUTH0']}/v2/logout?" + urlencode(
|
||||||
|
{
|
||||||
|
"returnTo": url_for("routes_user.logout_callback", _external=True),
|
||||||
|
"client_id": current_app.config['ID_AUTH0_CLIENT'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Helper_App.console_log(f"Redirecting to {url_logout}")
|
||||||
|
return redirect(url_logout)
|
||||||
|
|
||||||
|
@routes_user.route("/logout_callback")
|
||||||
|
@handle_db_disconnect
|
||||||
|
def logout_callback():
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
|
||||||
|
@routes_user.route(Model_View_User.HASH_PAGE_USER_ACCOUNT)
|
||||||
|
def user():
|
||||||
|
try:
|
||||||
|
user_session = Model_View_User.get_user_session()
|
||||||
|
if not user_session.get_is_logged_in():
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
form_filters = Filters_User.get_default()
|
||||||
|
model = Model_View_User(form_filters_old = form_filters)
|
||||||
|
model._title = model.user.firstname
|
||||||
|
# model.users = [model.user]
|
||||||
|
html_body = render_template('pages/user/_user.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
|
||||||
|
@routes_user.route(Model_View_User.HASH_PAGE_USER_ACCOUNTS)
|
||||||
|
def users():
|
||||||
|
try:
|
||||||
|
Helper_App.console_log(f'request_args: {request.args}')
|
||||||
|
user_session = Model_View_User.get_user_session()
|
||||||
|
if (not user_session.get_is_logged_in()) or (not user_session.can_admin_user):
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
try:
|
||||||
|
form_filters = Filters_User.from_json(request.args)
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {e}')
|
||||||
|
form_filters = Filters_User.get_default()
|
||||||
|
model = Model_View_User(form_filters, hash_page_current = Model_View_User.HASH_PAGE_USER_ACCOUNTS)
|
||||||
|
html_body = render_template('pages/user/_users.html', model = model)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return html_body
|
||||||
|
|
||||||
|
|
||||||
|
@routes_user.route(Model_View_User.HASH_SAVE_USER_USER, methods=['POST'])
|
||||||
|
def save_user():
|
||||||
|
data = Helper_App.get_request_data(request)
|
||||||
|
try:
|
||||||
|
form_filters = Filters_User.from_json(data[Model_View_User.FLAG_FORM_FILTERS])
|
||||||
|
if not form_filters.validate_on_submit():
|
||||||
|
return jsonify({
|
||||||
|
Model_View_User.FLAG_STATUS: Model_View_User.FLAG_FAILURE,
|
||||||
|
Model_View_User.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||||
|
})
|
||||||
|
model_return = Model_View_User(form_filters_old=form_filters)
|
||||||
|
if not model_return.is_user_logged_in:
|
||||||
|
return redirect(url_for('routes_mtg_game.home'))
|
||||||
|
|
||||||
|
users = data[Model_View_User.FLAG_USER]
|
||||||
|
if len(users) == 0:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_User.FLAG_STATUS: Model_View_User.FLAG_FAILURE,
|
||||||
|
Model_View_User.FLAG_MESSAGE: f'No users.'
|
||||||
|
})
|
||||||
|
objs_user = []
|
||||||
|
for user in users:
|
||||||
|
objs_user.append(User.from_json(user))
|
||||||
|
Helper_App.console_log(f'objs_user={objs_user}')
|
||||||
|
errors = DataStore_User.save_users(data.get('comment', 'No comment'), objs_user)
|
||||||
|
|
||||||
|
if (len(errors) > 0):
|
||||||
|
return jsonify({
|
||||||
|
Model_View_User.FLAG_STATUS: Model_View_User.FLAG_FAILURE,
|
||||||
|
Model_View_User.FLAG_MESSAGE: f'Error saving users.\n{model_return.convert_list_objects_to_json(errors)}'
|
||||||
|
})
|
||||||
|
return jsonify({
|
||||||
|
Model_View_User.FLAG_STATUS: Model_View_User.FLAG_SUCCESS,
|
||||||
|
Model_View_User.FLAG_DATA: Model_View_User.convert_list_objects_to_json(model_return.users)
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({
|
||||||
|
Model_View_User.FLAG_STATUS: Model_View_User.FLAG_FAILURE,
|
||||||
|
Model_View_User.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||||
|
})
|
||||||
11
datastores/__init__.py
Normal file
11
datastores/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Module Initialisation
|
||||||
|
Feature: DataStores
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises datastores module.
|
||||||
|
"""
|
||||||
225
datastores/datastore_base.py
Normal file
225
datastores/datastore_base.py
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: DataStores
|
||||||
|
Feature: Base DataStore
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Datastore for Store
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
# from routes import bp_home
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from business_objects.sql_error import SQL_Error, Parameters_SQL_Error
|
||||||
|
from business_objects.tcg.user import User
|
||||||
|
# from helpers.helper_db_sql import Helper_DB_SQL
|
||||||
|
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||||
|
from extensions import db
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# external
|
||||||
|
from sqlalchemy import text
|
||||||
|
from flask import Flask, session, current_app
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
import time
|
||||||
|
from sqlalchemy.exc import OperationalError
|
||||||
|
from typing import ClassVar
|
||||||
|
import uuid as uuid_lib
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DataStore_Base(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def db_procedure_execute(proc_name, argument_dict_list = None, argument_types_dict = None):
|
||||||
|
"""Execute a PostgreSQL procedure using autocommit to allow internal COMMIT/ROLLBACK"""
|
||||||
|
_m = 'DataStore_Base.db_procedure_execute'
|
||||||
|
av.val_str(proc_name, 'proc_name', _m)
|
||||||
|
proc_string = f'CALL {proc_name}('
|
||||||
|
has_arguments = argument_dict_list is not None
|
||||||
|
if has_arguments:
|
||||||
|
arg_keys = list(argument_dict_list.keys())
|
||||||
|
for i in range(len(arg_keys)):
|
||||||
|
param_name = arg_keys[i]
|
||||||
|
# Add explicit PostgreSQL CAST for typed parameters
|
||||||
|
if argument_types_dict and param_name in argument_types_dict:
|
||||||
|
type_name = argument_types_dict[param_name].__name__
|
||||||
|
pg_type = DataStore_Base.TYPE_CAST_MAP.get(type_name)
|
||||||
|
if pg_type:
|
||||||
|
param_expr = f'CAST(:{param_name} AS {pg_type})'
|
||||||
|
else:
|
||||||
|
param_expr = f':{param_name}'
|
||||||
|
else:
|
||||||
|
param_expr = f':{param_name}'
|
||||||
|
proc_string += f'{"" if i == 0 else ", "}{param_name} := {param_expr}'
|
||||||
|
proc_string += ')'
|
||||||
|
stmt = text(proc_string)
|
||||||
|
Helper_App.console_log(f'{_m}\nproc_string: {stmt}\nargs: {argument_dict_list}')
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
with db.engine.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
|
||||||
|
if has_arguments:
|
||||||
|
result = conn.execute(stmt, argument_dict_list)
|
||||||
|
else:
|
||||||
|
result = conn.execute(stmt)
|
||||||
|
# Fetch all rows as mappings before connection closes
|
||||||
|
if result.returns_rows:
|
||||||
|
rows = result.mappings().fetchall()
|
||||||
|
Helper_App.console_log(f'result: {rows}')
|
||||||
|
return rows
|
||||||
|
|
||||||
|
# Map SQLAlchemy types to PostgreSQL type names for CAST()
|
||||||
|
TYPE_CAST_MAP: ClassVar[dict[str, str]] = {
|
||||||
|
'String': 'varchar',
|
||||||
|
'Text': 'text',
|
||||||
|
'Integer': 'integer',
|
||||||
|
'Boolean': 'boolean',
|
||||||
|
'UUID': 'uuid',
|
||||||
|
'Uuid': 'uuid',
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def db_function_execute(func_name, argument_dict_list = None, argument_types_dict = None):
|
||||||
|
"""Execute a PostgreSQL function that returns a table using SELECT * FROM function_name()"""
|
||||||
|
_m = 'DataStore_Base.db_function_execute'
|
||||||
|
av.val_str(func_name, 'func_name', _m)
|
||||||
|
func_string = f'SELECT * FROM {func_name}('
|
||||||
|
has_arguments = argument_dict_list is not None
|
||||||
|
if has_arguments:
|
||||||
|
arg_keys = list(argument_dict_list.keys())
|
||||||
|
for i in range(len(arg_keys)):
|
||||||
|
param_name = arg_keys[i]
|
||||||
|
# Add explicit PostgreSQL CAST for typed parameters
|
||||||
|
if argument_types_dict and param_name in argument_types_dict:
|
||||||
|
type_name = argument_types_dict[param_name].__name__
|
||||||
|
pg_type = DataStore_Base.TYPE_CAST_MAP.get(type_name)
|
||||||
|
if pg_type:
|
||||||
|
param_expr = f'CAST(:{param_name} AS {pg_type})'
|
||||||
|
else:
|
||||||
|
param_expr = f':{param_name}'
|
||||||
|
else:
|
||||||
|
param_expr = f':{param_name}'
|
||||||
|
func_string += f'{"" if i == 0 else ", "}{param_name} := {param_expr}'
|
||||||
|
func_string += ')'
|
||||||
|
stmt = text(func_string)
|
||||||
|
|
||||||
|
Helper_App.console_log(f'{_m}\nfunc_string: {stmt}\nargs: {argument_dict_list}')
|
||||||
|
|
||||||
|
if has_arguments:
|
||||||
|
result = db.session.execute(stmt, argument_dict_list)
|
||||||
|
else:
|
||||||
|
result = db.session.execute(stmt)
|
||||||
|
Helper_App.console_log(f'result: {result}')
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def db_cursor_clear(cursor):
|
||||||
|
while cursor.nextset():
|
||||||
|
Helper_App.console_log(f'unexpected result set: {cursor.fetchall()}')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_user_session():
|
||||||
|
Helper_App.console_log('DataStore_Base.get_user_session')
|
||||||
|
user = User.from_json(session.get(User.FLAG_USER))
|
||||||
|
"""
|
||||||
|
if user.user_id <= 0:
|
||||||
|
user.user_id = 3
|
||||||
|
"""
|
||||||
|
Helper_App.console_log(f'User: {user}')
|
||||||
|
return user
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def upload_bulk(permanent_table_name, records, batch_size):
|
||||||
|
_m = 'DataStore_Base.upload_bulk'
|
||||||
|
Helper_App.console_log(f'{_m}\nstarting...')
|
||||||
|
Helper_App.console_log(f'permanent_table_name: {permanent_table_name}')
|
||||||
|
if db.session.dirty or db.session.new or db.session.deleted:
|
||||||
|
Helper_App.console_log("Session is not clean")
|
||||||
|
return
|
||||||
|
# Assuming `permanent_table_name` is a string representing the table name
|
||||||
|
table_object = db.metadata.tables.get(permanent_table_name)
|
||||||
|
Helper_App.console_log(f'Tables: {list(db.metadata.tables.keys())}')
|
||||||
|
if table_object is None:
|
||||||
|
Helper_App.console_log(f"Table {permanent_table_name} not found in metadata.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
||||||
|
Helper_App.console_log(f'table name: {table_object.name}')
|
||||||
|
Helper_App.console_log(f'expected_columns: {expected_columns}')
|
||||||
|
max_retries = 3
|
||||||
|
initial_backoff = 1
|
||||||
|
for i in range(0, len(records), batch_size):
|
||||||
|
batch = records[i:i + batch_size]
|
||||||
|
try:
|
||||||
|
retries = 0
|
||||||
|
while retries < max_retries:
|
||||||
|
try:
|
||||||
|
# Helper_App.console_log(f'Before upload batch.')
|
||||||
|
db.session.add_all(batch)
|
||||||
|
# db.session.bulk_save_objects(batch)
|
||||||
|
# Helper_App.console_log(f'Before commit batch.')
|
||||||
|
db.session.commit()
|
||||||
|
# Helper_App.console_log(f'Batch uploaded.')
|
||||||
|
break
|
||||||
|
except OperationalError as e:
|
||||||
|
if "Lock wait timeout exceeded" not in str(e) or retries == max_retries - 1:
|
||||||
|
raise
|
||||||
|
|
||||||
|
wait_time = initial_backoff * (2 ** retries)
|
||||||
|
current_app.logger.warning(f"Lock timeout encountered. Retrying in {wait_time} seconds... (Attempt {retries + 1}/{max_retries})")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
retries += 1
|
||||||
|
|
||||||
|
# Ensure the session is clean for the retry
|
||||||
|
db.session.rollback()
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
raise e
|
||||||
|
Helper_App.console_log(f'Records uploaded in batches.')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_error(cls, guid):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_error'
|
||||||
|
# user = cls.get_user_session()
|
||||||
|
arguments = Parameters_SQL_Error.get_default(guid)
|
||||||
|
argument_dict = arguments.to_json()
|
||||||
|
argument_types = Parameters_SQL_Error.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
error_result = cls.db_function_execute('tcg.public.FN_Error_Get_Many', argument_dict, argument_types)
|
||||||
|
error_result_set = error_result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw errors: {error_result_set}')
|
||||||
|
errors = []
|
||||||
|
error_indexes = {}
|
||||||
|
for row in error_result_set:
|
||||||
|
new_error = SQL_Error.from_db_error(row)
|
||||||
|
error_indexes[new_error.error_id] = len(errors)
|
||||||
|
errors.append(new_error)
|
||||||
|
Helper_App.console_log(f'error {str(type(new_error))}: {new_error}')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_error(cls, guid):
|
||||||
|
_m = f'{cls.__qualname__}.clear_error'
|
||||||
|
# user = cls.get_user_session()
|
||||||
|
arguments = Parameters_SQL_Error.get_default(guid)
|
||||||
|
argument_dict = arguments.to_json()
|
||||||
|
argument_types = Parameters_SQL_Error.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
cls.db_procedure_execute('tcg.public.USP_Error_Clear', argument_dict, argument_types)
|
||||||
|
|
||||||
341
datastores/datastore_mtg.py
Normal file
341
datastores/datastore_mtg.py
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: DataStores
|
||||||
|
Feature: MTG DataStore
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Datastore for MTG game data
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game, Parameters_MTG_Game
|
||||||
|
from business_objects.tcg.mtg_game_player import MTG_Game_Player, Parameters_MTG_Game_Player, MTG_Game_Player_Temp
|
||||||
|
from business_objects.tcg.mtg_game_round import MTG_Game_Round, Parameters_MTG_Game_Round, MTG_Game_Round_Temp
|
||||||
|
from business_objects.tcg.mtg_game_round_player_damage import MTG_Game_Round_Player_Damage, Parameters_MTG_Game_Round_Player_Damage, MTG_Game_Round_Player_Damage_Temp
|
||||||
|
from business_objects.tcg.mtg_deck import MTG_Deck, Parameters_MTG_Deck
|
||||||
|
from business_objects.sql_error import SQL_Error, Parameters_SQL_Error
|
||||||
|
from datastores.datastore_base import DataStore_Base
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
from helpers.helper_db_sql import Helper_DB_SQL
|
||||||
|
from extensions import db
|
||||||
|
# external
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from sqlalchemy import Uuid
|
||||||
|
from sqlalchemy.types import Text, Boolean, Integer
|
||||||
|
from sqlalchemy.dialects.postgresql import TIMESTAMP
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
|
||||||
|
class DataStore_MTG(DataStore_Base):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_mtg_game(cls, game_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_mtg_game'
|
||||||
|
# user = cls.get_user_session()
|
||||||
|
argument_dict = game_filters.to_json()
|
||||||
|
argument_types = Parameters_MTG_Game.get_type_hints()
|
||||||
|
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
games = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
game_result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Game_Get_Many', argument_dict, argument_types)
|
||||||
|
game_result_set = game_result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw games: {game_result_set}')
|
||||||
|
games = []
|
||||||
|
game_indexes = {}
|
||||||
|
for row in game_result_set:
|
||||||
|
new_game = MTG_Game.from_db_mtg_game(row)
|
||||||
|
game_indexes[new_game.game_id] = len(games)
|
||||||
|
games.append(new_game)
|
||||||
|
Helper_App.console_log(f'game {str(type(new_game))}: {new_game}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return games, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_mtg_game(cls, game):
|
||||||
|
_m = f'{cls.__qualname__}.save_mtg_game'
|
||||||
|
user = cls.get_user_session()
|
||||||
|
guid = Helper_DB_SQL.create_guid()
|
||||||
|
game_id = None
|
||||||
|
success = None
|
||||||
|
argument_dict = {
|
||||||
|
'a_comment': 'Save game'
|
||||||
|
, 'a_end_on': game.end_on
|
||||||
|
, 'a_game_id': game.game_id
|
||||||
|
, 'a_guid': guid
|
||||||
|
, 'a_location_name': game.location_name
|
||||||
|
, 'a_notes': game.notes
|
||||||
|
, 'a_starting_life': game.starting_life
|
||||||
|
, 'a_start_on': game.start_on
|
||||||
|
, 'a_user_id': user.user_id
|
||||||
|
, 'a_do_delete': False
|
||||||
|
, 'a_is_commander': True
|
||||||
|
, 'a_is_draft': False
|
||||||
|
, 'a_is_sealed': False
|
||||||
|
, 'o_game_id': game_id
|
||||||
|
, 'o_success': success
|
||||||
|
}
|
||||||
|
argument_type_hints = {
|
||||||
|
'a_comment': Text
|
||||||
|
, 'a_end_on': TIMESTAMP
|
||||||
|
, 'a_game_id': Integer
|
||||||
|
, 'a_guid': Uuid
|
||||||
|
, 'a_location_name': Text
|
||||||
|
, 'a_notes': Text
|
||||||
|
, 'a_starting_life': Integer
|
||||||
|
, 'a_start_on': TIMESTAMP
|
||||||
|
, 'a_user_id': Integer
|
||||||
|
, 'a_do_delete': Boolean
|
||||||
|
, 'a_is_commander': Boolean
|
||||||
|
, 'a_is_draft': Boolean
|
||||||
|
, 'a_is_sealed': Boolean
|
||||||
|
, 'o_game_id': Integer
|
||||||
|
, 'o_success': Boolean
|
||||||
|
}
|
||||||
|
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
rows = cls.db_procedure_execute('tcg.public.USP_TCG_MTG_Game_Save', argument_dict, argument_type_hints)
|
||||||
|
row = rows[0] if rows else None
|
||||||
|
game_id = row['o_game_id'] if row else None
|
||||||
|
success = row['o_success'] if row else False
|
||||||
|
Helper_App.console_log(f'Game ID: {game_id}')
|
||||||
|
Helper_App.console_log(f'Success: {success}')
|
||||||
|
if not success:
|
||||||
|
errors = cls.get_many_error(guid = guid)
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
cls.clear_error(guid = guid)
|
||||||
|
|
||||||
|
return game_id, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_mtg_game_player(cls, player_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_mtg_game_player'
|
||||||
|
argument_dict = player_filters.to_json()
|
||||||
|
argument_types = Parameters_MTG_Game_Player.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
players = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Game_Player_Get_Many', argument_dict, argument_types)
|
||||||
|
result_set = result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw players: {result_set}')
|
||||||
|
for row in result_set:
|
||||||
|
new_player = MTG_Game_Player.from_db_mtg_game_player(row)
|
||||||
|
players.append(new_player)
|
||||||
|
Helper_App.console_log(f'player {str(type(new_player))}: {new_player}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return players, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_mtg_game_round(cls, round_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_mtg_game_round'
|
||||||
|
argument_dict = round_filters.to_json()
|
||||||
|
argument_types = Parameters_MTG_Game_Round.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
rounds = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Game_Round_Get_Many', argument_dict, argument_types)
|
||||||
|
result_set = result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw rounds: {result_set}')
|
||||||
|
for row in result_set:
|
||||||
|
new_round = MTG_Game_Round.from_db_mtg_game_round(row)
|
||||||
|
rounds.append(new_round)
|
||||||
|
Helper_App.console_log(f'round {str(type(new_round))}: {new_round}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return rounds, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_mtg_game_round_player_damage(cls, damage_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_mtg_game_round_player_damage'
|
||||||
|
argument_dict = damage_filters.to_json()
|
||||||
|
argument_types = Parameters_MTG_Game_Round_Player_Damage.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
damages = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Game_Round_Player_Damage_Get_Many', argument_dict, argument_types)
|
||||||
|
result_set = result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw damages: {result_set}')
|
||||||
|
for row in result_set:
|
||||||
|
new_damage = MTG_Game_Round_Player_Damage.from_db_mtg_game_round_player_damage(row)
|
||||||
|
damages.append(new_damage)
|
||||||
|
Helper_App.console_log(f'damage {str(type(new_damage))}: {new_damage.damage_id}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return damages, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_mtg_deck(cls, deck_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_mtg_deck'
|
||||||
|
argument_dict = deck_filters.to_json()
|
||||||
|
argument_types = Parameters_MTG_Deck.get_type_hints()
|
||||||
|
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
decks = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Deck_Get_Many', argument_dict, argument_types)
|
||||||
|
result_set = result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw decks: {result_set}')
|
||||||
|
for row in result_set:
|
||||||
|
new_deck = MTG_Deck.from_db_mtg_deck(row)
|
||||||
|
decks.append(new_deck)
|
||||||
|
Helper_App.console_log(f'deck {str(type(new_deck))}: {new_deck}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return decks, errors
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_mtg_game_player(cls, players):
|
||||||
|
_m = f'{cls.__qualname__}.save_mtg_game_player'
|
||||||
|
user = cls.get_user_session()
|
||||||
|
guid = Helper_DB_SQL.create_guid()
|
||||||
|
success = None
|
||||||
|
argument_dict = {
|
||||||
|
'a_comment': 'Save game player'
|
||||||
|
, 'a_guid': guid
|
||||||
|
, 'a_user_id': user.user_id
|
||||||
|
, 'o_success': success
|
||||||
|
}
|
||||||
|
argument_type_hints = {
|
||||||
|
'a_comment': Text
|
||||||
|
, 'a_guid': Uuid
|
||||||
|
, 'a_user_id': Integer
|
||||||
|
, 'o_success': Boolean
|
||||||
|
}
|
||||||
|
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
objs_player_temp = []
|
||||||
|
for player in players:
|
||||||
|
obj_player_temp = MTG_Game_Player_Temp.from_player(player = player, guid = guid)
|
||||||
|
objs_player_temp.append(obj_player_temp)
|
||||||
|
|
||||||
|
success = False
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
cls.upload_bulk(
|
||||||
|
permanent_table_name = MTG_Game_Player_Temp.__tablename__
|
||||||
|
, records = objs_player_temp
|
||||||
|
, batch_size = 1000
|
||||||
|
)
|
||||||
|
rows = cls.db_procedure_execute('tcg.public.USP_TCG_MTG_Game_Player_Save', argument_dict, argument_type_hints)
|
||||||
|
row = rows[0] if rows else None
|
||||||
|
success = row['o_success'] if row else False
|
||||||
|
Helper_App.console_log(f'Success: {success}')
|
||||||
|
if not success:
|
||||||
|
errors = cls.get_many_error(guid = guid)
|
||||||
|
Helper_App.console_log(f'Errors: {str(errors)}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
cls.clear_error(guid = guid)
|
||||||
|
|
||||||
|
return success, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_mtg_game_round_player_damage(cls, rounds, damages):
|
||||||
|
_m = f'{cls.__qualname__}.save_mtg_game_round_player_damage'
|
||||||
|
user = cls.get_user_session()
|
||||||
|
guid = Helper_DB_SQL.create_guid()
|
||||||
|
success = None
|
||||||
|
argument_dict = {
|
||||||
|
'a_comment': 'Save game player'
|
||||||
|
, 'a_guid': guid
|
||||||
|
, 'a_user_id': user.user_id
|
||||||
|
, 'o_success': success
|
||||||
|
}
|
||||||
|
argument_type_hints = {
|
||||||
|
'a_comment': Text
|
||||||
|
, 'a_guid': Uuid
|
||||||
|
, 'a_user_id': Integer
|
||||||
|
, 'o_success': Boolean
|
||||||
|
}
|
||||||
|
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
objs_round_temp = []
|
||||||
|
for round in rounds:
|
||||||
|
obj_round_temp = MTG_Game_Round_Temp.from_round(round = round, guid = guid)
|
||||||
|
objs_round_temp.append(obj_round_temp)
|
||||||
|
|
||||||
|
objs_damage_temp = []
|
||||||
|
for damage in damages:
|
||||||
|
obj_damage_temp = MTG_Game_Round_Player_Damage_Temp.from_damage(damage = damage, guid = guid)
|
||||||
|
objs_damage_temp.append(obj_damage_temp)
|
||||||
|
|
||||||
|
success = False
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
cls.upload_bulk(
|
||||||
|
permanent_table_name = MTG_Game_Round_Temp.__tablename__
|
||||||
|
, records = objs_round_temp
|
||||||
|
, batch_size = 1000
|
||||||
|
)
|
||||||
|
cls.upload_bulk(
|
||||||
|
permanent_table_name = MTG_Game_Round_Player_Damage_Temp.__tablename__
|
||||||
|
, records = objs_damage_temp
|
||||||
|
, batch_size = 1000
|
||||||
|
)
|
||||||
|
rows = cls.db_procedure_execute('tcg.public.USP_TCG_MTG_Game_Round_Damage_Save', argument_dict, argument_type_hints)
|
||||||
|
row = rows[0] if rows else None
|
||||||
|
success = row['o_success'] if row else False
|
||||||
|
Helper_App.console_log(f'Success: {success}')
|
||||||
|
if not success:
|
||||||
|
errors = cls.get_many_error(guid = guid)
|
||||||
|
Helper_App.console_log(f'Errors: {str(errors)}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
cls.clear_error(guid = guid)
|
||||||
|
|
||||||
|
return success, errors
|
||||||
107
datastores/datastore_user.py
Normal file
107
datastores/datastore_user.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: DataStores
|
||||||
|
Feature: User DataStore
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Datastore for Users
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
# from routes import bp_home
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from business_objects.sql_error import SQL_Error
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_base import DataStore_Base
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
from helpers.helper_db_sql import Helper_DB_SQL
|
||||||
|
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||||
|
from extensions import db
|
||||||
|
# external
|
||||||
|
# from abc import ABC, abstractmethod, abstractproperty
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from sqlalchemy import text
|
||||||
|
import stripe
|
||||||
|
import os
|
||||||
|
from flask import Flask, session, current_app
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from typing import ClassVar
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
|
||||||
|
class DataStore_User(DataStore_Base):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_many_user(cls, user_filters):
|
||||||
|
_m = f'{cls.__qualname__}.get_many_user'
|
||||||
|
Helper_App.console_log(_m)
|
||||||
|
Helper_App.console_log(f'user_filters: {user_filters}')
|
||||||
|
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||||
|
|
||||||
|
argument_dict = user_filters.to_json()
|
||||||
|
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||||
|
|
||||||
|
users = []
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
user_result = cls.db_function_execute('tcg.public.FN_TCG_User_Get_Many', argument_dict, Parameters_User.get_type_hints())
|
||||||
|
user_result_set = user_result.fetchall()
|
||||||
|
Helper_App.console_log(f'raw users: {user_result_set}')
|
||||||
|
|
||||||
|
for row in user_result_set:
|
||||||
|
Helper_App.console_log(f'row: {row}')
|
||||||
|
user = User.from_db_user(row)
|
||||||
|
users.append(user)
|
||||||
|
Helper_App.console_log(f'user {str(type(user))}: {user}')
|
||||||
|
except Exception as e:
|
||||||
|
Helper_App.console_log(f'Error: {str(e)}')
|
||||||
|
error = SQL_Error()
|
||||||
|
error.msg = str(e)
|
||||||
|
errors.append(error)
|
||||||
|
|
||||||
|
return users, errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def login_user(cls, user):
|
||||||
|
_m = f'{cls}.login_user'
|
||||||
|
# av.val_str(comment, 'comment', _m)
|
||||||
|
|
||||||
|
guid = Helper_DB_SQL.create_guid_str()
|
||||||
|
|
||||||
|
Helper_App.console_log(f'login user: {user}')
|
||||||
|
|
||||||
|
success = False
|
||||||
|
user_id = None
|
||||||
|
try:
|
||||||
|
argument_dict_list = {
|
||||||
|
'a_user_auth0_id': user.user_auth0_id
|
||||||
|
, 'a_email': user.email
|
||||||
|
, 'a_guid': guid
|
||||||
|
, 'a_is_email_verified': user.is_email_verified
|
||||||
|
, 'o_success': success
|
||||||
|
, 'o_user_id': user_id
|
||||||
|
}
|
||||||
|
rows = cls.db_procedure_execute('tcg.public.USP_TCG_User_Login', argument_dict_list)
|
||||||
|
row = rows[0] if rows else None
|
||||||
|
success = row['o_success'] if row else False
|
||||||
|
user_id = row['o_user_id'] if row else None
|
||||||
|
Helper_App.console_log('User logged in')
|
||||||
|
Helper_App.console_log(f'Success: {success}\nUser ID: {user_id}')
|
||||||
|
|
||||||
|
user.user_id = user_id
|
||||||
|
user_filters = Parameters_User.from_user(user)
|
||||||
|
users, errors = cls.get_many_user(user_filters = user_filters)
|
||||||
|
user = users[0] if len(users) > 0 else None
|
||||||
|
if user is not None:
|
||||||
|
user.is_logged_in = True
|
||||||
|
return user, errors
|
||||||
|
except Exception as e:
|
||||||
|
return None, SQL_Error.from_exception(e)
|
||||||
|
|
||||||
14
extensions.py
Normal file
14
extensions.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, current_app
|
||||||
|
from flask_cors import CORS
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_mail import Mail, Message
|
||||||
|
from flask_wtf.csrf import CSRFProtect
|
||||||
|
from authlib.integrations.flask_client import OAuth
|
||||||
|
|
||||||
|
|
||||||
|
csrf = CSRFProtect()
|
||||||
|
# cors = CORS()
|
||||||
|
db = SQLAlchemy()
|
||||||
|
mail = Mail()
|
||||||
|
oauth = OAuth()
|
||||||
0
forms/__init__.py
Normal file
0
forms/__init__.py
Normal file
70
forms/base.py
Normal file
70
forms/base.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
"""
|
||||||
|
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
|
||||||
|
from 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):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
|
||||||
|
@classmethod
|
||||||
|
@abstractmethod
|
||||||
|
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, is_valid = True):
|
||||||
|
value = cls.get_select_valid_option_default_value() if is_valid else cls.get_select_invalid_option_default_value()
|
||||||
|
return (value, 'Select')
|
||||||
|
@classmethod
|
||||||
|
def get_select_option_all(cls):
|
||||||
|
return (cls.get_select_valid_option_default_value(), 'All')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_valid_option_default_value():
|
||||||
|
return '0'
|
||||||
|
@staticmethod
|
||||||
|
def get_select_invalid_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})"
|
||||||
|
|
||||||
|
'''
|
||||||
|
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
|
||||||
|
'''
|
||||||
0
forms/tcg/__init__.py
Normal file
0
forms/tcg/__init__.py
Normal file
185
forms/tcg/game.py
Normal file
185
forms/tcg/game.py
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Backend
|
||||||
|
Feature: MTG Game Form
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Defines Flask-WTF form for handling user input on MTG Games page.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game, Parameters_MTG_Game
|
||||||
|
from business_objects.tcg.mtg_game_player import MTG_Game_Player, Parameters_MTG_Game_Player
|
||||||
|
from business_objects.tcg.mtg_game_round import MTG_Game_Round, Parameters_MTG_Game_Round
|
||||||
|
from business_objects.tcg.mtg_game_round_player_damage import Parameters_MTG_Game_Round_Player_Damage
|
||||||
|
from business_objects.tcg.mtg_deck import MTG_Deck, Parameters_MTG_Deck
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
from forms.base import Form_Base
|
||||||
|
import 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, StringField, SubmitField, DateField
|
||||||
|
from wtforms.validators import DataRequired, Email, ValidationError, Optional
|
||||||
|
import markupsafe
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class Filters_MTG_Game(Form_Base):
|
||||||
|
search = StringField(
|
||||||
|
'Search'
|
||||||
|
)
|
||||||
|
active_only = BooleanField(
|
||||||
|
'Active'
|
||||||
|
, default=True
|
||||||
|
)
|
||||||
|
is_commander = BooleanField(
|
||||||
|
'Commander'
|
||||||
|
, default=False
|
||||||
|
)
|
||||||
|
is_draft = BooleanField(
|
||||||
|
'Draft'
|
||||||
|
, default=False
|
||||||
|
)
|
||||||
|
is_sealed = BooleanField(
|
||||||
|
'Sealed'
|
||||||
|
, default=False
|
||||||
|
)
|
||||||
|
date_from = DateField(
|
||||||
|
'From Date'
|
||||||
|
, validators=[Optional()]
|
||||||
|
)
|
||||||
|
date_to = DateField(
|
||||||
|
'To Date'
|
||||||
|
, validators=[Optional()]
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||||
|
filters = cls()
|
||||||
|
filters.search.data = json.get(Base.FLAG_SEARCH, '')
|
||||||
|
filters.active_only.data = av.input_bool(json.get(Base.FLAG_ACTIVE_ONLY, True), Base.FLAG_ACTIVE_ONLY, _m)
|
||||||
|
filters.is_commander.data = av.input_bool(json.get(MTG_Game.FLAG_IS_COMMANDER, False), MTG_Game.FLAG_IS_COMMANDER, _m)
|
||||||
|
filters.is_draft.data = av.input_bool(json.get(MTG_Game.FLAG_IS_DRAFT, False), MTG_Game.FLAG_IS_DRAFT, _m)
|
||||||
|
filters.is_sealed.data = av.input_bool(json.get(MTG_Game.FLAG_IS_SEALED, False), MTG_Game.FLAG_IS_SEALED, _m)
|
||||||
|
filters.date_from.data = json.get(Base.FLAG_DATE_FROM, None)
|
||||||
|
filters.date_to.data = json.get(Base.FLAG_DATE_TO, None)
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
Base.FLAG_SEARCH: self.search.data
|
||||||
|
, Base.FLAG_ACTIVE_ONLY: self.active_only.data
|
||||||
|
, MTG_Game.FLAG_IS_COMMANDER: self.is_commander.data
|
||||||
|
, MTG_Game.FLAG_IS_DRAFT: self.is_draft.data
|
||||||
|
, MTG_Game.FLAG_IS_SEALED: self.is_sealed.data
|
||||||
|
, Base.FLAG_DATE_FROM: self.date_from.data
|
||||||
|
, Base.FLAG_DATE_TO: self.date_to.data
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_parameters(self, user_id_session):
|
||||||
|
return Parameters_MTG_Game (
|
||||||
|
get_all_game = True
|
||||||
|
, get_inactive_game = not self.active_only.data
|
||||||
|
, game_ids = ''
|
||||||
|
, get_all_user = False
|
||||||
|
, get_inactive_user = False
|
||||||
|
, user_ids = '' if user_id_session is None else str(user_id_session)
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
, require_all_non_id_filters_met = False
|
||||||
|
, require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Filters_MTG_Game_Player(Form_Base):
|
||||||
|
search = StringField(
|
||||||
|
'Search'
|
||||||
|
)
|
||||||
|
active_only = BooleanField(
|
||||||
|
'Active'
|
||||||
|
, default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||||
|
filters = cls()
|
||||||
|
filters.search.data = json.get(Base.FLAG_SEARCH, '')
|
||||||
|
filters.active_only.data = av.input_bool(json.get(Base.FLAG_ACTIVE_ONLY, True), Base.FLAG_ACTIVE_ONLY, _m)
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
Base.FLAG_SEARCH: self.search.data
|
||||||
|
, Base.FLAG_ACTIVE_ONLY: self.active_only.data
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_parameters(self, user_id_session, game_id=None):
|
||||||
|
params = Parameters_MTG_Game_Player(
|
||||||
|
get_all_player = True
|
||||||
|
, get_inactive_player = not self.active_only.data
|
||||||
|
, player_ids = ''
|
||||||
|
, game_ids = str(game_id) if game_id else ''
|
||||||
|
, user_ids = str(user_id_session) if user_id_session else ''
|
||||||
|
, deck_ids = ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
, require_all_non_id_filters_met = False
|
||||||
|
, require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
class Filters_MTG_Deck(Form_Base):
|
||||||
|
search = StringField(
|
||||||
|
'Search'
|
||||||
|
)
|
||||||
|
active_only = BooleanField(
|
||||||
|
'Active'
|
||||||
|
, default=True
|
||||||
|
)
|
||||||
|
is_commander = BooleanField(
|
||||||
|
'Commander'
|
||||||
|
, default=False
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||||
|
filters = cls()
|
||||||
|
filters.search.data = json.get(Base.FLAG_SEARCH, '')
|
||||||
|
filters.active_only.data = av.input_bool(json.get(Base.FLAG_ACTIVE_ONLY, True), Base.FLAG_ACTIVE_ONLY, _m)
|
||||||
|
filters.is_commander.data = av.input_bool(json.get(MTG_Deck.FLAG_IS_COMMANDER, False), MTG_Deck.FLAG_IS_COMMANDER, _m)
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
Base.FLAG_SEARCH: self.search.data
|
||||||
|
, Base.FLAG_ACTIVE_ONLY: self.active_only.data
|
||||||
|
, MTG_Deck.FLAG_IS_COMMANDER: self.is_commander.data
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_parameters(self, user_id_session):
|
||||||
|
return Parameters_MTG_Deck(
|
||||||
|
get_all_deck = True
|
||||||
|
, get_inactive_deck = not self.active_only.data
|
||||||
|
, deck_ids = ''
|
||||||
|
, deck_names = ''
|
||||||
|
, commander_bracket_ids = ''
|
||||||
|
, user_ids = str(user_id_session) if user_id_session else ''
|
||||||
|
, require_all_id_filters_met = True
|
||||||
|
, require_any_id_filters_met = True
|
||||||
|
, require_all_non_id_filters_met = False
|
||||||
|
, require_any_non_id_filters_met = True
|
||||||
|
)
|
||||||
55
forms/tcg/user.py
Normal file
55
forms/tcg/user.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Backend
|
||||||
|
Feature: User Form
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Defines Flask-WTF form for handling user input on User page.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
from business_objects.base import Base
|
||||||
|
# from business_objects.user.user import User # Circular
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
# 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
|
||||||
|
import 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, StringField, 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_User(Form_Base):
|
||||||
|
search = StringField(
|
||||||
|
'Search'
|
||||||
|
)
|
||||||
|
active_only = BooleanField(
|
||||||
|
'Active'
|
||||||
|
, default = True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
_m = f'{cls.__qualname__}.from_json'
|
||||||
|
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||||
|
filters = cls()
|
||||||
|
filters.search.data = json[Base.FLAG_SEARCH]
|
||||||
|
filters.active_only.data = av.input_bool(json[Base.FLAG_ACTIVE_ONLY], Base.FLAG_ACTIVE_ONLY, f'{cls.__name__}.from_json')
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
Base.FLAG_SEARCH: self.search.data
|
||||||
|
, Base.FLAG_ACTIVE_ONLY: self.active_only.data
|
||||||
|
}
|
||||||
|
|
||||||
11
helpers/__init__.py
Normal file
11
helpers/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Module Initialisation
|
||||||
|
Feature: Helpers
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises helpers module.
|
||||||
|
"""
|
||||||
43
helpers/helper_app.py
Normal file
43
helpers/helper_app.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Helpers
|
||||||
|
Feature: App Helper
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
|
||||||
|
# external
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from flask import current_app
|
||||||
|
# from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
|
||||||
|
class Helper_App(BaseModel):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_request_data(request):
|
||||||
|
Helper_App.console_log(f'request={request}')
|
||||||
|
data = {}
|
||||||
|
try:
|
||||||
|
data = request.json
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
data = request.data
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
data = request.form
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
Helper_App.console_log(f'data={data}')
|
||||||
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def console_log(message):
|
||||||
|
if current_app.app_config.is_development:
|
||||||
|
print(message)
|
||||||
|
elif current_app.app_config.is_production:
|
||||||
|
pass
|
||||||
|
current_app.logger.info(message)
|
||||||
42
helpers/helper_db_sql.py
Normal file
42
helpers/helper_db_sql.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Helpers
|
||||||
|
Feature: MySQL Database Helper
|
||||||
|
|
||||||
|
Notes: This architecture does not work with Flask-SQLAlchemy - db connection must be initialised with Flask app initialisation
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
|
||||||
|
# external
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
class Helper_DB_SQL(BaseModel):
|
||||||
|
app: Flask
|
||||||
|
|
||||||
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||||
|
|
||||||
|
def __init__(self, app):
|
||||||
|
super().__init__(app=app)
|
||||||
|
# self.app = app
|
||||||
|
|
||||||
|
def get_db_connection(self):
|
||||||
|
db = SQLAlchemy()
|
||||||
|
db.init_app(self.app)
|
||||||
|
with self.app.app_context():
|
||||||
|
db.create_all()
|
||||||
|
db.engine.url = self.app.config['SQLALCHEMY_DATABASE_URI']
|
||||||
|
return db
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_guid_str():
|
||||||
|
return str(uuid.uuid4())
|
||||||
|
@staticmethod
|
||||||
|
def create_guid():
|
||||||
|
return str(uuid.uuid4())
|
||||||
11
lib/__init__.py
Normal file
11
lib/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Module Initialisation
|
||||||
|
Feature: Library
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises library module.
|
||||||
|
"""
|
||||||
1301
lib/argument_validation.py
Normal file
1301
lib/argument_validation.py
Normal file
File diff suppressed because it is too large
Load Diff
37
lib/data_types.py
Normal file
37
lib/data_types.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on Thu Apr 27 12:33:59 2023
|
||||||
|
|
||||||
|
@author: Edward Middleton-Smith
|
||||||
|
|
||||||
|
Argument Validation
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CLASSES
|
||||||
|
# ATTRIBUTE DECLARATION
|
||||||
|
# METHODS
|
||||||
|
# FUNCTION
|
||||||
|
# ARGUMENTS
|
||||||
|
# ARGUMENT VALIDATION
|
||||||
|
# ATTRIBUTE + VARIABLE INSTANTIATION
|
||||||
|
# METHODS
|
||||||
|
# RETURNS
|
||||||
|
|
||||||
|
# NORMAL METHODS
|
||||||
|
# FUNCTION
|
||||||
|
# ARGUMENTS
|
||||||
|
# ARGUMENT VALIDATION
|
||||||
|
# VARIABLE INSTANTIATION
|
||||||
|
# METHODS
|
||||||
|
# RETURNS
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
|
||||||
|
# CLASSES
|
||||||
|
|
||||||
|
# METHODS
|
||||||
|
def get_enum_member_by_text(enum_class, text):
|
||||||
|
for member in enum_class.__members__.values():
|
||||||
|
if member.name == text:
|
||||||
|
return member
|
||||||
|
raise ValueError(f'{text} is not in {enum_class}')
|
||||||
11
models/__init__.py
Normal file
11
models/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Module Initialisation
|
||||||
|
Feature: Models
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Initialises view data models module.
|
||||||
|
"""
|
||||||
22
models/model_view_accessibility_report.py
Normal file
22
models/model_view_accessibility_report.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Legal View Models
|
||||||
|
Feature: Accessibility Report View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for accessibility report view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
|
||||||
|
class Model_View_Accessibility_Report(Model_View_Base):
|
||||||
|
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_ACCESSIBILITY_REPORT):
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'Accessibility Report'
|
||||||
|
|
||||||
22
models/model_view_accessibility_statement.py
Normal file
22
models/model_view_accessibility_statement.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Legal View Models
|
||||||
|
Feature: Accessibility Statement View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for accessibility statement view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
|
||||||
|
class Model_View_Accessibility_Statement(Model_View_Base):
|
||||||
|
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_ACCESSIBILITY_STATEMENT):
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'Accessibility Statement'
|
||||||
|
|
||||||
346
models/model_view_base.py
Normal file
346
models/model_view_base.py
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: Base View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Base data model for views
|
||||||
|
"""
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# VARIABLE INSTANTIATION
|
||||||
|
# METHODS
|
||||||
|
|
||||||
|
# IMPORTS
|
||||||
|
# internal
|
||||||
|
# from routes import bp_home
|
||||||
|
from business_objects.base import Base
|
||||||
|
from business_objects.tcg.user import User
|
||||||
|
from datastores.datastore_base import DataStore_Base
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
# external
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask import Flask, session, current_app, jsonify
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class Model_View_Base(BaseModel, ABC):
|
||||||
|
ATTR_DATA_AMOUNT: ClassVar[str] = 'data-amount'
|
||||||
|
ATTR_TEXT_COLLAPSED: ClassVar[str] = 'textCollapsed'
|
||||||
|
ATTR_TEXT_EXPANDED: ClassVar[str] = 'textExpanded'
|
||||||
|
ATTR_USER_ID: ClassVar[str] = Base.ATTR_USER_ID
|
||||||
|
ATTR_VALUE_CURRENT: ClassVar[str] = 'current-value'
|
||||||
|
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
||||||
|
COLOUR_ACCENT: ClassVar[str] = '#C77DFF'
|
||||||
|
COLOUR_ERROR: ClassVar[str] = 'red'
|
||||||
|
COLOUR_PAGE_BACKGROUND: ClassVar[str] = '#E0AAFF'
|
||||||
|
COLOUR_PAGE_BACKGROUND_1: ClassVar[str] = '#F5ECFE'
|
||||||
|
COLOUR_PAGE_BACKGROUND_2: ClassVar[str] = '#FAE0E2'
|
||||||
|
COLOUR_PRIMARY: ClassVar[str] = '#240046'
|
||||||
|
COLOUR_SECONDARY: ClassVar[str] = '#3C096C'
|
||||||
|
COLOUR_TEXT: ClassVar[str] = '#10002B'
|
||||||
|
COLOUR_TEXT_BACKGROUND: ClassVar[str] = 'white'
|
||||||
|
COLOUR_TEXT_LINK_UNVISITED: ClassVar[str] = '#0000EE'
|
||||||
|
COLOUR_TEXT_LINK_VISITED: ClassVar[str] = '#551A8B'
|
||||||
|
COMPANY_ADDRESS_SHORT: ClassVar[str] = 'Russet, Sawbridge Road, Grandborough, United Kingdom, CV23 8DN'
|
||||||
|
COMPANY_NUMBER: ClassVar[str] = '13587499'
|
||||||
|
ENDPOINT_GET_ALTCHA_CHALLENGE: ClassVar[str] = 'routes_core_contact.create_altcha_challenge'
|
||||||
|
ENDPOINT_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = 'routes_legal.accessibility_report'
|
||||||
|
ENDPOINT_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = 'routes_legal.accessibility_statement'
|
||||||
|
ENDPOINT_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = 'routes_legal.retention_schedule'
|
||||||
|
ENDPOINT_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = 'routes_core.error_no_permission'
|
||||||
|
ENDPOINT_PAGE_HOME: ClassVar[str] = 'routes_mtg_game.home'
|
||||||
|
ENDPOINT_PAGE_LICENSE: ClassVar[str] = 'routes_legal.license'
|
||||||
|
ENDPOINT_PAGE_PRIVACY_POLICY: ClassVar[str] = 'routes_legal.privacy_policy'
|
||||||
|
ENDPOINT_POST_COMMAND: ClassVar[str] = 'routes_core_contact.contact_post'
|
||||||
|
FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
|
||||||
|
FLAG_ACTIVE_ONLY: ClassVar[str] = Base.FLAG_ACTIVE_ONLY
|
||||||
|
FLAG_ADD: ClassVar[str] = 'add'
|
||||||
|
# FLAG_ADD_DELETE: ClassVar[str] = 'add-delete'
|
||||||
|
FLAG_BENEFITS: ClassVar[str] = 'benefits'
|
||||||
|
FLAG_BOOL_FALSE: ClassVar[str] = 'false'
|
||||||
|
FLAG_BOOL_TRUE: ClassVar[str] = 'true'
|
||||||
|
# FLAG_BRIBE: ClassVar[str] = Bribe.FLAG_BRIBE
|
||||||
|
FLAG_BUTTON: ClassVar[str] = 'button'
|
||||||
|
FLAG_BUTTON_LIGHT: ClassVar[str] = 'button-light'
|
||||||
|
FLAG_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
|
||||||
|
FLAG_BUTTON_SUCCESS: ClassVar[str] = 'button-success'
|
||||||
|
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
||||||
|
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
||||||
|
FLAG_CAPTCHA: ClassVar[str] = 'captcha'
|
||||||
|
FLAG_CARD: ClassVar[str] = 'card'
|
||||||
|
FLAG_CHECKBOX: ClassVar[str] = 'checkbox'
|
||||||
|
FLAG_CLOSE_TEMPORARY_ELEMENT: ClassVar[str] = 'button-temporary-element-close'
|
||||||
|
FLAG_CODE: ClassVar[str] = Base.FLAG_CODE
|
||||||
|
FLAG_COLLAPSIBLE: ClassVar[str] = 'collapsible'
|
||||||
|
FLAG_COLUMN: ClassVar[str] = 'column'
|
||||||
|
FLAG_COMMENT: ClassVar[str] = 'comment'
|
||||||
|
FLAG_CONTAINER: ClassVar[str] = 'container'
|
||||||
|
FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
|
||||||
|
FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input'
|
||||||
|
# FLAG_CONTAINER_SAVE_CANCEL_BUTTONS: ClassVar[str] = 'container-save-cancel-buttons'
|
||||||
|
FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||||
|
FLAG_CTA_1: ClassVar[str] = 'cta-1'
|
||||||
|
FLAG_CTA_2: ClassVar[str] = 'cta-2'
|
||||||
|
FLAG_DATA: ClassVar[str] = 'data'
|
||||||
|
FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM
|
||||||
|
FLAG_DATE_TO: ClassVar[str] = Base.FLAG_DATE_TO
|
||||||
|
FLAG_DDL_PREVIEW: ClassVar[str] = "ddl-preview"
|
||||||
|
FLAG_DELETE: ClassVar[str] = 'delete'
|
||||||
|
FLAG_DESCRIPTION: ClassVar[str] = Base.FLAG_DESCRIPTION
|
||||||
|
FLAG_DETAIL: ClassVar[str] = 'detail'
|
||||||
|
FLAG_DIALOG: ClassVar[str] = 'dialog'
|
||||||
|
FLAG_DIRTY: ClassVar[str] = 'dirty'
|
||||||
|
FLAG_DISPLAY_ORDER: ClassVar[str] = Base.FLAG_DISPLAY_ORDER
|
||||||
|
FLAG_EDIT: ClassVar[str] = 'edit'
|
||||||
|
FLAG_EMAIL: ClassVar[str] = Base.FLAG_EMAIL
|
||||||
|
FLAG_END_ON: ClassVar[str] = Base.FLAG_END_ON
|
||||||
|
FLAG_ERROR: ClassVar[str] = 'error'
|
||||||
|
FLAG_EXPANDED: ClassVar[str] = 'expanded'
|
||||||
|
FLAG_FAILURE: ClassVar[str] = 'failure'
|
||||||
|
FLAG_FAQ: ClassVar[str] = 'faq'
|
||||||
|
FLAG_FEATURES: ClassVar[str] = 'features'
|
||||||
|
FLAG_FILTER: ClassVar[str] = 'filter'
|
||||||
|
FLAG_FIRSTNAME: ClassVar[str] = Base.FLAG_FIRSTNAME
|
||||||
|
FLAG_FORM: ClassVar[str] = 'form'
|
||||||
|
FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters'
|
||||||
|
FLAG_HAMBURGER: ClassVar[str] = 'hamburger'
|
||||||
|
FLAG_ICON: ClassVar[str] = "icon"
|
||||||
|
FLAG_IMAGE_LOGO: ClassVar[str] = 'image-logo'
|
||||||
|
FLAG_INITIALISED: ClassVar[str] = 'initialised'
|
||||||
|
FLAG_INPUT_ANSWER: ClassVar[str] = 'input-answer'
|
||||||
|
FLAG_IS_CHECKED: ClassVar[str] = 'is_checked'
|
||||||
|
FLAG_IS_COLLAPSED: ClassVar[str] = 'is_collapsed'
|
||||||
|
FLAG_LABEL_QUESTION: ClassVar[str] = 'label-question'
|
||||||
|
FLAG_LEFT_HAND_STUB: ClassVar[str] = 'lhs'
|
||||||
|
FLAG_LOGO: ClassVar[str] = 'logo'
|
||||||
|
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||||
|
FLAG_MODAL: ClassVar[str] = 'modal'
|
||||||
|
FLAG_NAME: ClassVar[str] = Base.FLAG_NAME
|
||||||
|
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_TEXT
|
||||||
|
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_VALUE
|
||||||
|
FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
|
||||||
|
# FLAG_NAME_SINGULAR: ClassVar[str] = Base.FLAG_NAME_SINGULAR
|
||||||
|
FLAG_NAV_ADMIN_HOME: ClassVar[str] = 'navAdminHome'
|
||||||
|
FLAG_NAV_MTG_DECKS: ClassVar[str] = 'navMtgDecks'
|
||||||
|
FLAG_NAV_MTG_GAME: ClassVar[str] = 'navMtgGame'
|
||||||
|
FLAG_NAV_MTG_GAMES: ClassVar[str] = 'navMtgGames'
|
||||||
|
FLAG_NAV_MTG_HOME: ClassVar[str] = 'navMtgHome'
|
||||||
|
FLAG_NAV_MTG_TRIAL_GAME: ClassVar[str] = 'navMtgTrialGame'
|
||||||
|
FLAG_NAV_HOME: ClassVar[str] = 'navHome'
|
||||||
|
FLAG_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccount'
|
||||||
|
FLAG_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccounts'
|
||||||
|
FLAG_NAV_USER_LOGIN: ClassVar[str] = 'navUserLogin'
|
||||||
|
FLAG_NAV_USER_LOGOUT: ClassVar[str] = 'navUserLogout'
|
||||||
|
FLAG_NOTES: ClassVar[str] = "notes"
|
||||||
|
FLAG_OVERLAY: ClassVar[str] = 'overlay'
|
||||||
|
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||||
|
FLAG_PRICE: ClassVar[str] = Base.FLAG_PRICE
|
||||||
|
FLAG_PRICING: ClassVar[str] = 'pricing'
|
||||||
|
FLAG_QUANTITY: ClassVar[str] = 'quantity'
|
||||||
|
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||||
|
FLAG_ROW: ClassVar[str] = 'row'
|
||||||
|
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
||||||
|
FLAG_ROWS: ClassVar[str] = Base.FLAG_ROWS
|
||||||
|
FLAG_SAVE: ClassVar[str] = 'save'
|
||||||
|
FLAG_SCROLLABLE: ClassVar[str] = 'scrollable'
|
||||||
|
FLAG_SEARCH: ClassVar[str] = Base.FLAG_SEARCH
|
||||||
|
FLAG_SLIDER: ClassVar[str] = 'slider'
|
||||||
|
FLAG_START_ON: ClassVar[str] = Base.FLAG_START_ON
|
||||||
|
FLAG_STATUS: ClassVar[str] = 'status'
|
||||||
|
FLAG_SUBMIT: ClassVar[str] = 'submit'
|
||||||
|
FLAG_SUCCESS: ClassVar[str] = 'success'
|
||||||
|
FLAG_SURNAME: ClassVar[str] = Base.FLAG_SURNAME
|
||||||
|
FLAG_TABLE_MAIN: ClassVar[str] = 'table-main'
|
||||||
|
FLAG_TEMPORARY_ELEMENT: ClassVar[str] = 'temporary-element'
|
||||||
|
FLAG_TESTIMONIAL: ClassVar[str] = 'testimonial'
|
||||||
|
FLAG_USER: ClassVar[str] = User.FLAG_USER
|
||||||
|
# FLAG_VALUE_PROPOSITION: ClassVar[str] = 'value-proposition'
|
||||||
|
FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
|
||||||
|
HASH_GET_ALTCHA_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
|
||||||
|
HASH_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
|
||||||
|
HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
|
||||||
|
HASH_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = '/retention-schedule'
|
||||||
|
HASH_PAGE_MTG_DECKS: ClassVar[str] = '/decks'
|
||||||
|
HASH_PAGE_MTG_GAME: ClassVar[str] = '/game'
|
||||||
|
HASH_PAGE_MTG_GAMES: ClassVar[str] = '/' # '/games'
|
||||||
|
HASH_PAGE_MTG_HOME: ClassVar[str] = '/home'
|
||||||
|
HASH_PAGE_MTG_TRIAL_GAME: ClassVar[str] = '/trial-game'
|
||||||
|
HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
|
||||||
|
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
||||||
|
HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
|
||||||
|
HASH_PAGE_USER_ACCOUNT: ClassVar[str] = '/user/user'
|
||||||
|
HASH_PAGE_USER_ACCOUNTS: ClassVar[str] = '/user/users'
|
||||||
|
HASH_PAGE_USER_LOGIN: ClassVar[str] = '/login'
|
||||||
|
HASH_PAGE_USER_LOGOUT: ClassVar[str] = '/logout'
|
||||||
|
HASH_SAVE_MTG_GAME: ClassVar[str] = '/mtg/save-game'
|
||||||
|
HASH_SAVE_MTG_GAME_PLAYER: ClassVar[str] = '/mtg/save-game-player'
|
||||||
|
HASH_SAVE_MTG_GAME_ROUND: ClassVar[str] = '/mtg/save-game-round'
|
||||||
|
HASH_SAVE_MTG_GAME_ROUND_PLAYER_DAMAGE: ClassVar[str] = '/mtg/save-game-round-player-damage'
|
||||||
|
HASH_SAVE_MTG_DECK: ClassVar[str] = '/mtg/save-deck'
|
||||||
|
HASH_SAVE_USER_USER: ClassVar[str] = '/user/save-user'
|
||||||
|
ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
|
||||||
|
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
||||||
|
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
||||||
|
ID_BUTTON_HAMBURGER: ClassVar[str] = 'buttonHamburger'
|
||||||
|
ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
|
||||||
|
ID_CONTAINER_TEMPLATE_ELEMENTS: ClassVar[str] = 'container-template-elements'
|
||||||
|
ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||||
|
ID_FORM_CONTACT: ClassVar[str] = 'formContact'
|
||||||
|
ID_FORM_FILTERS: ClassVar[str] = 'formFilters'
|
||||||
|
ID_LABEL_ERROR: ClassVar[str] = 'labelError'
|
||||||
|
ID_OVERLAY_CONFIRM: ClassVar[str] = 'overlayConfirm'
|
||||||
|
ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
|
||||||
|
ID_OVERLAY_HAMBURGER: ClassVar[str] = 'overlayHamburger'
|
||||||
|
ID_PAGE_BODY: ClassVar[str] = 'pageBody'
|
||||||
|
ID_TABLE_MAIN: ClassVar[str] = 'tableMain'
|
||||||
|
ID_TEXTAREA_CONFIRM: ClassVar[str] = 'textareaConfirm'
|
||||||
|
NAME_COMPANY: ClassVar[str] = 'Shuffle & Skirmish'
|
||||||
|
NAME_COMPANY_SHORT: ClassVar[str] = 'Shuffle & Skirmish'
|
||||||
|
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
|
||||||
|
USERNAME_DISCORD: ClassVar[str] = 'Fetch Metrics'
|
||||||
|
USERNAME_FACEBOOK: ClassVar[str] = 'Fetch Metrics'
|
||||||
|
USERNAME_GITHUB: ClassVar[str] = 'Teddy-1024'
|
||||||
|
USERNAME_INSTAGRAM: ClassVar[str] = 'fetchmetrics'
|
||||||
|
USERNAME_LINKEDIN: ClassVar[str] = 'fetchmetrics'
|
||||||
|
USERNAME_REDDIT: ClassVar[str] = 'Fetch-Metrics'
|
||||||
|
USERNAME_TIKTOK: ClassVar[str] = 'fetchmetrics'
|
||||||
|
USERNAME_TWITTER: ClassVar[str] = 'FetchMetrics'
|
||||||
|
URL_DISCORD: ClassVar[str] = f'https://discord.gg/HBSvutXSZf'
|
||||||
|
URL_FACEBOOK: ClassVar[str] = 'https://www.facebook.com/profile.php?id=61579039227559'
|
||||||
|
URL_GITHUB: ClassVar[str] = f'https://github.com/{USERNAME_GITHUB}'
|
||||||
|
URL_INSTAGRAM: ClassVar[str] = f'https://www.instagram.com/{USERNAME_INSTAGRAM}/'
|
||||||
|
URL_LINKEDIN: ClassVar[str] = f'https://www.linkedin.com/company/{USERNAME_LINKEDIN}'
|
||||||
|
URL_LINKEDIN_PERSONAL: ClassVar[str] = f'https://www.linkedin.com/in/teddyms'
|
||||||
|
URL_REDDIT: ClassVar[str] = f'https://www.reddit.com/u/{USERNAME_REDDIT}/s/gZKEz2ZwHN'
|
||||||
|
URL_TIKTOK: ClassVar[str] = f'https://www.tiktok.com/@{USERNAME_TIKTOK}'
|
||||||
|
URL_TWITTER: ClassVar[str] = f'https://x.com/{USERNAME_TWITTER}'
|
||||||
|
|
||||||
|
_title: str
|
||||||
|
hash_page_current: str
|
||||||
|
app: Flask = None
|
||||||
|
session: None = None
|
||||||
|
is_user_logged_in: bool = None
|
||||||
|
user: User = None
|
||||||
|
access_levels: list = None
|
||||||
|
|
||||||
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
# @abstractmethod
|
||||||
|
def title(self):
|
||||||
|
if self._title is None:
|
||||||
|
raise NotImplementedError("Model Title required.")
|
||||||
|
return self._title
|
||||||
|
|
||||||
|
def __init__(self, hash_page_current, **kwargs):
|
||||||
|
BaseModel.__init__(self, hash_page_current=hash_page_current, **kwargs)
|
||||||
|
self.app = current_app
|
||||||
|
with self.app.app_context():
|
||||||
|
self.session = session
|
||||||
|
Helper_App.console_log(f'session: {self.session}')
|
||||||
|
|
||||||
|
datastore_base = DataStore_Base()
|
||||||
|
self.user = datastore_base.get_user_session()
|
||||||
|
self.is_user_logged_in = self.user.get_is_logged_in()
|
||||||
|
# Helper_App.console_log(f'model_view_base init end - model.user: {self.user}')
|
||||||
|
|
||||||
|
def get_url_host(self):
|
||||||
|
return self.app.config['URL_HOST']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def output_bool(boolean):
|
||||||
|
return str(boolean).lower()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_user_session():
|
||||||
|
datastore_user = DataStore_User()
|
||||||
|
return datastore_user.get_user_session()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_many_access_level(filters=None):
|
||||||
|
_m = 'Model_View_Store.get_many_access_level'
|
||||||
|
# av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||||
|
access_levels, errors = DataStore_Base.get_many_access_level(filters)
|
||||||
|
return access_levels
|
||||||
|
@staticmethod
|
||||||
|
def get_many_unit_measurement(filters=None):
|
||||||
|
_m = 'Model_View_Store.get_many_unit_measurement'
|
||||||
|
# av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
||||||
|
units_measurement, errors = DataStore_Base.get_many_unit_measurement(filters)
|
||||||
|
return units_measurement
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_json(list_objects):
|
||||||
|
return [obj.to_json() for obj in list_objects]
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_list_options(list_objects):
|
||||||
|
return Base.convert_list_objects_to_list_options(list_objects)
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_dict_by_attribute_key(list_objects, key):
|
||||||
|
return {getattr(obj, key): obj for obj in list_objects}
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_dict_json_by_attribute_key(list_objects, key):
|
||||||
|
return {getattr(obj, key): obj.to_json() for obj in list_objects}
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_dict_by_attribute_key_default(list_objects):
|
||||||
|
if list_objects is None or len(list_objects) == 0:
|
||||||
|
return {}
|
||||||
|
obj_class = list_objects[0].__class__
|
||||||
|
return Model_View_Base.convert_list_objects_to_dict_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_dict_json_by_attribute_key_default(list_objects):
|
||||||
|
if list_objects is None or len(list_objects) == 0:
|
||||||
|
return {}
|
||||||
|
obj_class = list_objects[0].__class__
|
||||||
|
return Model_View_Base.convert_list_objects_to_dict_json_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||||
|
@staticmethod
|
||||||
|
def convert_dict_values_to_json(dict):
|
||||||
|
return {key: dict[key].to_json() for key in dict.keys()}
|
||||||
|
@staticmethod
|
||||||
|
def convert_list_objects_to_preview_str(list_objects):
|
||||||
|
preview_str = ''
|
||||||
|
for obj in list_objects:
|
||||||
|
if preview_str != '':
|
||||||
|
preview_str += '\n'
|
||||||
|
obj_json = obj.to_json()
|
||||||
|
preview_str += obj_json[obj_json[Base.FLAG_NAME_ATTR_OPTION_TEXT]]
|
||||||
|
return preview_str
|
||||||
|
@staticmethod
|
||||||
|
def join_with_linebreaks(strs):
|
||||||
|
str_multiline = ''
|
||||||
|
for str in strs:
|
||||||
|
if str_multiline != '':
|
||||||
|
str_multiline += '\n'
|
||||||
|
str_multiline += str
|
||||||
|
return str_multiline
|
||||||
|
@staticmethod
|
||||||
|
def format_date(date):
|
||||||
|
if date is None:
|
||||||
|
return ''
|
||||||
|
return date.strftime('%Y-%m-%d')
|
||||||
|
@staticmethod
|
||||||
|
def format_datetime(date_time):
|
||||||
|
if date_time is None:
|
||||||
|
return ''
|
||||||
|
return date_time.strftime('%Y-%m-%dT%H:%M')
|
||||||
|
@staticmethod
|
||||||
|
def format_datetime_text(date_time):
|
||||||
|
if date_time is None:
|
||||||
|
return ''
|
||||||
|
return date_time.strftime('%d/%m/%Y %H:%M')
|
||||||
|
@staticmethod
|
||||||
|
def jsonify(data):
|
||||||
|
return jsonify(data)
|
||||||
|
def get_mail_contact_public(self):
|
||||||
|
return self.app.config['MAIL_CONTACT_PUBLIC']
|
||||||
|
@staticmethod
|
||||||
|
def format_null_string_as_blank(string):
|
||||||
|
return '' if string is None else string
|
||||||
22
models/model_view_license.py
Normal file
22
models/model_view_license.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Legal View Models
|
||||||
|
Feature: License View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for license view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
|
||||||
|
class Model_View_License(Model_View_Base):
|
||||||
|
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_LICENSE):
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'License'
|
||||||
|
|
||||||
66
models/model_view_mtg_base.py
Normal file
66
models/model_view_mtg_base.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: MTG Parent View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Parent data model for MTG views
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game, Parameters_MTG_Game
|
||||||
|
from business_objects.tcg.mtg_game_player import MTG_Game_Player, Parameters_MTG_Game_Player
|
||||||
|
from business_objects.tcg.mtg_game_round import MTG_Game_Round, Parameters_MTG_Game_Round
|
||||||
|
from business_objects.tcg.mtg_game_round_player_damage import MTG_Game_Round_Player_Damage, Parameters_MTG_Game_Round_Player_Damage
|
||||||
|
from business_objects.tcg.mtg_deck import MTG_Deck, Parameters_MTG_Deck
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# external
|
||||||
|
from flask import send_file, jsonify
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
import locale
|
||||||
|
from typing import ClassVar
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
class Model_View_MTG_Base(Model_View_Base):
|
||||||
|
ATTR_GAME_ID: ClassVar[str] = MTG_Game.ATTR_GAME_ID
|
||||||
|
ATTR_PLAYER_ID: ClassVar[str] = MTG_Game_Player.ATTR_PLAYER_ID
|
||||||
|
ATTR_ROUND_ID: ClassVar[str] = MTG_Game_Round.ATTR_ROUND_ID
|
||||||
|
ATTR_DAMAGE_ID: ClassVar[str] = MTG_Game_Round_Player_Damage.ATTR_DAMAGE_ID
|
||||||
|
ATTR_DECK_ID: ClassVar[str] = MTG_Deck.ATTR_DECK_ID
|
||||||
|
FLAG_COMMANDER_DEATHS: ClassVar[str] = MTG_Game_Round_Player_Damage.FLAG_COMMANDER_DEATHS
|
||||||
|
FLAG_DAMAGE: ClassVar[str] = MTG_Game_Round_Player_Damage.FLAG_DAMAGE
|
||||||
|
FLAG_DECK: ClassVar[str] = MTG_Deck.FLAG_DECK
|
||||||
|
FLAG_GAME: ClassVar[str] = MTG_Game.FLAG_GAME
|
||||||
|
FLAG_HEALTH_CHANGE: ClassVar[str] = MTG_Game_Round_Player_Damage.FLAG_HEALTH_CHANGE
|
||||||
|
FLAG_IS_COMMANDER: ClassVar[str] = MTG_Game.FLAG_IS_COMMANDER
|
||||||
|
FLAG_IS_DRAFT: ClassVar[str] = MTG_Game.FLAG_IS_DRAFT
|
||||||
|
FLAG_IS_SEALED: ClassVar[str] = MTG_Game.FLAG_IS_SEALED
|
||||||
|
FLAG_LOCATION_NAME: ClassVar[str] = MTG_Game.FLAG_LOCATION_NAME
|
||||||
|
FLAG_PLAYER: ClassVar[str] = MTG_Game_Player.FLAG_PLAYER
|
||||||
|
FLAG_ROUND: ClassVar[str] = MTG_Game_Round.FLAG_ROUND
|
||||||
|
FLAG_STARTING_LIFE: ClassVar[str] = MTG_Game.FLAG_STARTING_LIFE
|
||||||
|
HASH_GET_MTG_GAME_PLAYERS: ClassVar[str] = '/mtg/api/game/<game_id>/players'
|
||||||
|
HASH_GET_MTG_GAME_ROUNDS: ClassVar[str] = '/mtg/api/game/<game_id>/rounds'
|
||||||
|
HASH_GET_MTG_GAME_DAMAGE_RECORDS: ClassVar[str] = '/mtg/api/game/<game_id>/damage-records'
|
||||||
|
HASH_SAVE_MTG_GAME: ClassVar[str] = '/mtg/save-game'
|
||||||
|
HASH_SAVE_MTG_GAME_PLAYER: ClassVar[str] = '/mtg/save-game-player'
|
||||||
|
HASH_SAVE_MTG_GAME_ROUND: ClassVar[str] = '/mtg/save-game-round'
|
||||||
|
HASH_SAVE_MTG_GAME_ROUND_PLAYER_DAMAGE: ClassVar[str] = '/mtg/save-game-round-player-damage'
|
||||||
|
HASH_SAVE_MTG_DECK: ClassVar[str] = '/mtg/save-deck'
|
||||||
|
|
||||||
|
is_page_mtg: bool = True
|
||||||
|
|
||||||
|
def __init__(self, hash_page_current, **kwargs):
|
||||||
|
_m = 'Model_View_MTG_Base.__init__'
|
||||||
|
Helper_App.console_log(f'{_m}\nstarting')
|
||||||
|
super().__init__(hash_page_current=hash_page_current, **kwargs)
|
||||||
|
self.is_page_mtg = True
|
||||||
|
if self.hash_page_current == Model_View_MTG_Base.HASH_PAGE_MTG_TRIAL_GAME:
|
||||||
|
self._title = 'MTG Home'
|
||||||
98
models/model_view_mtg_game.py
Normal file
98
models/model_view_mtg_game.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: MTG Games View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for MTG games view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.tcg.mtg_deck import MTG_Deck, Parameters_MTG_Deck
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game, Parameters_MTG_Game
|
||||||
|
from business_objects.tcg.mtg_game_player import MTG_Game_Player, Parameters_MTG_Game_Player
|
||||||
|
from business_objects.tcg.mtg_game_round import MTG_Game_Round, Parameters_MTG_Game_Round
|
||||||
|
from business_objects.tcg.mtg_game_round_player_damage import MTG_Game_Round_Player_Damage, Parameters_MTG_Game_Round_Player_Damage
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_mtg import DataStore_MTG
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from models.model_view_mtg_base import Model_View_MTG_Base
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
|
||||||
|
# external
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class Model_View_MTG_Game(Model_View_MTG_Base):
|
||||||
|
ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID: ClassVar[str] = MTG_Game_Round_Player_Damage.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID
|
||||||
|
FLAG_IS_ELIMINATED: ClassVar[str] = MTG_Game_Round_Player_Damage.FLAG_IS_ELIMINATED
|
||||||
|
PLAYER_SETUP_WRAPPER_TEMPLATE_ID: ClassVar[str] = 'player-setup-wrapper-template'
|
||||||
|
|
||||||
|
damage_records: list = None
|
||||||
|
decks: list = None
|
||||||
|
game: MTG_Game = None
|
||||||
|
players: list = None
|
||||||
|
rounds: list = None
|
||||||
|
users: list = None
|
||||||
|
"""
|
||||||
|
parameters_player: Parameters_MTG_Game_Player = None
|
||||||
|
parameters_round: Parameters_MTG_Game_Round = None
|
||||||
|
parameters_damage: Parameters_MTG_Game_Round_Player_Damage = None
|
||||||
|
parameters_deck: Parameters_MTG_Deck = None
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, game_id, hash_page_current=Model_View_MTG_Base.HASH_PAGE_MTG_GAME):
|
||||||
|
_m = 'Model_View_MTG_Game.__init__'
|
||||||
|
Helper_App.console_log(f'{_m}\nstarting...')
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'MTG Game'
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
|
||||||
|
# Get the specific game
|
||||||
|
parameters_game = Parameters_MTG_Game.get_default(user_session.user_id)
|
||||||
|
parameters_game.game_ids = str(game_id)
|
||||||
|
parameters_game.get_all_game = False
|
||||||
|
games, errors = datastore.get_many_mtg_game(parameters_game)
|
||||||
|
if len(games) > 0:
|
||||||
|
self.game = games[0]
|
||||||
|
|
||||||
|
# Get all decks
|
||||||
|
parameters_deck = Parameters_MTG_Deck.get_default()
|
||||||
|
parameters_deck.get_all_deck = True
|
||||||
|
parameters_deck.require_all_id_filters_met = False
|
||||||
|
parameters_deck.require_any_id_filters_met = False
|
||||||
|
parameters_deck.require_all_non_id_filters_met = False
|
||||||
|
parameters_deck.require_any_non_id_filters_met = False
|
||||||
|
self.decks, errors = datastore.get_many_mtg_deck(parameters_deck)
|
||||||
|
|
||||||
|
# Get all users
|
||||||
|
parameters_user = Parameters_User.get_default()
|
||||||
|
parameters_user.get_all_user = True
|
||||||
|
parameters_user.require_all_id_filters_met = False
|
||||||
|
parameters_user.require_any_id_filters_met = False
|
||||||
|
self.users, errors = DataStore_User.get_many_user(parameters_user)
|
||||||
|
|
||||||
|
# Get players for this game
|
||||||
|
parameters_player = Parameters_MTG_Game_Player.get_default(user_session.user_id)
|
||||||
|
parameters_player.get_all_game = False
|
||||||
|
parameters_player.game_ids = str(game_id)
|
||||||
|
self.players, errors = datastore.get_many_mtg_game_player(parameters_player)
|
||||||
|
|
||||||
|
# Get rounds for this game
|
||||||
|
parameters_round = Parameters_MTG_Game_Round.get_default(user_session.user_id)
|
||||||
|
parameters_round.get_all_game = False
|
||||||
|
parameters_round.game_ids = str(game_id)
|
||||||
|
self.rounds, errors = datastore.get_many_mtg_game_round(parameters_round)
|
||||||
|
|
||||||
|
# Get damage for this game
|
||||||
|
parameters_damage = Parameters_MTG_Game_Round_Player_Damage.get_default(user_session.user_id)
|
||||||
|
parameters_damage.get_all_game = False
|
||||||
|
parameters_damage.game_ids = str(game_id)
|
||||||
|
self.damage_records, errors = datastore.get_many_mtg_game_round_player_damage(parameters_damage)
|
||||||
|
|
||||||
45
models/model_view_mtg_games.py
Normal file
45
models/model_view_mtg_games.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: MTG Games View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for MTG games view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.tcg.mtg_game import MTG_Game, Parameters_MTG_Game
|
||||||
|
from datastores.datastore_mtg import DataStore_MTG
|
||||||
|
from models.model_view_mtg_base import Model_View_MTG_Base
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
|
||||||
|
# external
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class Model_View_MTG_Games(Model_View_MTG_Base):
|
||||||
|
form_filters: object = None
|
||||||
|
games: list = None
|
||||||
|
parameters_game: Parameters_MTG_Game = None
|
||||||
|
|
||||||
|
def __init__(self, parameters_game=None, hash_page_current=Model_View_MTG_Base.HASH_PAGE_MTG_GAMES):
|
||||||
|
_m = 'Model_View_MTG_Games.__init__'
|
||||||
|
Helper_App.console_log(f'{_m}\nstarting...')
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'MTG Games'
|
||||||
|
datastore = DataStore_MTG()
|
||||||
|
|
||||||
|
# Initialize parameters with defaults if not provided
|
||||||
|
if parameters_game is None:
|
||||||
|
user_session = datastore.get_user_session()
|
||||||
|
self.parameters_game = Parameters_MTG_Game.get_default(user_session.user_id)
|
||||||
|
else:
|
||||||
|
self.parameters_game = parameters_game
|
||||||
|
|
||||||
|
Helper_App.console_log(f'Query args: {self.parameters_game}')
|
||||||
|
self.games, errors = datastore.get_many_mtg_game(self.parameters_game)
|
||||||
32
models/model_view_mtg_home.py
Normal file
32
models/model_view_mtg_home.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: MTG Games View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for MTG games view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_mtg import DataStore_MTG
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from models.model_view_mtg_base import Model_View_MTG_Base
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
import lib.argument_validation as av
|
||||||
|
|
||||||
|
# external
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
|
class Model_View_MTG_Home(Model_View_MTG_Base):
|
||||||
|
|
||||||
|
def __init__(self, hash_page_current=Model_View_MTG_Base.HASH_PAGE_MTG_HOME):
|
||||||
|
_m = 'Model_View_MTG_Home.__init__'
|
||||||
|
Helper_App.console_log(f'{_m}\nstarting...')
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'MTG Home'
|
||||||
22
models/model_view_privacy_policy.py
Normal file
22
models/model_view_privacy_policy.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Legal View Models
|
||||||
|
Feature: Privacy Policy View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for privacy policy view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
|
||||||
|
class Model_View_Privacy_Policy(Model_View_Base):
|
||||||
|
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_PRIVACY_POLICY):
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'Privacy Policy'
|
||||||
|
|
||||||
22
models/model_view_retention_schedule.py
Normal file
22
models/model_view_retention_schedule.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: Legal View Models
|
||||||
|
Feature: Retention Schedule View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for retention schedule view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
|
||||||
|
class Model_View_Retention_Schedule(Model_View_Base):
|
||||||
|
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_DATA_RETENTION_SCHEDULE):
|
||||||
|
super().__init__(hash_page_current=hash_page_current)
|
||||||
|
self._title = 'Retention Schedule'
|
||||||
|
|
||||||
49
models/model_view_user.py
Normal file
49
models/model_view_user.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"""
|
||||||
|
Project: PARTS Website
|
||||||
|
Author: Edward Middleton-Smith
|
||||||
|
Precision And Research Technology Systems Limited
|
||||||
|
|
||||||
|
Technology: View Models
|
||||||
|
Feature: User View Model
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Data model for user view
|
||||||
|
"""
|
||||||
|
|
||||||
|
# internal
|
||||||
|
from business_objects.tcg.user import User, Parameters_User
|
||||||
|
from datastores.datastore_user import DataStore_User
|
||||||
|
from mtg_commander_life_tracker.forms.tcg.user import Filters_User
|
||||||
|
from helpers.helper_app import Helper_App
|
||||||
|
from models.model_view_base import Model_View_Base
|
||||||
|
# from routes import bp_home
|
||||||
|
# external
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
class Model_View_User(Model_View_Base):
|
||||||
|
FLAG_ERROR_OAUTH: ClassVar[str] = 'error'
|
||||||
|
FLAG_ERROR_DESCRIPTION_OAUTH: ClassVar[str] = 'error_description'
|
||||||
|
FLAG_FIRSTNAME: ClassVar[str] = User.FLAG_FIRSTNAME
|
||||||
|
FLAG_IS_EMAIL_VERIFIED: ClassVar[str] = User.FLAG_IS_EMAIL_VERIFIED
|
||||||
|
FLAG_IS_SUPER_USER: ClassVar[str] = User.FLAG_IS_SUPER_USER
|
||||||
|
FLAG_SURNAME: ClassVar[str] = User.FLAG_SURNAME
|
||||||
|
FLAG_STATE_OAUTH: ClassVar[str] = 'state'
|
||||||
|
form_filters: Filters_User = None
|
||||||
|
form_filters_old: Filters_User
|
||||||
|
users: list = None
|
||||||
|
|
||||||
|
def __init__(self, form_filters_old, hash_page_current = Model_View_Base.HASH_PAGE_USER_ACCOUNT):
|
||||||
|
super().__init__(hash_page_current = hash_page_current, form_filters_old = form_filters_old)
|
||||||
|
self._title = 'Users'
|
||||||
|
self.form_filters = form_filters_old
|
||||||
|
|
||||||
|
Helper_App.console_log(f'Form filters: {self.form_filters}')
|
||||||
|
|
||||||
|
datastore = DataStore_User()
|
||||||
|
|
||||||
|
parameters_user = Parameters_User.from_form_filters_user(self.form_filters)
|
||||||
|
if self.hash_page_current == Model_View_Base.HASH_PAGE_USER_ACCOUNT:
|
||||||
|
parameters_user.user_ids = str(self.user.user_id)
|
||||||
|
Helper_App.console_log(f'Query args: {parameters_user}')
|
||||||
|
self.users, errors = datastore.get_many_user(parameters_user)
|
||||||
|
|
||||||
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../acorn/bin/acorn
|
||||||
1
node_modules/.bin/baseline-browser-mapping
generated
vendored
Symbolic link
1
node_modules/.bin/baseline-browser-mapping
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../baseline-browser-mapping/dist/cli.js
|
||||||
1
node_modules/.bin/browserslist
generated
vendored
Symbolic link
1
node_modules/.bin/browserslist
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../browserslist/cli.js
|
||||||
1
node_modules/.bin/cssesc
generated
vendored
Symbolic link
1
node_modules/.bin/cssesc
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../cssesc/bin/cssesc
|
||||||
1
node_modules/.bin/envinfo
generated
vendored
Symbolic link
1
node_modules/.bin/envinfo
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../envinfo/dist/cli.js
|
||||||
1
node_modules/.bin/flat
generated
vendored
Symbolic link
1
node_modules/.bin/flat
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../flat/cli.js
|
||||||
1
node_modules/.bin/glob
generated
vendored
Symbolic link
1
node_modules/.bin/glob
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../glob/dist/esm/bin.mjs
|
||||||
1
node_modules/.bin/import-local-fixture
generated
vendored
Symbolic link
1
node_modules/.bin/import-local-fixture
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../import-local/fixtures/cli.js
|
||||||
1
node_modules/.bin/jsesc
generated
vendored
Symbolic link
1
node_modules/.bin/jsesc
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../jsesc/bin/jsesc
|
||||||
1
node_modules/.bin/json5
generated
vendored
Symbolic link
1
node_modules/.bin/json5
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../json5/lib/cli.js
|
||||||
1
node_modules/.bin/nanoid
generated
vendored
Symbolic link
1
node_modules/.bin/nanoid
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../nanoid/bin/nanoid.cjs
|
||||||
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../which/bin/node-which
|
||||||
1
node_modules/.bin/parser
generated
vendored
Symbolic link
1
node_modules/.bin/parser
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../@babel/parser/bin/babel-parser.js
|
||||||
1
node_modules/.bin/regjsparser
generated
vendored
Symbolic link
1
node_modules/.bin/regjsparser
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../regjsparser/bin/parser
|
||||||
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../resolve/bin/resolve
|
||||||
1
node_modules/.bin/semver
generated
vendored
Symbolic link
1
node_modules/.bin/semver
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../semver/bin/semver.js
|
||||||
1
node_modules/.bin/terser
generated
vendored
Symbolic link
1
node_modules/.bin/terser
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../terser/bin/terser
|
||||||
1
node_modules/.bin/update-browserslist-db
generated
vendored
Symbolic link
1
node_modules/.bin/update-browserslist-db
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../update-browserslist-db/cli.js
|
||||||
1
node_modules/.bin/webpack
generated
vendored
Symbolic link
1
node_modules/.bin/webpack
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../webpack/bin/webpack.js
|
||||||
1
node_modules/.bin/webpack-cli
generated
vendored
Symbolic link
1
node_modules/.bin/webpack-cli
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../webpack-cli/bin/cli.js
|
||||||
4197
node_modules/.package-lock.json
generated
vendored
Normal file
4197
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
node_modules/@babel/code-frame/LICENSE
generated
vendored
Normal file
22
node_modules/@babel/code-frame/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
19
node_modules/@babel/code-frame/README.md
generated
vendored
Normal file
19
node_modules/@babel/code-frame/README.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# @babel/code-frame
|
||||||
|
|
||||||
|
> Generate errors that contain a code frame that point to source locations.
|
||||||
|
|
||||||
|
See our website [@babel/code-frame](https://babeljs.io/docs/babel-code-frame) for more information.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Using npm:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save-dev @babel/code-frame
|
||||||
|
```
|
||||||
|
|
||||||
|
or using yarn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @babel/code-frame --dev
|
||||||
|
```
|
||||||
217
node_modules/@babel/code-frame/lib/index.js
generated
vendored
Normal file
217
node_modules/@babel/code-frame/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
var picocolors = require('picocolors');
|
||||||
|
var jsTokens = require('js-tokens');
|
||||||
|
var helperValidatorIdentifier = require('@babel/helper-validator-identifier');
|
||||||
|
|
||||||
|
function isColorSupported() {
|
||||||
|
return (typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? false : picocolors.isColorSupported
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const compose = (f, g) => v => f(g(v));
|
||||||
|
function buildDefs(colors) {
|
||||||
|
return {
|
||||||
|
keyword: colors.cyan,
|
||||||
|
capitalized: colors.yellow,
|
||||||
|
jsxIdentifier: colors.yellow,
|
||||||
|
punctuator: colors.yellow,
|
||||||
|
number: colors.magenta,
|
||||||
|
string: colors.green,
|
||||||
|
regex: colors.magenta,
|
||||||
|
comment: colors.gray,
|
||||||
|
invalid: compose(compose(colors.white, colors.bgRed), colors.bold),
|
||||||
|
gutter: colors.gray,
|
||||||
|
marker: compose(colors.red, colors.bold),
|
||||||
|
message: compose(colors.red, colors.bold),
|
||||||
|
reset: colors.reset
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const defsOn = buildDefs(picocolors.createColors(true));
|
||||||
|
const defsOff = buildDefs(picocolors.createColors(false));
|
||||||
|
function getDefs(enabled) {
|
||||||
|
return enabled ? defsOn : defsOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sometimesKeywords = new Set(["as", "async", "from", "get", "of", "set"]);
|
||||||
|
const NEWLINE$1 = /\r\n|[\n\r\u2028\u2029]/;
|
||||||
|
const BRACKET = /^[()[\]{}]$/;
|
||||||
|
let tokenize;
|
||||||
|
const JSX_TAG = /^[a-z][\w-]*$/i;
|
||||||
|
const getTokenType = function (token, offset, text) {
|
||||||
|
if (token.type === "name") {
|
||||||
|
const tokenValue = token.value;
|
||||||
|
if (helperValidatorIdentifier.isKeyword(tokenValue) || helperValidatorIdentifier.isStrictReservedWord(tokenValue, true) || sometimesKeywords.has(tokenValue)) {
|
||||||
|
return "keyword";
|
||||||
|
}
|
||||||
|
if (JSX_TAG.test(tokenValue) && (text[offset - 1] === "<" || text.slice(offset - 2, offset) === "</")) {
|
||||||
|
return "jsxIdentifier";
|
||||||
|
}
|
||||||
|
const firstChar = String.fromCodePoint(tokenValue.codePointAt(0));
|
||||||
|
if (firstChar !== firstChar.toLowerCase()) {
|
||||||
|
return "capitalized";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token.type === "punctuator" && BRACKET.test(token.value)) {
|
||||||
|
return "bracket";
|
||||||
|
}
|
||||||
|
if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
|
||||||
|
return "punctuator";
|
||||||
|
}
|
||||||
|
return token.type;
|
||||||
|
};
|
||||||
|
tokenize = function* (text) {
|
||||||
|
let match;
|
||||||
|
while (match = jsTokens.default.exec(text)) {
|
||||||
|
const token = jsTokens.matchToToken(match);
|
||||||
|
yield {
|
||||||
|
type: getTokenType(token, match.index, text),
|
||||||
|
value: token.value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function highlight(text) {
|
||||||
|
if (text === "") return "";
|
||||||
|
const defs = getDefs(true);
|
||||||
|
let highlighted = "";
|
||||||
|
for (const {
|
||||||
|
type,
|
||||||
|
value
|
||||||
|
} of tokenize(text)) {
|
||||||
|
if (type in defs) {
|
||||||
|
highlighted += value.split(NEWLINE$1).map(str => defs[type](str)).join("\n");
|
||||||
|
} else {
|
||||||
|
highlighted += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
let deprecationWarningShown = false;
|
||||||
|
const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
|
||||||
|
function getMarkerLines(loc, source, opts, startLineBaseZero) {
|
||||||
|
const startLoc = Object.assign({
|
||||||
|
column: 0,
|
||||||
|
line: -1
|
||||||
|
}, loc.start);
|
||||||
|
const endLoc = Object.assign({}, startLoc, loc.end);
|
||||||
|
const {
|
||||||
|
linesAbove = 2,
|
||||||
|
linesBelow = 3
|
||||||
|
} = opts || {};
|
||||||
|
const startLine = startLoc.line - startLineBaseZero;
|
||||||
|
const startColumn = startLoc.column;
|
||||||
|
const endLine = endLoc.line - startLineBaseZero;
|
||||||
|
const endColumn = endLoc.column;
|
||||||
|
let start = Math.max(startLine - (linesAbove + 1), 0);
|
||||||
|
let end = Math.min(source.length, endLine + linesBelow);
|
||||||
|
if (startLine === -1) {
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
if (endLine === -1) {
|
||||||
|
end = source.length;
|
||||||
|
}
|
||||||
|
const lineDiff = endLine - startLine;
|
||||||
|
const markerLines = {};
|
||||||
|
if (lineDiff) {
|
||||||
|
for (let i = 0; i <= lineDiff; i++) {
|
||||||
|
const lineNumber = i + startLine;
|
||||||
|
if (!startColumn) {
|
||||||
|
markerLines[lineNumber] = true;
|
||||||
|
} else if (i === 0) {
|
||||||
|
const sourceLength = source[lineNumber - 1].length;
|
||||||
|
markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
|
||||||
|
} else if (i === lineDiff) {
|
||||||
|
markerLines[lineNumber] = [0, endColumn];
|
||||||
|
} else {
|
||||||
|
const sourceLength = source[lineNumber - i].length;
|
||||||
|
markerLines[lineNumber] = [0, sourceLength];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (startColumn === endColumn) {
|
||||||
|
if (startColumn) {
|
||||||
|
markerLines[startLine] = [startColumn, 0];
|
||||||
|
} else {
|
||||||
|
markerLines[startLine] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
markerLines[startLine] = [startColumn, endColumn - startColumn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
markerLines
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function codeFrameColumns(rawLines, loc, opts = {}) {
|
||||||
|
const shouldHighlight = opts.forceColor || isColorSupported() && opts.highlightCode;
|
||||||
|
const startLineBaseZero = (opts.startLine || 1) - 1;
|
||||||
|
const defs = getDefs(shouldHighlight);
|
||||||
|
const lines = rawLines.split(NEWLINE);
|
||||||
|
const {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
markerLines
|
||||||
|
} = getMarkerLines(loc, lines, opts, startLineBaseZero);
|
||||||
|
const hasColumns = loc.start && typeof loc.start.column === "number";
|
||||||
|
const numberMaxWidth = String(end + startLineBaseZero).length;
|
||||||
|
const highlightedLines = shouldHighlight ? highlight(rawLines) : rawLines;
|
||||||
|
let frame = highlightedLines.split(NEWLINE, end).slice(start, end).map((line, index) => {
|
||||||
|
const number = start + 1 + index;
|
||||||
|
const paddedNumber = ` ${number + startLineBaseZero}`.slice(-numberMaxWidth);
|
||||||
|
const gutter = ` ${paddedNumber} |`;
|
||||||
|
const hasMarker = markerLines[number];
|
||||||
|
const lastMarkerLine = !markerLines[number + 1];
|
||||||
|
if (hasMarker) {
|
||||||
|
let markerLine = "";
|
||||||
|
if (Array.isArray(hasMarker)) {
|
||||||
|
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
|
||||||
|
const numberOfMarkers = hasMarker[1] || 1;
|
||||||
|
markerLine = ["\n ", defs.gutter(gutter.replace(/\d/g, " ")), " ", markerSpacing, defs.marker("^").repeat(numberOfMarkers)].join("");
|
||||||
|
if (lastMarkerLine && opts.message) {
|
||||||
|
markerLine += " " + defs.message(opts.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [defs.marker(">"), defs.gutter(gutter), line.length > 0 ? ` ${line}` : "", markerLine].join("");
|
||||||
|
} else {
|
||||||
|
return ` ${defs.gutter(gutter)}${line.length > 0 ? ` ${line}` : ""}`;
|
||||||
|
}
|
||||||
|
}).join("\n");
|
||||||
|
if (opts.message && !hasColumns) {
|
||||||
|
frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
|
||||||
|
}
|
||||||
|
if (shouldHighlight) {
|
||||||
|
return defs.reset(frame);
|
||||||
|
} else {
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function index (rawLines, lineNumber, colNumber, opts = {}) {
|
||||||
|
if (!deprecationWarningShown) {
|
||||||
|
deprecationWarningShown = true;
|
||||||
|
const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
|
||||||
|
if (process.emitWarning) {
|
||||||
|
process.emitWarning(message, "DeprecationWarning");
|
||||||
|
} else {
|
||||||
|
const deprecationError = new Error(message);
|
||||||
|
deprecationError.name = "DeprecationWarning";
|
||||||
|
console.warn(new Error(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colNumber = Math.max(colNumber, 0);
|
||||||
|
const location = {
|
||||||
|
start: {
|
||||||
|
column: colNumber,
|
||||||
|
line: lineNumber
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return codeFrameColumns(rawLines, location, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.codeFrameColumns = codeFrameColumns;
|
||||||
|
exports.default = index;
|
||||||
|
exports.highlight = highlight;
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
node_modules/@babel/code-frame/lib/index.js.map
generated
vendored
Normal file
1
node_modules/@babel/code-frame/lib/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
32
node_modules/@babel/code-frame/package.json
generated
vendored
Normal file
32
node_modules/@babel/code-frame/package.json
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@babel/code-frame",
|
||||||
|
"version": "7.29.0",
|
||||||
|
"description": "Generate errors that contain a code frame that point to source locations.",
|
||||||
|
"author": "The Babel Team (https://babel.dev/team)",
|
||||||
|
"homepage": "https://babel.dev/docs/en/next/babel-code-frame",
|
||||||
|
"bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen",
|
||||||
|
"license": "MIT",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/babel/babel.git",
|
||||||
|
"directory": "packages/babel-code-frame"
|
||||||
|
},
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-validator-identifier": "^7.28.5",
|
||||||
|
"js-tokens": "^4.0.0",
|
||||||
|
"picocolors": "^1.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"charcodes": "^0.2.0",
|
||||||
|
"import-meta-resolve": "^4.1.0",
|
||||||
|
"strip-ansi": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
},
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
22
node_modules/@babel/compat-data/LICENSE
generated
vendored
Normal file
22
node_modules/@babel/compat-data/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
19
node_modules/@babel/compat-data/README.md
generated
vendored
Normal file
19
node_modules/@babel/compat-data/README.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# @babel/compat-data
|
||||||
|
|
||||||
|
> The compat-data to determine required Babel plugins
|
||||||
|
|
||||||
|
See our website [@babel/compat-data](https://babeljs.io/docs/babel-compat-data) for more information.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Using npm:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save @babel/compat-data
|
||||||
|
```
|
||||||
|
|
||||||
|
or using yarn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @babel/compat-data
|
||||||
|
```
|
||||||
2
node_modules/@babel/compat-data/corejs2-built-ins.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/corejs2-built-ins.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file as Babel 8 drop support of core-js 2
|
||||||
|
module.exports = require("./data/corejs2-built-ins.json");
|
||||||
2
node_modules/@babel/compat-data/corejs3-shipped-proposals.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/corejs3-shipped-proposals.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file now that it is included in babel-plugin-polyfill-corejs3
|
||||||
|
module.exports = require("./data/corejs3-shipped-proposals.json");
|
||||||
2106
node_modules/@babel/compat-data/data/corejs2-built-ins.json
generated
vendored
Normal file
2106
node_modules/@babel/compat-data/data/corejs2-built-ins.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
node_modules/@babel/compat-data/data/corejs3-shipped-proposals.json
generated
vendored
Normal file
5
node_modules/@babel/compat-data/data/corejs3-shipped-proposals.json
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
"esnext.promise.all-settled",
|
||||||
|
"esnext.string.match-all",
|
||||||
|
"esnext.global-this"
|
||||||
|
]
|
||||||
18
node_modules/@babel/compat-data/data/native-modules.json
generated
vendored
Normal file
18
node_modules/@babel/compat-data/data/native-modules.json
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"es6.module": {
|
||||||
|
"chrome": "61",
|
||||||
|
"and_chr": "61",
|
||||||
|
"edge": "16",
|
||||||
|
"firefox": "60",
|
||||||
|
"and_ff": "60",
|
||||||
|
"node": "13.2.0",
|
||||||
|
"opera": "48",
|
||||||
|
"op_mob": "45",
|
||||||
|
"safari": "10.1",
|
||||||
|
"ios": "10.3",
|
||||||
|
"samsung": "8.2",
|
||||||
|
"android": "61",
|
||||||
|
"electron": "2.0",
|
||||||
|
"ios_saf": "10.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
35
node_modules/@babel/compat-data/data/overlapping-plugins.json
generated
vendored
Normal file
35
node_modules/@babel/compat-data/data/overlapping-plugins.json
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"transform-async-to-generator": [
|
||||||
|
"bugfix/transform-async-arrows-in-class"
|
||||||
|
],
|
||||||
|
"transform-parameters": [
|
||||||
|
"bugfix/transform-edge-default-parameters",
|
||||||
|
"bugfix/transform-safari-id-destructuring-collision-in-function-expression"
|
||||||
|
],
|
||||||
|
"transform-function-name": [
|
||||||
|
"bugfix/transform-edge-function-name"
|
||||||
|
],
|
||||||
|
"transform-block-scoping": [
|
||||||
|
"bugfix/transform-safari-block-shadowing",
|
||||||
|
"bugfix/transform-safari-for-shadowing"
|
||||||
|
],
|
||||||
|
"transform-template-literals": [
|
||||||
|
"bugfix/transform-tagged-template-caching"
|
||||||
|
],
|
||||||
|
"transform-optional-chaining": [
|
||||||
|
"bugfix/transform-v8-spread-parameters-in-optional-chaining"
|
||||||
|
],
|
||||||
|
"proposal-optional-chaining": [
|
||||||
|
"bugfix/transform-v8-spread-parameters-in-optional-chaining"
|
||||||
|
],
|
||||||
|
"transform-class-properties": [
|
||||||
|
"bugfix/transform-v8-static-class-fields-redefine-readonly",
|
||||||
|
"bugfix/transform-firefox-class-in-computed-class-key",
|
||||||
|
"bugfix/transform-safari-class-field-initializer-scope"
|
||||||
|
],
|
||||||
|
"proposal-class-properties": [
|
||||||
|
"bugfix/transform-v8-static-class-fields-redefine-readonly",
|
||||||
|
"bugfix/transform-firefox-class-in-computed-class-key",
|
||||||
|
"bugfix/transform-safari-class-field-initializer-scope"
|
||||||
|
]
|
||||||
|
}
|
||||||
203
node_modules/@babel/compat-data/data/plugin-bugfixes.json
generated
vendored
Normal file
203
node_modules/@babel/compat-data/data/plugin-bugfixes.json
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
{
|
||||||
|
"bugfix/transform-async-arrows-in-class": {
|
||||||
|
"chrome": "55",
|
||||||
|
"opera": "42",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "11",
|
||||||
|
"node": "7.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11",
|
||||||
|
"samsung": "6",
|
||||||
|
"opera_mobile": "42",
|
||||||
|
"electron": "1.6"
|
||||||
|
},
|
||||||
|
"bugfix/transform-edge-default-parameters": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "18",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"bugfix/transform-edge-function-name": {
|
||||||
|
"chrome": "51",
|
||||||
|
"opera": "38",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.2"
|
||||||
|
},
|
||||||
|
"bugfix/transform-safari-block-shadowing": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "44",
|
||||||
|
"safari": "11",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "11",
|
||||||
|
"ios": "11",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"bugfix/transform-safari-for-shadowing": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "4",
|
||||||
|
"safari": "11",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "11",
|
||||||
|
"ios": "11",
|
||||||
|
"samsung": "5",
|
||||||
|
"rhino": "1.7.13",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"bugfix/transform-safari-id-destructuring-collision-in-function-expression": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "2",
|
||||||
|
"safari": "16.3",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "16.3",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"bugfix/transform-tagged-template-caching": {
|
||||||
|
"chrome": "41",
|
||||||
|
"opera": "28",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "34",
|
||||||
|
"safari": "13",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13",
|
||||||
|
"samsung": "3.4",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "28",
|
||||||
|
"electron": "0.21"
|
||||||
|
},
|
||||||
|
"bugfix/transform-v8-spread-parameters-in-optional-chaining": {
|
||||||
|
"chrome": "91",
|
||||||
|
"opera": "77",
|
||||||
|
"edge": "91",
|
||||||
|
"firefox": "74",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "16.9",
|
||||||
|
"deno": "1.9",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "16",
|
||||||
|
"opera_mobile": "64",
|
||||||
|
"electron": "13.0"
|
||||||
|
},
|
||||||
|
"transform-optional-chaining": {
|
||||||
|
"chrome": "80",
|
||||||
|
"opera": "67",
|
||||||
|
"edge": "80",
|
||||||
|
"firefox": "74",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "14",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "13",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "57",
|
||||||
|
"electron": "8.0"
|
||||||
|
},
|
||||||
|
"proposal-optional-chaining": {
|
||||||
|
"chrome": "80",
|
||||||
|
"opera": "67",
|
||||||
|
"edge": "80",
|
||||||
|
"firefox": "74",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "14",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "13",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "57",
|
||||||
|
"electron": "8.0"
|
||||||
|
},
|
||||||
|
"transform-parameters": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"transform-async-to-generator": {
|
||||||
|
"chrome": "55",
|
||||||
|
"opera": "42",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "10.1",
|
||||||
|
"node": "7.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10.3",
|
||||||
|
"samsung": "6",
|
||||||
|
"opera_mobile": "42",
|
||||||
|
"electron": "1.6"
|
||||||
|
},
|
||||||
|
"transform-template-literals": {
|
||||||
|
"chrome": "41",
|
||||||
|
"opera": "28",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "34",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "3.4",
|
||||||
|
"opera_mobile": "28",
|
||||||
|
"electron": "0.21"
|
||||||
|
},
|
||||||
|
"transform-function-name": {
|
||||||
|
"chrome": "51",
|
||||||
|
"opera": "38",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.2"
|
||||||
|
},
|
||||||
|
"transform-block-scoping": {
|
||||||
|
"chrome": "50",
|
||||||
|
"opera": "37",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "37",
|
||||||
|
"electron": "1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
838
node_modules/@babel/compat-data/data/plugins.json
generated
vendored
Normal file
838
node_modules/@babel/compat-data/data/plugins.json
generated
vendored
Normal file
@@ -0,0 +1,838 @@
|
|||||||
|
{
|
||||||
|
"transform-explicit-resource-management": {
|
||||||
|
"chrome": "134",
|
||||||
|
"edge": "134",
|
||||||
|
"firefox": "141",
|
||||||
|
"node": "24",
|
||||||
|
"electron": "35.0"
|
||||||
|
},
|
||||||
|
"transform-duplicate-named-capturing-groups-regex": {
|
||||||
|
"chrome": "126",
|
||||||
|
"opera": "112",
|
||||||
|
"edge": "126",
|
||||||
|
"firefox": "129",
|
||||||
|
"safari": "17.4",
|
||||||
|
"node": "23",
|
||||||
|
"ios": "17.4",
|
||||||
|
"electron": "31.0"
|
||||||
|
},
|
||||||
|
"transform-regexp-modifiers": {
|
||||||
|
"chrome": "125",
|
||||||
|
"opera": "111",
|
||||||
|
"edge": "125",
|
||||||
|
"firefox": "132",
|
||||||
|
"node": "23",
|
||||||
|
"samsung": "27",
|
||||||
|
"electron": "31.0"
|
||||||
|
},
|
||||||
|
"transform-unicode-sets-regex": {
|
||||||
|
"chrome": "112",
|
||||||
|
"opera": "98",
|
||||||
|
"edge": "112",
|
||||||
|
"firefox": "116",
|
||||||
|
"safari": "17",
|
||||||
|
"node": "20",
|
||||||
|
"deno": "1.32",
|
||||||
|
"ios": "17",
|
||||||
|
"samsung": "23",
|
||||||
|
"opera_mobile": "75",
|
||||||
|
"electron": "24.0"
|
||||||
|
},
|
||||||
|
"bugfix/transform-v8-static-class-fields-redefine-readonly": {
|
||||||
|
"chrome": "98",
|
||||||
|
"opera": "84",
|
||||||
|
"edge": "98",
|
||||||
|
"firefox": "75",
|
||||||
|
"safari": "15",
|
||||||
|
"node": "12",
|
||||||
|
"deno": "1.18",
|
||||||
|
"ios": "15",
|
||||||
|
"samsung": "11",
|
||||||
|
"opera_mobile": "52",
|
||||||
|
"electron": "17.0"
|
||||||
|
},
|
||||||
|
"bugfix/transform-firefox-class-in-computed-class-key": {
|
||||||
|
"chrome": "74",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "126",
|
||||||
|
"safari": "16",
|
||||||
|
"node": "12",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "16",
|
||||||
|
"samsung": "11",
|
||||||
|
"opera_mobile": "53",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"bugfix/transform-safari-class-field-initializer-scope": {
|
||||||
|
"chrome": "74",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "69",
|
||||||
|
"safari": "16",
|
||||||
|
"node": "12",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "16",
|
||||||
|
"samsung": "11",
|
||||||
|
"opera_mobile": "53",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"transform-class-static-block": {
|
||||||
|
"chrome": "94",
|
||||||
|
"opera": "80",
|
||||||
|
"edge": "94",
|
||||||
|
"firefox": "93",
|
||||||
|
"safari": "16.4",
|
||||||
|
"node": "16.11",
|
||||||
|
"deno": "1.14",
|
||||||
|
"ios": "16.4",
|
||||||
|
"samsung": "17",
|
||||||
|
"opera_mobile": "66",
|
||||||
|
"electron": "15.0"
|
||||||
|
},
|
||||||
|
"proposal-class-static-block": {
|
||||||
|
"chrome": "94",
|
||||||
|
"opera": "80",
|
||||||
|
"edge": "94",
|
||||||
|
"firefox": "93",
|
||||||
|
"safari": "16.4",
|
||||||
|
"node": "16.11",
|
||||||
|
"deno": "1.14",
|
||||||
|
"ios": "16.4",
|
||||||
|
"samsung": "17",
|
||||||
|
"opera_mobile": "66",
|
||||||
|
"electron": "15.0"
|
||||||
|
},
|
||||||
|
"transform-private-property-in-object": {
|
||||||
|
"chrome": "91",
|
||||||
|
"opera": "77",
|
||||||
|
"edge": "91",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "15",
|
||||||
|
"node": "16.9",
|
||||||
|
"deno": "1.9",
|
||||||
|
"ios": "15",
|
||||||
|
"samsung": "16",
|
||||||
|
"opera_mobile": "64",
|
||||||
|
"electron": "13.0"
|
||||||
|
},
|
||||||
|
"proposal-private-property-in-object": {
|
||||||
|
"chrome": "91",
|
||||||
|
"opera": "77",
|
||||||
|
"edge": "91",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "15",
|
||||||
|
"node": "16.9",
|
||||||
|
"deno": "1.9",
|
||||||
|
"ios": "15",
|
||||||
|
"samsung": "16",
|
||||||
|
"opera_mobile": "64",
|
||||||
|
"electron": "13.0"
|
||||||
|
},
|
||||||
|
"transform-class-properties": {
|
||||||
|
"chrome": "74",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "14.1",
|
||||||
|
"node": "12",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "14.5",
|
||||||
|
"samsung": "11",
|
||||||
|
"opera_mobile": "53",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"proposal-class-properties": {
|
||||||
|
"chrome": "74",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "14.1",
|
||||||
|
"node": "12",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "14.5",
|
||||||
|
"samsung": "11",
|
||||||
|
"opera_mobile": "53",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"transform-private-methods": {
|
||||||
|
"chrome": "84",
|
||||||
|
"opera": "70",
|
||||||
|
"edge": "84",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "15",
|
||||||
|
"node": "14.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "15",
|
||||||
|
"samsung": "14",
|
||||||
|
"opera_mobile": "60",
|
||||||
|
"electron": "10.0"
|
||||||
|
},
|
||||||
|
"proposal-private-methods": {
|
||||||
|
"chrome": "84",
|
||||||
|
"opera": "70",
|
||||||
|
"edge": "84",
|
||||||
|
"firefox": "90",
|
||||||
|
"safari": "15",
|
||||||
|
"node": "14.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "15",
|
||||||
|
"samsung": "14",
|
||||||
|
"opera_mobile": "60",
|
||||||
|
"electron": "10.0"
|
||||||
|
},
|
||||||
|
"transform-numeric-separator": {
|
||||||
|
"chrome": "75",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "70",
|
||||||
|
"safari": "13",
|
||||||
|
"node": "12.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13",
|
||||||
|
"samsung": "11",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "54",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"proposal-numeric-separator": {
|
||||||
|
"chrome": "75",
|
||||||
|
"opera": "62",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "70",
|
||||||
|
"safari": "13",
|
||||||
|
"node": "12.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13",
|
||||||
|
"samsung": "11",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "54",
|
||||||
|
"electron": "6.0"
|
||||||
|
},
|
||||||
|
"transform-logical-assignment-operators": {
|
||||||
|
"chrome": "85",
|
||||||
|
"opera": "71",
|
||||||
|
"edge": "85",
|
||||||
|
"firefox": "79",
|
||||||
|
"safari": "14",
|
||||||
|
"node": "15",
|
||||||
|
"deno": "1.2",
|
||||||
|
"ios": "14",
|
||||||
|
"samsung": "14",
|
||||||
|
"opera_mobile": "60",
|
||||||
|
"electron": "10.0"
|
||||||
|
},
|
||||||
|
"proposal-logical-assignment-operators": {
|
||||||
|
"chrome": "85",
|
||||||
|
"opera": "71",
|
||||||
|
"edge": "85",
|
||||||
|
"firefox": "79",
|
||||||
|
"safari": "14",
|
||||||
|
"node": "15",
|
||||||
|
"deno": "1.2",
|
||||||
|
"ios": "14",
|
||||||
|
"samsung": "14",
|
||||||
|
"opera_mobile": "60",
|
||||||
|
"electron": "10.0"
|
||||||
|
},
|
||||||
|
"transform-nullish-coalescing-operator": {
|
||||||
|
"chrome": "80",
|
||||||
|
"opera": "67",
|
||||||
|
"edge": "80",
|
||||||
|
"firefox": "72",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "14",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "13",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "57",
|
||||||
|
"electron": "8.0"
|
||||||
|
},
|
||||||
|
"proposal-nullish-coalescing-operator": {
|
||||||
|
"chrome": "80",
|
||||||
|
"opera": "67",
|
||||||
|
"edge": "80",
|
||||||
|
"firefox": "72",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "14",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "13",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "57",
|
||||||
|
"electron": "8.0"
|
||||||
|
},
|
||||||
|
"transform-optional-chaining": {
|
||||||
|
"chrome": "91",
|
||||||
|
"opera": "77",
|
||||||
|
"edge": "91",
|
||||||
|
"firefox": "74",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "16.9",
|
||||||
|
"deno": "1.9",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "16",
|
||||||
|
"opera_mobile": "64",
|
||||||
|
"electron": "13.0"
|
||||||
|
},
|
||||||
|
"proposal-optional-chaining": {
|
||||||
|
"chrome": "91",
|
||||||
|
"opera": "77",
|
||||||
|
"edge": "91",
|
||||||
|
"firefox": "74",
|
||||||
|
"safari": "13.1",
|
||||||
|
"node": "16.9",
|
||||||
|
"deno": "1.9",
|
||||||
|
"ios": "13.4",
|
||||||
|
"samsung": "16",
|
||||||
|
"opera_mobile": "64",
|
||||||
|
"electron": "13.0"
|
||||||
|
},
|
||||||
|
"transform-json-strings": {
|
||||||
|
"chrome": "66",
|
||||||
|
"opera": "53",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "62",
|
||||||
|
"safari": "12",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "12",
|
||||||
|
"samsung": "9",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"proposal-json-strings": {
|
||||||
|
"chrome": "66",
|
||||||
|
"opera": "53",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "62",
|
||||||
|
"safari": "12",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "12",
|
||||||
|
"samsung": "9",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-optional-catch-binding": {
|
||||||
|
"chrome": "66",
|
||||||
|
"opera": "53",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "58",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "9",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"proposal-optional-catch-binding": {
|
||||||
|
"chrome": "66",
|
||||||
|
"opera": "53",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "58",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "9",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-parameters": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "18",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "16.3",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "16.3",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"transform-async-generator-functions": {
|
||||||
|
"chrome": "63",
|
||||||
|
"opera": "50",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "57",
|
||||||
|
"safari": "12",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "12",
|
||||||
|
"samsung": "8",
|
||||||
|
"opera_mobile": "46",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"proposal-async-generator-functions": {
|
||||||
|
"chrome": "63",
|
||||||
|
"opera": "50",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "57",
|
||||||
|
"safari": "12",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "12",
|
||||||
|
"samsung": "8",
|
||||||
|
"opera_mobile": "46",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-object-rest-spread": {
|
||||||
|
"chrome": "60",
|
||||||
|
"opera": "47",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "55",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "8.3",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "8",
|
||||||
|
"opera_mobile": "44",
|
||||||
|
"electron": "2.0"
|
||||||
|
},
|
||||||
|
"proposal-object-rest-spread": {
|
||||||
|
"chrome": "60",
|
||||||
|
"opera": "47",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "55",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "8.3",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "8",
|
||||||
|
"opera_mobile": "44",
|
||||||
|
"electron": "2.0"
|
||||||
|
},
|
||||||
|
"transform-dotall-regex": {
|
||||||
|
"chrome": "62",
|
||||||
|
"opera": "49",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "78",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "8.10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "8",
|
||||||
|
"rhino": "1.7.15",
|
||||||
|
"opera_mobile": "46",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-unicode-property-regex": {
|
||||||
|
"chrome": "64",
|
||||||
|
"opera": "51",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "78",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "9",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"proposal-unicode-property-regex": {
|
||||||
|
"chrome": "64",
|
||||||
|
"opera": "51",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "78",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "9",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-named-capturing-groups-regex": {
|
||||||
|
"chrome": "64",
|
||||||
|
"opera": "51",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "78",
|
||||||
|
"safari": "11.1",
|
||||||
|
"node": "10",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11.3",
|
||||||
|
"samsung": "9",
|
||||||
|
"opera_mobile": "47",
|
||||||
|
"electron": "3.0"
|
||||||
|
},
|
||||||
|
"transform-async-to-generator": {
|
||||||
|
"chrome": "55",
|
||||||
|
"opera": "42",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "11",
|
||||||
|
"node": "7.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11",
|
||||||
|
"samsung": "6",
|
||||||
|
"opera_mobile": "42",
|
||||||
|
"electron": "1.6"
|
||||||
|
},
|
||||||
|
"transform-exponentiation-operator": {
|
||||||
|
"chrome": "52",
|
||||||
|
"opera": "39",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "52",
|
||||||
|
"safari": "10.1",
|
||||||
|
"node": "7",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10.3",
|
||||||
|
"samsung": "6",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.3"
|
||||||
|
},
|
||||||
|
"transform-template-literals": {
|
||||||
|
"chrome": "41",
|
||||||
|
"opera": "28",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "34",
|
||||||
|
"safari": "13",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "13",
|
||||||
|
"samsung": "3.4",
|
||||||
|
"opera_mobile": "28",
|
||||||
|
"electron": "0.21"
|
||||||
|
},
|
||||||
|
"transform-literals": {
|
||||||
|
"chrome": "44",
|
||||||
|
"opera": "31",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "4",
|
||||||
|
"rhino": "1.7.15",
|
||||||
|
"opera_mobile": "32",
|
||||||
|
"electron": "0.30"
|
||||||
|
},
|
||||||
|
"transform-function-name": {
|
||||||
|
"chrome": "51",
|
||||||
|
"opera": "38",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.2"
|
||||||
|
},
|
||||||
|
"transform-arrow-functions": {
|
||||||
|
"chrome": "47",
|
||||||
|
"opera": "34",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "43",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"rhino": "1.7.13",
|
||||||
|
"opera_mobile": "34",
|
||||||
|
"electron": "0.36"
|
||||||
|
},
|
||||||
|
"transform-block-scoped-functions": {
|
||||||
|
"chrome": "41",
|
||||||
|
"opera": "28",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "46",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "11",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "3.4",
|
||||||
|
"opera_mobile": "28",
|
||||||
|
"electron": "0.21"
|
||||||
|
},
|
||||||
|
"transform-classes": {
|
||||||
|
"chrome": "46",
|
||||||
|
"opera": "33",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "45",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "33",
|
||||||
|
"electron": "0.36"
|
||||||
|
},
|
||||||
|
"transform-object-super": {
|
||||||
|
"chrome": "46",
|
||||||
|
"opera": "33",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "45",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "33",
|
||||||
|
"electron": "0.36"
|
||||||
|
},
|
||||||
|
"transform-shorthand-properties": {
|
||||||
|
"chrome": "43",
|
||||||
|
"opera": "30",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "33",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "4",
|
||||||
|
"rhino": "1.7.14",
|
||||||
|
"opera_mobile": "30",
|
||||||
|
"electron": "0.27"
|
||||||
|
},
|
||||||
|
"transform-duplicate-keys": {
|
||||||
|
"chrome": "42",
|
||||||
|
"opera": "29",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "34",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "3.4",
|
||||||
|
"opera_mobile": "29",
|
||||||
|
"electron": "0.25"
|
||||||
|
},
|
||||||
|
"transform-computed-properties": {
|
||||||
|
"chrome": "44",
|
||||||
|
"opera": "31",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "34",
|
||||||
|
"safari": "7.1",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "8",
|
||||||
|
"samsung": "4",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "32",
|
||||||
|
"electron": "0.30"
|
||||||
|
},
|
||||||
|
"transform-for-of": {
|
||||||
|
"chrome": "51",
|
||||||
|
"opera": "38",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.2"
|
||||||
|
},
|
||||||
|
"transform-sticky-regex": {
|
||||||
|
"chrome": "49",
|
||||||
|
"opera": "36",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "3",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"rhino": "1.7.15",
|
||||||
|
"opera_mobile": "36",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"transform-unicode-escapes": {
|
||||||
|
"chrome": "44",
|
||||||
|
"opera": "31",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "4",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "4",
|
||||||
|
"rhino": "1.7.15",
|
||||||
|
"opera_mobile": "32",
|
||||||
|
"electron": "0.30"
|
||||||
|
},
|
||||||
|
"transform-unicode-regex": {
|
||||||
|
"chrome": "50",
|
||||||
|
"opera": "37",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "46",
|
||||||
|
"safari": "12",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "12",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "37",
|
||||||
|
"electron": "1.1"
|
||||||
|
},
|
||||||
|
"transform-spread": {
|
||||||
|
"chrome": "46",
|
||||||
|
"opera": "33",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "45",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "33",
|
||||||
|
"electron": "0.36"
|
||||||
|
},
|
||||||
|
"transform-destructuring": {
|
||||||
|
"chrome": "51",
|
||||||
|
"opera": "38",
|
||||||
|
"edge": "15",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6.5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "41",
|
||||||
|
"electron": "1.2"
|
||||||
|
},
|
||||||
|
"transform-block-scoping": {
|
||||||
|
"chrome": "50",
|
||||||
|
"opera": "37",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "11",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "11",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "37",
|
||||||
|
"electron": "1.1"
|
||||||
|
},
|
||||||
|
"transform-typeof-symbol": {
|
||||||
|
"chrome": "48",
|
||||||
|
"opera": "35",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "36",
|
||||||
|
"safari": "9",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "9",
|
||||||
|
"samsung": "5",
|
||||||
|
"rhino": "1.8",
|
||||||
|
"opera_mobile": "35",
|
||||||
|
"electron": "0.37"
|
||||||
|
},
|
||||||
|
"transform-new-target": {
|
||||||
|
"chrome": "46",
|
||||||
|
"opera": "33",
|
||||||
|
"edge": "14",
|
||||||
|
"firefox": "41",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "5",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "33",
|
||||||
|
"electron": "0.36"
|
||||||
|
},
|
||||||
|
"transform-regenerator": {
|
||||||
|
"chrome": "50",
|
||||||
|
"opera": "37",
|
||||||
|
"edge": "13",
|
||||||
|
"firefox": "53",
|
||||||
|
"safari": "10",
|
||||||
|
"node": "6",
|
||||||
|
"deno": "1",
|
||||||
|
"ios": "10",
|
||||||
|
"samsung": "5",
|
||||||
|
"opera_mobile": "37",
|
||||||
|
"electron": "1.1"
|
||||||
|
},
|
||||||
|
"transform-member-expression-literals": {
|
||||||
|
"chrome": "7",
|
||||||
|
"opera": "12",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "2",
|
||||||
|
"safari": "5.1",
|
||||||
|
"node": "0.4",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "9",
|
||||||
|
"android": "4",
|
||||||
|
"ios": "6",
|
||||||
|
"phantom": "1.9",
|
||||||
|
"samsung": "1",
|
||||||
|
"rhino": "1.7.13",
|
||||||
|
"opera_mobile": "12",
|
||||||
|
"electron": "0.20"
|
||||||
|
},
|
||||||
|
"transform-property-literals": {
|
||||||
|
"chrome": "7",
|
||||||
|
"opera": "12",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "2",
|
||||||
|
"safari": "5.1",
|
||||||
|
"node": "0.4",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "9",
|
||||||
|
"android": "4",
|
||||||
|
"ios": "6",
|
||||||
|
"phantom": "1.9",
|
||||||
|
"samsung": "1",
|
||||||
|
"rhino": "1.7.13",
|
||||||
|
"opera_mobile": "12",
|
||||||
|
"electron": "0.20"
|
||||||
|
},
|
||||||
|
"transform-reserved-words": {
|
||||||
|
"chrome": "13",
|
||||||
|
"opera": "10.50",
|
||||||
|
"edge": "12",
|
||||||
|
"firefox": "2",
|
||||||
|
"safari": "3.1",
|
||||||
|
"node": "0.6",
|
||||||
|
"deno": "1",
|
||||||
|
"ie": "9",
|
||||||
|
"android": "4.4",
|
||||||
|
"ios": "6",
|
||||||
|
"phantom": "1.9",
|
||||||
|
"samsung": "1",
|
||||||
|
"rhino": "1.7.13",
|
||||||
|
"opera_mobile": "10.1",
|
||||||
|
"electron": "0.20"
|
||||||
|
},
|
||||||
|
"transform-export-namespace-from": {
|
||||||
|
"chrome": "72",
|
||||||
|
"deno": "1.0",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "80",
|
||||||
|
"node": "13.2.0",
|
||||||
|
"opera": "60",
|
||||||
|
"opera_mobile": "51",
|
||||||
|
"safari": "14.1",
|
||||||
|
"ios": "14.5",
|
||||||
|
"samsung": "11.0",
|
||||||
|
"android": "72",
|
||||||
|
"electron": "5.0"
|
||||||
|
},
|
||||||
|
"proposal-export-namespace-from": {
|
||||||
|
"chrome": "72",
|
||||||
|
"deno": "1.0",
|
||||||
|
"edge": "79",
|
||||||
|
"firefox": "80",
|
||||||
|
"node": "13.2.0",
|
||||||
|
"opera": "60",
|
||||||
|
"opera_mobile": "51",
|
||||||
|
"safari": "14.1",
|
||||||
|
"ios": "14.5",
|
||||||
|
"samsung": "11.0",
|
||||||
|
"android": "72",
|
||||||
|
"electron": "5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
2
node_modules/@babel/compat-data/native-modules.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/native-modules.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file, in Babel 8 users import the .json directly
|
||||||
|
module.exports = require("./data/native-modules.json");
|
||||||
2
node_modules/@babel/compat-data/overlapping-plugins.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/overlapping-plugins.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file, in Babel 8 users import the .json directly
|
||||||
|
module.exports = require("./data/overlapping-plugins.json");
|
||||||
40
node_modules/@babel/compat-data/package.json
generated
vendored
Normal file
40
node_modules/@babel/compat-data/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "@babel/compat-data",
|
||||||
|
"version": "7.29.0",
|
||||||
|
"author": "The Babel Team (https://babel.dev/team)",
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "The compat-data to determine required Babel plugins",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/babel/babel.git",
|
||||||
|
"directory": "packages/babel-compat-data"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
"./plugins": "./plugins.js",
|
||||||
|
"./native-modules": "./native-modules.js",
|
||||||
|
"./corejs2-built-ins": "./corejs2-built-ins.js",
|
||||||
|
"./corejs3-shipped-proposals": "./corejs3-shipped-proposals.js",
|
||||||
|
"./overlapping-plugins": "./overlapping-plugins.js",
|
||||||
|
"./plugin-bugfixes": "./plugin-bugfixes.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build-data": "./scripts/download-compat-table.sh && node ./scripts/build-data.mjs && node ./scripts/build-modules-support.mjs && node ./scripts/build-bugfixes-targets.mjs"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"babel",
|
||||||
|
"compat-table",
|
||||||
|
"compat-data"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"@mdn/browser-compat-data": "^6.0.8",
|
||||||
|
"core-js-compat": "^3.48.0",
|
||||||
|
"electron-to-chromium": "^1.5.278"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
},
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
2
node_modules/@babel/compat-data/plugin-bugfixes.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/plugin-bugfixes.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file, in Babel 8 users import the .json directly
|
||||||
|
module.exports = require("./data/plugin-bugfixes.json");
|
||||||
2
node_modules/@babel/compat-data/plugins.js
generated
vendored
Normal file
2
node_modules/@babel/compat-data/plugins.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Todo (Babel 8): remove this file, in Babel 8 users import the .json directly
|
||||||
|
module.exports = require("./data/plugins.json");
|
||||||
22
node_modules/@babel/core/LICENSE
generated
vendored
Normal file
22
node_modules/@babel/core/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
19
node_modules/@babel/core/README.md
generated
vendored
Normal file
19
node_modules/@babel/core/README.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# @babel/core
|
||||||
|
|
||||||
|
> Babel compiler core.
|
||||||
|
|
||||||
|
See our website [@babel/core](https://babeljs.io/docs/babel-core) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20core%22+is%3Aopen) associated with this package.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Using npm:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save-dev @babel/core
|
||||||
|
```
|
||||||
|
|
||||||
|
or using yarn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @babel/core --dev
|
||||||
|
```
|
||||||
5
node_modules/@babel/core/lib/config/cache-contexts.js
generated
vendored
Normal file
5
node_modules/@babel/core/lib/config/cache-contexts.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
0 && 0;
|
||||||
|
|
||||||
|
//# sourceMappingURL=cache-contexts.js.map
|
||||||
1
node_modules/@babel/core/lib/config/cache-contexts.js.map
generated
vendored
Normal file
1
node_modules/@babel/core/lib/config/cache-contexts.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"names":[],"sources":["../../src/config/cache-contexts.ts"],"sourcesContent":["import type { ConfigContext } from \"./config-chain.ts\";\nimport type {\n CallerMetadata,\n TargetsListOrObject,\n} from \"./validation/options.ts\";\n\nexport type { ConfigContext as FullConfig };\n\nexport type FullPreset = {\n targets: TargetsListOrObject;\n} & ConfigContext;\nexport type FullPlugin = {\n assumptions: Record<string, boolean>;\n} & FullPreset;\n\n// Context not including filename since it is used in places that cannot\n// process 'ignore'/'only' and other filename-based logic.\nexport type SimpleConfig = {\n envName: string;\n caller: CallerMetadata | undefined;\n};\nexport type SimplePreset = {\n targets: TargetsListOrObject;\n} & SimpleConfig;\nexport type SimplePlugin = {\n assumptions: Record<string, boolean>;\n} & SimplePreset;\n"],"mappings":"","ignoreList":[]}
|
||||||
261
node_modules/@babel/core/lib/config/caching.js
generated
vendored
Normal file
261
node_modules/@babel/core/lib/config/caching.js
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.assertSimpleType = assertSimpleType;
|
||||||
|
exports.makeStrongCache = makeStrongCache;
|
||||||
|
exports.makeStrongCacheSync = makeStrongCacheSync;
|
||||||
|
exports.makeWeakCache = makeWeakCache;
|
||||||
|
exports.makeWeakCacheSync = makeWeakCacheSync;
|
||||||
|
function _gensync() {
|
||||||
|
const data = require("gensync");
|
||||||
|
_gensync = function () {
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
var _async = require("../gensync-utils/async.js");
|
||||||
|
var _util = require("./util.js");
|
||||||
|
const synchronize = gen => {
|
||||||
|
return _gensync()(gen).sync;
|
||||||
|
};
|
||||||
|
function* genTrue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function makeWeakCache(handler) {
|
||||||
|
return makeCachedFunction(WeakMap, handler);
|
||||||
|
}
|
||||||
|
function makeWeakCacheSync(handler) {
|
||||||
|
return synchronize(makeWeakCache(handler));
|
||||||
|
}
|
||||||
|
function makeStrongCache(handler) {
|
||||||
|
return makeCachedFunction(Map, handler);
|
||||||
|
}
|
||||||
|
function makeStrongCacheSync(handler) {
|
||||||
|
return synchronize(makeStrongCache(handler));
|
||||||
|
}
|
||||||
|
function makeCachedFunction(CallCache, handler) {
|
||||||
|
const callCacheSync = new CallCache();
|
||||||
|
const callCacheAsync = new CallCache();
|
||||||
|
const futureCache = new CallCache();
|
||||||
|
return function* cachedFunction(arg, data) {
|
||||||
|
const asyncContext = yield* (0, _async.isAsync)();
|
||||||
|
const callCache = asyncContext ? callCacheAsync : callCacheSync;
|
||||||
|
const cached = yield* getCachedValueOrWait(asyncContext, callCache, futureCache, arg, data);
|
||||||
|
if (cached.valid) return cached.value;
|
||||||
|
const cache = new CacheConfigurator(data);
|
||||||
|
const handlerResult = handler(arg, cache);
|
||||||
|
let finishLock;
|
||||||
|
let value;
|
||||||
|
if ((0, _util.isIterableIterator)(handlerResult)) {
|
||||||
|
value = yield* (0, _async.onFirstPause)(handlerResult, () => {
|
||||||
|
finishLock = setupAsyncLocks(cache, futureCache, arg);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
value = handlerResult;
|
||||||
|
}
|
||||||
|
updateFunctionCache(callCache, cache, arg, value);
|
||||||
|
if (finishLock) {
|
||||||
|
futureCache.delete(arg);
|
||||||
|
finishLock.release(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function* getCachedValue(cache, arg, data) {
|
||||||
|
const cachedValue = cache.get(arg);
|
||||||
|
if (cachedValue) {
|
||||||
|
for (const {
|
||||||
|
value,
|
||||||
|
valid
|
||||||
|
} of cachedValue) {
|
||||||
|
if (yield* valid(data)) return {
|
||||||
|
valid: true,
|
||||||
|
value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
value: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function* getCachedValueOrWait(asyncContext, callCache, futureCache, arg, data) {
|
||||||
|
const cached = yield* getCachedValue(callCache, arg, data);
|
||||||
|
if (cached.valid) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
if (asyncContext) {
|
||||||
|
const cached = yield* getCachedValue(futureCache, arg, data);
|
||||||
|
if (cached.valid) {
|
||||||
|
const value = yield* (0, _async.waitFor)(cached.value.promise);
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
value: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function setupAsyncLocks(config, futureCache, arg) {
|
||||||
|
const finishLock = new Lock();
|
||||||
|
updateFunctionCache(futureCache, config, arg, finishLock);
|
||||||
|
return finishLock;
|
||||||
|
}
|
||||||
|
function updateFunctionCache(cache, config, arg, value) {
|
||||||
|
if (!config.configured()) config.forever();
|
||||||
|
let cachedValue = cache.get(arg);
|
||||||
|
config.deactivate();
|
||||||
|
switch (config.mode()) {
|
||||||
|
case "forever":
|
||||||
|
cachedValue = [{
|
||||||
|
value,
|
||||||
|
valid: genTrue
|
||||||
|
}];
|
||||||
|
cache.set(arg, cachedValue);
|
||||||
|
break;
|
||||||
|
case "invalidate":
|
||||||
|
cachedValue = [{
|
||||||
|
value,
|
||||||
|
valid: config.validator()
|
||||||
|
}];
|
||||||
|
cache.set(arg, cachedValue);
|
||||||
|
break;
|
||||||
|
case "valid":
|
||||||
|
if (cachedValue) {
|
||||||
|
cachedValue.push({
|
||||||
|
value,
|
||||||
|
valid: config.validator()
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cachedValue = [{
|
||||||
|
value,
|
||||||
|
valid: config.validator()
|
||||||
|
}];
|
||||||
|
cache.set(arg, cachedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class CacheConfigurator {
|
||||||
|
constructor(data) {
|
||||||
|
this._active = true;
|
||||||
|
this._never = false;
|
||||||
|
this._forever = false;
|
||||||
|
this._invalidate = false;
|
||||||
|
this._configured = false;
|
||||||
|
this._pairs = [];
|
||||||
|
this._data = void 0;
|
||||||
|
this._data = data;
|
||||||
|
}
|
||||||
|
simple() {
|
||||||
|
return makeSimpleConfigurator(this);
|
||||||
|
}
|
||||||
|
mode() {
|
||||||
|
if (this._never) return "never";
|
||||||
|
if (this._forever) return "forever";
|
||||||
|
if (this._invalidate) return "invalidate";
|
||||||
|
return "valid";
|
||||||
|
}
|
||||||
|
forever() {
|
||||||
|
if (!this._active) {
|
||||||
|
throw new Error("Cannot change caching after evaluation has completed.");
|
||||||
|
}
|
||||||
|
if (this._never) {
|
||||||
|
throw new Error("Caching has already been configured with .never()");
|
||||||
|
}
|
||||||
|
this._forever = true;
|
||||||
|
this._configured = true;
|
||||||
|
}
|
||||||
|
never() {
|
||||||
|
if (!this._active) {
|
||||||
|
throw new Error("Cannot change caching after evaluation has completed.");
|
||||||
|
}
|
||||||
|
if (this._forever) {
|
||||||
|
throw new Error("Caching has already been configured with .forever()");
|
||||||
|
}
|
||||||
|
this._never = true;
|
||||||
|
this._configured = true;
|
||||||
|
}
|
||||||
|
using(handler) {
|
||||||
|
if (!this._active) {
|
||||||
|
throw new Error("Cannot change caching after evaluation has completed.");
|
||||||
|
}
|
||||||
|
if (this._never || this._forever) {
|
||||||
|
throw new Error("Caching has already been configured with .never or .forever()");
|
||||||
|
}
|
||||||
|
this._configured = true;
|
||||||
|
const key = handler(this._data);
|
||||||
|
const fn = (0, _async.maybeAsync)(handler, `You appear to be using an async cache handler, but Babel has been called synchronously`);
|
||||||
|
if ((0, _async.isThenable)(key)) {
|
||||||
|
return key.then(key => {
|
||||||
|
this._pairs.push([key, fn]);
|
||||||
|
return key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._pairs.push([key, fn]);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
invalidate(handler) {
|
||||||
|
this._invalidate = true;
|
||||||
|
return this.using(handler);
|
||||||
|
}
|
||||||
|
validator() {
|
||||||
|
const pairs = this._pairs;
|
||||||
|
return function* (data) {
|
||||||
|
for (const [key, fn] of pairs) {
|
||||||
|
if (key !== (yield* fn(data))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
deactivate() {
|
||||||
|
this._active = false;
|
||||||
|
}
|
||||||
|
configured() {
|
||||||
|
return this._configured;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function makeSimpleConfigurator(cache) {
|
||||||
|
function cacheFn(val) {
|
||||||
|
if (typeof val === "boolean") {
|
||||||
|
if (val) cache.forever();else cache.never();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return cache.using(() => assertSimpleType(val()));
|
||||||
|
}
|
||||||
|
cacheFn.forever = () => cache.forever();
|
||||||
|
cacheFn.never = () => cache.never();
|
||||||
|
cacheFn.using = cb => cache.using(() => assertSimpleType(cb()));
|
||||||
|
cacheFn.invalidate = cb => cache.invalidate(() => assertSimpleType(cb()));
|
||||||
|
return cacheFn;
|
||||||
|
}
|
||||||
|
function assertSimpleType(value) {
|
||||||
|
if ((0, _async.isThenable)(value)) {
|
||||||
|
throw new Error(`You appear to be using an async cache handler, ` + `which your current version of Babel does not support. ` + `We may add support for this in the future, ` + `but if you're on the most recent version of @babel/core and still ` + `seeing this error, then you'll need to synchronously handle your caching logic.`);
|
||||||
|
}
|
||||||
|
if (value != null && typeof value !== "string" && typeof value !== "boolean" && typeof value !== "number") {
|
||||||
|
throw new Error("Cache keys must be either string, boolean, number, null, or undefined.");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
class Lock {
|
||||||
|
constructor() {
|
||||||
|
this.released = false;
|
||||||
|
this.promise = void 0;
|
||||||
|
this._resolve = void 0;
|
||||||
|
this.promise = new Promise(resolve => {
|
||||||
|
this._resolve = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
release(value) {
|
||||||
|
this.released = true;
|
||||||
|
this._resolve(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0 && 0;
|
||||||
|
|
||||||
|
//# sourceMappingURL=caching.js.map
|
||||||
1
node_modules/@babel/core/lib/config/caching.js.map
generated
vendored
Normal file
1
node_modules/@babel/core/lib/config/caching.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user