From c94b2fb2e710c002599357e6dae6c216772e7f9d Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 19 May 2021 18:05:41 -0400 Subject: [PATCH] Working on Journals module and using React with Axios. --- app/lib_general.py | 2 + app/main.py | 19 +++- app/models/common_field_schema.py | 2 + app/models/journal_entry_model.py | 69 +++++++++++++ app/models/journal_model.py | 68 +++++++++++++ app/routers/journal.py | 162 ++++++++++++++++++++++++++++++ app/routers/journal_entry.py | 161 +++++++++++++++++++++++++++++ 7 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 app/models/journal_entry_model.py create mode 100644 app/models/journal_model.py create mode 100644 app/routers/journal.py create mode 100644 app/routers/journal_entry.py diff --git a/app/lib_general.py b/app/lib_general.py index d9874db..c378e0d 100644 --- a/app/lib_general.py +++ b/app/lib_general.py @@ -38,6 +38,8 @@ async def get_account_header(x_account_id:str = Header(...)): elif x_account_id == '': log.info('The x-account-id header was empty.') account = { 'id': None, 'id_random': None } + #account = { 'id': 0, 'id_random': 'abcdef123456' } + return account # ### END ### API Lib General ### async get_account_header() ### diff --git a/app/main.py b/app/main.py index 9463b30..af68af9 100644 --- a/app/main.py +++ b/app/main.py @@ -18,7 +18,7 @@ from .lib_general import * from .log import * # Import the routers here first: -from .routers import api_crud, api, account, address, archive, archive_content, contact, event, event_exhibit, event_registration, event_session, flask_cfg, lookup, membership, order, order_cart, organization, page, person, post, post_comment, product, site, site_domain, user, user_person, websockets # , items, journals +from .routers import api_crud, api, account, address, archive, archive_content, contact, event, event_exhibit, event_registration, event_session, flask_cfg, journal, journal_entry, lookup, membership, order, order_cart, organization, page, person, post, post_comment, product, site, site_domain, user, user_person, websockets # , items, journals from .db_sql import db @@ -142,6 +142,22 @@ app.include_router( #dependencies=[Depends(get_account_header)], #responses={404: {'description': 'Not found'}}, ) +app.include_router( + journal.router, + prefix='/journal', + tags=['Journal'], + #dependencies=[Depends(get_token_header)], + #dependencies=[Depends(get_account_header)], + #responses={404: {'description': 'Not found'}}, +) +app.include_router( + journal_entry.router, + prefix='/journal/entry', + tags=['Journal Entry'], + #dependencies=[Depends(get_token_header)], + #dependencies=[Depends(get_account_header)], + #responses={404: {'description': 'Not found'}}, +) app.include_router( lookup.router, prefix='/lu', @@ -262,6 +278,7 @@ app.include_router( origins = [ 'http://fastapi.localhost', 'http://localhost', + 'http://localhost:3000', 'http://localhost:5000', 'http://fastapi.localhost:5000', 'http://demo.localhost:5000', diff --git a/app/models/common_field_schema.py b/app/models/common_field_schema.py index d1b02f5..2481ff4 100644 --- a/app/models/common_field_schema.py +++ b/app/models/common_field_schema.py @@ -42,6 +42,8 @@ base_fields['event_track_id_random'] = xxx_id_random_field_schema base_fields['flask_cfg_id_random'] = xxx_id_random_field_schema base_fields['fundraising_id_random'] = xxx_id_random_field_schema base_fields['hosted_file_id_random'] = xxx_id_random_field_schema +base_fields['journal_id_random'] = xxx_id_random_field_schema +base_fields['journal_entry_id_random'] = xxx_id_random_field_schema base_fields['membership_id_random'] = xxx_id_random_field_schema base_fields['membership_profile_id_random'] = xxx_id_random_field_schema base_fields['order_cart_id_random'] = xxx_id_random_field_schema diff --git a/app/models/journal_entry_model.py b/app/models/journal_entry_model.py new file mode 100644 index 0000000..d82fadd --- /dev/null +++ b/app/models/journal_entry_model.py @@ -0,0 +1,69 @@ +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 ..db_sql import redis_lookup_id_random +from ..lib_general import * + +from .common_field_schema import base_fields, default_num_bytes + + +class Journal_Entry_Base(BaseModel): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + id_random: Optional[str] = Field( + **base_fields['journal_entry_id_random'], + alias='journal_entry_id_random', + default_factory=lambda:secrets.token_urlsafe(default_num_bytes), + ) + id: Optional[int] = Field( + #alias='journal_entry_id' + ) + + title: Optional[str] + summary: Optional[str] + content: Optional[str] + + private: Optional[bool] = True + public: Optional[bool] = False + personal: Optional[bool] = True + professional: Optional[bool] = False + + hide: Optional[int] + priority: Optional[int] + sort: Optional[int] + group: Optional[str] + + notes: Optional[str] + created_on: Optional[datetime.datetime] = None + updated_on: Optional[datetime.datetime] = None + + _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) + + #@validator('journal_entry_id_random', always=True) + def journal_entry_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 journal_entry_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='journal_entry') + return None + + class Config: + underscore_attrs_are_private = True + fields = base_fields + +Journal_Entry_Base.update_forward_refs() diff --git a/app/models/journal_model.py b/app/models/journal_model.py new file mode 100644 index 0000000..2181287 --- /dev/null +++ b/app/models/journal_model.py @@ -0,0 +1,68 @@ +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 ..db_sql import redis_lookup_id_random +from ..lib_general import * + +from .common_field_schema import base_fields, default_num_bytes + + +class Journal_Base(BaseModel): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + id_random: Optional[str] = Field( + **base_fields['product_id_random'], + alias='product_id_random', + default_factory=lambda:secrets.token_urlsafe(default_num_bytes), + ) + id: Optional[int] = Field( + #alias='product_id' + ) + account_id_random: Optional[str] + account_id: Optional[int] + + user_id_random: Optional[str] + user_id: Optional[int] + + title: Optional[str] + summary: Optional[str] + + hide: Optional[int] + priority: Optional[int] + sort: Optional[int] + group: Optional[str] + + notes: Optional[str] + created_on: Optional[datetime.datetime] = None + updated_on: Optional[datetime.datetime] = None + + _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) + + #@validator('journal_id_random', always=True) + def journal_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 journal_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='journal') + return None + + class Config: + underscore_attrs_are_private = True + fields = base_fields + +Journal_Base.update_forward_refs() diff --git a/app/routers/journal.py b/app/routers/journal.py new file mode 100644 index 0000000..b1006c0 --- /dev/null +++ b/app/routers/journal.py @@ -0,0 +1,162 @@ +import datetime +#from datetime import datetime, time, timedelta +from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, status +from pydantic import BaseModel, EmailStr, Field +from typing import Dict, List, Optional, Set, Union + +from ..lib_general import * +from ..log import * +from app.config import settings +from app.db_sql import * + +from .api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template + +from ..models.journal_model import Journal_Base +from ..models.response_model import * + + +router = APIRouter() + + +@router.post('', response_model=Resp_Body_Base) +async def post_journal_obj( + obj: Journal_Base, + x_account_id: str = Header(...), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + result = post_obj_template( + obj_type=obj_type, + data=obj_data_dict, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.patch('/{obj_id}', response_model=Resp_Body_Base) +async def patch_journal_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + obj: Journal_Base = None, + x_account_id: Optional[str] = Header(..., ), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=obj_type) + obj_data_dict['id_random'] = obj_id + result = patch_obj_template( + obj_type=obj_type, + data=obj_data_dict, + obj_id=obj_id, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.get('/list', response_model=Resp_Body_Base) +async def get_journal_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), + #prod_type: Optional[str] = Query(None, min_length=2, max_length=50), + x_account_id: str = Header(...), + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal' + base_name = Journal_Base + data = {} + + if for_obj_type == 'account' and for_obj_id: + for_obj_id_random = for_obj_id + for_obj_id = redis_lookup_id_random(record_id_random=for_obj_id_random, table_name=for_obj_type) + + data['for_obj_type'] = for_obj_type + data['for_obj_id'] = for_obj_id + data['for_obj_id_random'] = for_obj_id_random + + sql_for_obj_type = f"""`journal`.account_id = :for_obj_id""" + elif for_obj_type == 'user' and for_obj_id: + for_obj_id_random = for_obj_id + for_obj_id = redis_lookup_id_random(record_id_random=for_obj_id_random, table_name=for_obj_type) + + data['for_obj_type'] = for_obj_type + data['for_obj_id'] = for_obj_id + data['for_obj_id_random'] = for_obj_id_random + + sql_for_obj_type = f"""`journal`.for_type = :for_obj_type AND `journal`.for_id = :for_obj_id""" + else: sql_for_obj_type = '' + + sql = f""" + SELECT * + FROM `v_journal` AS journal + WHERE {sql_for_obj_type} + """ + + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(data) + log.debug(sql) + + if sql_result := sql_select(data=data, sql=sql, as_list=True): + resp_data_li = [] + for record in sql_result: + resp_data = base_name(**record).dict(by_alias=by_alias, exclude_unset=exclude_unset) + resp_data_li.append(resp_data) + + return mk_resp(data=resp_data_li) + else: + log.debug(sql_result) + return mk_resp(data=False, status_code=404) + + +@router.get('/{obj_id}', response_model=Resp_Body_Base) +async def get_journal_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, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal' + result = get_obj_template( + obj_type=obj_type, + obj_id=obj_id, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.delete('/{obj_id}', response_model=Resp_Body_Base) +async def delete_journal_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + x_account_id: str = Header(...), + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal' + result = delete_obj_template( + obj_type=obj_type, + obj_id=obj_id, + ) + return result \ No newline at end of file diff --git a/app/routers/journal_entry.py b/app/routers/journal_entry.py new file mode 100644 index 0000000..a97d340 --- /dev/null +++ b/app/routers/journal_entry.py @@ -0,0 +1,161 @@ +import datetime +#from datetime import datetime, time, timedelta +from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, status +from pydantic import BaseModel, EmailStr, Field +from typing import Dict, List, Optional, Set, Union + +from ..lib_general import * +from ..log import * +from app.config import settings +from app.db_sql import * + +from .api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template + +from ..models.journal_entry_model import Journal_Entry_Base +from ..models.response_model import * + + +router = APIRouter() + + +@router.post('', response_model=Resp_Body_Base) +async def post_journal_entry_obj( + obj: Journal_Entry_Base, + x_account_id: str = Header(...), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal_entry' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + result = post_obj_template( + obj_type=obj_type, + data=obj_data_dict, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.patch('/{obj_id}', response_model=Resp_Body_Base) +async def patch_journal_entry_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + obj: Journal_Entry_Base = None, + x_account_id: Optional[str] = Header(..., ), + return_obj: Optional[bool] = True, + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal_entry' + obj_data_dict = obj.dict(by_alias=False, exclude_unset=True) + obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=obj_type) + obj_data_dict['id_random'] = obj_id + result = patch_obj_template( + obj_type=obj_type, + data=obj_data_dict, + obj_id=obj_id, + return_obj=True, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.get('/list', response_model=Resp_Body_Base) +async def get_journal_entry_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), + #prod_type: Optional[str] = Query(None, min_length=2, max_length=50), + #x_account_id: str = Header(...), + by_alias: Optional[bool] = True, + exclude_unset: Optional[bool] = True, + ): + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal_entry' + base_name = Journal_Entry_Base + data = {} + + if for_obj_type == 'account' and for_obj_id: + for_obj_id_random = for_obj_id + for_obj_id = redis_lookup_id_random(record_id_random=for_obj_id_random, table_name=for_obj_type) + + data['for_obj_type'] = for_obj_type + data['for_obj_id'] = for_obj_id + data['for_obj_id_random'] = for_obj_id_random + + sql_for_obj_type = f"""`journal_entry`.account_id = :for_obj_id""" + elif for_obj_type == 'user' and for_obj_id: + for_obj_id_random = for_obj_id + for_obj_id = redis_lookup_id_random(record_id_random=for_obj_id_random, table_name=for_obj_type) + + data['user_id'] = for_obj_id + data['user_id_id_random'] = for_obj_id_random + + sql_for_obj_type = f"""`journal_entry`.user_id = :user_id""" + else: sql_for_obj_type = '' + + sql = f""" + SELECT * + FROM `v_journal_entry` AS journal_entry + WHERE {sql_for_obj_type} + """ + + log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(data) + log.debug(sql) + + if sql_result := sql_select(data=data, sql=sql, as_list=True): + resp_data_li = [] + for record in sql_result: + resp_data = base_name(**record).dict(by_alias=by_alias, exclude_unset=exclude_unset) + resp_data_li.append(resp_data) + + return mk_resp(data=resp_data_li) + else: + log.debug(sql_result) + return mk_resp(data=False, status_code=404) + + +@router.get('/{obj_id}', response_model=Resp_Body_Base) +async def get_journal_entry_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, + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal_entry' + result = get_obj_template( + obj_type=obj_type, + obj_id=obj_id, + by_alias=True, + exclude_unset=True, + ) + return result + + +@router.delete('/{obj_id}', response_model=Resp_Body_Base) +async def delete_journal_entry_obj( + obj_id: str = Query(..., min_length=1, max_length=22), + x_account_id: str = Header(...), + ): + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + obj_type = 'journal_entry' + result = delete_obj_template( + obj_type=obj_type, + obj_id=obj_id, + ) + return result \ No newline at end of file