Skip to content

Commit 1715201

Browse files
authored
Merge pull request #1983 from GSA/main
09/19/2025 Production Deploy
2 parents 3c9fdf1 + f07eb8f commit 1715201

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1833
-2443
lines changed

.ds.baseline

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
"filename": "app/enums.py",
170170
"hashed_secret": "12322e07b94ee3c7cd65a2952ece441538b53eb3",
171171
"is_verified": false,
172-
"line_number": 123,
172+
"line_number": 129,
173173
"is_secret": false
174174
}
175175
],
@@ -295,7 +295,7 @@
295295
"filename": "tests/app/service/test_rest.py",
296296
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
297297
"is_verified": false,
298-
"line_number": 1288,
298+
"line_number": 1290,
299299
"is_secret": false
300300
}
301301
],
@@ -339,7 +339,7 @@
339339
"filename": "tests/app/user/test_rest.py",
340340
"hashed_secret": "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33",
341341
"is_verified": false,
342-
"line_number": 874,
342+
"line_number": 875,
343343
"is_secret": false
344344
}
345345
],
@@ -374,5 +374,5 @@
374374
}
375375
]
376376
},
377-
"generated_at": "2025-08-12T18:08:49Z"
377+
"generated_at": "2025-09-11T16:22:46Z"
378378
}

.github/actions/setup-project/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ runs:
99
sudo apt-get update \
1010
&& sudo apt-get install -y --no-install-recommends \
1111
libcurl4-openssl-dev
12-
- name: Set up Python 3.12.9
12+
- name: Set up Python 3.13.2
1313
uses: actions/setup-python@v4
1414
with:
15-
python-version: "3.12.9"
15+
python-version: "3.13.2"
1616
- name: Install poetry
1717
shell: bash
1818
run: pip install poetry==2.1.3

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ updates:
1313
- "dependabot" # Custom label to identify Dependabot PRs
1414
assignees:
1515
- "alexjanousekGSA"
16+
ignore:
17+
# gevent 25.8+ breaks Celery/Kombu compatibility (potentially)
18+
- dependency-name: "gevent"
19+
versions: [">=25.8.0"]

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ You will need the following items:
3939
This project currently works with these major versions of the following main
4040
components:
4141

42-
- Python 3.12.x
42+
- Python 3.13.x
4343
- PostgreSQL 15.x (version 12.x is used in the hosted environments)
4444

4545
These instructions will walk you through how to set your machine up with all of
@@ -178,12 +178,12 @@ session to make the changes take effect.
178178
Now we're ready to install the Python version we need with `pyenv`, like so:
179179

180180
```sh
181-
pyenv install 3.12
181+
pyenv install 3.13
182182
```
183183

184-
This will install the latest version of Python 3.12.
184+
This will install the latest version of Python 3.13.
185185

186-
_NOTE: This project currently runs on Python 3.12.x._
186+
_NOTE: This project currently runs on Python 3.13.x._
187187

188188
#### Python Dependency Installation
189189

@@ -264,12 +264,12 @@ git clone [email protected]:GSA/notifications-api.git
264264

265265
Now go into the project directory (`notifications-api` by default), create a
266266
virtual environment, and set the local Python version to point to the virtual
267-
environment (assumes version Python `3.12.9` is what is installed on your
267+
environment (assumes version Python `3.13.2` is what is installed on your
268268
machine):
269269

270270
```sh
271271
cd notifications-api
272-
pyenv virtualenv 3.12.9 notify-api
272+
pyenv virtualenv 3.13.2 notify-api
273273
pyenv local notify-api
274274
```
275275

@@ -317,10 +317,10 @@ If you're upgrading an existing project to a newer version of Python, you can
317317
follow these steps to get yourself up-to-date.
318318

319319
First, use `pyenv` to install the newer version of Python you'd like to use;
320-
we'll use `3.12` in our example here since we recently upgraded to this version:
320+
we'll use `3.13` in our example here since we recently upgraded to this version:
321321

322322
```sh
323-
pyenv install 3.12
323+
pyenv install 3.13
324324
```
325325

326326
Next, delete the virtual environment you previously had set up. If you followed
@@ -335,7 +335,7 @@ environment with the newer version of Python you just installed:
335335

336336
```sh
337337
cd notifications-api
338-
pyenv virtualenv 3.12.9 notify-api
338+
pyenv virtualenv 3.13.2 notify-api
339339
pyenv local notify-api
340340
```
341341

app/aws/s3.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,11 @@ def get_job_from_s3(service_id, job_id):
476476
def extract_phones(job, service_id, job_id):
477477
job_csv_data = StringIO(job)
478478
csv_reader = csv.reader(job_csv_data)
479-
first_row = next(csv_reader)
479+
try:
480+
first_row = next(csv_reader)
481+
except StopIteration:
482+
current_app.logger.warning(f"Empty CSV file for job {job_id} in service {service_id}")
483+
return {}
480484

481485
phone_index = 0
482486
for i, item in enumerate(first_row):
@@ -506,9 +510,18 @@ def extract_phones(job, service_id, job_id):
506510

507511

508512
def extract_personalisation(job):
513+
if job is None:
514+
current_app.logger.warning("No job data provided for personalisation extraction")
515+
return {}
509516
if isinstance(job, dict):
510517
job = job[0]
518+
if not job:
519+
current_app.logger.warning("Empty job data for personalisation extraction")
520+
return {}
511521
job = job.split("\r\n")
522+
if not job or not job[0]:
523+
current_app.logger.warning("Empty job data after split for personalisation extraction")
524+
return {}
512525
first_row = job[0]
513526
job.pop(0)
514527
first_row = first_row.split(",")
@@ -647,7 +660,7 @@ def s3upload(
647660
metadata = put_args["Metadata"] = metadata
648661

649662
try:
650-
current_app.logger.info(hilite(f"Going to try to upload this {key}"))
663+
current_app.logger.debug(hilite(f"Going to try to upload this {key}"))
651664
key.put(**put_args)
652665
except botocore.exceptions.NoCredentialsError as e:
653666
current_app.logger.exception(

app/celery/research_mode_tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def make_request(notification_type, provider, data, headers):
5151
)
5252
raise e
5353
finally:
54-
current_app.logger.info("Mocked provider callback request finished")
54+
current_app.logger.debug("Mocked provider callback request finished")
5555
return response.json()
5656

5757

app/celery/scheduled_tasks.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,6 @@ def cleanup_delivery_receipts(self):
304304
def batch_insert_notifications(self):
305305
batch = []
306306

307-
# TODO We probably need some way to clear the list if
308-
# things go haywire. A command?
309-
310-
# with redis_store.pipeline():
311-
# while redis_store.llen("message_queue") > 0:
312-
# redis_store.lpop("message_queue")
313-
# current_app.logger.info("EMPTY!")
314-
# return
315307
current_len = redis_store.llen("message_queue")
316308
with redis_store.pipeline():
317309
# since this list is being fed by other processes, just grab what is available when

app/celery/test_key_tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def make_request(notification_type, provider, data, headers):
5151
)
5252
raise e
5353
finally:
54-
current_app.logger.info("Mocked provider callback request finished")
54+
current_app.logger.debug("Mocked provider callback request finished")
5555
return response.json()
5656

5757

app/commands.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def insert_inbound_numbers_from_file(file_name):
183183
for line in file:
184184
line = line.strip()
185185
if line:
186-
current_app.logger.info(line)
186+
current_app.logger.debug(line)
187187
db.session.execute(sql, {"uuid": str(uuid.uuid4()), "line": line})
188188
db.session.commit()
189189

@@ -228,7 +228,6 @@ def bulk_invite_user_to_service(file_name, service_id, user_id, auth_type, permi
228228
# "send_texts,send_emails,view_activity"
229229
from app.service_invite.rest import create_invited_user
230230

231-
current_app.logger.info("ENTER")
232231
file = open(file_name)
233232
for email_address in file:
234233
data = {
@@ -239,7 +238,6 @@ def bulk_invite_user_to_service(file_name, service_id, user_id, auth_type, permi
239238
"auth_type": auth_type,
240239
"invite_link_host": current_app.config["ADMIN_BASE_URL"],
241240
}
242-
current_app.logger.info(f"DATA = {data}")
243241
with current_app.test_request_context(
244242
path=f"/service/{service_id}/invite/",
245243
method="POST",
@@ -248,12 +246,12 @@ def bulk_invite_user_to_service(file_name, service_id, user_id, auth_type, permi
248246
):
249247
try:
250248
response = create_invited_user(service_id)
251-
current_app.logger.info(f"RESPONSE {response[1]}")
249+
current_app.logger.debug(f"RESPONSE {response[1]}")
252250
if response[1] != 201:
253251
current_app.logger.warning(
254252
f"*** ERROR occurred for email address: {email_address.strip()}"
255253
)
256-
current_app.logger.info(response[0].get_data(as_text=True))
254+
current_app.logger.debug(response[0].get_data(as_text=True))
257255
except Exception:
258256
current_app.logger.exception(
259257
f"*** ERROR occurred for email address: {email_address.strip()}.",
@@ -337,7 +335,6 @@ def boolean_or_none(field):
337335

338336
for line in itertools.islice(f, 1, None):
339337
columns = line.split("|")
340-
current_app.logger.info(columns)
341338
email_branding = None
342339
email_branding_column = columns[5].strip()
343340
if len(email_branding_column) > 0:
@@ -439,20 +436,19 @@ def populate_go_live(file_name):
439436
# 6- Contact detail, 7-MOU, 8- LIVE date, 9- SMS, 10 - Email, 11 - Letters, 12 -CRM, 13 - Blue badge
440437
import csv
441438

442-
current_app.logger.info("Populate go live user and date")
443439
with open(file_name, "r") as f:
444440
rows = csv.reader(
445441
f,
446442
quoting=csv.QUOTE_MINIMAL,
447443
skipinitialspace=True,
448444
)
449-
current_app.logger.info(next(rows)) # ignore header row
445+
current_app.logger.debug(next(rows)) # ignore header row
450446
for index, row in enumerate(rows):
451-
current_app.logger.info(index, row)
447+
current_app.logger.debug(index, row)
452448
service_id = row[2]
453449
go_live_email = row[6]
454450
go_live_date = datetime.strptime(row[8], "%d/%m/%Y") + timedelta(hours=12)
455-
current_app.logger.info(service_id, go_live_email, go_live_date)
451+
current_app.logger.debug(service_id, go_live_email, go_live_date)
456452
try:
457453
if go_live_email:
458454
go_live_user = get_user_by_email(go_live_email)
@@ -506,13 +502,11 @@ def fix_billable_units():
506502
)
507503
db.session.execute(stmt)
508504
db.session.commit()
509-
current_app.logger.info("End fix_billable_units")
510505

511506

512507
@notify_command(name="delete-unfinished-jobs")
513508
def delete_unfinished_jobs():
514509
cleanup_unfinished_jobs()
515-
current_app.logger.info("End cleanup_unfinished_jobs")
516510

517511

518512
@notify_command(name="process-row-from-job")
@@ -618,7 +612,7 @@ def dump_user_info(user_email_address):
618612
with open("user_download.json", "wb") as f:
619613
f.write(json.dumps(content).encode("utf8"))
620614
f.close()
621-
current_app.logger.info("Successfully downloaded user info to user_download.json")
615+
current_app.logger.debug("Successfully downloaded user info to user_download.json")
622616

623617

624618
@notify_command(name="populate-annual-billing-with-defaults")

app/dao/organization_dao.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from app import db
55
from app.dao.dao_utils import VersionOptions, autocommit, version_class
6+
from app.enums import UserState
67
from app.models import Domain, Organization, Service, User
78

89

@@ -125,7 +126,7 @@ def dao_get_users_for_organization(organization_id):
125126
return (
126127
db.session.query(User)
127128
.join(User.organizations)
128-
.where(Organization.id == organization_id, User.state == "active")
129+
.where(Organization.id == organization_id, User.state == UserState.ACTIVE)
129130
.order_by(User.created_at)
130131
.all()
131132
)

0 commit comments

Comments
 (0)