ID Vision Phase 2: Standardize Page, Post, Person, Organization, and Hosted File objects

This commit is contained in:
Scott Idem
2026-01-19 18:04:17 -05:00
parent ab8afb72d2
commit 817bb80f87
11 changed files with 324 additions and 457 deletions

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import get_id_random, redis_lookup_id_random
from app.lib_general import log, logging
@@ -14,23 +14,15 @@ class Address_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['address_id_random'],
alias = 'address_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'address_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['address_id_random'])
address_id: Optional[str] = Field(None, **base_fields['address_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
for_type: Optional[str]
for_id_random: Optional[str]
for_id: Optional[int]
contact_id_random: Optional[str]
contact_id: Optional[int]
for_id: Optional[int] = Field(None, exclude=True)
#organization: Optional[Organization_Base] = Organization_Base()
@@ -72,63 +64,31 @@ class Address_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('address_id_random', always=True)
def address_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 address_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='address')
return None
@validator('account_id', always=True)
def account_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('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):
log.setLevel(logging.WARNING)
log.debug(locals())
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('for_id', always=True)
def for_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values.get('for_id_random') and values.get('for_type'):
return redis_lookup_id_random(record_id_random=values['for_id_random'], table_name=values['for_type'])
return None
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('address_id_random'):
values['id'] = rid
values['address_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if c_rid := values.get('contact_id_random'):
values['contact_id'] = c_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id', 'contact_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Address Models ### Address_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging
@@ -14,17 +14,10 @@ class Hosted_File_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['hosted_file_id_random'],
alias = 'hosted_file_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'hosted_file_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['hosted_file_id_random'])
hosted_file_id: Optional[str] = Field(None, **base_fields['hosted_file_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
hash_sha256: Optional[str]
title: Optional[str]
@@ -39,21 +32,11 @@ class Hosted_File_Base(BaseModel):
mimetype: Optional[str]
size: Optional[int] # In bytes
# cloud_storage: Optional[str]
# owner_user_id: Optional[int]
# group_user_id: Optional[str]
# package_name: Optional[str]
already_exists: Optional[str] # This will probably only be populated on upload results
copy_timer: Optional[str] # This will probably only be populated on upload results
saved: Optional[str] # This will probably only be populated on upload results
# metadata: Optional[str]
enable: Optional[bool]
# enable_from: Optional[datetime.datetime] = None
# enable_to: Optional[datetime.datetime] = None
hide: Optional[bool]
priority: Optional[bool]
@@ -78,28 +61,29 @@ class Hosted_File_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('hosted_file_id_random', always=True)
def hosted_file_id_random_copy(cls, v, values, **kwargs):
if values['id_random']:
return values['id_random']
return None
@validator('id', always=True)
def hosted_file_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='hosted_file')
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
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('hosted_file_id_random'):
values['id'] = rid
values['hosted_file_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Hosted File Models ### Hosted_File_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging
@@ -18,21 +18,13 @@ class Organization_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['organization_id_random'],
alias = 'organization_id_random',
)
id: Optional[int] = Field(
alias = 'organization_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
contact_id_random: Optional[str]
contact_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
user_id_random: Optional[str]
user_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['organization_id_random'])
organization_id: Optional[str] = Field(None, **base_fields['organization_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
name: Optional[str]
tagline: Optional[str]
@@ -67,71 +59,35 @@ class Organization_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('organization_id_random', always=True)
def organization_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 organization_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='organization')
return None
@validator('account_id', always=True)
def account_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('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):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['contact_id_random']:
return redis_lookup_id_random(record_id_random=values['contact_id_random'], table_name='contact')
return None
@validator('person_id', always=True)
def person_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['person_id_random']:
return redis_lookup_id_random(record_id_random=values['person_id_random'], table_name='person')
return None
@validator('user_id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if values['user_id_random']:
return redis_lookup_id_random(record_id_random=values['user_id_random'], table_name='user')
return None
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('organization_id_random'):
values['id'] = rid
values['organization_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if c_rid := values.get('contact_id_random'):
values['contact_id'] = c_rid
if p_rid := values.get('person_id_random'):
values['person_id'] = p_rid
if u_rid := values.get('user_id_random'):
values['user_id'] = u_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id', 'contact_id', 'person_id', 'user_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Organization Models ### Organization_Base() ###

View File

@@ -1,10 +1,10 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import *
from app.lib_general import log, logging
from app.models.common_field_schema import base_fields, default_num_bytes
@@ -14,29 +14,50 @@ class Page_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['page_id_random'],
alias = 'page_id_random',
)
id: Optional[int] = Field(
#alias = 'page_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['page_id_random'])
page_id: Optional[str] = Field(None, **base_fields['page_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
site_id: Optional[str] = Field(None, **base_fields['site_id_random'])
alias: Optional[str]
# page_id_random: Optional[str] = Field(
# **base_fields['page_id_random'],
# alias = 'page_id_random',
# )
# id: Optional[int] = Field(
# alias = 'page_id'
# )
code: Optional[str]
name: Optional[str]
title: Optional[str]
description: Optional[str]
summary: Optional[str]
outline: Optional[str]
head_html: Optional[str]
body_html: Optional[str]
footer_html: Optional[str]
content_html: Optional[str]
content_json: Optional[Union[Json, None]]
# keywords: Optional[str]
tags: Optional[str]
start_datetime: Optional[datetime.datetime]
end_datetime: Optional[datetime.datetime]
timezone: Optional[str] # = 'UTC' # Default to UTC
cfg_json: Optional[Union[Json, None]]
data_json: Optional[Union[Json, None]] # Used to store additional data for the page
meta_json: Optional[Union[Json, None]] # Used to store additional data for about the page
enable: Optional[bool]
enable_from: Optional[datetime.datetime] = None
enable_to: Optional[datetime.datetime] = None
title: Optional[str]
body: Optional[str]
style_href: Optional[str]
script_src: Optional[str]
authentication_required: Optional[bool]
hide: Optional[bool]
priority: Optional[bool]
sort: Optional[int]
group: Optional[str]
notes: Optional[str]
created_on: Optional[datetime.datetime] = None
@@ -44,27 +65,31 @@ class Page_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('page_id_random', always=True)
def page_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 page_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='page')
return None
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('page_id_random'):
values['id'] = rid
values['page_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if s_rid := values.get('site_id_random'):
values['site_id'] = s_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id', 'site_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Page Models ### Page_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging
@@ -23,31 +23,17 @@ class Person_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['person_id_random'],
alias = 'person_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'person_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['person_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
organization_id: Optional[str] = Field(None, **base_fields['organization_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
membership_person_id: Optional[str] = Field(None, **base_fields['membership_person_id_random'])
contact_id_random: Optional[str]
contact_id: Optional[int]
organization_id_random: Optional[str]
organization_id: Optional[int]
user_id_random: Optional[str]
user_id: Optional[int]
membership_person_id_random: Optional[str] # Linked from membership_person using the v_person view
membership_person_id: Optional[int] # Linked from membership_person using the v_person view
pronouns: Optional[str] # Preferred pronouns
informal_name: Optional[str] # Informal or nick name they commonly go by
# pronouns: Optional[str] # MISSING in physical table
# informal_name: Optional[str] # MISSING in physical table
title_names: Optional[str] # Title for generation, official position, or professional or academic qualification, other honorific, or other name prefix
prefix: Optional[str] # NOTE: Phasing out! Use *title_names* instead.
@@ -59,11 +45,7 @@ class Person_Base(BaseModel):
professional_title: Optional[str] # Professional title
# display_name: Optional[str] # NOTE: This will be changed to full_name_override to match event_badge, event_presenter, and event_profile
# informal_display_name: Optional[str] # Custom what they want for informal public display
# professional_display_name: Optional[str] # Custom what they want for professional public display. This should include professional title.
preferred_display_name: Optional[str] # Which name variant to display? '', 'informal', 'professional', etc
# preferred_display_name: Optional[str] # MISSING in physical table
# BEGIN # Auto created name variations
first_last_name: Optional[str] # With SQL view?
@@ -161,64 +143,34 @@ class Person_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('person_id_random', always=True)
def person_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 person_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='person')
return None
@validator('account_id', always=True)
def account_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('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):
log.setLevel(logging.WARNING)
log.debug(locals())
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):
log.setLevel(logging.WARNING)
log.debug(locals())
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('user_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
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('person_id_random'):
values['id'] = rid
values['person_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if c_rid := values.get('contact_id_random'):
values['contact_id'] = c_rid
if o_rid := values.get('organization_id_random'):
values['organization_id'] = o_rid
if u_rid := values.get('user_id_random'):
values['user_id'] = u_rid
if mp_rid := values.get('membership_person_id_random'):
values['membership_person_id'] = mp_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id', 'contact_id', 'organization_id', 'user_id', 'membership_person_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
@validator('given_name', always=True)
def given_name_validator(cls, v):
@@ -234,6 +186,6 @@ class Person_Base(BaseModel):
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Person Models ### Person_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging, secure_hash_string
@@ -17,25 +17,15 @@ class Post_Comment_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['post_comment_id_random'],
alias = 'post_comment_id_random',
)
id: Optional[int] = Field(
#alias = 'post_comment_id'
)
post_id_random: Optional[str]
post_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['post_comment_id_random'])
post_comment_id: Optional[str] = Field(None, **base_fields['post_comment_id_random'])
post_id: Optional[str] = Field(None, **base_fields['post_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
external_person_id: Optional[str] # Person ID generated by external system (should be stable and not change)
user_id_random: Optional[str]
user_id: Optional[int]
title: Optional[str]
content: Optional[str]
@@ -65,45 +55,33 @@ class Post_Comment_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('post_comment_id_random', always=True)
# def post_comment_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 post_comment_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='post_comment')
return None
@validator('post_id', always=True)
def post_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('post_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='post')
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('user_id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('user_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='user')
return None
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('post_comment_id_random'):
values['id'] = rid
values['post_comment_id'] = rid
if p_rid := values.get('post_id_random'):
values['post_id'] = p_rid
if per_rid := values.get('person_id_random'):
values['person_id'] = per_rid
if u_rid := values.get('user_id_random'):
values['user_id'] = u_rid
# 2. Prevent "Collision Population"
for k in ['id', 'post_id', 'person_id', 'user_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
allow_population_by_field_name = False
fields = base_fields
# ### END ### API Post Comment Models ### Post_Comment_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz
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, root_validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging, secure_hash_string
@@ -16,29 +16,23 @@ class Post_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
# **base_fields['post_id_random'],
alias = 'post_id_random',
)
id: Optional[int] = Field(
alias = 'post_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['post_id_random'])
post_id: Optional[str] = Field(None, **base_fields['post_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
external_person_id: Optional[str] # Person ID generated by external system (should be stable and not change)
user_id_random: Optional[str]
user_id: Optional[int]
# user_id_random: Optional[str]
# user_id: Optional[int]
type_id_random: Optional[str]
type_id: Optional[int]
# type_id_random: Optional[str]
# type_id: Optional[int]
topic_id_random: Optional[str]
topic_id: Optional[int]
# topic_id_random: Optional[str]
# topic_id: Optional[int]
type: Optional[str]
@@ -95,48 +89,33 @@ class Post_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
#@validator('post_id_random', always=True)
def post_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 post_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='post')
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('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('user_id', always=True)
def user_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('user_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='user')
return None
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
if rid := values.get('id_random') or values.get('post_id_random'):
values['id'] = rid
values['post_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if p_rid := values.get('person_id_random'):
values['person_id'] = p_rid
if u_rid := values.get('user_id_random'):
values['user_id'] = u_rid
# 2. Prevent "Collision Population"
for k in ['id', 'account_id', 'person_id', 'user_id']:
if k in values and not isinstance(values[k], str):
del values[k]
return values
class Config:
underscore_attrs_are_private = True
fields = base_fields
allow_population_by_field_name = True
allow_population_by_field_name = False
# ### END ### API Post Models ### Post_Base() ###