Feat: User Relationships and Session Members.

This commit is contained in:
2026-02-28 19:53:50 +00:00
parent c7db290aaf
commit e8e9a02e7b
73 changed files with 3818 additions and 571 deletions

2
app.py
View File

@@ -49,7 +49,7 @@ app.app_config = app_config
# app.config["config"] = app_config()
# logging
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)
handler = RotatingFileHandler('app.log', maxBytes=10_000_000, backupCount=16)
handler.setLevel(logging.DEBUG)
app.logger.addHandler(handler)

View File

@@ -38,7 +38,7 @@ class Base():
FLAG_CITY: ClassVar[str] = 'city'
FLAG_CODE: ClassVar[str] = 'code'
FLAG_COUNTY: ClassVar[str] = 'county'
FLAG_CREATED_BY: ClassVar[str] = 'created_by'
FLAG_CREATED_BY_USER_ID: ClassVar[str] = 'created_by_user_id'
FLAG_CREATED_ON: ClassVar[str] = 'created_on'
FLAG_CURRENCY: ClassVar[str] = 'currency'
FLAG_CURRENCY_COST: ClassVar[str] = 'currency_cost'
@@ -74,6 +74,8 @@ class Base():
FLAG_SURNAME: ClassVar[str] = 'surname'
FLAG_SYMBOL: ClassVar[str] = 'symbol'
FLAG_TEXT_COLOUR: ClassVar[str] = 'text_colour'
FLAG_UPDATED_LAST_BY_USER_ID: ClassVar[str] = 'updated_last_by_user_id'
FLAG_UPDATED_LAST_ON: ClassVar[str] = 'updated_last_on'
FLAG_URL: ClassVar[str] = 'url'
FLAG_USER: ClassVar[str] = 'authorisedUser' # 'user' already used
FLAG_VALUE: ClassVar[str] = 'value'

View File

@@ -52,8 +52,8 @@ class SQL_Error(SQLAlchemy_ABC, Base):
@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}')
# Helper_App.console_log(_m)
# Helper_App.console_log(f'record: {record}')
error = cls()
error.error_id = record[0]
error.guid = record[1]
@@ -68,14 +68,14 @@ class SQL_Error(SQLAlchemy_ABC, Base):
@classmethod
def from_exception(cls, exception: Exception, is_breaking: bool = True):
_m = f'{cls.__qualname__}.from_exception'
Helper_App.console_log(_m)
# 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}')
# Helper_App.console_log(f'Error: {error}')
return error
@classmethod

View File

@@ -114,24 +114,34 @@ class Parameters_MTG_Deck(Get_Many_Parameters_Base):
deck_names: str
commander_bracket_ids: str
include_commander_option: bool
created_by_user_ids: str
get_all_game: bool
get_inactive_game: bool
game_ids: str
filter_by_game_session_not_player: 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):
def get_default(cls, user_id):
return cls(
get_all_deck = True
get_all_deck = False
, get_inactive_deck = False
, deck_ids = ''
, deck_names = ''
, commander_bracket_ids = ''
, include_commander_option = True
, require_all_id_filters_met = True
, created_by_user_ids = str(user_id)
, get_all_game = False
, get_inactive_game = False
, game_ids = ''
, filter_by_game_session_not_player = False
, require_all_id_filters_met = False
, require_any_id_filters_met = True
, require_all_non_id_filters_met = False
, require_any_non_id_filters_met = True
, require_any_non_id_filters_met = False
)
@classmethod
@@ -143,6 +153,11 @@ class Parameters_MTG_Deck(Get_Many_Parameters_Base):
, 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)
, created_by_user_ids = json.get('a_created_by_user_ids', '')
, 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', '')
, filter_by_game_session_not_player = json.get('a_filter_by_game_session_not_player', 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)
@@ -157,6 +172,11 @@ class Parameters_MTG_Deck(Get_Many_Parameters_Base):
, 'a_deck_names': self.deck_names
, 'a_commander_bracket_ids': self.commander_bracket_ids
, 'a_include_commander_option': self.include_commander_option
, 'a_created_by_user_ids': self.created_by_user_ids
, 'a_get_all_game': self.get_all_game
, 'a_get_inactive_game': self.get_inactive_game
, 'a_game_ids': self.game_ids
, 'a_filter_by_game_session_not_player': self.filter_by_game_session_not_player
, '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
@@ -172,6 +192,11 @@ class Parameters_MTG_Deck(Get_Many_Parameters_Base):
, 'a_deck_names': Text
, 'a_commander_bracket_ids': Text
, 'a_include_commander_option': Boolean
, 'a_created_by_user_ids': Text
, 'a_get_all_game': Boolean
, 'a_get_inactive_game': Boolean
, 'a_game_ids': Text
, 'a_filter_by_game_session_not_player': Boolean
, 'a_require_all_id_filters_met': Boolean
, 'a_require_any_id_filters_met': Boolean
, 'a_require_all_non_id_filters_met': Boolean

View File

@@ -14,6 +14,7 @@ import lib.argument_validation as av
from extensions import db
from helpers.helper_app import Helper_App
# external
from datetime import datetime
from dataclasses import dataclass
from typing import ClassVar
from sqlalchemy import bindparam
@@ -74,6 +75,8 @@ class MTG_Game(SQLAlchemy_ABC, Base):
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]
game.updated_last_on = query_row[12]
game.updated_last_by_user_id = query_row[13]
return game
@classmethod
@@ -91,8 +94,16 @@ class MTG_Game(SQLAlchemy_ABC, Base):
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)
_created_on = json.get(Base.FLAG_CREATED_ON, None)
if isinstance(_created_on, str):
_created_on = datetime.strptime(_created_on, '%a, %d %b %Y %H:%M:%S %Z')
game.created_on = _created_on
game.created_by_user_id = json.get(Base.ATTR_USER_ID, None)
_updated_last_on = json.get(Base.FLAG_UPDATED_LAST_ON, None)
if isinstance(_updated_last_on, str):
_updated_last_on = datetime.strptime(_updated_last_on, '%a, %d %b %Y %H:%M:%S %Z')
game.updated_last_on = _updated_last_on
game.updated_last_by_user_id = json.get(Base.FLAG_UPDATED_LAST_BY_USER_ID, None)
return game
def to_json(self):
@@ -109,7 +120,9 @@ class MTG_Game(SQLAlchemy_ABC, Base):
, 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
, self.FLAG_CREATED_BY_USER_ID: self.created_by_user_id
, self.FLAG_UPDATED_LAST_ON: self.updated_last_on
, self.FLAG_UPDATED_LAST_BY_USER_ID: self.updated_last_by_user_id
}
return as_json
@@ -127,7 +140,9 @@ class MTG_Game(SQLAlchemy_ABC, Base):
{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}
{self.FLAG_CREATED_BY_USER_ID}: {self.created_by_user_id}
{self.FLAG_UPDATED_LAST_ON}: {self.updated_last_on}
{self.FLAG_UPDATED_LAST_BY_USER_ID}: {self.updated_last_by_user_id}
)
'''

View File

@@ -10,6 +10,8 @@ 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
from business_objects.tcg.mtg_deck import MTG_Deck
from business_objects.tcg.mtg_game import MTG_Game
import lib.argument_validation as av
from extensions import db
from helpers.helper_app import Helper_App
@@ -22,8 +24,6 @@ from sqlalchemy.types import Text, Boolean
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'
@@ -74,9 +74,9 @@ class MTG_Game_Player(SQLAlchemy_ABC, Base):
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.game_id = json.get(MTG_Game.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.deck_id = json.get(MTG_Deck.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)
@@ -89,9 +89,9 @@ class MTG_Game_Player(SQLAlchemy_ABC, Base):
as_json = {
**self.get_shared_json_attributes(self)
, self.ATTR_PLAYER_ID: self.player_id
, self.ATTR_GAME_ID: self.game_id
, MTG_Game.ATTR_GAME_ID: self.game_id
, Base.ATTR_USER_ID: self.user_id
, self.ATTR_DECK_ID: self.deck_id
, MTG_Deck.ATTR_DECK_ID: self.deck_id
, self.FLAG_NAME: self.name
, self.FLAG_NOTES: self.notes
, self.FLAG_DISPLAY_ORDER: self.display_order
@@ -104,9 +104,9 @@ class MTG_Game_Player(SQLAlchemy_ABC, Base):
return f'''
{self.__class__.__name__}(
{self.ATTR_PLAYER_ID}: {self.player_id}
{self.ATTR_GAME_ID}: {self.game_id}
{MTG_Game.ATTR_GAME_ID}: {self.game_id}
{Base.ATTR_USER_ID}: {self.user_id}
{self.ATTR_DECK_ID}: {self.deck_id}
{MTG_Deck.ATTR_DECK_ID}: {self.deck_id}
{self.FLAG_NAME}: {self.name}
{self.FLAG_NOTES}: {self.notes}
{self.FLAG_DISPLAY_ORDER}: {self.display_order}

View File

@@ -0,0 +1,194 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: MTG Game Session Member Business Object
"""
# internal
from business_objects.base import Base
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
from business_objects.tcg.mtg_game import MTG_Game
from business_objects.tcg.user import User
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_Session_Member(SQLAlchemy_ABC, Base):
ATTR_SESSION_MEMBER_ID: ClassVar[str] = 'member_id'
FLAG_IS_PERMITTED: ClassVar[str] = 'is_permitted'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_SESSION_MEMBER_ID
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
__tablename__ = 'tcg_mtg_game_session_member'
__table_args__ = { 'extend_existing': True }
member_id = db.Column(db.Integer, primary_key=True)
game_id = db.Column(db.Integer)
user_id = db.Column(db.Integer)
is_permitted = 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.member_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.member_id = query_row[0]
player.game_id = query_row[1]
player.user_id = query_row[2]
player.is_permitted = query_row[3]
player.active = av.input_bool(query_row[4], cls.FLAG_ACTIVE, _m)
player.created_on = query_row[5]
player.created_by_user_id = query_row[6]
return player
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
player = cls()
if json is None: return player
player.member_id = json.get(cls.ATTR_SESSION_MEMBER_ID, -1)
player.game_id = json.get(MTG_Game.ATTR_GAME_ID, None)
player.user_id = json.get(Base.ATTR_USER_ID, None)
player.is_permitted = json.get(cls.FLAG_IS_PERMITTED, None)
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_SESSION_MEMBER_ID: self.member_id
, MTG_Game.ATTR_GAME_ID: self.game_id
, Base.ATTR_USER_ID: self.user_id
, self.FLAG_IS_PERMITTED: self.is_permitted
, 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_SESSION_MEMBER_ID}: {self.member_id}
{MTG_Game.ATTR_GAME_ID}: {self.game_id}
{Base.ATTR_USER_ID}: {self.user_id}
{self.FLAG_IS_PERMITTED}: {self.is_permitted}
{self.FLAG_ACTIVE}: {self.active}
{self.FLAG_CREATED_ON}: {self.created_on}
)
'''
class MTG_Game_Session_Member_Temp(db.Model, Base):
__tablename__ = 'tcg_mtg_game_session_member_temp'
__table_args__ = { 'extend_existing': True }
temp_id = db.Column(db.Integer, primary_key=True)
member_id = db.Column(db.Integer)
game_id = db.Column(db.Integer)
user_id = db.Column(db.Integer)
is_permitted = db.Column(db.Boolean)
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_session_member(cls, member, guid):
_m = 'MTG_Game_Session_Member_Temp.from_session_member'
temp = cls()
temp.member_id = member.member_id
temp.game_id = member.game_id
temp.user_id = member.user_id
temp.is_permitted = member.is_permitted
temp.active = member.active
temp.created_on = member.created_on
temp.guid = guid
return temp
class Parameters_MTG_Game_Session_Member(Get_Many_Parameters_Base):
get_inactive_session_member: bool
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_inactive_session_member = False
, get_all_game = True
, get_inactive_game = False
, game_ids = ''
, get_all_user = True
, get_inactive_user = False
, user_ids = str(user_id_session)
, require_all_id_filters_met = True
, require_any_id_filters_met = True
)
@classmethod
def from_json(cls, json):
return cls(
get_inactive_session_member = json.get('a_get_inactive_session_member', False)
, 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_inactive_session_member': self.get_inactive_session_member
, 'a_get_all_game': self.get_all_game
, 'a_get_inactive_game': self.get_inactive_game
, 'a_game_ids': self.game_ids
, 'a_get_all_user': self.get_all_user
, 'a_get_inactive_user': self.get_inactive_user
, '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
}
@staticmethod
def get_type_hints():
return {
'a_get_inactive_session_member': Boolean
, '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
}

View File

@@ -55,7 +55,7 @@ class User(SQLAlchemy_ABC, Base):
updated_last_by_user_id, change_set_id
"""
_m = f'{cls.__qualname__}.from_db_user'
Helper_App.console_log(f'user record: {query_row}')
# Helper_App.console_log(f'user record: {query_row}')
user = cls()
user.user_id = query_row[0]
user.user_auth0_id = query_row[1]
@@ -72,7 +72,7 @@ class User(SQLAlchemy_ABC, Base):
_m = f'{cls.__qualname__}.from_json'
user = cls()
if json is None: return user
Helper_App.console_log(f'{_m}/n{json}')
# 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]
@@ -85,12 +85,12 @@ class User(SQLAlchemy_ABC, Base):
@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}')
# 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}')
# Helper_App.console_log(f'user_info: {user_info}')
user.user_id = None
user.user_auth0_id = user_info['sub']
user.firstname = None

View File

@@ -0,0 +1,197 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: User Relationship 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 User_Relationship(SQLAlchemy_ABC, Base):
ATTR_RELATIONSHIP_ID: ClassVar[str] = 'relationship_id'
FLAG_FOLLOWER_USER_ID: ClassVar[str] = 'follower_user_id'
FLAG_FOLLOWING_USER_ID: ClassVar[str] = 'following_user_id'
FLAG_IS_FOLLOWING: ClassVar[str] = 'is_following'
FLAG_IS_BLOCKED: ClassVar[str] = 'is_blocked'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_RELATIONSHIP_ID
NAME_ATTR_OPTION_TEXT: ClassVar[str] = ATTR_RELATIONSHIP_ID
__tablename__ = 'tcg_user_relationship'
__table_args__ = { 'extend_existing': True }
relationship_id = db.Column(db.Integer, primary_key=True)
follower_user_id = db.Column(db.Integer)
following_user_id = db.Column(db.Integer)
is_following = db.Column(db.Boolean)
is_blocked = 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.relationship_id = 0
self.is_new = False
super().__init__()
@classmethod
def from_db_user_relationship(cls, query_row):
_m = f'{cls.__qualname__}.from_db_user_relationship'
player = cls()
player.relationship_id = query_row[0]
player.follower_user_id = query_row[1]
player.following_user_id = query_row[2]
player.is_following = query_row[3]
player.is_blocked = query_row[4]
player.active = av.input_bool(query_row[5], cls.FLAG_ACTIVE, _m)
player.created_on = query_row[6]
player.created_by_user_id = query_row[7]
return player
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
player = cls()
if json is None: return player
player.relationship_id = json.get(cls.ATTR_RELATIONSHIP_ID, -1)
player.follower_user_id = json.get(cls.FLAG_FOLLOWER_USER_ID, None)
player.following_user_id = json.get(cls.FLAG_FOLLOWING_USER_ID, None)
player.is_following = json.get(cls.FLAG_IS_FOLLOWING, None)
player.is_blocked = json.get(cls.FLAG_IS_BLOCKED, None)
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_RELATIONSHIP_ID: self.relationship_id
, self.FLAG_FOLLOWER_USER_ID: self.follower_user_id
, self.FLAG_FOLLOWING_USER_ID: self.following_user_id
, self.FLAG_IS_FOLLOWING: self.is_following
, self.FLAG_IS_BLOCKED: self.is_blocked
, 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_RELATIONSHIP_ID}: {self.relationship_id}
{self.FLAG_FOLLOWER_USER_ID}: {self.follower_user_id}
{self.FLAG_FOLLOWING_USER_ID}: {self.following_user_id}
{self.FLAG_IS_FOLLOWING}: {self.is_following}
{self.FLAG_IS_BLOCKED}: {self.is_blocked}
{self.FLAG_ACTIVE}: {self.active}
{self.FLAG_CREATED_ON}: {self.created_on}
)
'''
class User_Relationship_Temp(db.Model, Base):
__tablename__ = 'tcg_user_relationship_temp'
__table_args__ = { 'extend_existing': True }
temp_id = db.Column(db.Integer, primary_key=True)
relationship_id = db.Column(db.Integer)
follower_user_id = db.Column(db.Integer)
following_user_id = db.Column(db.Integer)
is_following = db.Column(db.Boolean)
is_blocked = db.Column(db.Boolean)
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_user_relationship(cls, relationship, guid):
_m = 'User_Relationship_Temp.from_user_relationship'
temp = cls()
temp.relationship_id = relationship.relationship_id
temp.follower_user_id = relationship.follower_user_id
temp.following_user_id = relationship.following_user_id
temp.is_following = relationship.is_following
temp.is_blocked = relationship.is_blocked
temp.active = relationship.active
temp.created_on = relationship.created_on
temp.guid = guid
return temp
class Parameters_User_Relationship(Get_Many_Parameters_Base):
get_inactive_user_relationship: bool
get_all_user_follower: bool
follower_user_ids: str
get_all_user_following: bool
following_user_ids: str
get_inactive_user: bool
require_all_id_filters_met: bool
require_any_id_filters_met: bool
@classmethod
def get_default(cls, user_id_session):
return cls(
get_inactive_user_relationship = True
, get_all_user_follower = False
, follower_user_ids = ''
, get_all_user_following = True
, following_user_ids = ''
, get_inactive_user = False
, require_all_id_filters_met = True
, require_any_id_filters_met = True
)
@classmethod
def from_json(cls, json):
return cls(
get_inactive_user_relationship = json.get('a_get_inactive_user_relationship', False)
, get_all_user_follower = json.get('a_get_all_user_follower', False)
, follower_user_ids = json.get('a_follower_user_ids', '')
, get_all_user_following = json.get('a_get_all_user_following', False)
, following_user_ids = json.get('a_following_user_ids', '')
, get_inactive_user = json.get('a_get_inactive_user', False)
, 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_inactive_user_relationship': self.get_inactive_user_relationship
, 'a_get_all_user_follower': self.get_all_user_follower
, 'a_follower_user_ids': self.follower_user_ids
, 'a_get_all_user_following': self.get_all_user_following
, 'a_following_user_ids': self.following_user_ids
, 'a_get_inactive_user': self.get_inactive_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
}
@staticmethod
def get_type_hints():
return {
'a_get_inactive_user_relationship': Boolean
, 'a_get_all_user_follower': Boolean
, 'a_follower_user_ids': Text
, 'a_get_all_user_following': Boolean
, 'a_following_user_ids': Text
, 'a_get_inactive_user': Boolean
, 'a_require_all_id_filters_met': Boolean
, 'a_require_any_id_filters_met': Boolean
}

View File

@@ -105,10 +105,12 @@ class ProductionConfig(Config):
# 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':

View File

@@ -14,7 +14,7 @@ MTG Game Page Controller.
# internal
from business_objects.api import API
from business_objects.tcg.mtg_deck import MTG_Deck
from business_objects.tcg.mtg_game import MTG_Game
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
@@ -50,14 +50,14 @@ 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}')
# 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}')
# Helper_App.console_log(f'Error: {e}')
form_filters = Filters_MTG_Game()
Helper_App.console_log(f'form_filters={form_filters}')
# Helper_App.console_log(f'form_filters={form_filters}')
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -68,13 +68,13 @@ def games():
model = Model_View_MTG_Games(parameters_game = parameters_game)
model.form_filters = form_filters
Helper_App.console_log(f'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}')
# 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'))
@@ -88,7 +88,7 @@ def game_detail(game_id):
def save_game():
_m = 'routes_mtg_game.save_game'
data = Helper_App.get_request_data(request)
Helper_App.console_log(f'{_m}\n{data}')
# 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, {}))
@@ -111,10 +111,10 @@ def save_game():
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}")
# 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}')
# Helper_App.console_log(f'obj_game={obj_game}')
game_id, errors = DataStore_MTG.save_mtg_game(obj_game)
@@ -148,11 +148,69 @@ def trial_game():
return send_from_directory('templates/pages/tcg/mtg', 'trial_game.html')
@routes_mtg_game.route('/mtg/api/game/<int:game_id>/is-outdated', methods=['POST'])
def get_is_game_data_outdated(game_id):
"""Check if saved game has been updated since page load."""
_m = 'routes_mtg_game.get_is_game_data_outdated'
# Helper_App.console_log(f'{_m}: game_id={game_id}')
data = Helper_App.get_request_data(request)
# Helper_App.console_log(f'{_m}\n{data}')
try:
loaded_game = data.get(Model_View_MTG_Base.FLAG_GAME, None)
if loaded_game is None:
return jsonify({
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE
, Model_View_MTG_Base.FLAG_MESSAGE: 'Loaded game not sent for comparison.'
})
# Helper_App.console_log(f"Loaded game: {loaded_game}")
obj_loaded_game = MTG_Game.from_json(loaded_game)
# Helper_App.console_log(f'obj_loaded_game={obj_loaded_game}')
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 saved 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
saved_games, errors = datastore.get_many_mtg_game(parameters_game)
if (len(errors) > 0 or len(saved_games) == 0):
return jsonify({
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_FAILURE
, Model_View_MTG_Base.FLAG_MESSAGE: f'Error fetching saved game: {errors}'
}), 500
saved_game = saved_games[0]
saved_game.updated_last_on = saved_game.updated_last_on.replace(microsecond = 0)
is_game_data_outdated = saved_game.updated_last_on > obj_loaded_game.updated_last_on
# Helper_App.console_log(f"loaded game updated last on: {obj_loaded_game.updated_last_on}")
# Helper_App.console_log(f"saved game updated last on: {saved_game.updated_last_on}")
# Helper_App.console_log(f"game oudated?: {is_game_data_outdated}")
return jsonify({
Model_View_MTG_Base.FLAG_STATUS: Model_View_MTG_Base.FLAG_SUCCESS
, Model_View_MTG_Base.FLAG_DATA: is_game_data_outdated
})
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>/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}')
# Helper_App.console_log(f'{_m}: game_id={game_id}')
try:
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -182,7 +240,7 @@ def get_game_players(game_id):
, Model_View_MTG_Base.FLAG_DATA: players_json
})
except Exception as e:
Helper_App.console_log(f'{_m} Error: {str(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)}'
@@ -193,7 +251,7 @@ def get_game_players(game_id):
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}')
# Helper_App.console_log(f'{_m}: game_id={game_id}')
try:
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -223,7 +281,7 @@ def get_many_game_round(game_id):
, Model_View_MTG_Base.FLAG_DATA: rounds_json
})
except Exception as e:
Helper_App.console_log(f'{_m} Error: {str(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)}'
@@ -234,7 +292,7 @@ def get_many_game_round(game_id):
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}')
# Helper_App.console_log(f'{_m}: game_id={game_id}')
try:
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -263,7 +321,7 @@ def get_many_game_player_damage(game_id):
, Model_View_MTG_Base.FLAG_DATA: damage_records
})
except Exception as e:
Helper_App.console_log(f'{_m} Error: {str(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)}'
@@ -274,7 +332,7 @@ def get_many_game_player_damage(game_id):
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}')
# 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, {}))
@@ -301,7 +359,7 @@ def save_game_player():
objs_player = []
for player in players:
obj_player = MTG_Game_Player.from_json(player)
Helper_App.console_log(f'obj_player = {obj_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)
@@ -325,7 +383,7 @@ def save_game_player():
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}')
# Helper_App.console_log(f'{_m}\n{data}')
try:
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -342,7 +400,7 @@ def save_game_round_player_damage():
objs_round = []
for round in rounds:
obj_round = MTG_Game_Round.from_json(round)
Helper_App.console_log(f'obj_round = {obj_round}')
# Helper_App.console_log(f'obj_round = {obj_round}')
objs_round.append(obj_round)
damages = data.get(Model_View_MTG_Base.FLAG_DAMAGE, [])
@@ -355,7 +413,7 @@ def save_game_round_player_damage():
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}')
# 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)
@@ -379,14 +437,14 @@ def save_game_round_player_damage():
@routes_mtg_game.route(Model_View_MTG_Base.HASH_PAGE_MTG_DECKS, methods=['GET'])
def decks():
Helper_App.console_log('mtg decks')
Helper_App.console_log(f'request_args: {request.args}')
# Helper_App.console_log('mtg decks')
# Helper_App.console_log(f'request_args: {request.args}')
try:
form_filters = Filters_MTG_Deck.from_json(request.args)
except Exception as e:
Helper_App.console_log(f'Error: {e}')
# Helper_App.console_log(f'Error: {e}')
form_filters = Filters_MTG_Deck()
Helper_App.console_log(f'form_filters={form_filters}')
# Helper_App.console_log(f'form_filters={form_filters}')
datastore = DataStore_MTG()
user_session = datastore.get_user_session()
@@ -397,6 +455,6 @@ def decks():
model = Model_View_MTG_Decks(parameters_deck = parameters_deck)
model.form_filters = form_filters
Helper_App.console_log(f'form_filters={form_filters}')
# Helper_App.console_log(f'form_filters={form_filters}')
return render_template('pages/tcg/mtg/_decks.html', model=model)

View File

@@ -82,20 +82,22 @@ def login():
, state = quote(hash_callback)
)
except Exception as e:
Helper_App.console_log(f"Error: {str(e)}")
Helper_App.console_log(f"Login 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"""
"""
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:
@@ -113,17 +115,17 @@ def login_callback():
try:
token = oauth.auth0.authorize_access_token()
except Exception as e:
Helper_App.console_log(f"Error: {str(e)}")
Helper_App.console_log(f"Login callback token 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')
# Helper_App.console_log('hash is none')
state = request.args.get('state')
Helper_App.console_log(f'state: {state}')
# Helper_App.console_log(f'state: {state}')
hash_callback = state
Helper_App.console_log(f'hash_callback: {hash_callback}')
# Helper_App.console_log(f'hash_callback: {hash_callback}')
except:
Helper_App.console_log("get hash callback failed")
@@ -136,7 +138,7 @@ def login_callback():
return redirect(f"{current_app.config['URL_HOST']}{hash_callback}") # login()
user = User.from_json_auth0(token)
Helper_App.console_log(f'user: {user}')
# Helper_App.console_log(f'User from Auth0 json: {user}')
"""
session[Model_View_Base.FLAG_USER] = user.to_json()
Helper_App.console_log(f'user stored on session')
@@ -146,18 +148,19 @@ def login_callback():
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}')
if (saved_user is None): raise ValueError(f'Not found.')
# 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}')
# Helper_App.console_log(f'Saved user JSON: {saved_user_json}')
session[Model_View_Base.FLAG_USER] = saved_user_json
Helper_App.console_log(f'user stored on session')
# 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)")}')
# 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}'})
@@ -171,7 +174,7 @@ def logout():
"client_id": current_app.config['ID_AUTH0_CLIENT'],
}
)
Helper_App.console_log(f"Redirecting to {url_logout}")
# Helper_App.console_log(f"Redirecting to {url_logout}")
return redirect(url_logout)
@routes_user.route("/logout_callback")
@@ -197,14 +200,14 @@ def user():
@routes_user.route(Model_View_User.HASH_PAGE_USER_ACCOUNTS)
def users():
try:
Helper_App.console_log(f'request_args: {request.args}')
# 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}')
# 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)
@@ -236,7 +239,7 @@ def save_user():
objs_user = []
for user in users:
objs_user.append(User.from_json(user))
Helper_App.console_log(f'objs_user={objs_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):

View File

@@ -59,7 +59,7 @@ class DataStore_Base(BaseModel):
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}')
# 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:
@@ -70,7 +70,7 @@ class DataStore_Base(BaseModel):
# Fetch all rows as mappings before connection closes
if result.returns_rows:
rows = result.mappings().fetchall()
Helper_App.console_log(f'result: {rows}')
# Helper_App.console_log(f'result: {rows}')
return rows
# Map SQLAlchemy types to PostgreSQL type names for CAST()
@@ -108,49 +108,49 @@ class DataStore_Base(BaseModel):
func_string += ')'
stmt = text(func_string)
Helper_App.console_log(f'{_m}\nfunc_string: {stmt}\nargs: {argument_dict_list}')
# 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}')
# 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()}')
Helper_App.console_log(f'db_cursor_clear\nunexpected result set: {cursor.fetchall()}')
@staticmethod
def get_user_session():
Helper_App.console_log('DataStore_Base.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}')
# 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}')
# 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")
# 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())}')
# 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.")
# 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}')
# 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):
@@ -180,7 +180,7 @@ class DataStore_Base(BaseModel):
except Exception as e:
db.session.rollback()
raise e
Helper_App.console_log(f'Records uploaded in batches.')
# Helper_App.console_log(f'Records uploaded in batches.')
@classmethod
def get_many_error(cls, guid):
@@ -189,23 +189,23 @@ class DataStore_Base(BaseModel):
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}')
# 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}')
# 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}')
# Helper_App.console_log(f'error {str(type(new_error))}: {new_error}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -219,7 +219,7 @@ class DataStore_Base(BaseModel):
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}')
# Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
cls.db_procedure_execute('tcg.public.USP_Error_Clear', argument_dict, argument_types)

View File

@@ -18,6 +18,7 @@ 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_game_session_member import MTG_Game_Session_Member, Parameters_MTG_Game_Session_Member
from business_objects.tcg.statistic import Statistic, Statistic_Temp, Parameters_Statistic
from business_objects.sql_error import SQL_Error, Parameters_SQL_Error
from datastores.datastore_base import DataStore_Base
@@ -45,23 +46,23 @@ class DataStore_MTG(DataStore_Base):
# 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}')
# 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}')
# 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}')
# Helper_App.console_log(f'game {str(type(new_game))}: {new_game}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -109,7 +110,7 @@ class DataStore_MTG(DataStore_Base):
, 'o_game_id': Integer
, 'o_success': Boolean
}
Helper_App.console_log(f'argument_dict: {argument_dict}')
# Helper_App.console_log(f'argument_dict: {argument_dict}')
errors = []
try:
@@ -117,12 +118,12 @@ class DataStore_MTG(DataStore_Base):
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}')
# 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)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -136,20 +137,20 @@ class DataStore_MTG(DataStore_Base):
_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}')
# 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}')
# 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}')
# Helper_App.console_log(f'player {str(type(new_player))}: {new_player}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -161,20 +162,20 @@ class DataStore_MTG(DataStore_Base):
_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}')
# 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}')
# 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}')
# Helper_App.console_log(f'round {str(type(new_round))}: {new_round}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -186,20 +187,20 @@ class DataStore_MTG(DataStore_Base):
_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}')
# 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}')
# 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}')
# 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)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -211,20 +212,20 @@ class DataStore_MTG(DataStore_Base):
_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}')
# 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}')
# 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}')
# Helper_App.console_log(f'deck {str(type(new_deck))}: {new_deck}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -250,7 +251,7 @@ class DataStore_MTG(DataStore_Base):
, 'a_user_id': Integer
, 'o_success': Boolean
}
Helper_App.console_log(f'argument_dict: {argument_dict}')
# Helper_App.console_log(f'argument_dict: {argument_dict}')
objs_player_temp = []
for player in players:
@@ -268,12 +269,12 @@ class DataStore_MTG(DataStore_Base):
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}')
# 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)}')
# Helper_App.console_log(f'Errors: {str(errors)}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -300,7 +301,7 @@ class DataStore_MTG(DataStore_Base):
, 'a_user_id': Integer
, 'o_success': Boolean
}
Helper_App.console_log(f'argument_dict: {argument_dict}')
# Helper_App.console_log(f'argument_dict: {argument_dict}')
objs_round_temp = []
for round in rounds:
@@ -328,12 +329,12 @@ class DataStore_MTG(DataStore_Base):
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}')
# 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)}')
# Helper_App.console_log(f'Errors: {str(errors)}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -348,20 +349,20 @@ class DataStore_MTG(DataStore_Base):
_m = f'{cls.__qualname__}.get_many_mtg_deck_commander_bracket'
argument_dict = parameters_commander_bracket.to_json()
argument_types = Parameters_MTG_Deck.get_type_hints()
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
# Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
commander_brackets = []
errors = []
try:
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Deck_Commander_Bracket_Get_Many', argument_dict, argument_types)
result_set = result.fetchall()
Helper_App.console_log(f'raw commander brackets: {result_set}')
# Helper_App.console_log(f'raw commander brackets: {result_set}')
for row in result_set:
new_commander_bracket = MTG_Deck_Commander_Bracket.from_db_mtg_deck_commander_bracket(row)
commander_brackets.append(new_commander_bracket)
Helper_App.console_log(f'commander bracket {str(type(new_commander_bracket))}: {new_commander_bracket}')
# Helper_App.console_log(f'commander bracket {str(type(new_commander_bracket))}: {new_commander_bracket}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
@@ -374,22 +375,44 @@ class DataStore_MTG(DataStore_Base):
_m = f'{cls.__qualname__}.get_many_statistic'
argument_dict = parameters_statistic.to_json()
argument_types = Parameters_MTG_Deck.get_type_hints()
Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
# Helper_App.console_log(f'{_m}\nargument_dict: {argument_dict}')
statistics = []
errors = []
try:
result = cls.db_function_execute('tcg.public.FN_TCG_Statistic_Get_Many', argument_dict, argument_types)
result_set = result.fetchall()
Helper_App.console_log(f'raw commander brackets: {result_set}')
# Helper_App.console_log(f'raw commander brackets: {result_set}')
for row in result_set:
new_statistic = Statistic.from_db_statistic(row)
statistics.append(new_statistic)
Helper_App.console_log(f'statistic {str(type(new_statistic))}: {new_statistic}')
# Helper_App.console_log(f'statistic {str(type(new_statistic))}: {new_statistic}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
return statistics, errors
return statistics,
@classmethod
def get_many_mtg_game_session_member(cls, member_filters):
argument_dict = member_filters.to_json()
argument_types = Parameters_MTG_Game_Session_Member.get_type_hints()
members = []
errors = []
try:
result = cls.db_function_execute('tcg.public.FN_TCG_MTG_Game_Session_Member_Get_Many', argument_dict, argument_types)
result_set = result.fetchall()
for row in result_set:
new_member = MTG_Game_Session_Member.from_db_mtg_game_player(row)
members.append(new_member)
except Exception as e:
error = SQL_Error()
error.msg = str(e)
errors.append(error)
return members, errors

View File

@@ -15,6 +15,7 @@ Datastore for Users
import lib.argument_validation as av
from business_objects.sql_error import SQL_Error
from business_objects.tcg.user import User, Parameters_User
from business_objects.tcg.user_relationship import User_Relationship, Parameters_User_Relationship
from datastores.datastore_base import DataStore_Base
from helpers.helper_app import Helper_App
from helpers.helper_db_sql import Helper_DB_SQL
@@ -41,33 +42,55 @@ class DataStore_User(DataStore_Base):
@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}')
# 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}')
# 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}')
# Helper_App.console_log(f'raw users: {user_result_set}')
for row in user_result_set:
Helper_App.console_log(f'row: {row}')
# 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}')
# Helper_App.console_log(f'user {str(type(user))}: {user}')
except Exception as e:
Helper_App.console_log(f'Error: {str(e)}')
# Helper_App.console_log(f'Error: {str(e)}')
error = SQL_Error()
error.msg = str(e)
errors.append(error)
return users, errors
@classmethod
def get_many_user_relationship(cls, relationship_filters):
_m = f'{cls.__qualname__}.get_many_user_relationship'
av.val_instance(relationship_filters, 'relationship_filters', _m, Parameters_User_Relationship)
argument_dict = relationship_filters.to_json()
relationships = []
errors = []
try:
result = cls.db_function_execute('tcg.public.FN_TCG_User_Relationship_Get_Many', argument_dict, Parameters_User_Relationship.get_type_hints())
result_set = result.fetchall()
for row in result_set:
relationship = User_Relationship.from_db_user_relationship(row)
relationships.append(relationship)
except Exception as e:
error = SQL_Error()
error.msg = str(e)
errors.append(error)
return relationships, errors
@classmethod
def login_user(cls, user):
_m = f'{cls}.login_user'
@@ -75,7 +98,7 @@ class DataStore_User(DataStore_Base):
guid = Helper_DB_SQL.create_guid_str()
Helper_App.console_log(f'login user: {user}')
# Helper_App.console_log(f'login user: {user}')
success = False
user_id = None
@@ -92,8 +115,8 @@ class DataStore_User(DataStore_Base):
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}')
# 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)

View File

@@ -63,7 +63,7 @@ class Filters_MTG_Game(Form_Base):
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
Helper_App.console_log(f'{_m}\njson: {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)
@@ -112,7 +112,7 @@ class Filters_MTG_Game_Player(Form_Base):
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
Helper_App.console_log(f'{_m}\njson: {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)
@@ -156,7 +156,7 @@ class Filters_MTG_Deck(Form_Base):
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
Helper_App.console_log(f'{_m}\njson: {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)

View File

@@ -41,7 +41,7 @@ class Filters_User(Form_Base):
@classmethod
def from_json(cls, json):
_m = f'{cls.__qualname__}.from_json'
Helper_App.console_log(f'{_m}\njson: {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')

View File

@@ -19,7 +19,7 @@ class Helper_App(BaseModel):
@staticmethod
def get_request_data(request):
Helper_App.console_log(f'request={request}')
# Helper_App.console_log(f'request={request}')
data = {}
try:
data = request.json
@@ -31,7 +31,7 @@ class Helper_App(BaseModel):
data = request.form
except:
pass
Helper_App.console_log(f'data={data}')
# Helper_App.console_log(f'data={data}')
return data
@staticmethod

View File

@@ -249,7 +249,7 @@ class Model_View_Base(BaseModel, ABC):
self.app = current_app
with self.app.app_context():
self.session = session
Helper_App.console_log(f'session: {self.session}')
# Helper_App.console_log(f'session: {self.session}')
datastore_base = DataStore_Base()
self.user = datastore_base.get_user_session()

View File

@@ -75,7 +75,7 @@ class Model_View_MTG_Base(Model_View_Base):
def __init__(self, hash_page_current, **kwargs):
_m = 'Model_View_MTG_Base.__init__'
Helper_App.console_log(f'{_m}\nstarting')
# 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:

View File

@@ -34,21 +34,16 @@ class Model_View_MTG_Decks(Model_View_MTG_Base):
def __init__(self, parameters_deck=None, hash_page_current=Model_View_MTG_Base.HASH_PAGE_MTG_DECKS):
_m = 'Model_View_MTG_Decks.__init__'
Helper_App.console_log(f'{_m}\nstarting...')
# Helper_App.console_log(f'{_m}\nstarting...')
super().__init__(hash_page_current=hash_page_current)
self._title = 'MTG Decks'
datastore = DataStore_MTG()
# 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
parameters_deck = Parameters_MTG_Deck.get_default(self.user.user_id)
self.decks, errors = datastore.get_many_mtg_deck(parameters_deck)
Helper_App.console_log(f'Decks IDs: {self.decks}')
# Helper_App.console_log(f'Decks IDs: {self.decks}')
# Get all commander brackets
parameters_commander_bracket = Parameters_MTG_Deck_Commander_Bracket.get_default()
parameters_commander_bracket.get_all_commander_bracket = True
@@ -56,12 +51,12 @@ class Model_View_MTG_Decks(Model_View_MTG_Base):
parameters_commander_bracket.require_any_id_filters_met = False
self.commander_brackets, errors = datastore.get_many_mtg_deck_commander_bracket(parameters_commander_bracket = parameters_commander_bracket)
Helper_App.console_log(f'Brackets: {self.commander_brackets}')
# Helper_App.console_log(f'Brackets: {self.commander_brackets}')
commander_bracket_index = {}
for index_commander_bracket in range(len(self.commander_brackets)):
bracket = self.commander_brackets[index_commander_bracket]
commander_bracket_index[bracket.commander_bracket_id] = bracket
Helper_App.console_log(f'Bracket IDs: {commander_bracket_index}')
# Helper_App.console_log(f'Bracket IDs: {commander_bracket_index}')
deck_index = {}
for index_deck in range(len(self.decks)):

View File

@@ -36,6 +36,8 @@ class Model_View_MTG_Game(Model_View_MTG_Base):
FLAG_ROUND_DISPLAY_ORDER_BUTTON: ClassVar[str] = 'btn-round-display-order'
FLAG_ROUND_DISPLAY_ORDER_MINUS: ClassVar[str] = 'round-display-order-minus'
FLAG_ROUND_DISPLAY_ORDER_PLUS: ClassVar[str] = 'round-display-order-plus'
GAME_DATA_OUTDATED_LABEL_ID: ClassVar[str] = 'game-data-outdated-label'
ID_OVERLAY_GAME_OUTDATED: ClassVar[str] = 'overlay-game-outdated'
PLAYER_SETUP_WRAPPER_TEMPLATE_ID: ClassVar[str] = 'player-setup-wrapper-template'
damage_records: list = None
@@ -53,7 +55,7 @@ class Model_View_MTG_Game(Model_View_MTG_Base):
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...')
# Helper_App.console_log(f'{_m}\nstarting...')
super().__init__(hash_page_current=hash_page_current)
self._title = 'MTG Game'
datastore = DataStore_MTG()
@@ -68,7 +70,7 @@ class Model_View_MTG_Game(Model_View_MTG_Base):
self.game = games[0]
# Get all decks
parameters_deck = Parameters_MTG_Deck.get_default()
parameters_deck = Parameters_MTG_Deck.get_default(user_session.user_id)
parameters_deck.get_all_deck = True
parameters_deck.require_all_id_filters_met = False
parameters_deck.require_any_id_filters_met = False

View File

@@ -29,7 +29,7 @@ class Model_View_MTG_Games(Model_View_MTG_Base):
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...')
# Helper_App.console_log(f'{_m}\nstarting...')
super().__init__(hash_page_current=hash_page_current)
self._title = 'MTG Games'
datastore = DataStore_MTG()
@@ -41,5 +41,5 @@ class Model_View_MTG_Games(Model_View_MTG_Base):
else:
self.parameters_game = parameters_game
Helper_App.console_log(f'Query args: {self.parameters_game}')
# Helper_App.console_log(f'Query args: {self.parameters_game}')
self.games, errors = datastore.get_many_mtg_game(self.parameters_game)

View File

@@ -27,6 +27,6 @@ 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...')
# Helper_App.console_log(f'{_m}\nstarting...')
super().__init__(hash_page_current=hash_page_current)
self._title = 'MTG Home'

View File

@@ -37,13 +37,13 @@ class Model_View_User(Model_View_Base):
self._title = 'Users'
self.form_filters = form_filters_old
Helper_App.console_log(f'Form filters: {self.form_filters}')
# 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}')
# Helper_App.console_log(f'Query args: {parameters_user}')
self.users, errors = datastore.get_many_user(parameters_user)

View File

@@ -0,0 +1,29 @@
CREATE TABLE tcg.public.TCG_User_Relationship (
relationship_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, follower_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_follower_user_id
FOREIGN KEY (follower_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, following_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_following_user_id
FOREIGN KEY (following_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, is_following BOOLEAN NOT NULL DEFAULT TRUE
, is_blocked BOOLEAN NOT NULL DEFAULT FALSE
, active BOOLEAN NOT NULL DEFAULT TRUE
, created_on TIMESTAMP NOT NULL
, created_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_created_by_user_id
FOREIGN KEY (created_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, updated_last_on TIMESTAMP NOT NULL
, updated_last_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_updated_last_by_user_id
FOREIGN KEY (updated_last_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, change_set_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_change_set_id
FOREIGN KEY (change_set_id)
REFERENCES tcg.public.TCG_Change_Set(change_set_id)
);

View File

@@ -0,0 +1,15 @@
CREATE TABLE tcg.public.TCG_User_Relationship_Audit (
audit_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, relationship_id INT NOT NULL
, CONSTRAINT FK_TCG_User_Audit_relationship_id
FOREIGN KEY (relationship_id)
REFERENCES tcg.public.TCG_User_Relationship(relationship_id)
, name_field TEXT NOT NULL
, value_prev TEXT
, value_new TEXT
, change_set_id INT NOT NULL
, CONSTRAINT FK_TCG_User_Audit_change_set_id
FOREIGN KEY (change_set_id)
REFERENCES tcg.public.TCG_Change_Set(change_set_id)
);

View File

@@ -0,0 +1,17 @@
CREATE TABLE tcg.public.TCG_User_Relationship_Temp (
temp_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, relationship_id INT
, follower_user_id INT
, following_user_id INT
, is_following BOOLEAN
, is_blocked BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
, guid UUID NOT NULL
);

View File

@@ -3,17 +3,8 @@ CREATE TABLE tcg.public.TCG_MTG_Inventory_Temp (
temp_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, inventory_id INT
, card_id INT
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_card_id
FOREIGN KEY (card_id)
REFERENCES tcg.public.TCG_MTG_Card(card_id)
, finish_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_finish_id
FOREIGN KEY (finish_id)
REFERENCES tcg.public.TCG_MTG_Finish(finish_id)
, condition_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_condition_id
FOREIGN KEY (condition_id)
REFERENCES tcg.public.TCG_Condition(condition_id)
, sleeve_colour_name TEXT
, location_name TEXT
, acquired_from TEXT
@@ -31,40 +22,22 @@ CREATE TABLE tcg.public.TCG_MTG_Inventory_Temp (
, miscut_errors TEXT
, playability TEXT
, owner_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_owner_user_id
FOREIGN KEY (owner_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, ownership_status_name TEXT
, trading_status_name TEXT
, loaned_to_user_id INT
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_loaned_to_user_id
FOREIGN KEY (loaned_to_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, loan_start_on TIMESTAMP
, loan_end_on TIMESTAMP
, provenance TEXT
, signed_by_names TEXT
, signature_condition_name TEXT
, token_rear_side_card_id INT
, CONSTRAINT FK_TCG_MTG_Inventory_token_rear_side_card_id
FOREIGN KEY (token_rear_side_card_id)
REFERENCES tcg.public.TCG_MTG_Card(card_id)
, display_order INT NOT NULL
, active BOOLEAN NOT NULL DEFAULT TRUE
-- , created_on TIMESTAMP NOT NULL
, created_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_created_by_user_id
FOREIGN KEY (created_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
-- , updated_last_on TIMESTAMP NOT NULL
, updated_last_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_updated_last_by_user_id
FOREIGN KEY (updated_last_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, change_set_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Inventory_Temp_change_set_id
FOREIGN KEY (change_set_id)
REFERENCES tcg.public.TCG_Change_Set(change_set_id)
, guid UUID NOT NULL
, set_code TEXT

View File

@@ -0,0 +1,28 @@
CREATE TABLE tcg.public.TCG_MTG_Game_Session_Member (
member_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, game_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_game_id
FOREIGN KEY (game_id)
REFERENCES tcg.public.TCG_MTG_Game(game_id)
, user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_user_id
FOREIGN KEY (user_id)
REFERENCES tcg.public.TCG_User(user_id)
, is_permitted BOOLEAN NOT NULL DEFAULT FALSE
, active BOOLEAN NOT NULL DEFAULT TRUE
, created_on TIMESTAMP NOT NULL
, created_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_created_by_user_id
FOREIGN KEY (created_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, updated_last_on TIMESTAMP NOT NULL
, updated_last_by_user_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_updated_last_by_user_id
FOREIGN KEY (updated_last_by_user_id)
REFERENCES tcg.public.TCG_User(user_id)
, change_set_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_change_set_id
FOREIGN KEY (change_set_id)
REFERENCES tcg.public.TCG_Change_Set(change_set_id)
);

View File

@@ -0,0 +1,15 @@
CREATE TABLE tcg.public.TCG_MTG_Game_Session_Member_Audit (
audit_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, member_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_Audit_member_id
FOREIGN KEY (member_id)
REFERENCES tcg.public.TCG_MTG_Game_Session_Member(member_id)
, name_field TEXT NOT NULL
, value_prev TEXT
, value_new TEXT
, change_set_id INT NOT NULL
, CONSTRAINT FK_TCG_MTG_Game_Session_Member_Audit_change_set_id
FOREIGN KEY (change_set_id)
REFERENCES tcg.public.TCG_Change_Set(change_set_id)
);

View File

@@ -0,0 +1,16 @@
CREATE TABLE tcg.public.TCG_MTG_Game_Session_Member_Temp (
temp_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, member_id INT
, game_id INT
, user_id INT
, is_permitted BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
, guid UUID NOT NULL
);

View File

@@ -0,0 +1,84 @@
CREATE OR REPLACE FUNCTION tcg.public.FN_before_insert_TCG_User_Relationship()
RETURNS TRIGGER AS $$
DECLARE
r_change_set RECORD;
BEGIN
NEW.created_on = COALESCE(NEW.created_on, CURRENT_TIMESTAMP);
NEW.updated_last_on = COALESCE(NEW.updated_last_on, CURRENT_TIMESTAMP);
IF NEW.change_set_id IS NULL THEN
RAISE EXCEPTION 'Change Set ID must be provided.';
END IF;
SELECT *
INTO r_change_set
FROM tcg.public.TCG_Change_Set CHANGE_SET
WHERE NEW.change_set_id = CHANGE_SET.change_set_id
;
IF FOUND THEN
NEW.created_by_user_id := COALESCE(NEW.created_by_user_id, r_change_set.updated_last_by_user_id);
NEW.updated_last_by_user_id := COALESCE(NEW.updated_last_by_user_id, r_change_set.updated_last_by_user_id);
NEW.created_on := COALESCE(NEW.created_on, r_change_set.updated_last_on);
ELSE
RAISE EXCEPTION 'Change Set % not found.', NEW.change_set_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql
;
CREATE OR REPLACE FUNCTION tcg.public.FN_before_update_TCG_User_Relationship()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_last_on = CURRENT_TIMESTAMP;
IF OLD.change_set_id IS NOT DISTINCT FROM NEW.change_set_id THEN
RAISE EXCEPTION 'New Change Set ID must be provided.';
END IF;
INSERT INTO tcg.public.TCG_User_Relationship_Audit (
relationship_id
, name_field
, value_prev
, value_new
, change_set_id
)
-- Changed follower_user_id
SELECT NEW.relationship_id, 'follower_user_id', OLD.follower_user_id::TEXT, NEW.follower_user_id::TEXT, NEW.change_set_id
WHERE OLD.follower_user_id IS NOT DISTINCT FROM NEW.follower_user_id
UNION
-- Changed following_user_id
SELECT NEW.relationship_id, 'following_user_id', OLD.following_user_id::TEXT, NEW.following_user_id::TEXT, NEW.change_set_id
WHERE OLD.following_user_id IS NOT DISTINCT FROM NEW.following_user_id
UNION
-- Changed is_following
SELECT NEW.relationship_id, 'is_following', OLD.is_following::TEXT, NEW.is_following::TEXT, NEW.change_set_id
WHERE OLD.is_following IS NOT DISTINCT FROM NEW.is_following
UNION
-- Changed is_blocked
SELECT NEW.relationship_id, 'is_blocked', OLD.is_blocked::TEXT, NEW.is_blocked::TEXT, NEW.change_set_id
WHERE OLD.is_blocked IS NOT DISTINCT FROM NEW.is_blocked
UNION
-- Changed active
SELECT NEW.relationship_id, 'active', OLD.active::TEXT, NEW.active::TEXT, NEW.change_set_id
WHERE OLD.active IS NOT DISTINCT FROM NEW.active
;
RETURN NEW;
END;
$$ LANGUAGE plpgsql
;
CREATE TRIGGER TRI_before_insert_TCG_User_Relationship
BEFORE INSERT ON tcg.public.TCG_User_Relationship
FOR EACH ROW
EXECUTE FUNCTION tcg.public.FN_before_insert_TCG_User_Relationship()
;
CREATE TRIGGER TRI_before_update_TCG_User_Relationship
BEFORE UPDATE ON tcg.public.TCG_User_Relationship
FOR EACH ROW
EXECUTE FUNCTION tcg.public.FN_before_update_TCG_User_Relationship()
;

View File

@@ -0,0 +1,76 @@
CREATE OR REPLACE FUNCTION tcg.public.FN_before_insert_TCG_MTG_Game_Session_Member()
RETURNS TRIGGER AS $$
DECLARE
r_change_set RECORD;
BEGIN
NEW.created_on = COALESCE(NEW.created_on, CURRENT_TIMESTAMP);
NEW.updated_last_on = COALESCE(NEW.updated_last_on, CURRENT_TIMESTAMP);
IF NEW.change_set_id IS NULL THEN
RAISE EXCEPTION 'Change Set ID must be provided.';
END IF;
SELECT *
INTO r_change_set
FROM tcg.public.TCG_Change_Set CHANGE_SET
WHERE NEW.change_set_id = CHANGE_SET.change_set_id
;
IF FOUND THEN
NEW.created_by_user_id := COALESCE(NEW.created_by_user_id, r_change_set.updated_last_by_user_id);
NEW.updated_last_by_user_id := COALESCE(NEW.updated_last_by_user_id, r_change_set.updated_last_by_user_id);
NEW.created_on := COALESCE(NEW.created_on, r_change_set.updated_last_on);
ELSE
RAISE EXCEPTION 'Change Set % not found.', NEW.change_set_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql
;
CREATE OR REPLACE FUNCTION tcg.public.FN_before_update_TCG_MTG_Game_Session_Member()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_last_on = CURRENT_TIMESTAMP;
IF OLD.change_set_id IS NOT DISTINCT FROM NEW.change_set_id THEN
RAISE EXCEPTION 'New Change Set ID must be provided.';
END IF;
INSERT INTO tcg.public.TCG_MTG_Game_Session_Member_Audit (
member_id
, name_field
, value_prev
, value_new
, change_set_id
)
-- Changed user_id
SELECT NEW.member_id, 'user_id', OLD.user_id::TEXT, NEW.user_id::TEXT, NEW.change_set_id
WHERE OLD.user_id IS NOT DISTINCT FROM NEW.user_id
UNION
-- Changed is_permitted
SELECT NEW.member_id, 'is_permitted', OLD.is_permitted::TEXT, NEW.is_permitted::TEXT, NEW.change_set_id
WHERE OLD.is_permitted IS NOT DISTINCT FROM NEW.is_permitted
UNION
-- Changed active
SELECT NEW.member_id, 'active', OLD.active::TEXT, NEW.active::TEXT, NEW.change_set_id
WHERE OLD.active IS NOT DISTINCT FROM NEW.active
;
RETURN NEW;
END;
$$ LANGUAGE plpgsql
;
CREATE TRIGGER TRI_before_insert_TCG_MTG_Game_Session_Member
BEFORE INSERT ON tcg.public.TCG_MTG_Game_Session_Member
FOR EACH ROW
EXECUTE FUNCTION tcg.public.FN_before_insert_TCG_MTG_Game_Session_Member()
;
CREATE TRIGGER TRI_before_update_TCG_MTG_Game_Session_Member
BEFORE UPDATE ON tcg.public.TCG_MTG_Game_Session_Member
FOR EACH ROW
EXECUTE FUNCTION tcg.public.FN_before_update_TCG_MTG_Game_Session_Member()
;

View File

@@ -32,9 +32,10 @@ BEGIN
o_success := FALSE;
DROP TABLE IF EXISTS Temp_User_Save_User;
-- DROP TABLE IF EXISTS Temp_User_Save_User;
DROP TABLE IF EXISTS Temp_User_Save_Error;
/*
CREATE TEMP TABLE Temp_User_Save_User (
user_id INT NOT NULL
, user_auth0_id TEXT
@@ -50,6 +51,7 @@ BEGIN
, updated_last_by_user_id INT
, change_set_id INT
);
*/
CREATE TEMP TABLE Temp_User_Save_Error (
temp_id INT GENERATED ALWAYS AS IDENTITY
@@ -68,6 +70,7 @@ BEGIN
);
END IF;
/*
INSERT INTO Temp_User_Save_User (
user_id
, user_auth0_id
@@ -85,7 +88,7 @@ BEGIN
)
SELECT
TCG_USER.user_id
, TCG_USER.user_auth0_id
, v_user_auth0_id
, TCG_USER.firstname
, TCG_USER.surname
, TCG_USER.email
@@ -98,8 +101,11 @@ BEGIN
, COALESCE(TCG_USER.updated_last_by_user_id, v_bot_user_id) -- updated_last_by_user_id
, TCG_USER.change_set_id
FROM tcg.public.TCG_User TCG_USER
WHERE TCG_USER.user_auth0_id = v_user_auth0_id
WHERE
TCG_USER.user_auth0_id = v_user_auth0_id
OR TCG_USER.email = v_email
;
*/
-- Outputs
-- Change Set
@@ -116,7 +122,14 @@ BEGIN
IF NOT EXISTS (SELECT * FROM Temp_User_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
IF NOT EXISTS (SELECT * FROM Temp_User_Save_User T_USER LIMIT 1) THEN
IF NOT EXISTS (
SELECT *
FROM tcg.public.TCG_User TCG_USER
WHERE
TCG_USER.user_auth0_id = v_user_auth0_id
OR TCG_USER.email = v_email
LIMIT 1
) THEN
-- RAISE EXCEPTION 'Valid User Auth0 ID required.';
-- New User
@@ -148,7 +161,19 @@ BEGIN
, v_bot_user_id -- updated_last_by_user_id
, v_change_set_id -- change_set_id
);
ELSEIF NOT EXISTS (
SELECT *
FROM tcg.public.TCG_User TCG_USER
WHERE TCG_USER.user_auth0_id = v_user_auth0_id
) THEN
UPDATE tcg.public.TCG_User TCG_USER
SET
user_auth0_id = v_user_auth0_id
, change_set_id = v_change_set_id
WHERE
TCG_USER.email = v_email
AND TCG_USER.active
;
END IF;
ELSE
-- Error
@@ -252,3 +277,33 @@ SELECT *
FROM tcg.public.TCG_User TCG_USER
ORDER BY TCG_USER.user_id DESC
;
/*
SELECT *
FROM tcg.public.TCG_User TCG_USER
;
INSERT INTO tcg.public.tcg_change_set (
COMMENT, updated_last_by_user_id
)
VALUES ( 'Clear Auth0 id from Teddy.', 3);
SELECT *
FROM tcg.public.tcg_change_set cs
ORDER BY cs.change_set_id DESC
;
UPDATE tcg.public.TCG_User TCG_USER
SET
user_auth0_id = NULL
, change_set_id = 224
WHERE TCG_USER.user_id = 3
;
DELETE FROM tcg.public.TCG_User TCG_USER
WHERE TCG_USER.user_id = 13
;
*/

View File

@@ -0,0 +1,131 @@
CREATE OR REPLACE FUNCTION tcg.public.FN_TCG_User_Relationship_Get_Many (
a_get_inactive_user_relationship BOOLEAN
, a_get_all_user_follower BOOLEAN
, a_user_follower_ids TEXT
, a_get_all_user_following BOOLEAN
, a_user_following_ids TEXT
, a_get_inactive_user BOOLEAN
, a_require_all_id_filters_met BOOLEAN
, a_require_any_id_filters_met BOOLEAN
)
RETURNS TABLE (
relationship_id INT
, follower_user_id INT
, following_user_id INT
, is_following BOOLEAN
, is_blocked BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
)
LANGUAGE plpgsql
AS $$
DECLARE
v_get_inactive_user_relationship BOOLEAN;
v_get_all_user_follower BOOLEAN;
v_user_follower_ids TEXT;
v_get_all_user_following BOOLEAN;
v_user_following_ids TEXT;
v_get_inactive_user BOOLEAN;
v_require_all_id_filters_met BOOLEAN;
v_require_any_id_filters_met BOOLEAN;
BEGIN
v_get_inactive_user_relationship := COALESCE(a_get_inactive_user_relationship, FALSE);
v_get_all_user_follower := COALESCE(a_get_all_user_follower, FALSE);
v_user_follower_ids := TRIM(COALESCE(a_user_follower_ids, ''));
v_get_all_user_following := COALESCE(a_get_all_user_following, FALSE);
v_user_following_ids := TRIM(COALESCE(a_user_following_ids, ''));
v_get_inactive_user := COALESCE(a_get_inactive_user, FALSE);
v_require_all_id_filters_met := COALESCE(a_require_all_id_filters_met, FALSE);
v_require_any_id_filters_met := COALESCE(a_require_any_id_filters_met, FALSE);
-- Outputs
RETURN QUERY SELECT
RELATIONSHIP.relationship_id
, RELATIONSHIP.follower_user_id
, RELATIONSHIP.following_user_id
, RELATIONSHIP.is_following
, RELATIONSHIP.is_blocked
, RELATIONSHIP.active
, RELATIONSHIP.created_on
, RELATIONSHIP.created_by_user_id
, RELATIONSHIP.updated_last_on
, RELATIONSHIP.updated_last_by_user_id
, RELATIONSHIP.change_set_id
FROM tcg.public.TCG_User_Relationship RELATIONSHIP
INNER JOIN tcg.public.TCG_User USER_FOLLOWER ON RELATIONSHIP.follower_user_id = USER_FOLLOWER.user_id
INNER JOIN tcg.public.TCG_User USER_FOLLOWING ON RELATIONSHIP.following_user_id = USER_FOLLOWING.user_id
WHERE
(
(
NOT v_require_all_id_filters_met
AND NOT v_require_any_id_filters_met
)
OR (
v_require_all_id_filters_met
AND (
v_get_all_user_follower
OR USER_FOLLOWER.user_id = ANY(string_to_array(v_user_follower_ids, ',')::INT[])
)
AND (
v_get_all_user_following
OR USER_FOLLOWING.user_id = ANY(string_to_array(v_user_following_ids, ',')::INT[])
)
)
OR (
NOT v_require_all_id_filters_met
AND v_require_any_id_filters_met
AND (
(
v_get_all_user_follower
OR USER_FOLLOWER.user_id = ANY(string_to_array(v_user_follower_ids, ',')::INT[])
)
OR (
v_get_all_user_following
OR USER_FOLLOWING.user_id = ANY(string_to_array(v_user_following_ids, ',')::INT[])
)
)
)
)
AND (
v_get_inactive_user_relationship
OR RELATIONSHIP.active
)
AND (
v_get_inactive_user
OR (
USER_FOLLOWER.active
AND USER_FOLLOWING.active
)
)
ORDER BY
RELATIONSHIP.follower_user_id
, NOT RELATIONSHIP.is_following
, NOT RELATIONSHIP.is_blocked
, RELATIONSHIP.following_user_id
;
END;
$$;
SELECT *
FROM tcg.public.FN_TCG_User_Relationship_Get_Many (
a_get_inactive_user_relationship := FALSE
, a_get_all_user_follower := TRUE
, a_user_follower_ids := ''
, a_get_all_user_following := TRUE
, a_user_following_ids := ''
, a_get_inactive_user := FALSE
, a_require_all_id_filters_met := TRUE
, a_require_any_id_filters_met := FALSE
)
;
SELECT *
FROM tcg.public.TCG_User_Relationship
;

View File

@@ -0,0 +1,532 @@
CREATE OR REPLACE PROCEDURE tcg.public.USP_TCG_User_Relationship_Save (
a_comment TEXT
, a_guid UUID
, a_user_id INT
, OUT o_success BOOLEAN
)
LANGUAGE plpgsql
AS $$
DECLARE
v_bad_data_error_type_id INT;
v_change_set_id INT;
v_comment TEXT;
-- v_error_message TEXT;
v_guid UUID;
v_time_start TIMESTAMP;
v_user_id INT;
v_warning_error_type_id INT;
BEGIN
v_comment := TRIM(COALESCE(a_comment, ''));
v_guid := a_guid;
v_user_id := a_user_id;
v_bad_data_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'BAD_DATA' LIMIT 1);
v_warning_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'WARNING' LIMIT 1);
v_time_start := CURRENT_TIMESTAMP;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User_Relationship;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
CREATE TEMP TABLE Temp_User_Relationship_Save_User (
user_id INT NOT NULL
, user_auth0_id TEXT
, firstname TEXT
, surname TEXT
, email TEXT
, is_email_verified BOOLEAN
, is_super_user BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
);
CREATE TEMP TABLE Temp_User_Relationship_Save_User_Relationship (
temp_id INT NOT NULL
, relationship_id INT
, follower_user_id INT
, following_user_id INT
, is_following BOOLEAN
, is_blocked BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
, is_new BOOLEAN
, error_name TEXT
, is_duplicate BOOLEAN
);
CREATE TEMP TABLE Temp_User_Relationship_Save_Error (
temp_id INT GENERATED ALWAYS AS IDENTITY
, error_type_id INT
, message TEXT
);
WITH Temp_User_Relationship AS (
SELECT
RELATIONSHIP_T.temp_id
, CASE WHEN COALESCE(RELATIONSHIP_T.relationship_id, 0) < 1
THEN RELATIONSHIP.relationship_id
ELSE RELATIONSHIP_T.relationship_id
END AS relationship_id
, RELATIONSHIP_T.follower_user_id
, RELATIONSHIP_T.following_user_id
, COALESCE(RELATIONSHIP_T.is_following, TRUE) AS is_following
, COALESCE(RELATIONSHIP_T.is_blocked, FALSE) AS is_blocked
, COALESCE(RELATIONSHIP_T.active, TRUE) AS active
, COALESCE(RELATIONSHIP_T.created_on, v_time_start) AS created_on
, COALESCE(RELATIONSHIP_T.created_by_user_id, v_user_id) AS created_by_user_id
, COALESCE(RELATIONSHIP_T.updated_last_on, v_time_start) AS updated_last_on
, COALESCE(RELATIONSHIP_T.updated_last_by_user_id, v_user_id) AS updated_last_by_user_id
, RELATIONSHIP_T.change_set_id
, CASE WHEN RELATIONSHIP.relationship_id IS NULL THEN TRUE ELSE FALSE END AS is_new
FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
LEFT JOIN tcg.public.TCG_User_Relationship RELATIONSHIP
ON RELATIONSHIP_T.relationship_id = RELATIONSHIP.relationship_id
OR (
COALESCE(RELATIONSHIP_T.relationship_id, 0) < 1
AND RELATIONSHIP_T.follower_user_id = RELATIONSHIP.follower_user_id
AND RELATIONSHIP_T.following_user_id = RELATIONSHIP.following_user_id
)
)
INSERT INTO Temp_User_Relationship_Save_User_Relationship (
temp_id
, relationship_id
, follower_user_id
, following_user_id
, is_following
, is_blocked
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
, is_new
, error_name
)
SELECT
T_RELATIONSHIP.temp_id
, T_RELATIONSHIP.relationship_id
, T_RELATIONSHIP.follower_user_id
, T_RELATIONSHIP.following_user_id
, T_RELATIONSHIP.is_following
, T_RELATIONSHIP.is_blocked
, T_RELATIONSHIP.active
, T_RELATIONSHIP.created_on
, T_RELATIONSHIP.created_by_user_id
, T_RELATIONSHIP.updated_last_on
, T_RELATIONSHIP.updated_last_by_user_id
, T_RELATIONSHIP.change_set_id
, T_RELATIONSHIP.is_new
, CONCAT(
'User Relationship { id: '
, CAST(T_RELATIONSHIP.relationship_id AS VARCHAR)
, ', follower user id: '
, CAST(T_RELATIONSHIP.follower_user_id AS VARCHAR)
, ', following user id: '
, CAST(T_RELATIONSHIP.following_user_id AS VARCHAR)
, ', is following: '
, CAST(T_RELATIONSHIP.is_following AS VARCHAR)
, ', is blocked: '
, CAST(T_RELATIONSHIP.is_blocked AS VARCHAR)
, ' }'
) -- error_name
FROM Temp_User_Relationship T_RELATIONSHIP -- tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
-- LEFT JOIN tcg.public.TCG_User_Relationship RELATIONSHIP ON RELATIONSHIP_T.relationship_id = RELATIONSHIP.relationship_id
;
INSERT INTO Temp_User_Relationship_Save_User (
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
)
SELECT
TCG_USER.user_id
, TCG_USER.user_auth0_id
, TCG_USER.firstname
, TCG_USER.surname
, TCG_USER.email
, TCG_USER.is_email_verified
, TCG_USER.is_super_user
, TCG_USER.active
, TCG_USER.created_on
, TCG_USER.created_by_user_id
, TCG_USER.updated_last_on
, TCG_USER.updated_last_by_user_id
, TCG_USER.change_set_id
FROM tcg.public.TCG_User TCG_USER
INNER JOIN Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
ON TCG_USER.user_id = T_RELATIONSHIP.follower_user_id
OR TCG_USER.user_id = T_RELATIONSHIP.following_user_id
;
-- Missing fields
WITH Relationship_Missing_Field AS (
SELECT
T_RELATIONSHIP.temp_id
, 'follower_user_id' AS field
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE T_RELATIONSHIP.follower_user_id IS NULL
UNION
SELECT
T_RELATIONSHIP.temp_id
, 'following_user_id' AS field
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE T_RELATIONSHIP.following_user_id IS NULL
)
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Missing mandatory field: '
, RELATIONSHIP_MISSING_FIELD.field
, ' on '
, T_RELATIONSHIP.error_name
, '.'
) -- message
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
INNER JOIN Relationship_Missing_Field RELATIONSHIP_MISSING_FIELD ON T_RELATIONSHIP.temp_id = RELATIONSHIP_MISSING_FIELD.temp_id
;
-- Failed join fields
WITH Relationship_Failed_Join_Field AS (
SELECT
T_RELATIONSHIP.temp_id
, 'follower_user_id' AS field
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
LEFT JOIN Temp_User_Relationship_Save_User T_USER ON T_RELATIONSHIP.follower_user_id = T_USER.user_id
WHERE T_USER.user_id IS NULL
UNION
SELECT
T_RELATIONSHIP.temp_id
, 'following_user_id' AS field
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
LEFT JOIN Temp_User_Relationship_Save_User T_USER ON T_RELATIONSHIP.following_user_id = T_USER.user_id
WHERE T_USER.user_id IS NULL
)
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Failed relationship: '
, RELATIONSHIP_FAILED_JOIN_FIELD.field
, ' on '
, T_RELATIONSHIP.error_name
, '.'
) -- message
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
INNER JOIN Relationship_Failed_Join_Field RELATIONSHIP_FAILED_JOIN_FIELD ON T_RELATIONSHIP.temp_id = RELATIONSHIP_FAILED_JOIN_FIELD.temp_id
;
-- Duplicate Relationship
WITH
All_Relationship AS (
SELECT
T_RELATIONSHIP.temp_id
, T_RELATIONSHIP.follower_user_id
, T_RELATIONSHIP.following_user_id
, TRUE AS is_save_record
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
UNION
SELECT
NULL AS temp_id
, RELATIONSHIP.follower_user_id
, RELATIONSHIP.following_user_id
, FALSE AS is_save_record
FROM tcg.public.TCG_User_Relationship RELATIONSHIP
LEFT JOIN Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP ON RELATIONSHIP.relationship_id = T_RELATIONSHIP.relationship_id
WHERE
T_RELATIONSHIP.relationship_id IS NULL
AND RELATIONSHIP.active
)
, Relationship_Follow_Pair AS (
SELECT
ALL_RELATIONSHIP.follower_user_id
, ALL_RELATIONSHIP.following_user_id
, COUNT(*) AS count_pair
FROM All_Relationship ALL_RELATIONSHIP
GROUP BY
ALL_RELATIONSHIP.follower_user_id
, ALL_RELATIONSHIP.following_user_id
)
, Duplicate_Relationship AS (
SELECT
ALL_RELATIONSHIP.temp_id
, ALL_RELATIONSHIP.follower_user_id
, ALL_RELATIONSHIP.following_user_id
, CASE WHEN RELATIONSHIP_PAIR.count_pair = 1 THEN TRUE ELSE FALSE END AS is_unique
FROM All_Relationship ALL_RELATIONSHIP
INNER JOIN Relationship_Follow_Pair RELATIONSHIP_PAIR
ON ALL_RELATIONSHIP.follower_user_id = RELATIONSHIP_PAIR.follower_user_id
AND ALL_RELATIONSHIP.following_user_id = RELATIONSHIP_PAIR.following_user_id
)
UPDATE Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
SET is_duplicate = NOT DUPLICATE_RELATIONSHIP.is_unique
FROM Duplicate_Relationship DUPLICATE_RELATIONSHIP
WHERE T_RELATIONSHIP.temp_id = DUPLICATE_RELATIONSHIP.temp_id
;
IF EXISTS (
SELECT *
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE T_RELATIONSHIP.is_duplicate
LIMIT 1
) THEN
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Duplicate on '
, T_RELATIONSHIP.error_name
) -- message
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE T_RELATIONSHIP.is_duplicate
;
END IF;
-- Nothing to save
IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_User_Relationship LIMIT 1) THEN
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
VALUES (
v_warning_error_type_id
, 'Nothing to save.'
);
END IF;
-- Outputs
-- Change Set
INSERT INTO tcg.public.TCG_Change_Set (
comment
, updated_last_by_user_id
)
VALUES (
v_comment
, v_user_id
)
RETURNING change_set_id INTO v_change_set_id
;
IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
-- User relationship
INSERT INTO tcg.public.TCG_User_Relationship (
follower_user_id
, following_user_id
, is_following
, is_blocked
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
T_RELATIONSHIP.follower_user_id
, T_RELATIONSHIP.following_user_id
, T_RELATIONSHIP.is_following
, T_RELATIONSHIP.is_blocked
, T_RELATIONSHIP.active
, T_RELATIONSHIP.created_on
, T_RELATIONSHIP.created_by_user_id
, T_RELATIONSHIP.updated_last_on
, T_RELATIONSHIP.updated_last_by_user_id
, v_change_set_id -- change_set_id
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE
T_RELATIONSHIP.is_new = TRUE
AND T_RELATIONSHIP.active = TRUE
ORDER BY
T_RELATIONSHIP.is_following
, T_RELATIONSHIP.is_blocked
, T_RELATIONSHIP.follower_user_id
, T_RELATIONSHIP.following_user_id
;
UPDATE tcg.public.TCG_User_Relationship RELATIONSHIP
SET
follower_user_id = T_RELATIONSHIP.follower_user_id
, following_user_id = T_RELATIONSHIP.following_user_id
, is_following = T_RELATIONSHIP.is_following
, is_blocked = T_RELATIONSHIP.is_blocked
, active = T_RELATIONSHIP.active
, updated_last_on = v_time_start
, updated_last_by_user_id = v_user_id
, change_set_id = v_change_set_id
FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
WHERE
RELATIONSHIP.relationship_id = T_RELATIONSHIP.relationship_id
AND NOT T_RELATIONSHIP.is_new
;
ELSE
-- Error
INSERT INTO tcg.public.Error (
guid
, error_type_id
, message
, display_order
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
v_guid
, T_ERROR.error_type_id
, T_ERROR.message
, T_ERROR.temp_id
, v_time_start
, v_user_id
, v_time_start
, v_user_id
, v_change_set_id
FROM Temp_User_Relationship_Save_Error T_ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON T_ERROR.error_type_id = ERROR_TYPE.error_type_id
ORDER BY T_ERROR.temp_id
;
END IF;
COMMIT;
o_success := NOT EXISTS (
SELECT *
FROM Temp_User_Relationship_Save_Error T_ERROR
WHERE T_ERROR.error_type_id <> v_warning_error_type_id
LIMIT 1
);
DELETE FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T WHERE RELATIONSHIP_T.guid = v_guid;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User_Relationship;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
END;
$$;
-- Call it with:
DO $$
DECLARE
v_comment TEXT := 'User Relationship Save.';
v_guid UUID;
v_user_id INT := 3;
v_success BOOLEAN;
BEGIN
v_guid := gen_random_uuid();
INSERT INTO tcg.public.TCG_User_Relationship_Temp (
guid
, relationship_id
, follower_user_id
, following_user_id
, is_following
, is_blocked
, active
)
VALUES
(
v_guid
, NULL -- relationship_id
, 3 -- follower_user_id
, 4 -- following_user_id
, TRUE -- is_following
, FALSE -- is_blocked
, TRUE -- active
)
, (
v_guid
, NULL -- relationship_id
, 3 -- follower_user_id
, 5 -- following_user_id
, FALSE -- is_following
, TRUE -- is_blocked
, TRUE -- active
)
, (
v_guid
, NULL -- relationship_id
, 4 -- follower_user_id
, 3 -- following_user_id
, TRUE -- is_following
, FALSE -- is_blocked
, TRUE -- active
)
;
CALL tcg.public.USP_TCG_User_Relationship_Save (
v_comment -- a_comment
, v_guid -- a_guid
, v_user_id -- a_user_id
, v_success -- o_success
);
RAISE NOTICE 'Success: %', CASE WHEN v_success THEN 'TRUE' ELSE 'FALSE' END;
END;
$$;
SELECT *
-- DELETE
FROM tcg.public.Error ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON ERROR.error_type_id = ERROR_TYPE.error_type_id
;
SELECT *
FROM tcg.public.Error_Type ERROR_TYPE
;
SELECT *
FROM tcg.public.TCG_Change_Set CHANGE_SET
ORDER BY CHANGE_SET.change_set_id DESC
;
/*
SELECT *
FROM tcg.public.TCG_MTG_Game
;
*/
SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
;
SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship RELATIONSHIP
;

View File

@@ -79,7 +79,7 @@ BEGIN
, missing_mandatory_fields TEXT
);
CREATE TABLE Temp_MTG_Inventory_Save_Card (
CREATE TEMP TABLE Temp_MTG_Inventory_Save_Card (
card_id INT NOT NULL
, all_parts TEXT
, arena_id INTEGER

View File

@@ -5,8 +5,13 @@ CREATE OR REPLACE FUNCTION tcg.public.FN_TCG_MTG_Deck_Get_Many (
, a_deck_ids TEXT
, a_deck_names TEXT
, a_commander_bracket_ids TEXT
, a_created_by_user_ids TEXT
, a_include_commander_option BOOLEAN
, a_require_all_id_filters_met BOOLEAN
, a_get_all_game BOOLEAN
, a_get_inactive_game BOOLEAN
, a_game_ids TEXT
, a_filter_by_game_session_not_player 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
@@ -30,7 +35,12 @@ DECLARE
v_get_inactive_deck BOOLEAN;
v_deck_ids TEXT;
v_deck_names TEXT;
v_created_by_user_ids TEXT;
v_include_commander_option BOOLEAN;
v_get_all_game BOOLEAN;
v_get_inactive_game BOOLEAN;
v_game_ids TEXT;
v_filter_by_game_session_not_player BOOLEAN;
v_require_all_id_filters_met BOOLEAN;
v_require_any_id_filters_met BOOLEAN;
v_require_all_non_id_filters_met BOOLEAN;
@@ -41,13 +51,19 @@ BEGIN
v_deck_ids := TRIM(COALESCE(a_deck_ids, ''));
v_deck_names := TRIM(COALESCE(a_deck_names, ''));
v_include_commander_option := COALESCE(a_include_commander_option, TRUE);
v_created_by_user_ids := TRIM(COALESCE(a_created_by_user_ids, ''));
v_get_all_game := COALESCE(a_get_all_game, FALSE);
v_get_inactive_game := COALESCE(a_get_inactive_game, FALSE);
v_game_ids := TRIM(COALESCE(a_game_ids, ''));
v_filter_by_game_session_not_player := COALESCE(a_filter_by_game_session_not_player, TRUE);
v_require_all_id_filters_met := COALESCE(a_require_all_id_filters_met, FALSE);
v_require_any_id_filters_met := COALESCE(a_require_any_id_filters_met, FALSE);
v_require_all_non_id_filters_met := COALESCE(a_require_all_non_id_filters_met, FALSE);
v_require_any_non_id_filters_met := COALESCE(a_require_any_non_id_filters_met, FALSE);
-- Outputs
RETURN QUERY SELECT
RETURN QUERY
SELECT DISTINCT
DECK.deck_id
, DECK.name
, DECK.is_commander
@@ -59,6 +75,9 @@ BEGIN
, DECK.updated_last_by_user_id
, DECK.change_set_id
FROM tcg.public.TCG_MTG_Deck DECK
LEFT JOIN tcg.public.TCG_MTG_Game SESSION_GAME ON DECK.game_id = SESSION_GAME.game_id
LEFT JOIN tcg.public.TCG_MTG_Game_Player PLAYER ON DECK.deck_id = PLAYER.deck_id
LEFT JOIN tcg.public.TCG_MTG_Game PLAYER_GAME ON PLAYER.game_id = PLAYER_GAME.game_id
WHERE
(
(
@@ -69,7 +88,21 @@ BEGIN
v_require_all_id_filters_met
AND (
v_get_all_deck
OR DECK.deck_id = ANY(string_to_array(v_deck_ids, ',')::INT[])
OR (
DECK.deck_id = ANY(string_to_array(v_deck_ids, ',')::INT[])
AND DECK.created_by_user_id = ANY(string_to_array(v_created_by_user_ids, ',')::INT[])
AND (
v_get_all_game
OR (
v_filter_by_game_session_not_player
AND SESSION_GAME.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
OR (
NOT v_filter_by_game_session_not_player
AND PLAYER.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
)
)
)
)
OR (
@@ -78,6 +111,18 @@ BEGIN
AND (
v_get_all_deck
OR DECK.deck_id = ANY(string_to_array(v_deck_ids, ',')::INT[])
OR DECK.created_by_user_id = ANY(string_to_array(v_created_by_user_ids, ',')::INT[])
OR (
v_get_all_game
OR (
v_filter_by_game_session_not_player
AND SESSION_GAME.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
OR (
NOT v_filter_by_game_session_not_player
AND PLAYER.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
)
)
)
)
@@ -113,6 +158,17 @@ BEGIN
v_get_inactive_deck
OR DECK.active
)
AND (
v_get_inactive_game
OR (
v_filter_by_game_session_not_player
AND SESSION_GAME.active
)
OR (
NOT v_filter_by_game_session_not_player
AND PLAYER_GAME.active
)
)
ORDER BY DECK.name
;
END;
@@ -126,8 +182,13 @@ FROM tcg.public.FN_TCG_MTG_Deck_Get_Many (
, a_deck_ids := CAST(NULL AS TEXT)
, a_deck_names := CAST(NULL AS TEXT)
, a_commander_bracket_ids := CAST(NULL AS TEXT)
, a_include_commander_option := TRUE
, a_require_all_id_filters_met := FALSE
, a_include_commander_option := true
, a_created_by_user_ids := '3'
, a_get_all_game := FALSE
, a_get_inactive_game := FALSE
, a_game_ids := CAST(NULL AS TEXT)
, a_filter_by_game_session_not_player := TRUE
, a_require_all_id_filters_met := TRUE
, a_require_any_id_filters_met := FALSE
, a_require_all_non_id_filters_met := FALSE
, a_require_any_non_id_filters_met := FALSE

View File

@@ -22,6 +22,8 @@ RETURNS TABLE (
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
)
LANGUAGE plpgsql
AS $$
@@ -65,6 +67,8 @@ BEGIN
, GAME.active
, GAME.created_on
, GAME.created_by_user_id
, GAME.updated_last_on
, GAME.updated_last_by_user_id
FROM tcg.public.TCG_MTG_Game GAME
INNER JOIN tcg.public.TCG_User CREATOR_USER ON GAME.created_by_user_id = CREATOR_USER.user_id
WHERE

View File

@@ -37,7 +37,7 @@ BEGIN
v_require_any_id_filters_met := COALESCE(a_require_any_id_filters_met, FALSE);
-- Outputs
RETURN QUERY
WITH User_Name AS (
SELECT
TCG_USER.user_id
@@ -46,31 +46,31 @@ BEGIN
TRIM(COALESCE(TCG_USER.firstname, '')) <> ''
AND TRIM(COALESCE(TCG_USER.surname, '')) <> ''
THEN CONCAT(
TRIM(COALESCE(TCG_USER.firstname, '')) <> ''
TRIM(COALESCE(TCG_USER.firstname, ''))
, ' '
, TRIM(COALESCE(TCG_USER.surname, '')) <> ''
, TRIM(COALESCE(TCG_USER.surname, ''))
)
WHEN TRIM(COALESCE(TCG_USER.firstname, '')) <> ''
THEN TRIM(COALESCE(TCG_USER.firstname, '')) <> ''
ELSE TRIM(COALESCE(TCG_USER.surname, '')) <> ''
THEN TRIM(COALESCE(TCG_USER.firstname, ''))
ELSE TRIM(COALESCE(TCG_USER.surname, ''))
END AS name
FROM tcg.public.TCG_User TCG_USER
)
RETURN QUERY SELECT
SELECT
PLAYER.player_id
, PLAYER.game_id
, PLAYER.user_id
, PLAYER.deck_id
, CASE
WHEN TRIM(COALESCE(PLAYER.name, '')) <> ''
THEN TRIM(COALESCE(PLAYER.name, '')) <> ''
THEN TRIM(COALESCE(PLAYER.name, ''))
WHEN
USER_NAME.name <> ''
AND TRIM(COALESCE(DECK.name, '')) <> ''
THEN CONCAT(
USER_NAME.name <> ''
USER_NAME.name
, ' - '
, TRIM(COALESCE(DECK.name, '')) <> ''
, TRIM(COALESCE(DECK.name, ''))
)
ELSE CONCAT(
'Player '

View File

@@ -10,10 +10,17 @@ AS $$
DECLARE
v_bad_data_error_type_id INT;
v_change_set_id INT;
v_comment TEXT;
-- v_error_message TEXT;
v_guid UUID;
v_time_start TIMESTAMP;
v_user_id INT;
v_warning_error_type_id INT;
BEGIN
v_comment := TRIM(COALESCE(a_comment, ''));
v_guid := a_guid;
v_user_id := a_user_id;
v_bad_data_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'BAD_DATA' LIMIT 1);
v_warning_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'WARNING' LIMIT 1);
v_time_start := CURRENT_TIMESTAMP;
@@ -22,9 +29,10 @@ BEGIN
DROP TABLE IF EXISTS Temp_MTG_Player_Save_User;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Deck;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Player;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_User_Relationship;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Error;
CREATE TABLE Temp_MTG_Player_Save_Game (
CREATE TEMP TABLE Temp_MTG_Player_Save_Game (
game_id INT NOT NULL
, notes TEXT
, is_commander BOOLEAN
@@ -33,6 +41,7 @@ BEGIN
, location_name TEXT
, start_on TIMESTAMP
, end_on TIMESTAMP
, starting_life INT
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
@@ -41,7 +50,7 @@ BEGIN
, change_set_id INT
);
CREATE TABLE Temp_MTG_Player_Save_User (
CREATE TEMP TABLE Temp_MTG_Player_Save_User (
user_id INT NOT NULL
, user_auth0_id TEXT
, firstname TEXT
@@ -57,7 +66,7 @@ BEGIN
, change_set_id INT
);
CREATE TABLE Temp_MTG_Player_Save_Deck (
CREATE TEMP TABLE Temp_MTG_Player_Save_Deck (
deck_id INT NOT NULL
, name TEXT
, is_commander BOOLEAN
@@ -70,7 +79,7 @@ BEGIN
, change_set_id INT
);
CREATE TABLE Temp_MTG_Player_Save_Player (
CREATE TEMP TABLE Temp_MTG_Player_Save_Player (
temp_id INT NOT NULL
, player_id INT
, game_id INT
@@ -90,12 +99,57 @@ BEGIN
, is_duplicate BOOLEAN
);
CREATE TEMP TABLE Temp_MTG_Player_Save_User_Relationship (
relationship_id INT
, follower_user_id INT
, following_user_id INT
, is_following BOOLEAN
, is_blocked BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
, is_new BOOLEAN
, error_name TEXT
);
CREATE TEMP TABLE Temp_MTG_Player_Save_Error (
temp_id INT GENERATED ALWAYS AS IDENTITY
, error_type_id INT
, message TEXT
);
WITH Temp_Player AS (
SELECT
PLAYER_T.temp_id
, CASE WHEN COALESCE(PLAYER_T.player_id, 0) < 1
THEN PLAYER.player_id
ELSE PLAYER_T.player_id
END AS player_id
, PLAYER_T.game_id
, PLAYER_T.user_id
, PLAYER_T.deck_id
, PLAYER_T.name
, PLAYER_T.notes
, PLAYER_T.display_order
, COALESCE(PLAYER_T.active, TRUE) AS active
, COALESCE(PLAYER_T.created_on, v_time_start) AS created_on
, COALESCE(PLAYER_T.created_by_user_id, v_user_id) AS created_by_user_id
, COALESCE(PLAYER_T.updated_last_on, v_time_start) AS updated_last_on
, COALESCE(PLAYER_T.updated_last_by_user_id, v_user_id) AS updated_last_by_user_id
FROM tcg.public.TCG_MTG_Game_Player_Temp PLAYER_T
LEFT JOIN tcg.public.TCG_MTG_Game_Player PLAYER
ON PLAYER_T.player_id = PLAYER.player_id
OR (
COALESCE(PLAYER_T.player_id, 0) < 1
AND PLAYER_T.game_id = PLAYER.game_id
AND PLAYER_T.display_order = PLAYER.display_order
)
WHERE PLAYER_T.guid = v_guid
)
INSERT INTO Temp_MTG_Player_Save_Player (
temp_id
, player_id
@@ -115,37 +169,35 @@ BEGIN
, error_name
)
SELECT
PLAYER_T.temp_id
, PLAYER_T.player_id
, PLAYER_T.game_id
, PLAYER_T.user_id
, PLAYER_T.deck_id
, PLAYER_T.name
, PLAYER_T.notes
, PLAYER_T.display_order
, COALESCE(PLAYER_T.active, TRUE)
, COALESCE(PLAYER_T.created_on, v_time_start) -- created_on
, COALESCE(PLAYER_T.created_by_user_id, a_user_id) -- created_by_user_id
, COALESCE(PLAYER_T.updated_last_on, v_time_start) -- updated_last_on
, COALESCE(PLAYER_T.updated_last_by_user_id, a_user_id) -- updated_last_by_user_id
T_PLAYER.temp_id
, T_PLAYER.player_id
, T_PLAYER.game_id
, T_PLAYER.user_id
, T_PLAYER.deck_id
, T_PLAYER.name
, T_PLAYER.notes
, T_PLAYER.display_order
, T_PLAYER.active
, T_PLAYER.created_on
, T_PLAYER.created_by_user_id
, T_PLAYER.updated_last_on
, T_PLAYER.updated_last_by_user_id
, CASE WHEN PLAYER.player_id IS NULL THEN TRUE ELSE FALSE END AS is_new
, CASE WHEN T_PLAYER.player_id IS NULL THEN TRUE ELSE FALSE END AS is_new
, CONCAT(
'Player { id: '
, CAST(PLAYER_T.player_id AS VARCHAR)
, CAST(T_PLAYER.player_id AS VARCHAR)
, ', temp id: '
, CAST(PLAYER_T.temp_id AS VARCHAR)
, CAST(T_PLAYER.temp_id AS VARCHAR)
, ', display order: '
, CAST(PLAYER_T.display_order AS VARCHAR)
, CAST(T_PLAYER.display_order AS VARCHAR)
, ', game id: '
, CAST(PLAYER_T.game_id AS VARCHAR)
, CAST(T_PLAYER.game_id AS VARCHAR)
, ', name: '
, PLAYER_T.name
, T_PLAYER.name
, ' }'
) -- error_name
FROM tcg.public.TCG_MTG_Game_Player_Temp PLAYER_T
LEFT JOIN tcg.public.TCG_MTG_Game_Player PLAYER ON PLAYER_T.player_id = PLAYER.player_id
WHERE PLAYER_T.guid = a_guid
FROM Temp_Player T_PLAYER
;
INSERT INTO Temp_MTG_Player_Save_Game (
@@ -157,6 +209,7 @@ BEGIN
, location_name
, start_on
, end_on
, starting_life
, active
, created_on
, created_by_user_id
@@ -164,7 +217,7 @@ BEGIN
, updated_last_by_user_id
, change_set_id
)
SELECT
SELECT DISTINCT
GAME.game_id
, GAME.notes
, GAME.is_commander
@@ -173,6 +226,7 @@ BEGIN
, GAME.location_name
, GAME.start_on
, GAME.end_on
, GAME.starting_life
, GAME.active
, GAME.created_on
, GAME.created_by_user_id
@@ -180,7 +234,7 @@ BEGIN
, GAME.updated_last_by_user_id
, GAME.change_set_id
FROM tcg.public.TCG_MTG_Game GAME
INNER JOIN Temp_MTG_Player_Save_Player PLAYER ON GAME.game_id = PLAYER.game_id
INNER JOIN Temp_MTG_Player_Save_Player PLAYER_T ON GAME.game_id = PLAYER_T.game_id
;
INSERT INTO Temp_MTG_Player_Save_User (
@@ -198,7 +252,7 @@ BEGIN
, updated_last_by_user_id
, change_set_id
)
SELECT
SELECT DISTINCT
TCG_USER.user_id
, TCG_USER.user_auth0_id
, TCG_USER.firstname
@@ -213,7 +267,7 @@ BEGIN
, TCG_USER.updated_last_by_user_id
, TCG_USER.change_set_id
FROM tcg.public.TCG_User TCG_USER
INNER JOIN Temp_MTG_Player_Save_Player PLAYER ON TCG_USER.user_id = PLAYER.user_id
INNER JOIN Temp_MTG_Player_Save_Player PLAYER_T ON TCG_USER.user_id = PLAYER_T.user_id
;
INSERT INTO Temp_MTG_Player_Save_Deck (
@@ -243,6 +297,90 @@ BEGIN
INNER JOIN Temp_MTG_Player_Save_Player PLAYER ON DECK.deck_id = DECK.deck_id
;
WITH
All_Game_User_Link AS (
SELECT
T_GAME.game_id
, T_USER.user_id
FROM Temp_MTG_Player_Save_Game T_GAME
CROSS JOIN Temp_MTG_Player_Save_User T_USER
WHERE
T_GAME.active
AND T_USER.active
)
, All_User_Relationship AS (
SELECT DISTINCT
RELATIONSHIP.relationship_id
, GAME_USER_FOLLOWER.user_id AS follower_user_id
, GAME_USER_FOLLOWING.user_id AS following_user_id
, COALESCE(RELATIONSHIP.is_following, TRUE) AS is_following
, COALESCE(RELATIONSHIP.is_blocked, FALSE) AS is_blocked
, COALESCE(RELATIONSHIP.active, TRUE) AS active
, COALESCE(RELATIONSHIP.created_on, v_time_start) AS created_on
, COALESCE(RELATIONSHIP.created_by_user_id, v_user_id) AS created_by_user_id
, COALESCE(RELATIONSHIP.updated_last_on, v_time_start) AS updated_last_on
, COALESCE(RELATIONSHIP.updated_last_by_user_id, v_user_id) AS updated_last_by_user_id
, RELATIONSHIP.change_set_id
, CASE WHEN RELATIONSHIP.relationship_id IS NULL THEN TRUE ELSE FALSE END AS Is_New
FROM All_Game_User_Link GAME_USER_FOLLOWER
CROSS JOIN All_Game_User_Link GAME_USER_FOLLOWING
LEFT JOIN tcg.public.TCG_User_Relationship RELATIONSHIP
ON GAME_USER_FOLLOWER.user_id = RELATIONSHIP.follower_user_id
AND GAME_USER_FOLLOWING.user_id = RELATIONSHIP.following_user_id
WHERE
GAME_USER_FOLLOWER.user_id <> GAME_USER_FOLLOWING.user_id
AND GAME_USER_FOLLOWER.game_id = GAME_USER_FOLLOWING.game_id
)
INSERT INTO Temp_MTG_Player_Save_User_Relationship (
relationship_id
, follower_user_id
, following_user_id
, is_following
, is_blocked
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
, is_new
, error_name
)
SELECT
ALL_RELATIONSHIP.relationship_id
, ALL_RELATIONSHIP.follower_user_id
, ALL_RELATIONSHIP.following_user_id
, ALL_RELATIONSHIP.is_following
, ALL_RELATIONSHIP.is_blocked
, ALL_RELATIONSHIP.active
, ALL_RELATIONSHIP.created_on
, ALL_RELATIONSHIP.created_by_user_id
, ALL_RELATIONSHIP.updated_last_on
, ALL_RELATIONSHIP.updated_last_by_user_id
, ALL_RELATIONSHIP.change_set_id
, ALL_RELATIONSHIP.Is_New
, CONCAT(
'User Relationship { id: '
, CAST(ALL_RELATIONSHIP.relationship_id AS VARCHAR)
, ', follower user id: '
, CAST(ALL_RELATIONSHIP.follower_user_id AS VARCHAR)
, ', following user id: '
, CAST(ALL_RELATIONSHIP.following_user_id AS VARCHAR)
, ', is following: '
, CAST(ALL_RELATIONSHIP.is_following AS VARCHAR)
, ', is blocked: '
, CAST(ALL_RELATIONSHIP.is_blocked AS VARCHAR)
, ' is new: '
, CAST(ALL_RELATIONSHIP.is_new AS VARCHAR)
, ' }'
) -- error_name
FROM All_User_Relationship ALL_RELATIONSHIP
-- WHERE ALL_RELATIONSHIP.Is_New
;
-- Missing fields
WITH Player_Missing_Field AS (
SELECT
@@ -354,7 +492,7 @@ BEGIN
SELECT
ALL_PLAYER.game_id
, ALL_PLAYER.display_order
, COUNT(*) AS count
, COUNT(*) AS count_display_order
FROM All_Player ALL_PLAYER
GROUP BY
ALL_PLAYER.game_id
@@ -364,7 +502,7 @@ BEGIN
SELECT
ALL_PLAYER.game_id
, ALL_PLAYER.deck_id
, COUNT(*) AS count
, COUNT(*) AS count_deck
FROM All_Player ALL_PLAYER
GROUP BY
ALL_PLAYER.game_id
@@ -377,14 +515,21 @@ BEGIN
, ALL_PLAYER.deck_id
, ALL_PLAYER.display_order
-- , CASE WHEN CARD.temp_id IS NULL THEN TRUE ELSE FALSE END AS is_unique
, CASE WHEN PLAYER_DECK.count = 1 THEN TRUE ELSE FALSE END AS is_unique_deck
, CASE WHEN PLAYER_DISPLAY_ORDER.count = 1 THEN TRUE ELSE FALSE END AS is_unique_display_order
, CASE WHEN PLAYER_DECK.count_deck = 1 THEN TRUE ELSE FALSE END AS is_unique_deck
, CASE WHEN PLAYER_DISPLAY_ORDER.count_display_order = 1 THEN TRUE ELSE FALSE END AS is_unique_display_order
FROM All_Player ALL_PLAYER
INNER JOIN Player_Deck PLAYER_DECK ON PLAYER.deck_id = PLAYER_DECK.deck_id
INNER JOIN Player_Display_Order PLAYER_DISPLAY_ORDER ON PLAYER.display_order = PLAYER_DISPLAY_ORDER.display_order
INNER JOIN Player_Deck PLAYER_DECK
ON ALL_PLAYER.game_id = PLAYER_DECK.game_id
AND ALL_PLAYER.deck_id = PLAYER_DECK.deck_id
INNER JOIN Player_Display_Order PLAYER_DISPLAY_ORDER
ON ALL_PLAYER.game_id = PLAYER_DISPLAY_ORDER.game_id
AND ALL_PLAYER.display_order = PLAYER_DISPLAY_ORDER.display_order
)
UPDATE Temp_MTG_Player_Save_Player T_PLAYER
SET is_duplicate = CASE WHEN NOT ( is_unique_deck AND is_unique_display_order ) THEN TRUE ELSE FALSE END
SET is_duplicate = CASE WHEN NOT (
DUPLICATE_PLAYER.is_unique_deck
AND DUPLICATE_PLAYER.is_unique_display_order
) THEN TRUE ELSE FALSE END
FROM Duplicate_Player DUPLICATE_PLAYER
WHERE T_PLAYER.temp_id = DUPLICATE_PLAYER.temp_id
;
@@ -422,6 +567,29 @@ BEGIN
);
END IF;
/*
INSERT INTO Temp_MTG_Player_Save_Error (
error_type_id
, message
)
SELECT
v_warning_error_type_id AS error_type_id
, CONCAT(
'Users: '
, STRING_AGG(T_PLAYER.error_name, ', ')
) AS message
FROM Temp_MTG_Player_Save_Player T_PLAYER
UNION
SELECT
v_warning_error_type_id AS error_type_id
, CONCAT(
'User relationships: '
, STRING_AGG(T_RELATIONSHIP.error_name, ', ')
) AS message
FROM Temp_MTG_Player_Save_User_Relationship T_RELATIONSHIP
;
*/
-- Outputs
-- Change Set
INSERT INTO tcg.public.TCG_Change_Set (
@@ -429,14 +597,42 @@ BEGIN
, updated_last_by_user_id
)
VALUES (
a_comment
, a_user_id
v_comment
, v_user_id
)
RETURNING change_set_id INTO v_change_set_id
;
IF NOT EXISTS (SELECT * FROM Temp_MTG_Player_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
-- User relationship
INSERT INTO tcg.public.TCG_User_Relationship (
follower_user_id
, following_user_id
, is_following
, is_blocked
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
T_RELATIONSHIP.follower_user_id
, T_RELATIONSHIP.following_user_id
, T_RELATIONSHIP.is_following
, T_RELATIONSHIP.is_blocked
, T_RELATIONSHIP.active
, T_RELATIONSHIP.created_on
, T_RELATIONSHIP.created_by_user_id
, T_RELATIONSHIP.updated_last_on
, T_RELATIONSHIP.updated_last_by_user_id
, v_change_set_id -- change_set_id
FROM Temp_MTG_Player_Save_User_Relationship T_RELATIONSHIP
WHERE T_RELATIONSHIP.is_new
;
-- Player
INSERT INTO tcg.public.TCG_MTG_Game_Player (
game_id
@@ -460,11 +656,11 @@ BEGIN
, T_PLAYER.notes
, T_PLAYER.display_order
, T_PLAYER.active
, v_time_start -- created_on
, a_user_id -- created_by_user_id
, v_time_start -- updated_last_on
, a_user_id -- updated_last_by_user_id
, v_change_set_id -- change_set_id
, T_PLAYER.created_on
, T_PLAYER.created_by_user_id
, T_PLAYER.updated_last_on
, T_PLAYER.updated_last_by_user_id
, v_change_set_id -- change_set_id
FROM Temp_MTG_Player_Save_Player T_PLAYER
LEFT JOIN Temp_MTG_Player_Save_Game T_GAME ON T_PLAYER.game_id = T_GAME.game_id
WHERE
@@ -485,42 +681,43 @@ BEGIN
, display_order = T_PLAYER.display_order
, active = T_PLAYER.active
, updated_last_on = v_time_start
, updated_last_by_user_id = a_user_id
, updated_last_by_user_id = v_user_id
, change_set_id = v_change_set_id
FROM Temp_MTG_Player_Save_Player T_PLAYER
WHERE
PLAYER.player_id = T_PLAYER.player_id
AND NOT T_PLAYER.is_new
;
ELSE
-- Error
INSERT INTO tcg.public.Error (
guid
, error_type_id
, message
, display_order
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
a_guid
, T_ERROR.error_type_id
, T_ERROR.message
, T_ERROR.temp_id
, v_time_start
, a_user_id
, v_time_start
, a_user_id
, v_change_set_id
FROM Temp_MTG_Player_Save_Error T_ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON T_ERROR.error_type_id = ERROR_TYPE.error_type_id
ORDER BY T_ERROR.temp_id
;
END IF;
-- Error
INSERT INTO tcg.public.Error (
guid
, error_type_id
, message
, display_order
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
v_guid
, T_ERROR.error_type_id
, T_ERROR.message
, T_ERROR.temp_id
, v_time_start
, v_user_id
, v_time_start
, v_user_id
, v_change_set_id
FROM Temp_MTG_Player_Save_Error T_ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON T_ERROR.error_type_id = ERROR_TYPE.error_type_id
ORDER BY T_ERROR.temp_id
;
COMMIT;
o_success := NOT EXISTS (
@@ -530,12 +727,13 @@ BEGIN
LIMIT 1
);
DELETE FROM tcg.public.TCG_MTG_Game_Player_Temp PLAYER_T WHERE PLAYER_T.guid = a_guid;
DELETE FROM tcg.public.TCG_MTG_Game_Player_Temp PLAYER_T WHERE PLAYER_T.guid = v_guid;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Game;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_User;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Deck;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Player;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_User_Relationship;
DROP TABLE IF EXISTS Temp_MTG_Player_Save_Error;
END;
$$;
@@ -657,5 +855,14 @@ FROM tcg.public.TCG_MTG_Game_Player PLAYER
LEFT JOIN tcg.public.TCG_MTG_Game GAME ON PLAYER.game_id = GAME.game_id
;
SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship_Audit RELATIONSHIP_AUDIT
;
SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship RELATIONSHIP
;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
CREATE OR REPLACE FUNCTION tcg.public.FN_TCG_MTG_Game_Session_Member_Get_Many (
a_get_inactive_session_member BOOLEAN
, 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
)
RETURNS TABLE (
member_id INT
, game_id INT
, user_id INT
, is_permitted BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
)
LANGUAGE plpgsql
AS $$
DECLARE
v_get_inactive_session_member BOOLEAN;
v_get_all_game BOOLEAN;
v_get_inactive_game BOOLEAN;
v_game_ids TEXT;
v_get_all_user BOOLEAN;
v_get_inactive_user BOOLEAN;
v_user_ids TEXT;
v_require_all_id_filters_met BOOLEAN;
v_require_any_id_filters_met BOOLEAN;
-- , v_require_all_non_id_filters_met BOOLEAN
-- , v_require_any_non_id_filters_met BOOLEAN
BEGIN
v_get_inactive_session_member := COALESCE(a_get_inactive_session_member, FALSE);
v_get_all_game := COALESCE(a_get_all_game, FALSE);
v_get_inactive_game := COALESCE(a_get_inactive_game, FALSE);
v_game_ids := TRIM(COALESCE(a_game_ids, ''));
v_get_all_user := COALESCE(a_get_all_user, FALSE);
v_get_inactive_user := COALESCE(a_get_inactive_user, FALSE);
v_user_ids := TRIM(COALESCE(a_user_ids, ''));
v_require_all_id_filters_met := COALESCE(a_require_all_id_filters_met, FALSE);
v_require_any_id_filters_met := COALESCE(a_require_any_id_filters_met, FALSE);
-- Outputs
RETURN QUERY SELECT
SESSION_MEMBER.member_id
, SESSION_MEMBER.game_id
, SESSION_MEMBER.user_id
, SESSION_MEMBER.is_permitted
, SESSION_MEMBER.active
, SESSION_MEMBER.created_on
, SESSION_MEMBER.created_by_user_id
, SESSION_MEMBER.updated_last_on
, SESSION_MEMBER.updated_last_by_user_id
FROM tcg.public.TCG_MTG_Game_Session_Member SESSION_MEMBER
INNER JOIN tcg.public.TCG_MTG_Game GAME ON SESSION_MEMBER.game_id = GAME.game_id
INNER JOIN tcg.public.TCG_User MEMBER_USER ON SESSION_MEMBER.user_id = MEMBER_USER.user_id
WHERE
(
(
NOT v_require_all_id_filters_met
AND NOT v_require_any_id_filters_met
)
OR (
v_require_all_id_filters_met
AND (
v_get_all_game
OR SESSION_MEMBER.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
AND (
a_get_all_user
OR MEMBER_USER.user_id = ANY(string_to_array(v_user_ids, ',')::INT[])
)
)
OR (
NOT v_require_all_id_filters_met
AND v_require_any_id_filters_met
AND (
v_get_all_game
OR SESSION_MEMBER.game_id = ANY(string_to_array(v_game_ids, ',')::INT[])
)
AND (
v_get_all_user
OR MEMBER_USER.user_id = ANY(string_to_array(v_user_ids, ',')::INT[])
)
)
)
AND (
v_get_inactive_session_member
OR SESSION_MEMBER.active
)
AND (
v_get_inactive_game
OR GAME.active
)
AND (
v_get_inactive_user
OR MEMBER_USER.active
)
ORDER BY
GAME.game_id
, MEMBER_USER.firstname
, MEMBER_USER.surname
;
END;
$$;
SELECT *
FROM tcg.public.FN_TCG_MTG_Game_Session_Member_Get_Many (
a_get_inactive_session_member := FALSE
, a_get_all_game := TRUE
, a_get_inactive_game := FALSE
, a_game_ids := ''
, a_get_all_user := TRUE
, a_get_inactive_user := FALSE
, a_user_ids := ''
, a_require_all_id_filters_met := TRUE
, a_require_any_id_filters_met := FALSE
)
;
/*
SELECT *
FROM tcg.public.TCG_MTG_Game_Session_Member
;
SELECT *
FROM tcg.public.TCG_User
;
SELECT *
FROM tcg.public.TCG_MTG_Deck
;
*/

View File

@@ -0,0 +1,532 @@
CREATE OR REPLACE PROCEDURE tcg.public.USP_TCG_MTG_Game_Session_Member_Save (
a_comment TEXT
, a_guid UUID
, a_user_id INT
, OUT o_success BOOLEAN
)
LANGUAGE plpgsql
AS $$
DECLARE
v_bad_data_error_type_id INT;
v_change_set_id INT;
-- v_error_message TEXT;
v_time_start TIMESTAMP;
v_warning_error_type_id INT;
BEGIN
v_bad_data_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'BAD_DATA' LIMIT 1);
v_warning_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'WARNING' LIMIT 1);
v_time_start := CURRENT_TIMESTAMP;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Game;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Session_Member;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
CREATE TEMP TABLE Temp_User_Relationship_Save_Game (
game_id INT NOT NULL
, notes TEXT
, is_commander BOOLEAN
, is_draft BOOLEAN
, is_sealed BOOLEAN
, location_name TEXT
, start_on TIMESTAMP
, end_on TIMESTAMP
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
);
CREATE TEMP TABLE Temp_User_Relationship_Save_User (
user_id INT NOT NULL
, user_auth0_id TEXT
, firstname TEXT
, surname TEXT
, email TEXT
, is_email_verified BOOLEAN
, is_super_user BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, change_set_id INT
);
CREATE TEMP TABLE Temp_User_Relationship_Save_Session_Member (
temp_id INT NOT NULL
, member_id INT
, game_id INT
, user_id INT
, is_permitted BOOLEAN
, active BOOLEAN
, created_on TIMESTAMP
, created_by_user_id INT
, updated_last_on TIMESTAMP
, updated_last_by_user_id INT
, is_new BOOLEAN
, error_name TEXT
, is_duplicate BOOLEAN
);
CREATE TEMP TABLE Temp_User_Relationship_Save_Error (
temp_id INT GENERATED ALWAYS AS IDENTITY
, error_type_id INT
, message TEXT
);
INSERT INTO Temp_User_Relationship_Save_Session_Member (
temp_id
, member_id
, game_id
, user_id
, is_permitted
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, is_new
, error_name
)
SELECT
SESSION_MEMBER_T.temp_id
, SESSION_MEMBER_T.member_id
, SESSION_MEMBER_T.game_id
, SESSION_MEMBER_T.user_id
, COALESCE(SESSION_MEMBER_T.is_permitted, FALSE) -- is_permitted
, COALESCE(SESSION_MEMBER_T.active, TRUE) -- active
, COALESCE(SESSION_MEMBER_T.created_on, v_time_start) -- created_on
, COALESCE(SESSION_MEMBER_T.created_by_user_id, a_user_id) -- created_by_user_id
, COALESCE(SESSION_MEMBER_T.updated_last_on, v_time_start) -- updated_last_on
, COALESCE(SESSION_MEMBER_T.updated_last_by_user_id, a_user_id) -- updated_last_by_user_id
, CASE WHEN SESSION_MEMBER .member_id IS NULL THEN TRUE ELSE FALSE END AS is_new
, CONCAT(
'Member { id: '
, CAST(SESSION_MEMBER_T.member_id AS VARCHAR)
, ', temp id: '
, CAST(SESSION_MEMBER_T.temp_id AS VARCHAR)
, ', game id: '
, CAST(SESSION_MEMBER_T.game_id AS VARCHAR)
, ', user id: '
, CAST(SESSION_MEMBER_T.user_id AS VARCHAR)
, ' }'
) -- error_name
FROM tcg.public.TCG_MTG_Game_Session_Member_Temp SESSION_MEMBER_T
LEFT JOIN tcg.public.TCG_MTG_Game_Session_Member SESSION_MEMBER ON SESSION_MEMBER_T.member_id = SESSION_MEMBER.member_id
WHERE SESSION_MEMBER_T.guid = a_guid
;
INSERT INTO Temp_User_Relationship_Save_Game (
game_id
, notes
, is_commander
, is_draft
, is_sealed
, location_name
, start_on
, end_on
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT DISTINCT
GAME.game_id
, GAME.notes
, GAME.is_commander
, GAME.is_draft
, GAME.is_sealed
, GAME.location_name
, GAME.start_on
, GAME.end_on
, GAME.active
, GAME.created_on
, GAME.created_by_user_id
, GAME.updated_last_on
, GAME.updated_last_by_user_id
, GAME.change_set_id
FROM tcg.public.TCG_MTG_Game GAME
INNER JOIN Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T ON GAME.game_id = SESSION_MEMBER_T.game_id
;
INSERT INTO Temp_User_Relationship_Save_User (
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
)
SELECT DISTINCT
TCG_USER.user_id
, TCG_USER.user_auth0_id
, TCG_USER.firstname
, TCG_USER.surname
, TCG_USER.email
, TCG_USER.is_email_verified
, TCG_USER.is_super_user
, TCG_USER.active
, TCG_USER.created_on
, TCG_USER.created_by_user_id
, TCG_USER.updated_last_on
, TCG_USER.updated_last_by_user_id
, TCG_USER.change_set_id
FROM tcg.public.TCG_User TCG_USER
INNER JOIN Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T ON TCG_USER.user_id = SESSION_MEMBER_T.user_id
;
-- Missing fields
WITH Session_Member_Missing_Field AS (
SELECT
SESSION_MEMBER_T.temp_id
, 'game_id' AS field
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
WHERE SESSION_MEMBER_T.game_id IS NULL
UNION
SELECT
SESSION_MEMBER_T.temp_id
, 'user_id' AS field
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
WHERE SESSION_MEMBER_T.user_id IS NULL
)
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Missing mandatory field: '
, SESSION_MEMBER_MISSING_FIELD.field
, ' on '
, SESSION_MEMBER_T.error_name
, '.'
) -- message
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
INNER JOIN Session_Member_Missing_Field SESSION_MEMBER_MISSING_FIELD ON SESSION_MEMBER_T.temp_id = SESSION_MEMBER_MISSING_FIELD.temp_id
;
-- Failed join fields
WITH Session_Member_Failed_Join_Field AS (
SELECT
SESSION_MEMBER_T.temp_id
, 'game_id' AS field
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
LEFT JOIN Temp_User_Relationship_Save_Game T_GAME ON SESSION_MEMBER_T.game_id = T_GAME.game_id
WHERE T_GAME.game_id IS NULL
UNION
SELECT
SESSION_MEMBER_T.temp_id
, 'user_id' AS field
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
LEFT JOIN Temp_User_Relationship_Save_User T_USER ON SESSION_MEMBER_T.user_id = T_USER.user_id
WHERE T_USER.user_id IS NULL
)
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Failed relationship: '
, SESSION_MEMBER_FAILED_JOIN_FIELD.field
, ' on '
, SESSION_MEMBER_T.error_name
, '.'
) -- message
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
INNER JOIN Session_Member_Failed_Join_Field SESSION_MEMBER_FAILED_JOIN_FIELD ON SESSION_MEMBER_T.temp_id = SESSION_MEMBER_FAILED_JOIN_FIELD.temp_id
;
-- Duplicate Session Member
-- By game and user
WITH
All_Session_Member AS (
SELECT
SESSION_MEMBER_T.temp_id
, SESSION_MEMBER_T.game_id
, SESSION_MEMBER_T.user_id
, TRUE AS is_save_record
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
UNION
SELECT
NULL AS temp_id
, SESSION_MEMBER.game_id
, SESSION_MEMBER.user_id
, FALSE AS is_save_record
FROM tcg.public.TCG_MTG_Game_Session_Member SESSION_MEMBER
LEFT JOIN Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T ON SESSION_MEMBER.member_id = SESSION_MEMBER_T.member_id
WHERE
SESSION_MEMBER_T.member_id IS NULL
AND SESSION_MEMBER.active
)
, Session_Member_Count AS (
SELECT
ALL_SESSION_MEMBER.game_id
, ALL_SESSION_MEMBER.user_id
, COUNT(*) AS count_members
FROM All_Session_Member ALL_SESSION_MEMBER
GROUP BY
ALL_SESSION_MEMBER.game_id
, ALL_SESSION_MEMBER.user_id
)
, Duplicate_Session_Member AS (
SELECT
ALL_SESSION_MEMBER.temp_id
, ALL_SESSION_MEMBER.game_id
, ALL_SESSION_MEMBER.user_id
, CASE WHEN SESSION_MEMBER_COUNT.count_members = 1 THEN TRUE ELSE FALSE END AS is_unique_member
FROM All_Session_Member ALL_SESSION_MEMBER
INNER JOIN Session_Member_Count SESSION_MEMBER_COUNT
ON ALL_SESSION_MEMBER.game_id = SESSION_MEMBER_COUNT.game_id
AND ALL_SESSION_MEMBER.user_id = SESSION_MEMBER_COUNT.user_id
)
UPDATE Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
SET is_duplicate = CASE WHEN NOT DUPLICATE_SESSION_MEMBER.is_unique_member THEN TRUE ELSE FALSE END
FROM Duplicate_Session_Member DUPLICATE_SESSION_MEMBER
WHERE SESSION_MEMBER_T.temp_id = DUPLICATE_SESSION_MEMBER.temp_id
;
IF EXISTS (
SELECT *
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
WHERE SESSION_MEMBER_T.is_duplicate
LIMIT 1
) THEN
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
SELECT
v_bad_data_error_type_id -- error_type_id
, CONCAT(
'Duplicate on '
, SESSION_MEMBER_T.error_name
) -- message
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
WHERE SESSION_MEMBER_T.is_duplicate
;
END IF;
-- Nothing to save
IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_Session_Member LIMIT 1) THEN
INSERT INTO Temp_User_Relationship_Save_Error (
error_type_id
, message
)
VALUES (
v_warning_error_type_id
, 'Nothing to save.'
);
END IF;
-- Outputs
-- Change Set
INSERT INTO tcg.public.TCG_Change_Set (
comment
, updated_last_by_user_id
)
VALUES (
a_comment
, a_user_id
)
RETURNING change_set_id INTO v_change_set_id
;
IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
-- Session Member
INSERT INTO tcg.public.TCG_MTG_Game_Session_Member (
game_id
, user_id
, is_permitted
, active
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
SESSION_MEMBER_T.game_id
, SESSION_MEMBER_T.user_id
, SESSION_MEMBER_T.is_permitted
, SESSION_MEMBER_T.active
, v_time_start -- created_on
, a_user_id -- created_by_user_id
, v_time_start -- updated_last_on
, a_user_id -- updated_last_by_user_id
, v_change_set_id -- change_set_id
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
LEFT JOIN Temp_User_Relationship_Save_Game T_GAME ON SESSION_MEMBER_T.game_id = T_GAME.game_id
WHERE
SESSION_MEMBER_T.is_new = TRUE
AND SESSION_MEMBER_T.active = TRUE
ORDER BY
T_GAME.created_on
, T_GAME.game_id
, SESSION_MEMBER_T.is_permitted
, SESSION_MEMBER_T.user_id
;
UPDATE tcg.public.TCG_MTG_Game_Session_Member SESSION_MEMBER
SET
game_id = SESSION_MEMBER_T.game_id
, user_id = SESSION_MEMBER_T.user_id
, is_permitted = SESSION_MEMBER_T.is_permitted
, active = SESSION_MEMBER_T.active
, updated_last_on = v_time_start
, updated_last_by_user_id = a_user_id
, change_set_id = v_change_set_id
FROM Temp_User_Relationship_Save_Session_Member SESSION_MEMBER_T
WHERE
SESSION_MEMBER.member_id = SESSION_MEMBER_T.member_id
AND NOT SESSION_MEMBER_T.is_new
;
END IF;
-- Error
INSERT INTO tcg.public.Error (
guid
, error_type_id
, message
, display_order
, created_on
, created_by_user_id
, updated_last_on
, updated_last_by_user_id
, change_set_id
)
SELECT
a_guid
, T_ERROR.error_type_id
, T_ERROR.message
, T_ERROR.temp_id
, v_time_start
, a_user_id
, v_time_start
, a_user_id
, v_change_set_id
FROM Temp_User_Relationship_Save_Error T_ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON T_ERROR.error_type_id = ERROR_TYPE.error_type_id
ORDER BY T_ERROR.temp_id
;
COMMIT;
o_success := NOT EXISTS (
SELECT *
FROM Temp_User_Relationship_Save_Error T_ERROR
WHERE T_ERROR.error_type_id <> v_warning_error_type_id
LIMIT 1
);
DELETE FROM tcg.public.TCG_MTG_Game_Session_Member_Temp SESSION_MEMBER_T WHERE SESSION_MEMBER_T.guid = a_guid;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Game;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_User;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Session_Member;
DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
END;
$$;
-- Call it with:
DO $$
DECLARE
v_comment TEXT := 'MTG Game Session Member Save.';
v_guid UUID;
v_user_id INT := 3;
v_success BOOLEAN;
BEGIN
v_guid := gen_random_uuid();
INSERT INTO tcg.public.TCG_MTG_Game_Session_Member_Temp (
guid
, member_id
, game_id
, user_id
, is_permitted
, active
)
VALUES
(
v_guid
, NULL -- member_id
, 4 -- game_id
, 3 -- user_id
, TRUE -- is_permitted
, TRUE -- active
)
, (
v_guid
, NULL -- member_id
, 4 -- game_id
, 4 -- user_id
, FALSE -- is_permitted
, TRUE -- active
)
/*
, (
v_guid
, NULL -- member_id
, 4 -- game_id
, 3 -- user_id
, FALSE -- is_permitted
, TRUE -- active
)
*/
;
CALL tcg.public.USP_TCG_MTG_Game_Session_Member_Save (
v_comment -- a_comment
, v_guid -- a_guid
, v_user_id -- a_user_id
, v_success -- o_success
);
RAISE NOTICE 'Success: %', CASE WHEN v_success THEN 'TRUE' ELSE 'FALSE' END;
END;
$$;
SELECT *
-- DELETE
FROM tcg.public.Error ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON ERROR.error_type_id = ERROR_TYPE.error_type_id
;
SELECT *
FROM tcg.public.Error_Type ERROR_TYPE
;
SELECT *
FROM tcg.public.TCG_Change_Set CHANGE_SET
ORDER BY CHANGE_SET.change_set_id DESC
;
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Session_Member_Temp
;
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Session_Member SESSION_MEMBER
LEFT JOIN tcg.public.TCG_MTG_Game GAME ON SESSION_MEMBER.game_id = GAME.game_id
;

View File

@@ -854,6 +854,7 @@ BEGIN
AND T_ROUND_PLAYER.display_order >= T_ROUND_DAMAGE.display_order
INNER JOIN Temp_Statistic_Calc_Round_Player_Damage T_PLAYER_DAMAGE
ON T_ROUND_DAMAGE.round_id = T_PLAYER_DAMAGE.round_id
AND ALL_PLAYER_ROUND.player_id = T_PLAYER_DAMAGE.player_id
AND T_PLAYER_DAMAGE.received_from_commander_player_id IS NOT NULL
GROUP BY
ALL_PLAYER_ROUND.game_id
@@ -889,6 +890,7 @@ BEGIN
AND T_ROUND_PLAYER.display_order >= T_ROUND_DAMAGE.display_order
INNER JOIN Temp_Statistic_Calc_Round_Player_Damage T_PLAYER_DAMAGE
ON T_ROUND_DAMAGE.round_id = T_PLAYER_DAMAGE.round_id
AND ALL_PLAYER_ROUND.player_id = T_PLAYER_DAMAGE.player_id
AND T_PLAYER_DAMAGE.received_from_commander_player_id = ALL_PLAYER_ROUND.player_id
GROUP BY
ALL_PLAYER_ROUND.game_id
@@ -910,6 +912,7 @@ BEGIN
AND T_ROUND_PLAYER.display_order >= T_ROUND_DAMAGE.display_order
INNER JOIN Temp_Statistic_Calc_Round_Player_Damage T_PLAYER_DAMAGE
ON T_ROUND_DAMAGE.round_id = T_PLAYER_DAMAGE.round_id
AND ALL_PLAYER_ROUND.player_id = T_PLAYER_DAMAGE.player_id
AND T_PLAYER_DAMAGE.life_loss > 0
GROUP BY
ALL_PLAYER_ROUND.game_id
@@ -931,6 +934,7 @@ BEGIN
AND T_ROUND_PLAYER.display_order >= T_ROUND_DAMAGE.display_order
INNER JOIN Temp_Statistic_Calc_Round_Player_Damage T_PLAYER_DAMAGE
ON T_ROUND_DAMAGE.round_id = T_PLAYER_DAMAGE.round_id
AND ALL_PLAYER_ROUND.player_id = T_PLAYER_DAMAGE.player_id
GROUP BY
ALL_PLAYER_ROUND.game_id
, ALL_PLAYER_ROUND.player_id
@@ -951,6 +955,7 @@ BEGIN
AND T_ROUND_PLAYER.display_order >= T_ROUND_DAMAGE.display_order
INNER JOIN Temp_Statistic_Calc_Round_Player_Damage T_PLAYER_DAMAGE
ON T_ROUND_DAMAGE.round_id = T_PLAYER_DAMAGE.round_id
AND ALL_PLAYER_ROUND.player_id = T_PLAYER_DAMAGE.player_id
AND T_PLAYER_DAMAGE.life_gain > 0
GROUP BY
ALL_PLAYER_ROUND.game_id
@@ -1010,7 +1015,7 @@ BEGIN
INNER JOIN Temp_Statistic_Calc_Game T_GAME ON T_PLAYER_ROUND_LINK.game_id = T_GAME.game_id
WHERE
T_PLAYER_ROUND_LINK.max_total_commander_damage_received >= v_commander_damage_limit
OR T_PLAYER_ROUND_LINK.total_damage_received >= T_GAME.starting_life
OR T_PLAYER_ROUND_LINK.total_damage_received - T_PLAYER_ROUND_LINK.total_life_gained >= T_GAME.starting_life
OR T_PLAYER_ROUND_LINK.is_eliminated
GROUP BY
T_PLAYER_ROUND_LINK.player_id
@@ -9376,6 +9381,8 @@ BEGIN
IF NOT EXISTS (SELECT * FROM Temp_Statistic_Calc_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
DELETE FROM tcg.public.TCG_Statistic;
-- Statistic
INSERT INTO tcg.public.TCG_Statistic (
entity_type_code

View File

@@ -1,8 +1,7 @@
.tcg-card {
margin-top: 1vh;
margin-bottom: 0;
margin: 1vh 0 auto;
}

View File

@@ -1,5 +1,9 @@
/* MTG Single Game Page Styles */
.tcg-title.dirty {
background-color: var(--tcg-accent-purple);
}
#buttonHamburger {
display: none;
}
@@ -100,7 +104,7 @@
.control-group {
display: flex;
align-items: center;
gap: 1rem;
gap: 0.5rem;
}
.control-group .tcg-input {
@@ -113,7 +117,7 @@
.player-names-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
gap: 0.5rem;
max-width: 800px;
margin: 0 auto 2rem;
justify-content: center;
@@ -230,7 +234,7 @@
transition: all 0.4s ease;
animation: tcg-scaleIn 0.5s ease-out backwards;
width: fit-content;
max-width: 38vw;
max-width: 35vw;
min-width: 20vw;
margin: 0 auto;
}
@@ -256,7 +260,7 @@
align-items: center;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
gap: 0.5rem;
}
.player-info {
@@ -353,7 +357,7 @@
.life-gain-controls,
.life-loss-controls {
display: flex;
gap: 1rem;
gap: 0.5rem;
justify-content: center;
margin-bottom: 1vh;
}
@@ -364,7 +368,7 @@
border: 2px solid var(--tcg-border-color);
color: var(--tcg-text-primary);
width: 60px;
height: 60px;
height: 45px;
border-radius: 12px;
font-family: 'Cinzel', serif;
font-size: 1.8rem;

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
@@ -67,8 +66,7 @@
.tcg-card {
margin-top: 1vh;
margin-bottom: 0;
margin: 1vh 0 auto;
}

View File

@@ -1 +1 @@
{"version":3,"file":"css/tcg_decks.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;AC/DA;IACI,eAAe;IACf,gBAAgB;AACpB;;;AAGA;IACI,gBAAgB;IAChB,gBAAgB;AACpB;;AAEA;IACI,aAAa;AACjB;AACA;IACI,yCAAyC;AAC7C;AACA;IACI,gBAAgB;IAChB,gBAAgB;AACpB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/tcg/decks.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n\n.tcg-card {\n margin-top: 1vh;\n margin-bottom: 0;\n}\n\n\ntable.table-main tbody {\n max-height: 30vh;\n overflow-y: auto;\n}\n\ntable.statistics {\n margin-top: 0;\n}\ntable.statistics thead {\n background-color: var(--background-color);\n}\ntable.statistics tbody {\n max-height: 30vh;\n overflow-y: auto;\n}\ntable.statistics thead tr th.deck,\ntable.statistics tbody tr td.deck_id {\n min-width: 20vh;\n max-width: 20vh;\n}\ntable.statistics thead tr th.name,\ntable.statistics tbody tr td.name {\n min-width: 40vh;\n max-width: 40vh;\n}\ntable.statistics thead tr th.value,\ntable.statistics tbody tr td.value {\n min-width: 10vh;\n max-width: 10vh;\n}"],"names":[],"sourceRoot":""}
{"version":3,"file":"css/tcg_decks.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;AC9DA;IACI,kBAAkB;AACtB;;;AAGA;IACI,gBAAgB;IAChB,gBAAgB;AACpB;;AAEA;IACI,aAAa;AACjB;AACA;IACI,yCAAyC;AAC7C;AACA;IACI,gBAAgB;IAChB,gBAAgB;AACpB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/tcg/decks.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0 auto;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n\n.tcg-card {\n margin: 1vh 0 auto;\n}\n\n\ntable.table-main tbody {\n max-height: 30vh;\n overflow-y: auto;\n}\n\ntable.statistics {\n margin-top: 0;\n}\ntable.statistics thead {\n background-color: var(--background-color);\n}\ntable.statistics tbody {\n max-height: 30vh;\n overflow-y: auto;\n}\ntable.statistics thead tr th.deck,\ntable.statistics tbody tr td.deck_id {\n min-width: 20vh;\n max-width: 20vh;\n}\ntable.statistics thead tr th.name,\ntable.statistics tbody tr td.name {\n min-width: 40vh;\n max-width: 40vh;\n}\ntable.statistics thead tr th.value,\ntable.statistics tbody tr td.value {\n min-width: 10vh;\n max-width: 10vh;\n}"],"names":[],"sourceRoot":""}

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
@@ -66,6 +65,10 @@
}
/* MTG Single Game Page Styles */
.tcg-title.dirty {
background-color: var(--tcg-accent-purple);
}
#buttonHamburger {
display: none;
}
@@ -166,7 +169,7 @@
.control-group {
display: flex;
align-items: center;
gap: 1rem;
gap: 0.5rem;
}
.control-group .tcg-input {
@@ -179,7 +182,7 @@
.player-names-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
gap: 0.5rem;
max-width: 800px;
margin: 0 auto 2rem;
justify-content: center;
@@ -296,7 +299,7 @@
transition: all 0.4s ease;
animation: tcg-scaleIn 0.5s ease-out backwards;
width: fit-content;
max-width: 38vw;
max-width: 35vw;
min-width: 20vw;
margin: 0 auto;
}
@@ -322,7 +325,7 @@
align-items: center;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
gap: 0.5rem;
}
.player-info {
@@ -419,7 +422,7 @@
.life-gain-controls,
.life-loss-controls {
display: flex;
gap: 1rem;
gap: 0.5rem;
justify-content: center;
margin-bottom: 1vh;
}
@@ -430,7 +433,7 @@
border: 2px solid var(--tcg-border-color);
color: var(--tcg-text-primary);
width: 60px;
height: 60px;
height: 45px;
border-radius: 12px;
font-family: 'Cinzel', serif;
font-size: 1.8rem;

File diff suppressed because one or more lines are too long

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}

File diff suppressed because one or more lines are too long

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}

View File

@@ -1 +1 @@
{"version":3,"file":"css/tcg_home.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;ACjEA;IACI,iBAAiB;AACrB;AACA;IACI,iBAAiB;IACjB,kBAAkB;AACtB,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/tcg/home.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","#pageBody .column .row {\n margin-top: 0.5vh;\n}\n#pageBody .column .row .button {\n margin-left: auto;\n margin-right: auto;\n}"],"names":[],"sourceRoot":""}
{"version":3,"file":"css/tcg_home.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;AChEA;IACI,iBAAiB;AACrB;AACA;IACI,iBAAiB;IACjB,kBAAkB;AACtB,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/tcg/home.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0 auto;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","#pageBody .column .row {\n margin-top: 0.5vh;\n}\n#pageBody .column .row .button {\n margin-left: auto;\n margin-right: auto;\n}"],"names":[],"sourceRoot":""}

View File

@@ -16,7 +16,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -25,7 +25,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}

View File

@@ -1 +1 @@
{"version":3,"file":"css/user_account.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;AChEA;IACI,aAAa;AACjB;;AAEA;IACI,eAAe;IACf,SAAS;IACT,WAAW;AACf;;AAEA;IACI,cAAc;AAClB;AACA;IACI,iBAAiB;AACrB;AACA;IACI,gBAAgB;AACpB;;AAEA;;;IAGI,kCAAkC;IAClC,2CAA2C;AAC/C,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/user/user.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n#formFilters {\n display: none;\n}\n\n.container.save.button-cancel {\n position: fixed;\n top: 10vh;\n right: 10vh;\n}\n\n.container-input {\n margin: 0 auto;\n}\nlabel {\n font-weight: bold;\n}\n.container-input input {\n max-width: 250px;\n}\n\ninput.dirty, \ntextarea.dirty, \nselect.dirty {\n border-color: var(--primary-color);\n background-color: var(--background-color-2);\n}"],"names":[],"sourceRoot":""}
{"version":3,"file":"css/user_account.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;AC/DA;IACI,aAAa;AACjB;;AAEA;IACI,eAAe;IACf,SAAS;IACT,WAAW;AACf;;AAEA;IACI,cAAc;AAClB;AACA;IACI,iBAAiB;AACrB;AACA;IACI,gBAAgB;AACpB;;AAEA;;;IAGI,kCAAkC;IAClC,2CAA2C;AAC/C,C","sources":["webpack://app/./static/css/sections/tcg.css","webpack://app/./static/css/pages/user/user.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0 auto;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n#formFilters {\n display: none;\n}\n\n.container.save.button-cancel {\n position: fixed;\n top: 10vh;\n right: 10vh;\n}\n\n.container-input {\n margin: 0 auto;\n}\nlabel {\n font-weight: bold;\n}\n.container-input input {\n max-width: 250px;\n}\n\ninput.dirty, \ntextarea.dirty, \nselect.dirty {\n border-color: var(--primary-color);\n background-color: var(--background-color-2);\n}"],"names":[],"sourceRoot":""}

View File

@@ -17,7 +17,7 @@
#pageBody {
max-height: 82vh;
padding: 0 5vw;
margin: 0;
margin: 0 auto;
border: 0;
align-content: center;
justify-content: flex-start;
@@ -26,7 +26,6 @@
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}

View File

@@ -1 +1 @@
{"version":3,"file":"css/user_accounts.bundle.css","mappings":";;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C","sources":["webpack://app/./static/css/sections/tcg.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}"],"names":[],"sourceRoot":""}
{"version":3,"file":"css/user_accounts.bundle.css","mappings":";;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;;AAGA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;AACf;IACI,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,mBAAmB;QACnB,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C","sources":["webpack://app/./static/css/sections/tcg.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n#pageBody {\n max-height: 82vh;\n padding: 0 5vw;\n margin: 0 auto;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0.75vh 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}"],"names":[],"sourceRoot":""}

View File

@@ -417,6 +417,12 @@ class API {
}
// MTG Game API methods
static async getIsGameDataOutdated(game) {
const url = `/mtg/api/game/${game[attrGameId]}/is-outdated`;
let dataRequest = {};
dataRequest[flagGame] = game;
return await API.request(url, 'POST', dataRequest);
}
static async saveGame(game, formFilters, comment) {
let dataRequest = {};
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
@@ -1616,6 +1622,7 @@ class PageMtgDecks extends TableBasePage {
class PageMtgGame extends TableBasePage {
static hash = hashPageMtgGame;
static attrIdRowObject = attrGameId;
@@ -1630,6 +1637,9 @@ class PageMtgGame extends TableBasePage {
hookupFilters() {
// this.sharedHookupFilters();
}
callFilterTableContent() {
window.location.reload();
}
loadRowTable(rowJson) {
return;
}
@@ -1667,6 +1677,8 @@ class PageMtgGame extends TableBasePage {
this.hookupPlayerLifeIncrementButtons();
this.hookupCommanderDamageIncrementButtons();
*/
PageMtgGame.hookupOverlayGameOutdated();
PageMtgGame.hookupGameUpdateCheck();
}
static hookupResetButton() {
const resetGameButton = document.querySelector('header.game-header .header-right .btn-tcg.btn-tcg-secondary');
@@ -1722,7 +1734,55 @@ class PageMtgGame extends TableBasePage {
}
}
*/
static hookupGameUpdateCheck() {
const intervalId = setInterval(async () => {
const isGameDataOutdated = await PageMtgGame.checkLastGameUpdate();
if (isGameDataOutdated) {
clearInterval(intervalId);
}
}, 30000);
}
static async checkLastGameUpdate() {
try {
// Fetch players, rounds, and damage records from API
const isGameDataOutdatedResponse = await API.getIsGameDataOutdated(game);
const isGameDataOutdated = isGameDataOutdatedResponse[flagData];
console.log({
isGameDataOutdatedResponse,
isGameDataOutdated
});
if (isGameDataOutdated) {
// const gameDataOutdatedLabel = document.querySelector(gameDataOutdatedLabelId);
// gameDataOutdatedLabel.classList.remove(flagIsCollapsed);
const pageTitleElement = document.querySelector('.topnav .tcg-title');
pageTitleElement.classList.add(flagDirty);
PageMtgGame.showOverlayGameOutdated();
}
return isGameDataOutdated;
} catch (error) {
console.error('Error checking for game update from server:', error);
}
}
static hookupOverlayGameOutdated() {
Events.initialiseEventHandler(idOverlayGameOutdated + ' button.' + flagCancel, flagInitialised, buttonCancel => {
buttonCancel.addEventListener('click', () => {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.style.visibility = 'hidden';
});
});
Events.initialiseEventHandler(idOverlayGameOutdated + ' button.' + flagSubmit, flagInitialised, buttonConfirm => {
buttonConfirm.addEventListener('click', () => {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.style.visibility = 'hidden';
window.location.reload();
});
});
}
static showOverlayGameOutdated() {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.classList.remove(flagIsCollapsed);
overlay.style.visibility = 'visible';
}
async loadGameFromServer() {
console.log("loading game from server");
try {
@@ -1805,7 +1865,7 @@ class PageMtgGame extends TableBasePage {
maxCommanderDamageReceived = Math.max(maxCommanderDamageReceived, damageRecords.filter(damage => damage[attrPlayerId] == playerId && damage[attrReceivedFromCommanderPlayerId] == sourceId && damage[attrReceivedFromCommanderPlayerId] != null && previousRoundIds.includes(damage[attrRoundId])).map(damage => damage[flagLifeLoss]).reduce((a, b) => a + b, 0));
});
const totalDamage = damageRecords.filter(damage => damage[attrPlayerId] == playerId && previousRoundIds.includes(damage[attrRoundId])).map(damage => damage[flagLifeLoss] - damage[flagLifeGain]).reduce((a, b) => a + b, 0);
let life = startingLife - totalDamage;
let life = game[flagStartingLife] - totalDamage;
let isEliminatedByForce = damageRecords.filter(damage => damage[attrPlayerId] == playerId && previousRoundIds.includes(damage[attrRoundId])).map(damage => damage[flagIsEliminated]).some(Boolean);
console.log("renderPlayers");
console.log({
@@ -1887,7 +1947,6 @@ class PageMtgGame extends TableBasePage {
if (damage[flagActive] && (damage[flagCommanderDeaths] > 0 || damage[flagLifeGain] != 0 || damage[flagLifeLoss] != 0 || damage[flagIsEliminated])
// && rounds.filter(r => r[attrRoundId] == damage[attrRoundId])[0][flagDisplayOrder] <= currentRoundDisplayOrder
&& previousRoundIds.includes(damage[attrRoundId])) {
debugger;
let round = rounds.filter(r => r[attrRoundId] == damage[attrRoundId])[0];
let player = players.filter(p => p[attrPlayerId] == damage[attrPlayerId])[0];
let receivedFromPlayer = damage[attrReceivedFromCommanderPlayerId] == null ? {
@@ -2020,7 +2079,6 @@ class PageMtgGame extends TableBasePage {
// Life gain buttons
let lifeGainButtonSelector = '.life-gain-btn';
Events.hookupEventHandler("click", lifeGainButtonSelector, (event, button) => {
debugger;
const playerId = parseInt(button.dataset.playerId);
const amount = parseInt(button.dataset.amount);
const activeRoundId = PageMtgGame.getActiveRoundId();
@@ -2120,7 +2178,7 @@ class PageMtgGame extends TableBasePage {
damageRecords[damageIndex][flagLifeLoss] += amount;
let isLifeGainNotLoss = false;
this.changeLife(playerId // playerId
, -amount // amount
, amount // amount
, isLifeGainNotLoss // isLifeGainNotLoss
, false // updateDamage
, damageIndex // damageIndex
@@ -2228,7 +2286,7 @@ class PageMtgGame extends TableBasePage {
maxDamageFromOtherCommander,
totalDamageTaken
});
return hasDamageWithIsEliminated || maxDamageFromOtherCommander >= 21 || totalDamageTaken >= startingLife;
return hasDamageWithIsEliminated || maxDamageFromOtherCommander >= 21 || totalDamageTaken >= game[flagStartingLife];
}
static updatePlayerSetup() {
const playerCountInput = document.getElementById('playerCount');
@@ -2384,6 +2442,19 @@ class PageMtgGame extends TableBasePage {
alert(message);
}
}
updateAndToggleShowButtonsSaveCancel() {
// let pageBody = document.querySelector(idPageBody);
let isDirty = DOM.hasDirtyChildrenContainer(pageBody);
let buttonContainerSelector = '.' + flagContainer + '.' + flagSave + '.' + flagCancel;
let buttonSave = document.querySelector(buttonContainerSelector + ' ' + idButtonSave);
let areVisibleSaveCancelButtons = !buttonSave.classList.contains(flagIsCollapsed);
console.log({
pageBody,
isDirty,
areVisibleSaveCancelButtons
});
this.toggleShowButtonsSaveCancel(isDirty || areVisibleSaveCancelButtons);
}
leave() {
super.leave();
}

File diff suppressed because one or more lines are too long

View File

@@ -81,6 +81,13 @@ export default class API {
}
// MTG Game API methods
static async getIsGameDataOutdated(game) {
const url = `/mtg/api/game/${game[attrGameId]}/is-outdated`;
let dataRequest = {};
dataRequest[flagGame] = game;
return await API.request(url, 'POST', dataRequest);
}
static async saveGame(game, formFilters, comment) {
let dataRequest = {};
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);

View File

@@ -4,6 +4,7 @@ import API from "../../api.js";
import TableBasePage from "../base_table.js";
import DOM from "../../dom.js";
import Events from "../../lib/events.js";
import OverlayConfirm from "../../components/common/temporary/overlay_confirm.js";
export default class PageMtgGame extends TableBasePage {
static hash = hashPageMtgGame;
@@ -21,6 +22,9 @@ export default class PageMtgGame extends TableBasePage {
hookupFilters() {
// this.sharedHookupFilters();
}
callFilterTableContent() {
window.location.reload();
}
loadRowTable(rowJson) {
return;
}
@@ -64,6 +68,8 @@ export default class PageMtgGame extends TableBasePage {
this.hookupPlayerLifeIncrementButtons();
this.hookupCommanderDamageIncrementButtons();
*/
PageMtgGame.hookupOverlayGameOutdated();
PageMtgGame.hookupGameUpdateCheck();
}
static hookupResetButton() {
const resetGameButton = document.querySelector('header.game-header .header-right .btn-tcg.btn-tcg-secondary');
@@ -117,6 +123,55 @@ export default class PageMtgGame extends TableBasePage {
}
}
*/
static hookupGameUpdateCheck() {
const intervalId = setInterval(async () => {
const isGameDataOutdated = await PageMtgGame.checkLastGameUpdate();
if (isGameDataOutdated) {
clearInterval(intervalId);
}
}, 30000);
}
static async checkLastGameUpdate() {
try {
// Fetch players, rounds, and damage records from API
const isGameDataOutdatedResponse = await API.getIsGameDataOutdated(game);
const isGameDataOutdated = isGameDataOutdatedResponse[flagData];
console.log({ isGameDataOutdatedResponse, isGameDataOutdated });
if (isGameDataOutdated) {
// const gameDataOutdatedLabel = document.querySelector(gameDataOutdatedLabelId);
// gameDataOutdatedLabel.classList.remove(flagIsCollapsed);
const pageTitleElement = document.querySelector('.topnav .tcg-title');
pageTitleElement.classList.add(flagDirty);
PageMtgGame.showOverlayGameOutdated();
}
return isGameDataOutdated;
} catch (error) {
console.error('Error checking for game update from server:', error);
}
}
static hookupOverlayGameOutdated() {
Events.initialiseEventHandler(idOverlayGameOutdated + ' button.' + flagCancel, flagInitialised, (buttonCancel) => {
buttonCancel.addEventListener('click', () => {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.style.visibility = 'hidden';
});
});
Events.initialiseEventHandler(idOverlayGameOutdated + ' button.' + flagSubmit, flagInitialised, (buttonConfirm) => {
buttonConfirm.addEventListener('click', () => {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.style.visibility = 'hidden';
window.location.reload();
});
});
}
static showOverlayGameOutdated() {
let overlay = document.querySelector(idOverlayGameOutdated);
overlay.classList.remove(flagIsCollapsed);
overlay.style.visibility = 'visible';
}
async loadGameFromServer() {
console.log("loading game from server");
@@ -244,7 +299,7 @@ export default class PageMtgGame extends TableBasePage {
))
.map(damage => damage[flagLifeLoss] - damage[flagLifeGain])
.reduce((a, b) => a + b, 0);
let life = startingLife - totalDamage;
let life = game[flagStartingLife] - totalDamage;
let isEliminatedByForce = damageRecords.filter(damage => (
damage[attrPlayerId] == playerId
@@ -482,7 +537,7 @@ export default class PageMtgGame extends TableBasePage {
, [flagActive]: true
};
}
hookupPlayerCardEvents() {
hookupPlayerCardEvents() {
// Life gain buttons
let lifeGainButtonSelector = '.life-gain-btn';
Events.hookupEventHandler("click", lifeGainButtonSelector, (event, button) => {
@@ -609,7 +664,7 @@ export default class PageMtgGame extends TableBasePage {
let isLifeGainNotLoss = false;
this.changeLife(
playerId // playerId
, -amount // amount
, amount // amount
, isLifeGainNotLoss // isLifeGainNotLoss
, false // updateDamage
, damageIndex // damageIndex
@@ -757,7 +812,7 @@ export default class PageMtgGame extends TableBasePage {
return (
hasDamageWithIsEliminated
|| maxDamageFromOtherCommander >= 21
|| totalDamageTaken >= startingLife
|| totalDamageTaken >= game[flagStartingLife]
);
}
@@ -936,6 +991,19 @@ export default class PageMtgGame extends TableBasePage {
}
}
updateAndToggleShowButtonsSaveCancel() {
// let pageBody = document.querySelector(idPageBody);
let isDirty = DOM.hasDirtyChildrenContainer(pageBody);
let buttonContainerSelector = '.' + flagContainer + '.' + flagSave + '.' + flagCancel;
let buttonSave = document.querySelector(buttonContainerSelector + ' ' + idButtonSave);
let areVisibleSaveCancelButtons = !buttonSave.classList.contains(flagIsCollapsed);
console.log({ pageBody, isDirty, areVisibleSaveCancelButtons });
this.toggleShowButtonsSaveCancel(isDirty || areVisibleSaveCancelButtons);
}
leave() {
super.leave();
}

View File

@@ -25,6 +25,7 @@
var flagLifeLoss = "{{ model.FLAG_LIFE_LOSS }}";
var flagPlayer = "{{ model.FLAG_PLAYER }}";
var flagRound = "{{ model.FLAG_ROUND }}";
var flagStartingLife = "{{ model.FLAG_STARTING_LIFE }}";
var flagUser = "{{ model.FLAG_USER }}";
var flagValueBool = "{{ model.FLAG_VALUE_BOOL }}";
var flagValueFloat = "{{ model.FLAG_VALUE_FLOAT }}";

View File

@@ -40,6 +40,7 @@
var flagContainerInput = "{{ model.FLAG_CONTAINER_INPUT }}";
{# var flagContainerSaveCancelButtons = "{{ model.FLAG_CONTAINER_SAVE_CANCEL_BUTTONS }}"; #}
var flagCsrfToken = "{{ model.FLAG_CSRF_TOKEN }}";
var flagData = "{{ model.FLAG_DATA }}";
var flagDdlPreview = "{{ model.FLAG_DDL_PREVIEW }}";
var flagDelete = "{{ model.FLAG_DELETE }}";
var flagDescription = "{{ model.FLAG_DESCRIPTION }}";

View File

@@ -174,29 +174,43 @@
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<div class="{{ model.FLAG_OVERLAY }} {{ model.FLAG_IS_COLLAPSED }} {{ model.FLAG_CARD }} {{ model.FLAG_COLUMN }}" id="{{ model.ID_OVERLAY_GAME_OUTDATED }}" style="visibility: hidden;" z-index="2">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<h2>Game updated elsewhere, reload page?</h2>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
{% set block_id = 'button_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
{% set block_id = 'button_confirm' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<script>
var attrGameId = "{{ model.ATTR_GAME_ID }}";
var attrPlayerId = "{{ model.ATTR_PLAYER_ID }}";
var attrReceivedFromCommanderPlayerId = "{{ model.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID }}";
var damageRecords = {{ model.convert_list_objects_to_json(model.damage_records) | tojson | safe }};
var damageRecordsOnLoad = {{ model.convert_list_objects_to_json(model.damage_records) | tojson | safe }};
var decks = {{ model.convert_list_objects_to_json(model.decks) | tojson | safe }};
var flagDamageLog = "{{ model.FLAG_DAMAGE_LOG }}";
var flagPlayer = "{{ model.FLAG_PLAYER }}";
var flagRoundDisplayOrderButton = "{{ model.FLAG_ROUND_DISPLAY_ORDER_BUTTON }}";
var flagRoundDisplayOrderMinus = "{{ model.FLAG_ROUND_DISPLAY_ORDER_MINUS }}";
var flagRoundDisplayOrderPlus = "{{ model.FLAG_ROUND_DISPLAY_ORDER_PLUS }}";
var flagPlayer = "{{ model.FLAG_PLAYER }}";
var game = {{ model.game.to_json() | tojson | safe }};
var gameDataOutdatedLabelId = "#{{ model.GAME_DATA_OUTDATED_LABEL_ID }}";
var gameId = {{ model.game.game_id }};
var hashSaveGamePlayer = "{{ model.HASH_SAVE_MTG_GAME_PLAYER }}";
var hashSaveGameRound = "{{ model.HASH_SAVE_MTG_GAME_ROUND }}";
var hashSaveGameRoundPlayerDamage = "{{ model.HASH_SAVE_MTG_GAME_ROUND_PLAYER_DAMAGE }}";
var hashPageGames = "{{ model.HASH_PAGE_MTG_GAMES }}";
var idInputRound = "#{{ model.ID_INPUT_ROUND }}";
var idOverlayGameOutdated = "#{{ model.ID_OVERLAY_GAME_OUTDATED }}";
var players = {{ model.convert_list_objects_to_json(model.players) | tojson | safe }};
var playerSetupWrapperTemplateId = "{{ model.PLAYER_SETUP_WRAPPER_TEMPLATE_ID }}";
var rounds = {{ model.convert_list_objects_to_json(model.rounds) | tojson | safe }};
var startingLife = 40;
var user = {{ model.user.to_json() | tojson | safe }};
var users = {{ model.convert_list_objects_to_dict_json_by_attribute_key_default(model.users) | tojson | safe }};
</script>

View File

@@ -1,11 +1,26 @@
Winner of game animation - bring to centre with trophy icon and show updates player + deck stats (+ charts?), add end time
Game start + end times left / right of game location
Deck mulligan rate - add to player table and then just get statistics whenever wanted
Ensure no duplicate players by Game ID and User ID and Deck ID
player save with null name not pulling user and deck names
create damage from commander fills is_eliminated with false, but create from player's own damage leaves is_eliminated undefined
Track counters
- settings / advanced customisation section at game creation to toggle which counters are visible
Change round - update player cards to show damage at that point for easier editing
Track mana pool during turn
dice roll feature
REPLACE VARCHAR WITH TEXT
, INTEGER WITH INT
share button on game page, deck page
# Hardware project
undo last change - display for button for a few seconds after knob stops moving
Components:
1x Knob display
1x 134N3P LiPo power bank module
1x 1000mAh LiPo battery
1x USB-C charger (not included)