From 59e96d7d3c00136bdb0caa1aabcb5da9d4b132ea Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Mon, 13 Dec 2021 15:12:54 -0500 Subject: [PATCH] Work on event meeting list end point, methods, and models --- app/db_sql.py | 2 +- app/methods/event_methods.py | 168 +++++++++++++++++++++++- app/models/event_models.py | 239 ++++++++++++++++++++++++++++++++++- app/routers/event.py | 60 ++++++++- 4 files changed, 460 insertions(+), 9 deletions(-) diff --git a/app/db_sql.py b/app/db_sql.py index 86ed5ba..29f6303 100644 --- a/app/db_sql.py +++ b/app/db_sql.py @@ -449,7 +449,7 @@ def sql_select( as_list: bool|None = False, max_count: int = 100000, ) -> None|bool|list: - log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) if table_name and not (record_id or record_id_random or field_name or field_value or sql or data): diff --git a/app/methods/event_methods.py b/app/methods/event_methods.py index 8a13d66..b2d0189 100644 --- a/app/methods/event_methods.py +++ b/app/methods/event_methods.py @@ -322,7 +322,8 @@ def get_event_rec_list( user_id: str = None, limit: int = 500, enabled: str = 'enabled', # enabled, disabled, all - archived: str = 'archived', # archived, not_archived, all + hidden: str = 'not_hidden', # hidden, not_hidden, all + archived: str = 'not_archived', # archived, not_archived, all conference: bool = False, # If it is a conference then organization, person, and user are queried as participants (not the owner/organizer) ) -> list|bool: log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL @@ -362,6 +363,18 @@ def get_event_rec_list( else: sql_archived = f'AND `event`.archive = :archive' + if hidden in ['hidden', 'not_hidden', 'all']: + if hidden == 'hidden': + data['hide'] = True + sql_hidden = f'AND `event`.hide = :hide' + elif hidden == 'not_hidden': + data['hide'] = False + sql_hidden = f'AND (`event`.hide = :hide OR `event`.hide IS NULL)' + elif hidden == 'all': + sql_hidden = '' + else: + sql_hidden = f'AND `event`.hide = :hide' + if conference: data['conference'] = True sql_conference = f'AND `event`.conference = :conference' @@ -402,8 +415,9 @@ def get_event_rec_list( FROM `event` AS `event` WHERE {sql_where_type_id} - {sql_enabled} {sql_archived} + {sql_hidden} + {sql_enabled} {sql_conference} ORDER BY `event`.created_on DESC, `event`.updated_on DESC {sql_limit}; @@ -423,16 +437,21 @@ def get_event_rec_list( /*INNER JOIN `person` ON event_person.person_id = person.id*/ INNER JOIN {sql_inner_join} WHERE 1=1 - {sql_enabled} {sql_archived} + {sql_hidden} + {sql_enabled} {sql_conference} ORDER BY `event`.created_on DESC, `event`.updated_on DESC {sql_limit}; """ + log.debug(sql) if event_rec_li_result := sql_select(data=data, sql=sql, as_list=True): + log.info('Got a list of events') + log.debug(event_rec_li_result) event_rec_li = event_rec_li_result else: + log.info('No events were found') event_rec_li = [] log.debug(event_rec_li_result) @@ -440,6 +459,149 @@ def get_event_rec_list( # ### END ### API Event Methods ### get_event_rec_list() ### +# ### BEGIN ### API Event Methods ### get_event_meeting_rec_list() ### +# Updated 2021-12-13 +def get_event_meeting_rec_list( + account_id: str = None, + organization_id: str = None, + person_id: str = None, + user_id: str = None, + limit: int = 500, + enabled: str = 'enabled', # enabled, disabled, all + hidden: str = 'not_hidden', # hidden, not_hidden, all + archived: str = 'not_archived', # archived, not_archived, all + ) -> list|bool: + log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + if account_id or organization_id or person_id or user_id: pass + else: return False + + if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass + else: pass + + if organization_id := redis_lookup_id_random(record_id_random=organization_id, table_name='organization'): pass + else: pass + + if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass + else: pass + + if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass + else: pass + + data = {} + data['account_id'] = account_id + data['organization_id'] = organization_id + data['person_id'] = person_id + data['user_id'] = user_id + # data['conference'] = conference + + if archived in ['archived', 'not_archived', 'all']: + if archived == 'archived': + data['archive'] = True + sql_archived = f'AND `event`.archive = :archive' + elif archived == 'not_archived': + data['archive'] = False + sql_archived = f'AND (`event`.archive = :archive OR `event`.archive IS NULL)' + elif archived == 'all': + sql_archived = '' + else: + sql_archived = f'AND `event`.archive = :archive' + + if hidden in ['hidden', 'not_hidden', 'all']: + if hidden == 'hidden': + data['hide'] = True + sql_hidden = f'AND `event`.hide = :hide' + elif hidden == 'not_hidden': + data['hide'] = False + sql_hidden = f'AND (`event`.hide = :hide OR `event`.hide IS NULL)' + elif hidden == 'all': + sql_hidden = '' + else: + sql_hidden = f'AND `event`.hide = :hide' + + # if conference: + # data['conference'] = True + # sql_conference = f'AND `event`.conference = :conference' + # else: + # data['conference'] = False + # sql_conference = f'AND `event`.conference = :conference' + + if enabled in ['enabled', 'disabled', 'all']: + if enabled == 'enabled': + data['enable'] = True + sql_enabled = f'AND `event`.enable = :enable' + elif enabled == 'disabled': + data['enable'] = False + sql_enabled = f'AND `event`.enable = :enable' + elif enabled == 'all': + sql_enabled = '' + else: + sql_enabled = f'AND `event`.enable = :enable' + + if limit: + data['limit'] = limit + sql_limit = f'LIMIT :limit' + else: + sql_limit = '' + + if account_id or not conference and (organization_id or person_id or user_id): + if account_id: + sql_where_type_id = f'`event`.account_id = :account_id' + elif organization_id: + sql_where_type_id = f'`event`.organization_id = :organization_id' + elif person_id: + sql_where_type_id = f'`event`.person_id = :person_id' + elif user_id: + sql_where_type_id = f'`event`.user_id = :user_id' + + sql = f""" + SELECT * + FROM `v_event` AS `event` + WHERE + {sql_where_type_id} + {sql_archived} + {sql_hidden} + {sql_enabled} + ORDER BY `event`.priority DESC, `event`.sort ASC, `event`.updated_on DESC, `event`.created_on DESC + {sql_limit}; + """ + elif conference and (organization_id or person_id or user_id): # If it is a conference then organization, person, and user are queried as participants (not the owner/organizer) + if organization_id: # Not sure if this makes sense? + sql_inner_join = f'`organization` ON event_person.organization_id = organization.id AND organization.id AND organization.id = :organization_id' + elif person_id: + sql_inner_join = f'`person` ON event_person.person_id = person.id AND person.id AND person.id = :person_id' + elif user_id: + sql_inner_join = f'`user` ON event_person.user_id = user.id AND user.id AND user.id = :user_id' + + sql = f""" + SELECT `event`.id AS 'event_id', `event`.id_random AS 'event_id_random' + FROM `v_event` AS `event` + INNER JOIN `event_person` ON event.id = event_person.event_id + /*INNER JOIN `person` ON event_person.person_id = person.id*/ + INNER JOIN {sql_inner_join} + WHERE 1=1 + {sql_archived} + {sql_hidden} + {sql_enabled} + ORDER BY `event`.priority DESC, `event`.sort ASC, `event`.updated_on DESC, `event`.created_on DESC + {sql_limit}; + """ + log.debug(sql) + + if event_rec_li_result := sql_select(data=data, sql=sql, as_list=True): + log.info('Got a list of events') + log.debug(event_rec_li_result) + event_rec_li = event_rec_li_result + else: + log.info('No events were found') + event_rec_li = [] + log.debug(event_rec_li_result) + + return event_rec_li +# ### END ### API Event Methods ### get_event_meeting_rec_list() ### + + # ### BEGIN ### API Event Methods ### load_event_obj_list() ### def load_event_obj_list( account_id: int|str|None = None, diff --git a/app/models/event_models.py b/app/models/event_models.py index 5832ce9..d0a32c2 100644 --- a/app/models/event_models.py +++ b/app/models/event_models.py @@ -264,4 +264,241 @@ class Event_Base(BaseModel): allow_population_by_field_name = True fields = base_fields -# Event_Base.update_forward_refs() # NOTE: This is needed since Event_Cfg_Base is below Event_Base. + +# Updated 2021-12-13 +class Event_Meeting_Flat_Base(BaseModel): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + id_random: Optional[str] = Field( + **base_fields['event_id_random'], + alias = 'event_id_random', + default_factory = lambda:secrets.token_urlsafe(default_num_bytes), + ) + id: Optional[int] = Field( + alias = 'event_id' + ) + + code: Optional[str] = Field( + alias = 'event_code' + ) + + account_id_random: Optional[str] + account_id: Optional[int] + + # poc_event_person_id_random: Optional[str] + # poc_event_person_id: Optional[int] + + # poc_person_id_random: Optional[str] + # poc_person_id: Optional[int] + + # user_id_random: Optional[str] + # user_id: Optional[int] + + lu_event_type_id: Optional[int] + #lu_event_type: Optional[str] # Needs to be reviewed + + conference: Optional[bool] # Also in Event_Cfg_Base model + + # type_name: Optional[str] = Field( + # alias = 'type' + # ) + type: Optional[str] + + name: Optional[str] + summary: Optional[str] + description: Optional[str] + format: Optional[str] + + lu_time_zone_id: Optional[int] + timezone: Optional[str] + start_datetime: Optional[datetime.datetime] = None + end_datetime: Optional[datetime.datetime] = None + + recurring: Optional[bool] + recurring_pattern: Optional[str] + recurring_start_time: Optional[datetime.time] + recurring_end_time: Optional[datetime.time] + recurring_text: Optional[str] + + weekday_sunday: Optional[bool] + weekday_monday: Optional[bool] + weekday_tuesday: Optional[bool] + weekday_wednesday: Optional[bool] + weekday_thursday: Optional[bool] + weekday_friday: Optional[bool] + weekday_saturday: Optional[bool] + + address_location_id_random: Optional[str] + address_location_id: Optional[int] + location_text: Optional[str] + + online_start: Optional[datetime.datetime] = None + online_end: Optional[datetime.datetime] = None + + reg_deadline_1: Optional[datetime.datetime] = None + reg_deadline_2: Optional[datetime.datetime] = None + reg_deadline_3: Optional[datetime.datetime] = None + reg_deadline_4: Optional[datetime.datetime] = None + + max_registrants: Optional[int] + + private: Optional[bool] # invite only + physical: Optional[bool] # physical in person event + virtual: Optional[bool] # virtual remote access event + + contact_1_id_random: Optional[str] + contact_1_id: Optional[int] + contact_2_id_random: Optional[str] + contact_2_id: Optional[int] + contact_3_id_random: Optional[str] + contact_3_id: Optional[int] + + attend_url: Optional[str] + attend_url_passcode: Optional[str] + attend_phone: Optional[str] + attend_phone_passcode: Optional[str] + attend_text: Optional[str] + + # NOT FINISHED YET + + # access_key: Optional[str] # Maybe use in the future? + + file_count: Optional[int] + + enable: Optional[bool] # Also in Event_Cfg_Base model + enable_from: Optional[datetime.datetime] = None + enable_to: Optional[datetime.datetime] = None + + archive: Optional[bool] # Also in Event_Cfg_Base model + archive_on: Optional[datetime.datetime] # Also in Event_Cfg_Base model + + hide: Optional[bool] # Also in Event_Cfg_Base model + priority: Optional[bool] + sort: Optional[int] + group: Optional[str] + + notes: Optional[str] + created_on: Optional[datetime.datetime] = None + updated_on: Optional[datetime.datetime] = None + + # Including convenience data + address_id_random: Optional[str] + address_id: Optional[int] + address_name: Optional[str] + address_line_1: Optional[str] + address_line_2: Optional[str] + address_line_3: Optional[str] + address_city: Optional[str] + address_country_subdivision_code: Optional[str] + address_country_subdivision_name: Optional[str] + address_postal_code: Optional[str] + address_country_alpha_2_code: Optional[str] + address_country_name: Optional[str] + + contact_1_id_random: Optional[str] + contact_1_id: Optional[int] + contact_1_name: Optional[str] + contact_1_email: Optional[str] + contact_1_phone_mobile: Optional[str] + contact_1_phone_home: Optional[str] + contact_1_phone_office: Optional[str] + contact_1_phone_land: Optional[str] + contact_1_phone_fax: Optional[str] + contact_1_phone_other: Optional[str] + contact_1_other_text: Optional[str] + + contact_2_id_random: Optional[str] + contact_2_id: Optional[int] + contact_2_name: Optional[str] + contact_2_email: Optional[str] + contact_2_phone_mobile: Optional[str] + contact_2_phone_home: Optional[str] + contact_2_phone_office: Optional[str] + contact_2_phone_land: Optional[str] + contact_2_phone_fax: Optional[str] + contact_2_phone_other: Optional[str] + contact_2_other_text: Optional[str] + + _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) + + #@validator('event_id_random', always=True) + def event_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 event_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='event') + return None + + # @validator('account_id', always=True) + # 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('address_id', always=True) + # def address_id_lookup(cls, v, values, **kwargs): + # log.setLevel(logging.WARNING) + # log.debug(locals()) + + # if values['address_id_random']: + # return redis_lookup_id_random(record_id_random=values['address_id_random'], table_name='address') + # return None + + # @validator('contact_1_id', always=True) + # def contact_1_id_lookup(cls, v, values, **kwargs): + # log.setLevel(logging.WARNING) + # log.debug(locals()) + + # if values['contact_1_id_random']: + # return redis_lookup_id_random(record_id_random=values['contact_1_id_random'], table_name='contact') + # return None + + # @validator('contact_2_id', always=True) + # def contact_2_id_lookup(cls, v, values, **kwargs): + # log.setLevel(logging.WARNING) + # log.debug(locals()) + + # if values['contact_2_id_random']: + # return redis_lookup_id_random(record_id_random=values['contact_2_id_random'], table_name='contact') + # return None + + # @validator('contact_3_id', always=True) + # def contact_3_id_lookup(cls, v, values, **kwargs): + # log.setLevel(logging.WARNING) + # log.debug(locals()) + + # if values['contact_3_id_random']: + # return redis_lookup_id_random(record_id_random=values['contact_3_id_random'], table_name='contact') + # return None + + @validator('created_on', always=True) + def created_on_utc(cls, v, values, **kwargs): + if isinstance(v, datetime.datetime): + return v.astimezone(pytz.UTC).isoformat() + else: return v + + @validator('updated_on', always=True) + def updated_on_utc(cls, v, values, **kwargs): + if isinstance(v, datetime.datetime): + return v.astimezone(pytz.UTC).isoformat() + else: return v + + class Config: + underscore_attrs_are_private = True + allow_population_by_field_name = True + fields = base_fields diff --git a/app/routers/event.py b/app/routers/event.py index 39a7bf8..18ce146 100644 --- a/app/routers/event.py +++ b/app/routers/event.py @@ -9,9 +9,9 @@ from app.db_sql import sql_insert, sql_update, sql_insert_or_update, sql_select, from app.routers.api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template -from app.methods.event_methods import get_event_rec_list, load_event_obj, update_event_obj +from app.methods.event_methods import get_event_rec_list, get_event_meeting_rec_list, load_event_obj, update_event_obj -from app.models.event_models import Event_Base +from app.models.event_models import Event_Base, Event_Meeting_Flat_Base from app.models.response_models import Resp_Body_Base, mk_resp @@ -306,13 +306,14 @@ async def get_event_obj( # ### BEGIN ### API Event ### get_account_obj_event_list() ### -# Updated 2021-09-28 +# Updated 2021-12-13 @router.get('/account/{account_id}/event/list', response_model=Resp_Body_Base) async def get_account_obj_event_list( account_id: str = Query(..., min_length=11, max_length=22), limit: int = 500, enabled: str = 'enabled', archived: str = 'not_archived', # archived, not_archived, all + hidden: str = 'not_hidden', # hidden, not_hidden, all conference: bool = False, # Events with badges, sessions, presentations, presenters, registration, etc # inc_account_cfg: bool = False, inc_address: bool = False, # Under event and under contact @@ -357,12 +358,13 @@ async def get_account_obj_event_list( response_data = None # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL - # Updated 2021-09-28 + # Updated 2021-12-13 if event_rec_list_result := get_event_rec_list( account_id = account_id, limit = limit, enabled = enabled, archived = archived, + hidden = hidden, conference = conference, ): event_result_list = [] @@ -408,6 +410,56 @@ async def get_account_obj_event_list( else: return mk_resp(data=False, status_code=400, response=response) # Bad Request + log.debug(response_data) + return mk_resp(data=response_data, response=response) +# ### END ### API Event ### get_account_obj_event_list() ### + + +# ### BEGIN ### API Event ### get_account_obj_event_meeting_list_flat() ### +# Updated 2021-12-13 +@router.get('/account/{account_id}/event/meeting_list_flat', response_model=Resp_Body_Base) +async def get_account_obj_event_meeting_list_flat( + account_id: str = Query(..., min_length=11, max_length=22), + limit: int = 500, + enabled: str = 'enabled', + archived: str = 'not_archived', # archived, not_archived, all + hidden: str = 'not_hidden', # hidden, not_hidden, all + x_account_id: str = Header(...), + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + response: Response = Response, + ): + log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass + else: return mk_resp(data=None, status_code=404, response=response) + + response_data = None + # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + + # Updated 2021-12-13 + if event_meeting_rec_list_result := get_event_meeting_rec_list( + account_id = account_id, + limit = limit, + enabled = enabled, + archived = archived, + hidden = hidden, + ): + event_result_list = [] + for event_rec in event_meeting_rec_list_result: + try: + event_obj = Event_Meeting_Flat_Base(**event_rec) + log.debug(event_obj) + except ValidationError as e: + log.error(e.json()) + return False + event_result_list.append(event_obj) + response_data = event_result_list + else: + return mk_resp(data=False, status_code=404, response=response) # Not Found + + log.debug(response_data) return mk_resp(data=response_data, response=response) # ### END ### API Event ### get_account_obj_event_list() ###