feat: Implement Event File Hosted Data Fix and API Guide Update

Address critical data visibility issues for Event Files and enhance frontend documentation.

This commit resolves the persistent problem where top-level hosted file convenience fields
(e.g., , , ) were
returning as  in V3 Event File API responses, even when .

Key changes include:
- Refactored  Pydantic model:
    - Removed redundant  definitions from top-level hosted file convenience fields,
      allowing direct mapping from SQL view columns.
    - Simplified  to focus solely on conditionally loading the nested
       object, as top-level fields are now populated directly by Pydantic
      from the  view.
    - Added comprehensive comments to clarify data flow, Pydantic's behavior, and the
      expected origin of these convenience fields from SQL views.
- Updated :
    - Introduced a new section detailing how to retrieve Event File data, including the
      use of  to get both top-level convenience fields and a nested
       object.
    - Clarified all ID references as random string IDs.
    - Renumbered the troubleshooting section.
- Copied updated guide to .
- Continued ID Vision compliance audit, ensuring consistent handling of random string IDs
  across various core and event models (Account, Address, Contact, DataStore, Event Badge Template).
- Consolidated ID Vision E2E tests and updated related documentation.
- Minor updates to  and
  to support Event File data retrieval with .
This commit is contained in:
Scott Idem
2026-02-19 15:22:17 -05:00
parent 577d784fb8
commit 17a627a981
17 changed files with 391 additions and 185 deletions

View File

@@ -83,7 +83,15 @@ def load_event_file_obj(
enabled = enabled,
):
event_file_obj.hosted_file = hosted_file_obj
# event_file_obj.hosted_file = hosted_file_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset)
# Explicitly populate convenience fields from hosted_file_obj
if hosted_file_obj.hash_sha256:
event_file_obj.hosted_file_hash_sha256 = hosted_file_obj.hash_sha256
if hosted_file_obj.subdirectory_path:
event_file_obj.hosted_file_subdirectory_path = hosted_file_obj.subdirectory_path
if hosted_file_obj.content_type:
event_file_obj.hosted_file_content_type = hosted_file_obj.content_type
if hosted_file_obj.size:
event_file_obj.hosted_file_size = str(hosted_file_obj.size) # Ensure it's a string as per model definition
else:
event_file_obj.hosted_file = {}
else:

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 typing import Dict, List, Optional, Set, Union, ClassVar
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
@@ -22,16 +22,12 @@ class Account_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['account_id_random'],
alias = 'account_id_random',
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'account_id'
)
# account_id: Optional[int] = Field(
# )
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['account_id_random'])
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='account_id_random', exclude=True)
code: Optional[str]
name: Optional[str]
@@ -77,28 +73,29 @@ class Account_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True)
def account_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='account')
return None
# @validator('account_id', always=True)
# def account_id_duplicate(cls, v, values, **kwargs):
# log.setLevel(logging.DEBUG)
# log.debug(locals())
# if values['id']:
# log.debug(values['id'])
# return values['id']
# 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('account_id_random'):
values['id'] = rid
values['account_id'] = rid
# 2. Final Vision Enforcement: Strip internal integers from public fields
for k in ['id', 'account_id']:
val = values.get(k)
if val is not None:
# If it's not a valid random string ID
if not isinstance(val, str) or len(val) < 11:
values[k] = None
return values
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = False
fields = base_fields
allow_population_by_field_name = True
# ### END ### API Account Models ### Account_Base() ###

View File

@@ -14,15 +14,21 @@ class Address_Base(BaseModel):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# --- Standardized Vision IDs (Strings) ---
# 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'])
# Standardized Polymorphic Target
for_type: Optional[str]
for_id_random: Optional[str]
for_id: Optional[int] = Field(None, exclude=True)
for_id: Optional[str] = Field(**base_fields['obj_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='address_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
contact_id_random: Optional[str] = Field(None, exclude=True)
for_id_random: Optional[str] = Field(None, exclude=True)
#organization: Optional[Organization_Base] = Organization_Base()
@@ -42,7 +48,7 @@ class Address_Base(BaseModel):
country_name: Optional[str] # From country lookup table
country: Optional[str] # Avoid using
lu_time_zone_id: Optional[str]
lu_time_zone_id: Optional[str] = Field(None, exclude=True)
timezone: Optional[str]
latitude: Optional[str]
@@ -70,20 +76,47 @@ class Address_Base(BaseModel):
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
# 1. Map Primary Object ID
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]
# 2. Map & Resolve Relational IDs
id_map = [
('account_id', 'account'),
('contact_id', 'contact'),
]
for field, table in id_map:
r_val = values.get(f'{field}_random')
if r_val and isinstance(r_val, str):
values[field] = r_val
elif values.get(field) and isinstance(values[field], (int, str)):
is_random = isinstance(values[field], str) and len(values[field]) >= 11
if not is_random:
resolved_rid = get_id_random(values[field], table)
if resolved_rid:
values[field] = resolved_rid
values[f'{field}_random'] = resolved_rid
# 3. Handle Polymorphic for_id
if f_rid := values.get('for_id_random'):
values['for_id'] = f_rid
elif values.get('for_id') and values.get('for_type'):
# Resolve based on the for_type
is_random = isinstance(values['for_id'], str) and len(values['for_id']) >= 11
if not is_random:
resolved_for_rid = get_id_random(values['for_id'], values['for_type'])
if resolved_for_rid:
values['for_id'] = resolved_for_rid
values['for_id_random'] = resolved_for_rid
# 4. Final Vision Enforcement
for k in ['id', 'address_id', 'account_id', 'contact_id', 'for_id']:
val = values.get(k)
if val is not None:
if not isinstance(val, str) or len(val) < 11:
values[k] = None
return values

View File

@@ -26,9 +26,16 @@ class Contact_Base(BaseModel):
# NOTE: Linked Address ID is actually the old contact.address_id (Legacy?)
linked_address_id: Optional[str] = Field(None, **base_fields['address_id_random'])
# Standardized Polymorphic Target
for_type: Optional[str]
for_id: Optional[int]
for_id_random: Optional[Union[str,None]] = None # lambda:get_id_random(values.get('for_id'), table_name=values.get('for_type')),
for_id: Optional[str] = Field(**base_fields['obj_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='contact_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
address_id_random: Optional[str] = Field(None, exclude=True)
linked_address_id_random: Optional[str] = Field(None, exclude=True)
for_id_random: Optional[str] = Field(None, exclude=True)
name: Optional[str]
title: Optional[str]
@@ -87,65 +94,51 @@ class Contact_Base(BaseModel):
Vision Transformer:
Map DB keys to clean API keys and strip internal integers.
"""
# 1. Map Random Strings to Clean Names
# 1. Map Primary Object ID
if rid := values.get('id_random') or values.get('contact_id_random'):
values['id'] = rid
values['contact_id'] = rid
if a_rid := values.get('account_id_random'):
values['account_id'] = a_rid
if ad_rid := values.get('address_id_random'):
values['address_id'] = ad_rid
if lad_rid := values.get('linked_address_id_random'):
values['linked_address_id'] = lad_rid
# 2. Prevent "Collision Population"
for k in ['id', 'contact_id', 'account_id', 'address_id', 'linked_address_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
del values[k]
# 2. Map & Resolve Relational IDs
id_map = [
('account_id', 'account'),
('address_id', 'address'),
('linked_address_id', 'address'),
]
for field, table in id_map:
r_val = values.get(f'{field}_random')
if r_val and isinstance(r_val, str):
values[field] = r_val
elif values.get(field) and isinstance(values[field], (int, str)):
is_random = isinstance(values[field], str) and len(values[field]) >= 11
if not is_random:
resolved_rid = get_id_random(values[field], table)
if resolved_rid:
values[field] = resolved_rid
values[f'{field}_random'] = resolved_rid
# 3. Handle Polymorphic for_id
if f_rid := values.get('for_id_random'):
values['for_id'] = f_rid
elif values.get('for_id') and values.get('for_type'):
# Resolve based on the for_type
is_random = isinstance(values['for_id'], str) and len(values['for_id']) >= 11
if not is_random:
resolved_for_rid = get_id_random(values['for_id'], values['for_type'])
if resolved_for_rid:
values['for_id'] = resolved_for_rid
values['for_id_random'] = resolved_for_rid
# 4. Final Vision Enforcement
for k in ['id', 'contact_id', 'account_id', 'address_id', 'linked_address_id', 'for_id']:
val = values.get(k)
if val is not None:
if not isinstance(val, str) or len(val) < 11:
values[k] = None
return values
@validator('for_id', pre=True, always=True)
def for_id_lookup(cls, v, values, **kwargs):
log.setLevel(logging.DEBUG)
log.debug(locals())
for_type = values.get('for_type')
for_id = v # values.get('for_id')
for_id_random = values.get('for_id_random')
if for_id and for_type:
log.info(f'Got For ID: {for_id}; For Type: {for_type}')
for_id_random = get_id_random(for_id, table_name=for_type)
values['for_id_random'] = for_id_random
return for_id
elif values.get('for_id_random') and values.get('for_type'):
log.info(f'Got For ID Random: {for_id_random}; For Type: {for_type}')
return redis_lookup_id_random(record_id_random=values['for_id_random'], table_name=values['for_type'])
log.info(f'Got nothing? For ID: {for_id}; For ID Random: {for_id_random}; For Type: {for_type}')
return None
@validator('for_id_random', always=True)
def for_id_random_lookup(cls, v, values, **kwargs):
log.setLevel(logging.DEBUG)
log.debug(locals())
for_type = values.get('for_type')
for_id = values.get('for_id')
for_id_random = v
if for_id_random:
log.info(f'Got For ID Random: {for_id_random}')
return for_id_random
elif for_id and for_type:
log.info(f'Got For ID: {for_id}; For Type: {for_type}')
for_id_random = get_id_random(for_id, table_name=for_type)
log.info(f'Got ID Random: {for_id_random}')
return for_id_random
log.info(f'Got nothing? For ID: {for_id}; For ID Random: {for_id_random}; For Type: {for_type}')
return None
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = False

View File

@@ -3,7 +3,7 @@ import datetime, pytz
from typing import Dict, List, Optional, Set, Union, ClassVar
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_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.models.common_field_schema import base_fields
@@ -22,18 +22,16 @@ class Data_Store_Base(BaseModel):
person_id: Optional[str] = Field(None, **base_fields['person_id_random'])
user_id: Optional[str] = Field(None, **base_fields['user_id_random'])
# Internal Integer IDs (Excluded from API)
# We use Optional[Union[int, str]] here to prevent validation crashes
# if the DB returns stringified integers or "NULL" strings.
id_int: Optional[Union[int, str]] = Field(None, alias='id', exclude=True)
account_id_int: Optional[Union[int, str]] = Field(None, alias='account_id', exclude=True)
person_id_int: Optional[Union[int, str]] = Field(None, alias='person_id', exclude=True)
user_id_int: Optional[Union[int, str]] = Field(None, alias='user_id', exclude=True)
# Standardized Polymorphic Target
for_type: Optional[str]
for_id: Optional[str] # Random ID string
for_id_random: Optional[str] # Svelte often uses this name
for_id_int: Optional[Union[int, str]] = Field(None, alias='for_id', exclude=True)
for_id: Optional[str] = Field(**base_fields['obj_id_random'])
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='data_store_id_random', exclude=True)
account_id_random: Optional[str] = Field(None, exclude=True)
person_id_random: Optional[str] = Field(None, exclude=True)
user_id_random: Optional[str] = Field(None, exclude=True)
for_id_random: Optional[str] = Field(None, exclude=True)
code: Optional[str]
name: Optional[str]
@@ -82,28 +80,50 @@ class Data_Store_Base(BaseModel):
if isinstance(v, str) and v.upper() == 'NULL':
values[k] = None
# 1. Map Random Strings to Clean Names
# 1. Map Primary Object ID
if rid := values.get('id_random') or values.get('data_store_id_random'):
values['id'] = rid
values['data_store_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. Map & Resolve Relational IDs
id_map = [
('account_id', 'account'),
('person_id', 'person'),
('user_id', 'user'),
]
for field, table in id_map:
r_val = values.get(f'{field}_random')
if r_val and isinstance(r_val, str):
values[field] = r_val
elif values.get(field) and isinstance(values[field], (int, str)):
# If it's a string but doesn't look like a random ID (e.g. integer string), resolve it
is_random = isinstance(values[field], str) and len(values[field]) >= 11
if not is_random:
resolved_rid = get_id_random(values[field], table)
if resolved_rid:
values[field] = resolved_rid
values[f'{field}_random'] = resolved_rid
# 3. Handle Polymorphic for_id
if f_rid := values.get('for_id_random'):
values['for_id'] = f_rid
values['for_id_random'] = f_rid
# 2. Prevent "Collision Population"
# We only want strings in our primary ID fields.
# If the key exists and isn't a string, it's a DB integer; remove it
# so it doesn't fail length validation on the string fields.
elif values.get('for_id') and values.get('for_type'):
# Resolve based on the for_type
is_random = isinstance(values['for_id'], str) and len(values['for_id']) >= 11
if not is_random:
resolved_for_rid = get_id_random(values['for_id'], values['for_type'])
if resolved_for_rid:
values['for_id'] = resolved_for_rid
values['for_id_random'] = resolved_for_rid
# 4. Final Vision Enforcement: Strip internal integers from public fields
for k in ['id', 'data_store_id', 'account_id', 'person_id', 'user_id', 'for_id']:
if k in values and not isinstance(values[k], str):
del values[k]
val = values.get(k)
# If value is present but not a valid random string ID
if val is not None:
if not isinstance(val, str) or len(val) < 11:
values[k] = None
return values

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 typing import Dict, List, Optional, Set, Union, ClassVar
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
@@ -15,19 +15,14 @@ class Event_Badge_Template_Base(BaseModel):
# log.info('Using base template')
id_random: Optional[str] = Field(
**base_fields['event_badge_template_id_random'],
alias = 'event_badge_template_id_random',
)
id: Optional[int] = Field(
alias = 'event_badge_template_id'
)
# --- Standardized Vision IDs (Strings) ---
id: Optional[str] = Field(None, **base_fields['event_badge_template_id_random'])
event_badge_template_id: Optional[str] = Field(None, **base_fields['event_badge_template_id_random'])
event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
# account_id_random: Optional[str]
# account_id: Optional[int]
event_id_random: Optional[str]
event_id: Optional[int]
# --- Standardized Legacy / Internal IDs (Excluded) ---
id_random: Optional[str] = Field(None, alias='event_badge_template_id_random', exclude=True)
event_id_random: Optional[str] = Field(None, exclude=True)
name: Optional[str]
description: Optional[str]
@@ -83,23 +78,30 @@ class Event_Badge_Template_Base(BaseModel):
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True)
def event_badge_template_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_template')
return None
@validator('event_id', always=True)
def event_id_lookup(cls, v, values, **kwargs):
if isinstance(v, int) and v > 0: return v
elif id_random := values.get('event_id_random'):
return redis_lookup_id_random(record_id_random=id_random, table_name='event')
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('event_badge_template_id_random'):
values['id'] = rid
values['event_badge_template_id'] = rid
if e_rid := values.get('event_id_random'):
values['event_id'] = e_rid
# 2. Prevent "Collision Population" (ensure no integers leak into the clean string fields)
for k in ['id', 'event_badge_template_id', 'event_id']:
if k in values and not isinstance(values[k], str) and values[k] is not None:
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

View File

@@ -46,6 +46,9 @@ class Event_File_Base(BaseModel):
event_session_id_random: Optional[str] = Field(None, exclude=True)
event_track_id_random: Optional[str] = Field(None, exclude=True)
# Internal flag to signal the model to load nested hosted_file
inc_hosted_file: Optional[bool] = Field(False, exclude=True)
@root_validator(pre=True)
def map_v3_ids(cls, values):
"""
@@ -102,9 +105,20 @@ class Event_File_Base(BaseModel):
val = values.get(k)
if val is not None and not isinstance(val, str):
values[k] = None
# 4. Conditionally load nested 'hosted_file' object
if values.get('inc_hosted_file') and values.get('hosted_file_id'):
from app.methods.hosted_file_methods import load_hosted_file_obj
if hosted_file_obj := load_hosted_file_obj(hosted_file_id=values['hosted_file_id']):
values['hosted_file'] = hosted_file_obj
# Clean up internal inc_hosted_file flag after processing
if 'inc_hosted_file' in values:
del values['inc_hosted_file']
return values
for_type: Optional[str]
filename: Optional[str]
@@ -114,7 +128,7 @@ class Event_File_Base(BaseModel):
title: Optional[str]
description: Optional[str]
lu_file_purpose_id: Optional[int]
lu_file_purpose_id: Optional[int] = Field(None, exclude=True)
file_purpose: Optional[str]
# New internal use fields to help with logistics and planning 2022-09-15
@@ -143,21 +157,21 @@ class Event_File_Base(BaseModel):
created_on: Optional[datetime.datetime] = None
updated_on: Optional[datetime.datetime] = None
# Including convenience data
# This is only for convenience. Probably going to keep unless it causes a problem.
hosted_file_hash_sha256: Optional[str] = Field(
alias = 'hash_sha256'
)
hosted_file_subdirectory_path: Optional[str] = Field( # NOTE: This will frequently only contain numbers, but it still needs to be a string
alias = 'subdirectory_path',
exclude = True
)
hosted_file_content_type: Optional[str] = Field(
alias = 'content_type'
)
hosted_file_size: Optional[str] = Field(
alias = 'file_size'
)
# Including convenience data for Hosted Files (top-level properties)
# These fields provide direct access to frequently needed properties from the associated
# hosted file, effectively flattening some aspects of the nested 'hosted_file' object.
#
# IMPORTANT: These fields are designed to be populated directly from the SQL View
# (e.g., `v_event_file_simple`) via JOINs. They should **NOT** have Pydantic `alias`
# definitions here if the view provides them with matching names (e.g., `hosted_file_hash_sha256`).
# Pydantic's default mapping will handle them directly from the incoming data dictionary
# (the `sql_result` in `api_crud_v3.py`).
# The `root_validator` does **NOT** populate these top-level fields; its role is
# solely to conditionally load the *nested* `hosted_file` object.
hosted_file_hash_sha256: Optional[str]
hosted_file_subdirectory_path: Optional[str]
hosted_file_content_type: Optional[str]
hosted_file_size: Optional[str]
lu_event_file_purpose_name: Optional[str] = Field(
alias = 'file_purpose_name'
@@ -194,6 +208,6 @@ class Event_File_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 Event File Models ### Event_File_Base() ###

View File

@@ -67,6 +67,7 @@ events_general_obj_li = {
'base_name': Event_File_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_id', 'event_file_id', 'hosted_file_id',
'event_file_id_random', 'hosted_file_id_random', 'event_id_random',
'event_exhibit_id_random', 'event_location_id_random',
@@ -114,6 +115,7 @@ events_general_obj_li = {
'base_name': Event_Cfg_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_cfg_id_random', 'event_id_random',
'status', 'notes', 'updated_on'
],

View File

@@ -20,6 +20,7 @@ events_presentation_obj_li = {
'base_name': Event_Abstract_In,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_abstract_id_random', 'event_id_random', 'event_person_id_random',
'code', 'external_id', 'name', 'description', 'abstract', 'enable',
'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on'
@@ -41,6 +42,7 @@ events_presentation_obj_li = {
'base_name': Event_Location_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_location_id_random', 'event_id_random', 'code', 'name',
'description', 'location_type', 'internal_use', 'enable', 'hide',
'public', 'public_hide', 'hide_event_launcher', 'priority', 'sort',
@@ -63,6 +65,7 @@ events_presentation_obj_li = {
'base_name': Event_Presentation_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_presentation_id_random', 'event_id_random',
'event_abstract_id_random', 'event_location_id_random',
'event_session_id_random', 'event_track_id_random', 'code', 'name',
@@ -97,6 +100,7 @@ events_presentation_obj_li = {
],
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_presenter_id_random', 'event_id_random',
'event_person_id_random', 'event_presentation_id_random',
'event_session_id_random', 'person_id_random', 'code', 'informal_name',
@@ -123,6 +127,7 @@ events_presentation_obj_li = {
'base_name': Event_Session_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_session_id_random', 'event_id_random',
'event_location_id_random', 'event_track_id_random', 'code', 'name',
'description', 'type_code', 'start_datetime', 'end_datetime',
@@ -145,6 +150,7 @@ events_presentation_obj_li = {
'base_name': Event_Track_Base,
# V3 Search Security:
'searchable_fields': [
'account_id', 'account_id_random',
'event_track_id_random', 'event_id_random',
'event_location_id_random', 'name', 'description', 'track_type',
'enable', 'hide', 'poc_agree', 'file_count', 'file_count_all', 'public', 'public_hide', 'hide_event_launcher',

View File

@@ -48,9 +48,9 @@ events_registration_obj_li = {
'base_name': Event_Badge_Template_Base,
# V3 Search Security:
'searchable_fields': [
'id', 'event_badge_template_id', 'event_id',
'id_random', 'event_badge_template_id_random', 'event_id_random', 'name',
'description', 'layout', 'notes', 'enable',
'id', 'event_badge_template_id', 'event_id', 'account_id',
'id_random', 'event_badge_template_id_random', 'event_id_random', 'account_id_random',
'name', 'description', 'layout', 'notes', 'enable',
'created_on', 'updated_on'
],
},

View File

@@ -110,6 +110,7 @@ async def get_obj(
obj_type_l1: str = Path(min_length=2, max_length=50),
obj_id: str = Path(min_length=11, max_length=22),
view: str = Query('default'),
inc_hosted_file: Optional[bool] = Query(False), # Added inc_hosted_file parameter
account: AccountContext = Depends(get_account_context_optional),
serialization: SerializationParams = Depends(),
delay: DelayParams = Depends(),
@@ -150,6 +151,11 @@ async def get_obj(
if not check_account_access(sql_result, account, obj_name):
return mk_resp(data=False, status_code=403, response=response, status_message="Access denied. Record belongs to another account.")
# Pass inc_hosted_file to the Pydantic model if applicable
if obj_name == 'event_file' and inc_hosted_file:
sql_result['inc_hosted_file'] = True
resp_data = base_name(**sql_result).dict(by_alias=serialization.by_alias, exclude_unset=serialization.exclude_unset, exclude_defaults=serialization.exclude_defaults, exclude_none=serialization.exclude_none)
return mk_resp(data=resp_data, response=response)
else: