Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apcd_cms/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ COPY /src/taccsite_cms /code/taccsite_cms

# install node 20.x
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get install -y nodejs
RUN apt-get install -y nodejs python3
RUN pip3 install httpx hvac

RUN chmod u+x /code/client/build_client.sh && /code/client/build_client.sh
RUN cp -R /code/client/dist/static/assets/. /code/taccsite_custom/apcd_cms/static/assets/
Expand Down
79 changes: 17 additions & 62 deletions apcd_cms/src/apps/admin_exception/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from apps.utils.utils import title_case, table_filter
from apps.components.paginator.paginator import paginator
from dateutil import parser
from apps.utils import apcd_api
from apps.base.base import BaseAPIView, APCDAdminAccessAPIMixin, APCDAdminAccessTemplateMixin
import logging
import json
Expand All @@ -18,9 +19,11 @@ class AdminExceptionsTable(APCDAdminAccessTemplateMixin, TemplateView):
class AdminExceptionsApi(APCDAdminAccessAPIMixin, BaseAPIView):

def get(self, *args, **kwargs):
exception_content = get_all_exceptions()
key = apcd_api.login('test_apcd_admin')
exceptions = apcd_api.sub_exc(key) # will be (request.user.apcd_api_key) or something like that

context = self.get_exception_list_json(exception_content, *args, **kwargs)

context = self.get_exception_list_json(exceptions)
return JsonResponse({'response': context})

def get_exception_list_json(self, exception_content, *args, **kwargs):
Expand All @@ -44,71 +47,28 @@ def get_exception_list_json(self, exception_content, *args, **kwargs):
org_filter = self.request.GET.get('org')
def _set_exception(exception):
return {
'exception_id': exception[0],
'submitter_id': exception[1],
'requestor_name': exception[2],
'request_type': title_case(exception[3]) if exception[3] else None, # to make sure if val doesn't exist, utils don't break page
'explanation_justification': exception[4],
'outcome': title_case(exception[5]) if exception[5] else 'None',
'outcome': title_case(exception[5]) if exception[5] else 'None',
'created_at': exception[6],
'updated_at': exception[7],
'submitter_code': exception[8],
'payor_code': exception[9],
'user_id': exception[10],
'requestor_email': exception[11],
'data_file': exception[12],
'field_number': exception[13],
'required_threshold': exception[14],
'requested_threshold': exception[15],
'requested_expiration_date': exception[16],
'approved_threshold': exception[17],
'approved_expiration_date': exception[18],
'status': title_case(exception[19]) if exception[19] else 'None',
'notes': exception[20],
'entity_name': exception[21],
'data_file_name': exception[22],
'view_modal_content': {
'exception_id': exception[0],
'created_at': exception[6],
'requestor_name': exception[2],
'requestor_email': exception[11],
'request_type': title_case(exception[3]) if exception[3] else None,
'status': title_case(exception[19]) if exception[3] else None,
'outcome': title_case(exception[5]) if exception[3] else None,
'data_file_name': exception[22],
'field_number': exception[13],
'required_threshold': exception[14],
'requested_threshold': exception[15],
'approved_threshold': exception[17],
'requested_expiration_date': exception[16],
'approved_expiration_date': exception[18],
'explanation_justification': exception[4],
'notes': exception[20],
'entity_name': exception[21],
'payor_code': exception[9],
'updated_at': exception[7],
}
**exception,
'view_modal_content': exception
}
def getDate(row):
date = row[6]
return date if date is not None else parser.parse('1-1-0001')

# sort exceptions by newest to oldest
exception_content = sorted(exception_content, key=lambda row:getDate(row), reverse=True)
#exception_content = sorted(exception_content, key=lambda row:getDate(row), reverse=True)

limit = 50
offset = limit * (page_num - 1)

exception_table_entries = []
for exception in exception_content:
for exception in exception_content['records']:
# to be used by paginator
exception_table_entries.append(_set_exception(exception))
# to be able to access any exception in a template using exceptions var in the future
context['exceptions'].append(_set_exception(exception))
entity_name = title_case(exception[21])
status = title_case(exception[19]) if exception[19] else 'None'
outcome = title_case(exception[5]) if exception[5] else 'None'
entity_name = title_case(exception["entity_name"])
status = title_case(exception["status"]) if exception["status"] else 'None'
outcome = title_case(exception["outcome"]) if exception["outcome"] else 'None'
if entity_name not in context['org_options']:
context['org_options'].append(entity_name)
# to make sure All is first in the dropdown filter options after sorting alphabetically
Expand All @@ -134,16 +94,11 @@ def getDate(row):
exception_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), exception_table_entries, 'entity_name')

context['query_str'] = queryStr
page_info = paginator(page_num, exception_table_entries, limit)
context['page'] = [{'entity_name': obj['entity_name'], 'payor_code': obj['payor_code'], 'created_at': obj['created_at'], 'request_type': obj['request_type'],
'requestor_name': obj['requestor_name'], 'outcome': obj['outcome'], 'status': obj['status'],
'approved_threshold': obj['approved_threshold'],'approved_expiration_date': obj['approved_expiration_date'],
'notes': obj['notes'], 'exception_id': obj['exception_id'], 'view_modal_content': obj['view_modal_content'],
'requested_threshold': obj['requested_threshold'],}
for obj in page_info['page']]

context['page_num'] = page_num
context['total_pages'] = page_info['page'].paginator.num_pages
#page_info = paginator(page_num, exception_table_entries, limit)
context['page'] = exception_table_entries

context['page_num'] = exception_content['current_page']
context['total_pages'] = exception_content['total_pages']

context['pagination_url_namespaces'] = 'admin_exception:list-exceptions'

Expand Down
83 changes: 16 additions & 67 deletions apcd_cms/src/apps/exception/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from apps.utils.utils import title_case, table_filter
from apps.components.paginator.paginator import paginator
from dateutil import parser
from apps.utils import apcd_api

logger = logging.getLogger(__name__)

Expand All @@ -22,16 +23,10 @@ class ExceptionFormApi(APCDGroupAccessAPIMixin, BaseAPIView):

def get(self, request):
if (request.user.is_authenticated and has_apcd_group(request.user)):
formatted_exception_data = []
submitter_codes = []
submitters = apcd_database.get_submitter_info(request.user.username)
submitter_codes = []

for submitter in submitters:
submitter_codes.append(submitter[1])
key = apcd_api.login(request.user.username)
exceptions = apcd_api.sub_exc(key) # will be (request.user.apcd_api_key) or something like that

formatted_exception_data = apcd_database.get_all_exceptions(submitter_codes=submitter_codes)
context = self.get_exception_list_json(formatted_exception_data)
context = self.get_exception_list_json(exceptions)
return JsonResponse({'response': context})
else:
return JsonResponse({'error': 'Unauthorized'}, status=403)
Expand All @@ -57,69 +52,28 @@ def get_exception_list_json(self, exception_content, *args, **kwargs):
org_filter = self.request.GET.get('org')
def _set_exception(exception):
return {
'exception_id': exception[0],
'submitter_id': exception[1],
'requestor_name': exception[2],
'request_type': title_case(exception[3]) if exception[3] else None, # to make sure if val doesn't exist, utils don't break page
'explanation_justification': exception[4],
'outcome': title_case(exception[5]) if exception[5] else 'None',
'outcome': title_case(exception[5]) if exception[5] else 'None',
'created_at': exception[6],
'updated_at': exception[7],
'submitter_code': exception[8],
'payor_code': exception[9],
'user_id': exception[10],
'requestor_email': exception[11],
'data_file': exception[12],
'field_number': exception[13],
'required_threshold': exception[14],
'requested_threshold': exception[15],
'requested_expiration_date': exception[16],
'approved_threshold': exception[17],
'approved_expiration_date': exception[18],
'status': title_case(exception[19]) if exception[19] else 'None',
'entity_name': exception[21],
'data_file_name': exception[22],
'view_modal_content': {
'exception_id': exception[0],
'created_at': exception[6],
'requestor_name': exception[2],
'requestor_email': exception[11],
'request_type': title_case(exception[3]) if exception[3] else None,
'status': title_case(exception[19]) if exception[3] else None,
'outcome': title_case(exception[5]) if exception[3] else None,
'data_file_name': exception[22],
'field_number': exception[13],
'required_threshold': exception[14],
'requested_threshold': exception[15],
'approved_threshold': exception[17],
'requested_expiration_date': exception[16],
'approved_expiration_date': exception[18],
'explanation_justification': exception[4],
'entity_name': exception[21],
'payor_code': exception[9],
'updated_at': exception[7],
}
**exception,
'view_modal_content': exception
}
def getDate(row):
date = row[6]
return date if date is not None else parser.parse('1-1-0001')

# sort exceptions by newest to oldest
exception_content = sorted(exception_content, key=lambda row:getDate(row), reverse=True)
#exception_content = sorted(exception_content, key=lambda row:getDate(row), reverse=True)

limit = 50
offset = limit * (page_num - 1)

exception_table_entries = []
for exception in exception_content:
for exception in exception_content['records']:
# to be used by paginator
exception_table_entries.append(_set_exception(exception))
# to be able to access any exception in a template using exceptions var in the future
context['exceptions'].append(_set_exception(exception))
entity_name = title_case(exception[21])
status = title_case(exception[19]) if exception[19] else 'None'
outcome = title_case(exception[5]) if exception[5] else 'None'
entity_name = title_case(exception["entity_name"])
status = title_case(exception["status"]) if exception["status"] else 'None'
outcome = title_case(exception["outcome"]) if exception["outcome"] else 'None'
if entity_name not in context['org_options']:
context['org_options'].append(entity_name)
# to make sure All is first in the dropdown filter options after sorting alphabetically
Expand All @@ -145,16 +99,11 @@ def getDate(row):
exception_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), exception_table_entries, 'entity_name')

context['query_str'] = queryStr
page_info = paginator(page_num, exception_table_entries, limit)
context['page'] = [{'entity_name': obj['entity_name'], 'payor_code': obj['payor_code'], 'created_at': obj['created_at'], 'request_type': obj['request_type'],
'requestor_name': obj['requestor_name'], 'outcome': obj['outcome'], 'status': obj['status'],
'approved_threshold': obj['approved_threshold'],'approved_expiration_date': obj['approved_expiration_date'],
'exception_id': obj['exception_id'], 'view_modal_content': obj['view_modal_content'],
'requested_threshold': obj['requested_threshold'],}
for obj in page_info['page']]

context['page_num'] = page_num
context['total_pages'] = page_info['page'].paginator.num_pages
#page_info = paginator(page_num, exception_table_entries, limit)
context['page'] = exception_table_entries

context['page_num'] = exception_content['current_page']
context['total_pages'] = exception_content['total_pages']

context['pagination_url_namespaces'] = 'exception:exception-list'

Expand Down
6 changes: 5 additions & 1 deletion apcd_cms/src/apps/extension/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from apps.utils.utils import table_filter
from apps.utils.utils import title_case
from apps.components.paginator.paginator import paginator
from apps.utils import testing_api_connection

logger = logging.getLogger(__name__)

Expand All @@ -24,9 +25,12 @@ class ExtensionFormApi(APCDGroupAccessAPIMixin, BaseAPIView):

def get(self, request):
if (request.user.is_authenticated and has_apcd_group(request.user)):
print("Testing API connection")
test_out = testing_api_connection.main()
print(test_out)
formatted_extension_data = []
submitter_codes = []
# submitter_id = request.GET.get('s_id', None)
#submitter_id = request.GET.get('s_id', None)
submitters = apcd_database.get_submitter_info(request.user.username)
submitter_codes = []

Expand Down
88 changes: 88 additions & 0 deletions apcd_cms/src/apps/utils/apcd_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import os

import httpx
import hvac
from django.conf import settings


VAULT_URL = 'https://vault.txapcd.org'
VAULT_ROLE = getattr(settings, 'VAULT_ROLE', '')
VAULT_SECRET = getattr(settings, 'VAULT_SECRET', '')
API_URL = 'https://apcd-etl-dev.txapcd.org'
API_USER = 'gedmonds'


def get_api_key_from_vault() -> str:
"""Get the API key from HashiCorp Vault."""
vault = hvac.Client(url=VAULT_URL)
vault.auth.approle.login(role_id=VAULT_ROLE, secret_id=VAULT_SECRET, use_token=True)
vault_secret = vault.secrets.kv.v2.read_secret(path='keys/api-key', mount_point='apcd')
print('api key:',vault_secret['data']['data']['api-key'])
return vault_secret['data']['data']['api-key']


def login(username: str) -> None:
API_KEY = get_api_key_from_vault()
"""Login and return api access token."""
login_data = {'username': username, 'password': API_KEY}
response = api_client(url='/auth/access-token', method='post', data=login_data)
print('\nPOST request status:', response.status_code)
response.raise_for_status()
token_response = response.json()
print('Created resource:', token_response)
return token_response['access_token']


def ping(client: httpx.Client) -> None:
"""Ping the API to check connectivity."""
response = client.get('')
print('\nGET /root request status:', response.status_code)
response.raise_for_status()
print('Ping Response:', response.json())


def status(client: httpx.Client) -> None:
"""Check API status."""
response = client.get('/status')
print('\nGET /status request status:', response.status_code)
response.raise_for_status()
print('API Status:', response.json())

def me(client: httpx.Client) -> None:
"""Get current user information."""
response = client.get('/users/me')
print('\nGET /users/me request status:', response.status_code)
response.raise_for_status()
print('Current User Info:', response.json())


def sub_exc(token: str) -> None:
"""Get submitter exceptions information."""
response = api_client(url='/submitter-exceptions/paged_view?page=1&per_page=50', method='get', token=token)
print('\nGET /submitter-exceptions request status:', response.status_code)
response.raise_for_status()
print('Submitter Exceptions Data:', response.json())
return response.json()


def api_client(url: str, method: str, data: object = None, token: str = None) -> None:
response = {}
try:
with httpx.Client(timeout=5.0, base_url=API_URL) as client:
if not 'auth' in url:
client.headers.update({'Authorization': f'Bearer {token}'})
if method == 'get':
response = client.get(url)
if method == 'post':
response = client.post(url, data=data)
except httpx.RequestError as exc:
print(f'An error occurred while requesting {exc.request.url!r}: {exc}')
response = exc.response
except httpx.HTTPStatusError as exc:
print(f'Error response {exc.response.status_code} while requesting {exc.request.url!r}')
response = exc.response
return response


if __name__ == '__main__':
main()
Loading