Adding activity_log routes, methods, and models.

This commit is contained in:
Scott Idem
2021-12-10 21:51:41 -05:00
parent 08335c8b11
commit b22a84f054
6 changed files with 414 additions and 2 deletions

View File

@@ -18,7 +18,7 @@ from app.lib_general import log, logging
from app.log import log
# Import the routers here first:
from app.routers import api_crud, api, importing, account, address, archive, archive_content, contact, cont_edu_cert, cont_edu_cert_person, event, event_badge, event_badge_template, event_exhibit, event_file, event_importing, event_location, event_person, event_person_detail, event_person_tracking, event_presentation, event_presenter, event_registration, event_session, flask_cfg, hosted_file, journal, journal_entry, log_client_viewing, lookup, membership_cfg, membership_group, membership_group_person, membership_person, membership_person_profile, membership_type, membership_type_person, order, order_line, order_cart, organization, page, person, person_user, post, post_comment, product, site, site_domain, user, websockets#, e_impexium
from app.routers import api_crud, api, importing, account, activity_log, address, archive, archive_content, contact, cont_edu_cert, cont_edu_cert_person, event, event_badge, event_badge_template, event_exhibit, event_file, event_importing, event_location, event_person, event_person_detail, event_person_tracking, event_presentation, event_presenter, event_registration, event_session, flask_cfg, hosted_file, journal, journal_entry, log_client_viewing, lookup, membership_cfg, membership_group, membership_group_person, membership_person, membership_person_profile, membership_type, membership_type_person, order, order_line, order_cart, organization, page, person, person_user, post, post_comment, product, site, site_domain, user, websockets#, e_impexium
from app.db_sql import db
@@ -83,6 +83,11 @@ app.include_router(
prefix='/account',
tags=['Account'],
)
app.include_router(
activity_log.router,
prefix='/activity_log',
tags=['Activity Log'],
)
app.include_router(
address.router,
prefix='/address',

View File

@@ -0,0 +1,97 @@
from __future__ import annotations
import datetime
from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
from app.db_sql import redis_lookup_id_random, sql_insert, sql_insert_or_update, sql_select, sql_update
from app.lib_general import log, logging
from app.models.common_field_schema import default_num_bytes
from app.models.activity_log_models import Activity_Log_Base
# ### BEGIN ### API Activity Log Methods ### load_activity_log_obj() ###
def load_activity_log_obj(
activity_log_id: int|str,
limit: int = 10000,
by_alias: bool = True,
exclude_unset: bool = True,
model_as_dict: bool = False,
) -> Activity_Log_Base|bool:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if activity_log_id := redis_lookup_id_random(record_id_random=activity_log_id, table_name='activity_log'): pass
else: return False
if activity_log_rec := sql_select(table_name='v_activity_log', record_id=activity_log_id): pass
else: return False
try:
activity_log_obj = Activity_Log_Base(**activity_log_rec)
log.debug(activity_log_obj)
except ValidationError as e:
log.error(e.json())
if model_as_dict:
return activity_log_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
else:
return activity_log_obj
# ### END ### API Activity Log Methods ### load_activity_log_obj() ###
# ### BEGIN ### API Activity Log Methods ### get_activity_log_rec_list() ###
def get_activity_log_rec_list(
account_id: str,
from_datetime: datetime.datetime = None,
to_datetime: datetime.datetime = None,
limit: int = 1000,
enabled: str = 'enabled', # enabled, disabled, all
) -> list|bool:
log.setLevel(logging.WARNING) # 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 False
data = {}
data['account_id'] = account_id
sql_account_id = f'`activity_log`.account_id = :account_id'
# if enabled in ['enabled', 'disabled', 'all']:
# if enabled == 'enabled':
# data['enable'] = True
# sql_enabled = f'AND `activity_log`.enable = :enable'
# elif enabled == 'disabled':
# data['enable'] = False
# sql_enabled = f'AND `activity_log`.enable = :enable'
# elif enabled == 'all':
# sql_enabled = ''
sql_enabled = ''
if limit:
data['limit'] = limit
sql_limit = f'LIMIT :limit'
else:
sql_limit = ''
sql = f"""
SELECT `activity_log`.id AS 'activity_log_id', `activity_log`.id_random AS 'activity_log_id_random'
FROM `activity_log` AS `activity_log`
WHERE
{sql_account_id}
{sql_enabled}
ORDER BY `activity_log`.created_on DESC, `activity_log`.updated_on DESC
{sql_limit};
"""
if activity_log_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
activity_log_rec_li = activity_log_rec_li_result
else:
activity_log_rec_li = []
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(activity_log_rec_li_result)
return activity_log_rec_li
# ### END ### API Activity Log Methods ### get_activity_log_rec_list() ###

View File

@@ -0,0 +1,128 @@
from __future__ import annotations
import datetime, hashlib, logging, os, pytz, redis, secrets
from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
from app.db_sql import redis_lookup_id_random
from app.lib_general import log, logging
from app.models.common_field_schema import base_fields, default_num_bytes
class Activity_Log_Base(BaseModel):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
id_random: Optional[str] = Field(
**base_fields['activity_log_id_random'],
alias = 'activity_log_id_random',
default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
)
id: Optional[int] = Field(
alias = 'activity_log_id'
)
account_id_random: Optional[str]
account_id: Optional[int]
person_id_random: Optional[str]
person_id: Optional[int]
user_id_random: Optional[str]
user_id: Optional[int]
external_client_id: Optional[str]
google_ga: Optional[str]
google_gid: Optional[str]
name: Optional[str]
description: Optional[str]
source: Optional[str]
url_root: Optional[str]
url_full_path: Optional[str]
url_params: Optional[str]
object_type: Optional[str]
object_id_random: Optional[str]
object_id: Optional[int]
action: Optional[str]
action_with: Optional[str]
action_on_type: Optional[str]
action_on_id_random: Optional[str]
action_on_id: Optional[int]
action_on_code: Optional[str]
action_data: Optional[str]
code: Optional[str]
type_id: Optional[int]
type_name: Optional[str]
details: Optional[str]
# For now just using string instead of Json Pydantic data type
other_json: Optional[str] # When getting the dict version for SQL this should be a string.
meta_json: Optional[str] # When getting the dict version for SQL this should be a string.
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)
#@validator('activity_log_id_random', always=True)
def activity_log_id_random_copy(cls, v, values, **kwargs):
log.setLevel(logging.WARNING)
log.debug(locals())
if id_random := values.get('id_random'):
return id_random
return None
@validator('id', always=True)
def activity_log_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='activity_log')
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('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
class Config:
underscore_attrs_are_private = True
allow_population_by_field_name = True
fields = base_fields
#Activity_Log_Base.update_forward_refs()

View File

@@ -24,6 +24,7 @@ base_fields = {}
base_fields['obj_id_random'] = xxx_id_random_field_schema # General or generic object_id_random
base_fields['account_id_random'] = xxx_id_random_field_schema
base_fields['account_cfg_id_random'] = xxx_id_random_field_schema
base_fields['activity_log_id_random'] = xxx_id_random_field_schema
base_fields['address_id_random'] = xxx_id_random_field_schema
base_fields['archive_id_random'] = xxx_id_random_field_schema
base_fields['archive_content_id_random'] = xxx_id_random_field_schema

180
app/routers/activity_log.py Normal file
View File

@@ -0,0 +1,180 @@
import datetime
#from datetime import datetime, time, timedelta
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, Response, status
from pydantic import BaseModel, EmailStr, Field
from typing import Dict, List, Optional, Set, Union
from app.lib_general import log, logging
#from ..log import *
from app.config import settings
from app.db_sql import *
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.activity_log_methods import get_activity_log_rec_list, load_activity_log_obj
from app.models.activity_log_models import Activity_Log_Base
from app.models.response_models import *
router = APIRouter()
@router.post('/activity_log', response_model=Resp_Body_Base)
async def post_activity_log_obj(
activity_log_obj: Activity_Log_Base,
x_account_id: str = Header(...),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
response: Response = Response,
):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_type = 'activity_log'
activity_log_obj_data_dict = activity_log_obj.dict(by_alias=False, exclude_unset=True)
result = post_obj_template(
obj_type = obj_type,
data = activity_log_obj_data_dict,
return_obj = True,
by_alias = True,
exclude_unset = True,
)
return result
@router.patch('/activity_log/{activity_log_id}', response_model=Resp_Body_Base)
async def patch_activity_log_obj(
activity_log_obj: Activity_Log_Base,
activity_log_id: str = Query(..., min_length=1, max_length=22),
x_account_id: Optional[str] = Header(..., ),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
response: Response = Response,
):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_type = 'activity_log'
activity_log_obj_data_dict = activity_log_obj.dict(by_alias=False, exclude_unset=True)
activity_log_obj_data_dict['id'] = redis_lookup_id_random(record_id_random=activity_log_id, table_name=obj_type)
activity_log_obj_data_dict['id_random'] = activity_log_id
result = patch_obj_template(
obj_type = obj_type,
data = activity_log_obj_data_dict,
obj_id = activity_log_id,
return_obj = True,
by_alias = True,
exclude_unset = True,
)
return result
@router.get('/activity_log/list', response_model=Resp_Body_Base)
async def get_activity_log_obj_li(
for_obj_type: Optional[str] = Query(None, min_length=2, max_length=50),
for_obj_id: Optional[str] = Query(None, min_length=1, max_length=22),
x_account_id: str = Header(...),
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
response: Response = Response,
):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_type = 'activity_log'
result = get_obj_li_template(
obj_type=obj_type,
for_obj_type=for_obj_type,
for_obj_id=for_obj_id,
by_alias=True,
exclude_unset=True,
)
return result
@router.get('/activity_log/{obj_id}', response_model=Resp_Body_Base)
async def get_activity_log_obj(
obj_id: str = Query(..., min_length=1, max_length=22),
x_account_id: str = Header(...),
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
response: Response = Response,
):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_type = 'activity_log'
result = get_obj_template(
obj_type=obj_type,
obj_id=obj_id,
by_alias=True,
exclude_unset=True,
)
return result
# ### BEGIN ### API Activity Log ### get_account_obj_activity_log_list() ###
# Updated 2021-09-21
@router.get('/account/{account_id}/activity_log/list', response_model=Resp_Body_Base)
async def get_account_obj_activity_log_list(
account_id: str = Query(..., min_length=11, max_length=22),
limit: int = 500, # For now this covers any included objects or object lists
enabled: str = 'enabled', # For now this covers any included objects or object lists
x_account_id: str = Header(...),
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
response: Response = Response,
):
log.setLevel(logging.WARNING) # 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)
# Updated 2021-09-21
if activity_log_rec_list_result := get_activity_log_rec_list(
account_id = account_id,
enabled = enabled,
limit = limit,
):
activity_log_result_list = []
for activity_log_rec in activity_log_rec_list_result:
if load_activity_log_result := load_activity_log_obj(
activity_log_id = activity_log_rec.get('activity_log_id', None),
enabled = enabled,
limit = limit,
by_alias = by_alias,
exclude_unset = exclude_unset,
# model_as_dict = model_as_dict,
):
activity_log_result_list.append(load_activity_log_result)
else:
activity_log_result_list.append(None)
response_data = activity_log_result_list
elif isinstance(activity_log_rec_list_result, list):
return mk_resp(data=False, status_code=404, response=response) # Not Found
else:
return mk_resp(data=False, status_code=400, response=response) # Bad Request
return mk_resp(data=response_data, response=response)
# ### END ### API Activity Log ### get_account_obj_activity_log_list() ###
@router.delete('/activity_log/{obj_id}', response_model=Resp_Body_Base)
async def delete_activity_log_obj(
obj_id: str = Query(..., min_length=1, max_length=22),
x_account_id: str = Header(...),
response: Response = Response,
):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_type = 'activity_log'
result = delete_obj_template(
obj_type=obj_type,
obj_id=obj_id,
)
return result

View File

@@ -12,6 +12,7 @@ from app.models.response_models import *
from app.models.account_models import *
from app.models.account_cfg_models import *
from app.models.activity_log_models import *
from app.models.address_models import *
from app.models.archive_models import *
from app.models.archive_content_models import *
@@ -65,7 +66,7 @@ obj_type_li = {}
obj_type_li['account'] = {'table_name': 'account', 'base_name': Account_Base}
obj_type_li['account_cfg'] = {'table_name': 'v_account_cfg_detail', 'base_name': Account_Cfg_Base} # NOTE check view name: *_detail?
#obj_type_li['activity_log'] = {'table_name': 'activity_log', 'base_name': Activity_Log_Base}
obj_type_li['activity_log'] = {'table_name': 'activity_log', 'base_name': Activity_Log_Base}
obj_type_li['address'] = {'table_name': 'v_address', 'base_name': Address_Base}
obj_type_li['archive'] = {'table_name': 'v_archive', 'base_name': Archive_Base}
obj_type_li['archive_content'] = {'table_name': 'v_archive_content', 'base_name': Archive_Content_Base}