Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 5/3/2024 #335

Merged
merged 47 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c6c55d5
move calculators to state folders
CalebPena Apr 10, 2024
bab377d
change the default Medicaid values
CalebPena Apr 10, 2024
bfec5a6
Fix merge confilcts
CalebPena Apr 16, 2024
69d43ab
update dependencies
CalebPena Apr 17, 2024
1fec8a9
add emergency rental assistance program
CalebPena Apr 17, 2024
3f03367
Merge pull request #327 from Gary-Community-Ventures/feat/emergency_r…
CalebPena Apr 17, 2024
45e5da9
email users their results link when they sign up.
CalebPena Apr 23, 2024
fae4b54
Merge branch 'dev' into refactor/nc_calculators
CalebPena Apr 24, 2024
d07205a
Merge pull request #318 from Gary-Community-Ventures/refactor/nc_calc…
CalebPena Apr 24, 2024
663784c
refactor emailing
CalebPena Apr 24, 2024
89056af
Add ForeclosureFinAssistProgram to urgent_need_functions
ivonne-hernandez Apr 24, 2024
d37ad4f
Add ffap property to need_functions
ivonne-hernandez Apr 24, 2024
b6eaffc
remove old cell and email functions
CalebPena Apr 24, 2024
f85a64e
Add double quotes
ivonne-hernandez Apr 24, 2024
9395eab
Remove double quotes
ivonne-hernandez Apr 24, 2024
103c222
Removing duplicate "emergency medicaid" program
andrewshaodev Apr 25, 2024
bb55c08
Merge pull request #338 from Gary-Community-Ventures/feat/ffap-urgent…
CalebPena Apr 26, 2024
5c8c9fd
use the new message class to send emails/text messages
CalebPena Apr 29, 2024
7855769
dont sent emails for tests
CalebPena Apr 29, 2024
39ad40b
update MessageUser imports
CalebPena Apr 29, 2024
48dfd37
dont prefetch cache on startup
CalebPena Apr 30, 2024
e0b8c39
refactor google sheets
CalebPena Apr 30, 2024
2a8da19
use new sheets cache for cccap
CalebPena Apr 30, 2024
ed5e44c
use new sheets cache for leap
CalebPena Apr 30, 2024
976666b
use new sheets cache for connect for health
CalebPena Apr 30, 2024
23f8e56
remove duplicate emergency rental assistance
CalebPena Apr 30, 2024
373a5e6
use updated cache for emergency_rental_assistance
CalebPena Apr 30, 2024
f5f43fe
use updated cache for rental assistance grant
CalebPena Apr 30, 2024
3cf3580
use updated cache for urgent need functions
CalebPena Apr 30, 2024
8d35c0c
use the column headers with leap
CalebPena Apr 30, 2024
aa6d621
fix imports
CalebPena Apr 30, 2024
8dc067c
Merge pull request #340 from Gary-Community-Ventures/feat/automatical…
CalebPena Apr 30, 2024
0e402bb
Add ChildFirst function and property
ivonne-hernandez May 1, 2024
a73e94c
Empty Commit
ivonne-hernandez May 1, 2024
884a182
update myspark age ranges
CalebPena May 1, 2024
18f3038
rerun gh actions
CalebPena May 1, 2024
65dd665
Merge pull request #345 from Gary-Community-Ventures/feat/child-first…
CalebPena May 1, 2024
68b05f1
update medicare savings income and asset limits
CalebPena May 1, 2024
1a372c8
Merge pull request #348 from Gary-Community-Ventures/update/myspark
CalebPena May 1, 2024
5975c68
Merge pull request #349 from Gary-Community-Ventures/update/medicare_…
CalebPena May 1, 2024
49765a7
Merge pull request #339 from andrewshaodev/patch-1
CalebPena May 1, 2024
cb87bfb
fix bug where cccap value could be 0
CalebPena May 1, 2024
ce13ae6
Merge pull request #350 from Gary-Community-Ventures/bug/cccap_0_value
ivonne-hernandez May 3, 2024
8d80f5a
Update integrations/services/sheets/sheets.py
CalebPena May 3, 2024
41a983e
Update integrations/services/sheets/sheets.py
CalebPena May 3, 2024
cdaf0d7
Merge pull request #344 from Gary-Community-Ventures/refactor/google_…
CalebPena May 3, 2024
52459f3
fix rag cache
CalebPena May 3, 2024
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
8 changes: 8 additions & 0 deletions authentication/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from authentication.models import User
from integrations.services.communications import MessageUser
from screener.models import Screen
from rest_framework import viewsets, permissions, mixins
from rest_framework.response import Response
Expand Down Expand Up @@ -34,6 +35,12 @@ def update(self, request, pk=None):
if user and user.external_id and not screen.is_test_data and not settings.DEBUG:
update_send_offers_hubspot(user.external_id, user.send_offers, user.send_updates)
else:
message = MessageUser(screen, screen.get_language_code())
if screen.user.email is not None:
message.email(screen.user.email)
if screen.user.cell is not None:
message.text(str(screen.user.cell))

try:
upsert_user_to_hubspot(screen, screen.user)
except Exception:
Expand Down Expand Up @@ -68,3 +75,4 @@ def upsert_user_to_hubspot(screen, user):
user.save()
else:
raise Exception('Failed to upsert user')

4 changes: 2 additions & 2 deletions integrations/services/communications/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .email import email_link
from .cell import text_link
from .message import MessageUser

20 changes: 0 additions & 20 deletions integrations/services/communications/cell.py

This file was deleted.

23 changes: 0 additions & 23 deletions integrations/services/communications/email.py

This file was deleted.

95 changes: 95 additions & 0 deletions integrations/services/communications/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from typing import Literal
from translations.models import Translation
from screener.models import Message, Screen
import sendgrid
from sendgrid.helpers.mail import Mail, Email, To, Content
from decouple import config
from django.conf import settings
from twilio.rest import Client
from django.utils import timezone


class MessageUser:
front_end_domain = config("FRONTEND_DOMAIN")

cell_account_sid = config("TWILIO_SID")
cell_auth_token = config("TWILIO_TOKEN")
cell_from_phone_number = config("TWILIO_PHONE_NUMBER")

email_from = '[email protected]'
email_api_key = config('SENDGRID')

def __init__(self, screen: Screen, lang: str) -> None:
self.screen = screen
self.lang = lang

def should_send(self) -> bool:
if settings.DEBUG:
return False

if self.screen.is_test_data:
return False

return True

def email(self, email: str, send_tests=False):
if not self.should_send() and not send_tests:
return

sg = self._email_client()
from_email = Email(self.email_from) # Change to your verified sender
to_email = To(email) # Change to your recipient
subject = self._email_subject()
content = Content("text/html", self._email_body())
mail = Mail(from_email, to_email, subject, content)

sg.client.mail.send.post(request_body=mail.get())

self.log('emailScreen')

def _email_client(self):
return sendgrid.SendGridAPIClient(api_key=self.email_api_key)

def _email_subject(self):
return Translation.objects.get(label='sendResults.email-subject').get_lang(self.lang).text

def _email_body(self):
words = Translation.objects.get(label='sendResults.email').get_lang(self.lang).text
url = self._generate_link()

return words + f' <a href="{url}">{url}</a>'

def text(self, cell: str, send_tests=False):
if not self.should_send() and not send_tests:
return

self._cell_client().messages.create(
from_=self.cell_from_phone_number,
body=self._text_body(),
to=cell,
)

self.log('textScreen')

def _text_body(self):
words = Translation.objects.get(label='sendResults.email').get_lang(self.lang).text
url = self._generate_link()

return f'{words} {url}'

def _cell_client(self):
return Client(self.cell_account_sid, self.cell_auth_token)


def _generate_link(self):
return f"{self.front_end_domain}/{self.screen.uuid}/results"

def log(self, type: Literal['emailScreen', 'textScreen']):
self.screen.last_email_request_date = timezone.now()
self.screen.save()

Message.objects.create(
type=type,
screen=self.screen,
)

1 change: 1 addition & 0 deletions integrations/services/sheets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .sheets import GoogleSheets, GoogleSheetsCache
98 changes: 98 additions & 0 deletions integrations/services/sheets/sheets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from decouple import config
from googleapiclient.discovery import build
from google.oauth2 import service_account
import json
from integrations.util.cache import Cache


class GoogleSheets:
info = json.loads(config('GOOGLE_APPLICATION_CREDENTIALS'))
creds = service_account.Credentials.from_service_account_info(info)
service = build('sheets', 'v4', credentials=creds)
sheet = service.spreadsheets()

class ColumnDoesNotExist(Exception):
pass

def __init__(self, spreadsheet_id: str, cell_range: str) -> None:
self.spreadsheet_id = spreadsheet_id
self.cell_range = cell_range

def data(self) -> list[list[any]]:
'''
return a list of rows in the cell range
'''
result = self.sheet.values().get(
spreadsheetId=self.spreadsheet_id, range=self.cell_range
).execute()
values = result.get('values', [])

return values

def data_by_column(self, *column_names: str) -> list[dict[str, any]]:
'''
return an array of dictionaries containing the column names and their values
'''
data = self.data()

raw_column_names = data[0]

remaining_rows = data[1:]

needed_columns = {}
for i, name in enumerate(raw_column_names):
if name in column_names:
needed_columns[i] = name

if len(needed_columns) != len(column_names):
self._raise_missing_columns(column_names, needed_columns.values())

organized_data = []
for row in remaining_rows:
row_data = {}
for i, value in enumerate(row):
if i not in needed_columns:
continue

row_data[needed_columns[i]] = value

organized_data.append(row_data)

return organized_data

def print_raw_column_names(self):
'''
print the column names of the spreadsheet

WARN: this should only be used during development
'''
raw_column_names = self.data()[0]

for name in raw_column_names:
print(repr(name))

def _raise_missing_columns(self, needed_columns: list[str], existing_columns: list[str]):
'''
raise an exception with the column names from needed_columns that are not in existing_columns
'''
missing_columns = []

for column in needed_columns:
if column not in existing_columns:
missing_columns.append(column)

raise self.ColumnDoesNotExist(f"The following column headers are missing: {missing_columns}")


class GoogleSheetsCache(Cache):
expire_time = 60 * 60 * 24
default = []

sheet_id = ''
range_name = ''

def update(self):
sheet_values = GoogleSheets(self.sheet_id, self.range_name).data()

return sheet_values

9 changes: 2 additions & 7 deletions integrations/util/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,8 @@ class Cache():
default = 0

def __init__(self):
try:
self.data = self.update()
self.last_update = datetime.datetime.now()
except Exception:
self.data = self.default
self.last_update = datetime.datetime.now() - datetime.timedelta(seconds=self.expire_time)
capture_message(f'Failed to update {self.__class__.__name__}', level='warning')
self.data = self.default
self.last_update = datetime.datetime.now() - datetime.timedelta(seconds=self.expire_time)

def update(self):
raise NotImplementedError()
Expand Down
1 change: 0 additions & 1 deletion programs/management/commands/quick_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ class Command(BaseCommand):
{'abbr': 'ssi', 'external': 'ssi'},
{'abbr': 'trua', 'external': 'trua'},
{'abbr': 'rhc', 'external': 'rhc'},
{'abbr': 'emergency_medicaid', 'external': 'emergency_medicaid'},
{'abbr': 'wic', 'external': 'wic'},
{'abbr': 'omnisalud', 'external': 'omnisalud'},
{'abbr': 'dpp', 'external': 'dpp'},
Expand Down
64 changes: 4 additions & 60 deletions programs/programs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,8 @@
from .rtdlive.calculator import RtdLive
from .child_care_assistance.calculator import ChildCareAssistance
from .mydenver.calculator import MyDenver
from .cash_back.calculator import CashBack
from .energy_assistance.calculator import EnergyAssistance
from .energy_resource_center.calculator import EnergyResourceCenter
from .omnisalud.calculator import OmniSalud
from .dental_health_care_seniors.calculator import DentalHealthCareSeniors
from .reproductive_health_care.calculator import ReproductiveHealthCare
from .connect_for_health.calculator import ConnectForHealth
from .medicaid.family_planning_services.calculator import FamilyPlanningServices
from .denver_preschool_program.calculator import DenverPreschoolProgram
from .head_start.calculator import HeadStart
from .every_day_eats.calculator import EveryDayEats
from .property_credit_rebate.calculator import PropertyCreditRebate
from .universal_preschool.calculator import UniversalPreschool
from .my_spark.calculator import MySpark
from .ssdi.calculator import Ssdi
from .low_wage_covid_relief.calculator import LowWageCovidRelief
from .medicaid.child_with_disability.calculator import MedicaidChildWithDisability
from .medicaid.adult_with_disability.calculator import MedicaidAdultWithDisability
from .medicaid.emergency.calculator import EmergencyMedicaid
from .medicare_savings.calculator import MedicareSavings
from .basic_cash_assistance.calculator import BasicCashAssistance
from .weatherization_assistance.calculator import WeatherizationAssistance
from .tabor.calculator import Tabor
from .trua.calculator import Trua
from .utility_bill_pay.calculator import UtilityBillPay
from .co import co_calculators
from .federal import federal_calculators
from .calc import ProgramCalculator
from .rental_assistance_grant.calculator import RentalAssistanceGrant
from .emergency_rental_assistance.calculator import EmergencyRentalAssistance

calculators: dict[str, type[ProgramCalculator]] = {
'rtdlive': RtdLive,
'cccap': ChildCareAssistance,
'mydenver': MyDenver,
'cocb': CashBack,
'leap': EnergyAssistance,
'erc': EnergyResourceCenter,
'omnisalud': OmniSalud,
'cdhcs': DentalHealthCareSeniors,
'rhc': ReproductiveHealthCare,
'cfhc': ConnectForHealth,
'fps': FamilyPlanningServices,
'chs': HeadStart,
'dpp': DenverPreschoolProgram,
'ede': EveryDayEats,
'cpcr': PropertyCreditRebate,
'upk': UniversalPreschool,
'myspark': MySpark,
'ssdi': Ssdi,
'lwcr': LowWageCovidRelief,
'cwd_medicaid': MedicaidChildWithDisability,
'awd_medicaid': MedicaidAdultWithDisability,
'emergency_medicaid': EmergencyMedicaid,
'medicare_savings': MedicareSavings,
'bca': BasicCashAssistance,
'cowap': WeatherizationAssistance,
'tabor': Tabor,
'trua': Trua,
'ubp': UtilityBillPay,
'rag': RentalAssistanceGrant,
'erap': EmergencyRentalAssistance,
**co_calculators,
**federal_calculators
}
Loading