feat(v3): robust search wildcards, smart status filtering, and fixed ID population

This commit is contained in:
Scott Idem
2026-01-06 15:54:31 -05:00
parent a42f32acf4
commit 45f6303219
19 changed files with 452 additions and 279 deletions

View File

@@ -2034,6 +2034,7 @@ def sql_and_in_dict_li_part(
# ### BEGIN ### API DB SQL Methods ### sql_enable_part() ### # ### BEGIN ### API DB SQL Methods ### sql_enable_part() ###
# Updated 2022-01-17 # Updated 2022-01-17
# Updated 2026-01-06 to handle missing enable column gracefully.
@logger_reset @logger_reset
def sql_enable_part(table_name: str, enabled: str) -> bool|dict: def sql_enable_part(table_name: str, enabled: str) -> bool|dict:
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
@@ -2043,19 +2044,25 @@ def sql_enable_part(table_name: str, enabled: str) -> bool|dict:
if enabled in ['enabled', 'disabled', 'all']: if enabled in ['enabled', 'disabled', 'all']:
log.info(f'Creating partial SQL string for "enabled" check. Enabled: {enabled}') log.info(f'Creating partial SQL string for "enabled" check. Enabled: {enabled}')
if enabled == 'all':
return '', None
# Check if column exists
try:
db.execute(text(f"SELECT enable FROM `{table_name}` LIMIT 0"))
except:
log.warning(f"Table/View '{table_name}' does not have an 'enable' column. Skipping filter.")
return '', None
if enabled == 'enabled': if enabled == 'enabled':
# sql = f'AND `person`.enable = :enable'
sql = f'AND `{table_name}`.enable = true' sql = f'AND `{table_name}`.enable = true'
enable = True enable = True
elif enabled == 'disabled': elif enabled == 'disabled':
# sql = f'AND `person`.enable = :enable'
sql = f'AND `{table_name}`.enable = false' sql = f'AND `{table_name}`.enable = false'
enable = False enable = False
elif enabled == 'all':
sql = ''
enable = None
log.debug(sql) log.debug(sql)
return sql, enable return sql, enable
else: else:
return False return False
@@ -2064,6 +2071,7 @@ def sql_enable_part(table_name: str, enabled: str) -> bool|dict:
# ### BEGIN ### API DB SQL Methods ### sql_hidden_part() ### # ### BEGIN ### API DB SQL Methods ### sql_hidden_part() ###
# Updated 2022-01-17 # Updated 2022-01-17
# Updated 2026-01-06 to handle missing hide column gracefully.
@logger_reset @logger_reset
def sql_hidden_part(table_name: str, hidden: str) -> bool|dict: def sql_hidden_part(table_name: str, hidden: str) -> bool|dict:
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
@@ -2073,17 +2081,25 @@ def sql_hidden_part(table_name: str, hidden: str) -> bool|dict:
if hidden in ['hidden', 'not_hidden', 'all']: if hidden in ['hidden', 'not_hidden', 'all']:
log.info(f'Creating partial SQL string for "hidden" check. Hide: {hidden}') log.info(f'Creating partial SQL string for "hidden" check. Hide: {hidden}')
if hidden == 'all':
return '', None
# Check if column exists
try:
db.execute(text(f"SELECT hide FROM `{table_name}` LIMIT 0"))
except:
log.warning(f"Table/View '{table_name}' does not have a 'hide' column. Skipping filter.")
return '', None
if hidden == 'hidden': if hidden == 'hidden':
sql = f'AND `{table_name}`.hide = true' sql = f'AND `{table_name}`.hide = true'
hide = True hide = True
elif hidden == 'not_hidden': elif hidden == 'not_hidden':
sql = f'AND (`{table_name}`.hide = false OR `{table_name}`.hide IS NULL)' sql = f'AND (`{table_name}`.hide = false OR `{table_name}`.hide IS NULL)'
hide = False hide = False
elif hidden == 'all':
sql = ''
hide = None
log.debug(sql) log.debug(sql)
return sql, hide return sql, hide
else: else:
return False return False
@@ -2258,4 +2274,4 @@ def sql_search_qry_part(
if sql_where: if sql_where:
return f"AND ({sql_where})", data return f"AND ({sql_where})", data
return "", {} return "", {}
# ### END ### API DB SQL Methods ### sql_search_qry_part() ### # ### END ### API DB SQL Methods ### sql_search_qry_part() ###

View File

@@ -38,6 +38,11 @@ class Account_Base(BaseModel):
short_name: Optional[str] short_name: Optional[str]
description: Optional[str] description: Optional[str]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
enable: Optional[bool] enable: Optional[bool]
enable_from: Optional[datetime.datetime] = None enable_from: Optional[datetime.datetime] = None
enable_to: Optional[datetime.datetime] = None enable_to: Optional[datetime.datetime] = None

View File

@@ -60,10 +60,13 @@ class Address_Base(BaseModel):
congressional_district: Optional[str] congressional_district: Optional[str]
#priority: Optional[int] enable: Optional[bool]
#sort: Optional[int] hide: Optional[bool]
#group: Optional[str] priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
@@ -98,6 +101,13 @@ class Address_Base(BaseModel):
return redis_lookup_id_random(record_id_random=id_random, table_name='account') return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None
@validator('contact_id', always=True) @validator('contact_id', always=True)
def contact_id_lookup(cls, v, values, **kwargs): def contact_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
@@ -121,4 +131,4 @@ class Address_Base(BaseModel):
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True
fields = base_fields fields = base_fields
# ### END ### API Address Models ### Address_Base() ### # ### END ### API Address Models ### Address_Base() ###

View File

@@ -72,10 +72,13 @@ class Contact_Base(BaseModel):
other_text: Optional[str] other_text: Optional[str]
other_json: Optional[Json] other_json: Optional[Json]
enable: Optional[bool]
hide: Optional[bool]
priority: Optional[bool] priority: Optional[bool]
sort: Optional[int] sort: Optional[int]
group: Optional[str] group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
@@ -114,6 +117,13 @@ class Contact_Base(BaseModel):
return redis_lookup_id_random(record_id_random=id_random, table_name='account') return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None
@validator('address_id', always=True) @validator('address_id', always=True)
def address_id_lookup(cls, v, values, **kwargs): def address_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)

View File

@@ -220,6 +220,9 @@ class Event_Badge_Basic_Base(BaseModel):
**base_fields['event_badge_id_random'], **base_fields['event_badge_id_random'],
alias = 'event_badge_id_random', alias = 'event_badge_id_random',
) )
id: Optional[int] = Field(
alias = 'event_badge_id'
)
event_badge_template_id_random: Optional[str] event_badge_template_id_random: Optional[str]
# event_badge_template_id: Optional[int] # event_badge_template_id: Optional[int]
@@ -298,15 +301,15 @@ class Event_Badge_Basic_Base(BaseModel):
print_last_datetime: Optional[datetime.datetime] = None print_last_datetime: Optional[datetime.datetime] = None
print_count: Optional[int] print_count: Optional[int]
# hide: Optional[bool] hide: Optional[bool]
# priority: Optional[bool] priority: Optional[bool]
# sort: Optional[int] sort: Optional[int]
# group: Optional[str] group: Optional[str]
# enable: Optional[bool] enable: Optional[bool]
# notes: Optional[str] notes: Optional[str]
# created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
# updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
# Including other related objects # Including other related objects
# order: Optional[Union[Order_Base, None]] # order: Optional[Union[Order_Base, None]]
@@ -315,6 +318,13 @@ class Event_Badge_Basic_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True)
def event_badge_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event_badge')
return None
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = True

View File

@@ -42,6 +42,15 @@ class Membership_Group_Base(BaseModel):
expire_in_days: Optional[int] expire_in_days: Optional[int]
enable: Optional[bool]
enable_from: Optional[datetime.datetime] = None
enable_to: Optional[datetime.datetime] = None
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str] notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
@@ -104,5 +113,6 @@ class Membership_Group_Base(BaseModel):
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
fields = base_fields fields = base_fields
allow_population_by_field_name = True
# Membership_Group_Base.update_forward_refs() # Membership_Group_Base.update_forward_refs()

View File

@@ -55,6 +55,12 @@ class Membership_Person_Group_Base(BaseModel):
flag: Optional[bool] flag: Optional[bool]
flag_message: Optional[str] flag_message: Optional[str]
enable: Optional[bool]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str] notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
@@ -117,5 +123,6 @@ class Membership_Person_Group_Base(BaseModel):
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
fields = base_fields fields = base_fields
allow_population_by_field_name = True
# Membership_Base.update_forward_refs() # Membership_Base.update_forward_refs()

View File

@@ -58,6 +58,7 @@ class Membership_Type_Base(BaseModel):
enable_from: Optional[datetime.datetime] = None enable_from: Optional[datetime.datetime] = None
enable_to: Optional[datetime.datetime] = None enable_to: Optional[datetime.datetime] = None
hide: Optional[bool]
priority: Optional[bool] priority: Optional[bool]
sort: Optional[int] = Field(0, ge=0, lt=100) # Essentially the membership level. Should there be a range limit? sort: Optional[int] = Field(0, ge=0, lt=100) # Essentially the membership level. Should there be a range limit?
group: Optional[str] group: Optional[str]
@@ -106,4 +107,9 @@ class Membership_Type_Base(BaseModel):
# return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') # return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account')
# return None # return None
class Config:
underscore_attrs_are_private = True
fields = base_fields
allow_population_by_field_name = True
# Membership_Type_Base.update_forward_refs() # Membership_Type_Base.update_forward_refs()

View File

@@ -34,6 +34,16 @@ class Order_Cfg_Base(BaseModel):
stripe_publishable_key: Optional[str] # Publish/Sharable stripe_publishable_key: Optional[str] # Publish/Sharable
stripe_account_id: Optional[str] # Connected Stripe Account ID stripe_account_id: Optional[str] # Connected Stripe Account ID
enable: Optional[bool]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('account_id', always=True) @validator('account_id', always=True)
@@ -44,3 +54,8 @@ class Order_Cfg_Base(BaseModel):
if values['account_id_random']: if values['account_id_random']:
return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account')
return None return None
class Config:
underscore_attrs_are_private = True
fields = base_fields
allow_population_by_field_name = True

View File

@@ -49,6 +49,8 @@ class Organization_Base(BaseModel):
thumbnail_path: Optional[str] thumbnail_path: Optional[str]
thumbnail_bg_color: Optional[str] thumbnail_bg_color: Optional[str]
enable: Optional[bool]
hide: Optional[bool]
priority: Optional[int] priority: Optional[int]
sort: Optional[int] sort: Optional[int]
group: Optional[str] group: Optional[str]
@@ -89,8 +91,16 @@ class Organization_Base(BaseModel):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
log.debug(locals()) log.debug(locals())
if values['account_id_random']: if isinstance(v, int) and v > 0: return v
return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None return None
@validator('contact_id', always=True) @validator('contact_id', always=True)

View File

@@ -138,4 +138,5 @@ class Post_Base(BaseModel):
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
fields = base_fields fields = base_fields
allow_population_by_field_name = True
# ### END ### API Post Models ### Post_Base() ### # ### END ### API Post Models ### Post_Base() ###

View File

@@ -3,7 +3,7 @@ import datetime, pytz
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
from app.db_sql import redis_lookup_id_random from app.db_sql import get_id_random, redis_lookup_id_random
from app.lib_general import log, logging from app.lib_general import log, logging
from app.models.common_field_schema import base_fields, default_num_bytes from app.models.common_field_schema import base_fields, default_num_bytes
@@ -38,6 +38,12 @@ class Site_Domain_Base(BaseModel):
cfg_json: Optional[Union[Json, None]] # In use 2024-03-04 cfg_json: Optional[Union[Json, None]] # In use 2024-03-04
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
@@ -53,9 +59,23 @@ class Site_Domain_Base(BaseModel):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
log.debug(locals()) log.debug(locals())
if values['id_random']: if isinstance(v, int) and v > 0: return v
log.debug(values['id_random']) elif id_random := values.get('id_random'):
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='site_domain') return redis_lookup_id_random(record_id_random=id_random, table_name='site_domain')
return None
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None return None
@validator('site_id', always=True) @validator('site_id', always=True)
@@ -104,12 +124,18 @@ class Site_Domain_FQDN_ID_Base(BaseModel):
valid_for: Optional[int] # number of hours valid_for: Optional[int] # number of hours
enable: Optional[bool] enable: Optional[bool]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
# Including convenience data # Including convenience data
# This is only for convenience. Probably going to keep unless it causes a problem. # This is only for convenience. Probably going to keep unless it causes a problem.
# account_id: Optional[int] account_id: Optional[int]
account_id_random: Optional[str] account_id_random: Optional[str]
account_code: Optional[str] # Useful for export file naming account_code: Optional[str] # Useful for export file naming
account_name: Optional[str] # Generally useful for display account_name: Optional[str] # Generally useful for display
@@ -131,24 +157,19 @@ class Site_Domain_FQDN_ID_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
# @validator('id', always=True) @validator('account_id', always=True)
# def site_domain_id_lookup(cls, v, values, **kwargs): def account_id_lookup(cls, v, values, **kwargs):
# log.setLevel(logging.WARNING) if isinstance(v, int) and v > 0: return v
# log.debug(locals()) elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
# if values['id_random']: @validator('account_id_random', always=True)
# log.debug(values['id_random']) def account_id_random_lookup(cls, v, values, **kwargs):
# return redis_lookup_id_random(record_id_random=values['id_random'], table_name='site_domain') if isinstance(v, str) and len(v) >= 11: return v
# return None elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
# @validator('account_id', always=True) return None
# def account_id_lookup(cls, v, values, **kwargs):
# log.setLevel(logging.WARNING)
# log.debug(locals())
# if values['account_id_random']:
# return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account')
# return None
@validator('site_id', always=True) @validator('site_id', always=True)
def site_id_lookup(cls, v, values, **kwargs): def site_id_lookup(cls, v, values, **kwargs):

View File

@@ -87,6 +87,11 @@ class Site_Base(BaseModel):
cfg_json: Optional[Union[Json, None]] # In use 2024-03-04 cfg_json: Optional[Union[Json, None]] # In use 2024-03-04
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str] notes: Optional[str]
created_on: Optional[datetime.datetime] = None created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None updated_on: Optional[datetime.datetime] = None
@@ -111,8 +116,16 @@ class Site_Base(BaseModel):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
log.debug(locals()) log.debug(locals())
if values['account_id_random']: if isinstance(v, int) and v > 0: return v
return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None return None
class Config: class Config:

View File

@@ -1,10 +1,9 @@
import datetime, pytz, secrets import datetime, hashlib, logging, os, pytz, redis, secrets
# import datetime, hashlib, logging, os, pytz, redis, secrets
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
from app.db_sql import redis_lookup_id_random from app.db_sql import get_id_random, redis_lookup_id_random
from app.lib_general import log, logging, secure_hash_string from app.lib_general import log, logging, secure_hash_string
from app.models.common_field_schema import base_fields, default_num_bytes from app.models.common_field_schema import base_fields, default_num_bytes
@@ -14,212 +13,6 @@ from app.models.organization_models import Organization_Base
# from app.models.user_role_models import User_Role_Base # from app.models.user_role_models import User_Role_Base
# ### BEGIN ### API User Models ### User_New_Base() ###
class User_New_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['user_id_random'],
alias = 'user_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'user_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
account_name: Optional[str]
contact_id_random: Optional[str]
contact_id: Optional[int]
organization_id_random: Optional[str]
organization_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
username: str
name: str
email: str
email_verified: bool = False
new_password: str = Field(default_factory = lambda:secrets.token_urlsafe(default_num_bytes))
password: Optional[str] # If new_password is found then the validator below will create secure_hash_string() from the new password string.
allow_auth_key: bool = False
enable: bool = False
enable_from: Optional[datetime.datetime] = datetime.datetime.now(datetime.timezone.utc)
#enable_from: Optional[datetime.datetime] = datetime.datetime.now()
enable_to: Optional[datetime.datetime] = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
#enable_to: Optional[datetime.datetime] = datetime.datetime.now() + datetime.timedelta(days=365)
#super: Optional[bool] = False
#manager: Optional[bool] = False
administrator: bool = False
public: bool = False
verified: bool = False
group: Optional[str]
notes: Optional[str]
# Including JSON data
other_json: Optional[Json]
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('user_id_random', always=True)
def user_id_random_copy(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['id_random']:
return values['id_random']
return None
@validator('id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['id_random']:
log.debug(values['id_random'])
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='user')
return None
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('contact_id', always=True)
def contact_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('contact_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='contact')
return None
@validator('organization_id', always=True)
def organization_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('organization_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='organization')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
@validator('password', always=True)
def hash_new_password(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('new_password'):
return secure_hash_string(string=values['new_password'])
return None
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
fields = base_fields
# ### END ### API User Models ### User_New_Base() ###
# ### BEGIN ### API User Models ### User_Out_Base() ###
class User_Out_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['user_id_random'],
alias = 'user_id_random',
)
id: Optional[int] = Field(
alias = 'user_id'
)
account_id_random: Optional[str]
#account_id: Optional[int]
account_name: Optional[str]
contact_id_random: Optional[str]
#contact_id: Optional[int]
organization_id_random: Optional[str]
#organization_id: Optional[int]
person_id_random: Optional[str]
#person_id: Optional[int]
username: Optional[str]
name: Optional[str]
email: Optional[str]
email_verified: Optional[bool]
password: Optional[str]
allow_auth_key: Optional[int]
auth_key: Optional[str]
enable: Optional[bool]
enable_from: Optional[datetime.datetime]
enable_to: Optional[datetime.datetime]
super: Optional[bool]
manager: Optional[bool]
administrator: Optional[bool]
public: Optional[bool]
verified: Optional[bool]
status_id: Optional[int]
status_name: Optional[str]
password_set_on: Optional[datetime.datetime]
password_reset_token: Optional[str]
password_reset_expire_on: Optional[datetime.datetime]
logged_in_on: Optional[datetime.datetime]
last_activity_on: Optional[datetime.datetime]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime]
updated_on: Optional[datetime.datetime]
# Including other related objects
# from app.models.person_models import Person_Base # Causes circular import
# archive_list: Optional[list] # Archive_Base()
# contact: Optional[Contact_Base]
event_list: Optional[list] # Event_Base() # Priority complete
hosted_file_list: Optional[list] # Hosted_File_Base() # Priority l3
journal_list: Optional[list] # Journal_Base() # Priority l3
# membership_person: Optional[Membership_Person_Base] # Priority l2
# membership_person_list: Optional[list] # Membership_Base() ???
order_list: Optional[list] # Order_Base() # Priority l2
order_cart_list: Optional[list] # Order_Base() # Priority l2
organization: Optional[Union[Organization_Base, None]] # Organization_Base() # Priority l3
person: Optional[dict] # Person_Base() # Priority l2
# person: Optional[Union[Person_Base, None]]
post_list: Optional[list] # Post_Base() # Priority l1
user_role_list: Optional[list] = Field(
alias = 'role_list'
) # User_Role_Base()
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
fields = base_fields
# ### END ### API User Models ### User_Out_Base() ###
# ### BEGIN ### API User Models ### User_Base() ### # ### BEGIN ### API User Models ### User_Base() ###
class User_Base(BaseModel): class User_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
@@ -271,12 +64,9 @@ class User_Base(BaseModel):
status_id: Optional[int] status_id: Optional[int]
status_name: Optional[str] status_name: Optional[str]
password_set_on: Optional[datetime.datetime] = None hide: Optional[bool]
password_reset_token: Optional[str] = None priority: Optional[bool]
password_reset_expire_on: Optional[datetime.datetime] = None sort: Optional[int]
logged_in_on: Optional[datetime.datetime] = None
last_activity_on: Optional[datetime.datetime] = None
group: Optional[str] group: Optional[str]
notes: Optional[str] notes: Optional[str]
@@ -317,18 +107,23 @@ class User_Base(BaseModel):
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
log.debug(locals()) log.debug(locals())
if values['id_random']: if isinstance(v, int) and v > 0: return v
log.debug(values['id_random']) elif id_random := values.get('id_random'):
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='user') return redis_lookup_id_random(record_id_random=id_random, table_name='user')
return None return None
@validator('account_id', always=True) @validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs): def account_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING) if isinstance(v, int) and v > 0: return v
log.debug(locals()) elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
if values['account_id_random']: @validator('account_id_random', always=True)
return redis_lookup_id_random(record_id_random=values['account_id_random'], table_name='account') def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None return None
# @validator('contact_id', always=True) # @validator('contact_id', always=True)
@@ -368,3 +163,243 @@ class User_Base(BaseModel):
allow_population_by_field_name = True allow_population_by_field_name = True
fields = base_fields fields = base_fields
# ### END ### API User Models ### User_Base() ### # ### END ### API User Models ### User_Base() ###
# ### BEGIN ### API User Models ### User_New_Base() ###
class User_New_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['user_id_random'],
alias = 'user_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'user_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
account_name: Optional[str]
contact_id_random: Optional[str]
contact_id: Optional[int]
organization_id_random: Optional[str]
organization_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
username: str
name: str
email: str
email_verified: bool = False
new_password: str = Field(default_factory = lambda:secrets.token_urlsafe(default_num_bytes))
password: Optional[str] # If new_password is found then the validator below will create secure_hash_string() from the new password string.
allow_auth_key: bool = False
enable: bool = False
enable_from: Optional[datetime.datetime] = datetime.datetime.now(datetime.timezone.utc)
#enable_from: Optional[datetime.datetime] = datetime.datetime.now()
enable_to: Optional[datetime.datetime] = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
#enable_to: Optional[datetime.datetime] = datetime.datetime.now() + datetime.timedelta(days=365)
#super: Optional[bool] = False
#manager: Optional[bool] = False
administrator: bool = False
public: bool = False
verified: bool = False
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
# Including JSON data
other_json: Optional[Json]
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('user_id_random', always=True)
def user_id_random_copy(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['id_random']:
return values['id_random']
return None
@validator('id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='user')
return None
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None
@validator('contact_id', always=True)
def contact_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('contact_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='contact')
return None
@validator('organization_id', always=True)
def organization_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('organization_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='organization')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
@validator('password', always=True)
def hash_new_password(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('new_password'):
return secure_hash_string(string=values['new_password'])
return None
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
fields = base_fields
# ### END ### API User Models ### User_New_Base() ###
# ### BEGIN ### API User Models ### User_Out_Base() ###
class User_Out_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['user_id_random'],
alias = 'user_id_random',
)
id: Optional[int] = Field(
alias = 'user_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
account_name: Optional[str]
contact_id_random: Optional[str]
contact_id: Optional[int]
organization_id_random: Optional[str]
organization_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
username: Optional[str]
name: Optional[str]
email: Optional[str]
email_verified: Optional[bool]
password: Optional[str]
allow_auth_key: Optional[int]
auth_key: Optional[str]
enable: Optional[bool]
enable_from: Optional[datetime.datetime]
enable_to: Optional[datetime.datetime]
super: Optional[bool]
manager: Optional[bool]
administrator: Optional[bool]
public: Optional[bool]
verified: Optional[bool]
status_id: Optional[int]
status_name: Optional[str]
password_set_on: Optional[datetime.datetime]
password_reset_token: Optional[str]
password_reset_expire_on: Optional[datetime.datetime]
logged_in_on: Optional[datetime.datetime]
last_activity_on: Optional[datetime.datetime]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime]
updated_on: Optional[datetime.datetime]
# Including other related objects
# from app.models.person_models import Person_Base # Causes circular import
# archive_list: Optional[list] # Archive_Base()
# contact: Optional[Contact_Base]
event_list: Optional[list] # Event_Base() # Priority l1
hosted_file_list: Optional[list] # Hosted_File_Base() # Priority l2
journal_list: Optional[list] # Journal_Base() # Priority l3
# membership_person: Optional[Membership_Person_Base] # Priority l2
# membership_person_list: Optional[list] # Membership_Base() ???
order_list: Optional[list] # Order_Base() # Priority l2
order_cart_list: Optional[list] # Order_Base() # Priority l2
organization: Optional[Union[Organization_Base, None]] # Organization_Base() # Priority l3
person: Optional[dict] # Person_Base() # Priority l2
# person: Optional[Union[Person_Base, None]]
post_list: Optional[list] # Post_Base() # Priority l1
user_role_list: Optional[list] = Field(
alias = 'role_list'
) # User_Role_Base()
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('account_id', always=True)
def account_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('account_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
return None
@validator('account_id_random', always=True)
def account_id_random_lookup(cls, v, values, **kwargs):
if isinstance(v, str) and len(v) >= 11: return v
elif account_id := values.get('account_id'):
return get_id_random(record_id=account_id, table_name='account')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('person_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
return None
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
fields = base_fields
# ### END ### API User Models ### User_Out_Base() ###

View File

@@ -48,7 +48,7 @@ core_obj_li = {
# V3 Search Security: # V3 Search Security:
'searchable_fields': [ 'searchable_fields': [
'account_id_random', 'code', 'name', 'short_name', 'description', 'account_id_random', 'code', 'name', 'short_name', 'description',
'enable', 'created_on', 'updated_on' 'enable', 'hide', 'priority', 'sort', 'group', 'created_on', 'updated_on'
], ],
}, },
'account_cfg': { 'account_cfg': {

View File

@@ -107,7 +107,8 @@ events_general_obj_li = {
# V3 Search Security: # V3 Search Security:
'searchable_fields': [ 'searchable_fields': [
'event_cfg_id_random', 'event_id_random', 'enable', 'conference', 'event_cfg_id_random', 'event_id_random', 'enable', 'conference',
'status', 'hide', 'priority', 'group', 'notes' 'status', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on',
'updated_on'
], ],
}, },
} }

View File

@@ -25,7 +25,8 @@ events_registration_obj_li = {
'title_names', 'given_name', 'middle_name', 'family_name', 'designations', 'title_names', 'given_name', 'middle_name', 'family_name', 'designations',
'professional_title', 'full_name', 'affiliations', 'email', 'phone', 'professional_title', 'full_name', 'affiliations', 'email', 'phone',
'location', 'allow_tracking', 'print_count', 'print_first_datetime', 'location', 'allow_tracking', 'print_count', 'print_first_datetime',
'print_last_datetime' 'print_last_datetime', 'enable', 'hide', 'priority', 'sort', 'group',
'notes', 'created_on', 'updated_on'
], ],
}, },
'event_badge_template': { 'event_badge_template': {
@@ -43,7 +44,8 @@ events_registration_obj_li = {
# V3 Search Security: # V3 Search Security:
'searchable_fields': [ 'searchable_fields': [
'event_badge_template_id_random', 'event_id_random', 'name', 'event_badge_template_id_random', 'event_id_random', 'name',
'description', 'layout', 'notes' 'description', 'layout', 'notes', 'enable', 'hide', 'priority',
'sort', 'group', 'created_on', 'updated_on'
], ],
}, },
'event_person': { 'event_person': {

View File

@@ -22,7 +22,7 @@ journal_obj_li = {
'searchable_fields': [ 'searchable_fields': [
'journal_id_random', 'name', 'short_name', 'summary', 'outline', 'journal_id_random', 'name', 'short_name', 'summary', 'outline',
'description', 'type_code', 'tags', 'billable', 'enable', 'hide', 'description', 'type_code', 'tags', 'billable', 'enable', 'hide',
'priority', 'group', 'created_on', 'updated_on' 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on'
], ],
}, },
'journal_entry': { 'journal_entry': {
@@ -44,8 +44,8 @@ journal_obj_li = {
'searchable_fields': [ 'searchable_fields': [
'journal_entry_id_random', 'journal_id_random', 'name', 'short_name', 'journal_entry_id_random', 'journal_id_random', 'name', 'short_name',
'summary', 'content', 'type_code', 'topic_code', 'category_code', 'summary', 'content', 'type_code', 'topic_code', 'category_code',
'tags', 'location', 'billable', 'enable', 'hide', 'priority', 'group', 'tags', 'location', 'billable', 'enable', 'hide', 'priority', 'sort',
'created_on', 'updated_on' 'group', 'notes', 'created_on', 'updated_on'
], ],
}, },
} }

View File

@@ -110,7 +110,8 @@ order_obj_li = {
# V3 Search Security: # V3 Search Security:
'searchable_fields': [ 'searchable_fields': [
'account_id_random', 'account_name', 'default_no_reply_email', 'account_id_random', 'account_name', 'default_no_reply_email',
'confirm_email' 'confirm_email', 'enable', 'hide', 'priority', 'sort', 'group',
'notes', 'created_on', 'updated_on'
], ],
}, },
} }