Skip to content

Commit

Permalink
Merge pull request #1364 from GSA/main
Browse files Browse the repository at this point in the history
Admin Production Deploy - 3/28/2024
  • Loading branch information
stvnrlly authored Apr 3, 2024
2 parents c2d1524 + e572d78 commit 5cee174
Show file tree
Hide file tree
Showing 49 changed files with 1,147 additions and 950 deletions.
6 changes: 3 additions & 3 deletions .github/actions/setup-project/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ runs:
sudo apt-get update \
&& sudo apt-get install -y --no-install-recommends \
libcurl4-openssl-dev
- name: Set up Python 3.9
uses: actions/setup-python@v3
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: "3.9"
python-version: "3.12"
- name: Install poetry
shell: bash
run: pip install poetry
Expand Down
91 changes: 39 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,12 @@ session to make the changes take effect.
Now we're ready to install the Python version we need with `pyenv`, like so:

```sh
pyenv install 3.9
pyenv install 3.12
```

This will install the latest version of Python 3.9.
This will install the latest version of Python 3.12.

_NOTE: This project currently runs on Python 3.9.x._
_NOTE: This project currently runs on Python 3.12.x._

#### [API Step] Python Dependency Installation

Expand Down Expand Up @@ -234,20 +234,20 @@ Once all of pre-requisites for the project are installed and you have a
cloud.gov account, you can now set up the admin project and get things running
locally!

First, clone the respository in the directory of your choosing on your machine:
First, clone the repository in the directory of your choosing on your machine:

```sh
git clone [email protected]:GSA/notifications-admin.git
```

Now go into the project directory (`notifications-admin` by default), create a
virtual environment, and set the local Python version to point to the virtual
environment (assumes version Python `3.9.18` is what is installed on your
environment (assumes version Python `3.12.2` is what is installed on your
machine):

```sh
cd notifications-admin
pyenv virtualenv 3.9.18 notify-admin
pyenv virtualenv 3.12.2 notify-admin
pyenv local notify-admin
```

Expand All @@ -274,6 +274,39 @@ In addition to some infrastructure setup, this will also create a local `.env`
file for you in the project's root directory, which will include a handful of
project-specific environment variables.

#### Upgrading Python in existing projects

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

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

```sh
pyenv install 3.12
```

Next, delete the virtual environment you previously had set up. If you followed
the instructions above with the first-time set up, you can do this with `pyenv`:

```sh
pyenv virtualenv-delete notify-admin
```

Now, make sure you are in your project directory and recreate the same virtual
environment with the newer version of Python you just installed:

```sh
cd notifications-admin
pyenv virtualenv 3.12.2 notify-admin
pyenv local notify-admin
```

At this point, proceed with the rest of the instructions here in the README and
you'll be set with an upgraded version of Python.

_If you're not sure about the details of your current virtual environment, you can run `poetry env info` to get more information. If you've been using `pyenv` for everything, you can also see all available virtual environments with `pyenv virtualenvs`._

#### Updating the .env file for E2E tests

With the newly created `.env` file in place, you'll need to make one more
Expand Down Expand Up @@ -380,52 +413,6 @@ You can do this by going through these steps:
- Make a new PR with the change
- Have the PR get reviewed and merged

### Python dependency management

We're using [`Poetry`](https://python-poetry.org/) for managing our Python
dependencies and local virtual environments. When it comes to managing the
Python dependencies, there are a couple of things to bear in mind.

For situations where you manually manipulate the `pyproject.toml` file, you
should use the `make py-lock` command to sync the `poetry.lock` file. This will
ensure that you don't inadvertently bring in other transitive dependency updates
that have not been fully tested with the project yet.

If you're just trying to update a dependency to a newer (or the latest) version,
you should let Poetry take care of that for you by running the following:

```sh
poetry update <dependency> [<dependency>...]
```

You can specify more than one dependency together. With this command, Poetry
will do the following for you:

- Find the latest compatible version(s) of the specified dependency/dependencies
- Install the new versions
- Update and sync the `poetry.lock` file

In either situation, once you are finished and have verified the dependency
changes are working, please be sure to commit both the `pyproject.toml` and
`poetry.lock` files.

### Keeping the notification-utils dependency up-to-date

The `notifications-utils` dependency references the other repository we have at
https://github.com/GSA/notifications-utils - this dependency requires a bit of
extra legwork to ensure it stays up-to-date.

Whenever a PR is merged in the `notifications-utils` repository, we need to make
sure the changes are pulled in here and committed to this repository as well.
You can do this by going through these steps:

- Make sure your local `main` branch is up-to-date
- Create a new branch to work in
- Run `make update-utils`
- Commit the updated `poetry.lock` file and push the changes
- Make a new PR with the change
- Have the PR get reviewed and merged

## Known Installation Issues

### Python Installation Errors
Expand Down
6 changes: 2 additions & 4 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@
format_datetime_human,
format_datetime_normal,
format_datetime_relative,
format_datetime_short,
format_datetime_short_america,
format_datetime_table,
format_day_of_week,
format_delta,
format_delta_days,
Expand Down Expand Up @@ -552,8 +551,7 @@ def add_template_filters(application):
format_datetime,
format_datetime_24h,
format_datetime_normal,
format_datetime_short,
format_datetime_short_america,
format_datetime_table,
valid_phone_number,
linkable_name,
format_date,
Expand Down
8 changes: 8 additions & 0 deletions app/assets/sass/uswds/_legacy-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@
margin: -20px units(1) 20px units(1);
}

h2.sms-message-header {
margin-bottom: 0.5rem;
}

h2.recipient-list {
margin-bottom: 0.5rem;
}

.sms-message-status-outbound {
text-align: right;
}
Expand Down
45 changes: 26 additions & 19 deletions app/assets/sass/uswds/_uswds-theme-custom-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -168,26 +168,33 @@ td.table-empty-message {
flex-wrap: wrap;
justify-content: space-between;
padding: 1rem;
.user-list-item {
@include at-media(desktop) {
width: calc(50% - units(1));
margin-bottom: 1rem;
box-sizing: border-box;
}
// flex: 1 1 calc(100% - units(2));
border: 1px solid color('gray-cool-10');
padding: units(2);
.tick-cross-list-permissions {
margin: units(1) 0;
padding-left: units(2);
}
.hint {
display: block;
font-size: size("body", "sm");
font-weight: normal;
}
}

.user-list-item {
@include at-media(desktop) {
width: calc(50% - units(1));
margin-bottom: 1rem;
box-sizing: border-box;
}
}
.user-list-item-heading .live-search-relevant {
display: block;
word-wrap: break-word;
}

border: 1px solid color('gray-cool-10');
padding: units(2);

.tick-cross-list-permissions {
margin: units(1) 0;
padding-left: units(2);
}

.hint {
display: block;
font-size: size("body", "sm");
font-weight: normal;
}
}

.template-list-item-without-ancestors .template-list-folder:active,
.template-list-item-without-ancestors .template-list-folder:active::before,
Expand Down
27 changes: 7 additions & 20 deletions app/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,28 +87,15 @@ def format_time(date):


def format_datetime_normal(date):
# example: February 20, 2024 at 07:00 PM US/Eastern, used for datetimes that's not within tables
return "{} at {} {}".format(
format_date_normal(date), format_time_24h(date), get_user_preferred_timezone()
format_date_normal(date), format_time_12h(date), get_user_preferred_timezone()
)


def format_datetime_short(date):
return "{} at {} {}".format(
format_date_short(date), format_time_24h(date), get_user_preferred_timezone()
)


def format_datetime_short_america(date):
return "{} at {}".format(format_date_numeric_america(date), format_time_12h(date))


def format_date_numeric_america(date):
date = parse_naive_dt(date)

preferred_tz = pytz.timezone(get_user_preferred_timezone())
return (
date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%m-%d-%Y")
)
def format_datetime_table(date):
# example: 03-18-2024 at 04:53 PM, intended for datetimes in tables
return "{} at {}".format(format_date_numeric(date), format_time_12h(date))


def format_time_12h(date):
Expand Down Expand Up @@ -137,7 +124,7 @@ def format_date_numeric(date):

preferred_tz = pytz.timezone(get_user_preferred_timezone())
return (
date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%Y-%m-%d")
date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%m-%d-%Y")
)


Expand Down Expand Up @@ -186,7 +173,7 @@ def format_date(date):

def format_date_normal(date):
date = parse_naive_dt(date)
return date.strftime("%d %B %Y").lstrip("0")
return date.strftime("%B %d, %Y").lstrip("0")


def format_date_short(date):
Expand Down
9 changes: 9 additions & 0 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,15 @@ class RegisterUserForm(StripWhitespaceForm):
auth_type = HiddenField("auth_type", default="sms_auth")


class SetupUserProfileForm(StripWhitespaceForm):
name = GovukTextInputField(
"Full name", validators=[DataRequired(message="Cannot be empty")]
)
mobile_number = international_phone_number()
# TODO This should be replaced with a select widget when one is available.
preferred_timezone = HiddenField("preferred_timezone", default="US/Eastern")


class RegisterUserFromInviteForm(RegisterUserForm):
def __init__(self, invited_user):
super().__init__(
Expand Down
5 changes: 5 additions & 0 deletions app/main/views/index.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

from flask import abort, redirect, render_template, request, url_for
from flask_login import current_user

Expand All @@ -8,6 +10,8 @@
from app.main.views.sub_navigation_dictionaries import features_nav, using_notify_nav
from app.utils.user import user_is_logged_in

login_dot_gov_url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL")


@main.route("/")
def index():
Expand All @@ -18,6 +22,7 @@ def index():
"views/signedout.html",
sms_rate=CURRENT_SMS_RATE,
counts=status_api_client.get_count_of_live_services_and_organizations(),
login_dot_gov_url=login_dot_gov_url,
)


Expand Down
13 changes: 11 additions & 2 deletions app/main/views/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
redirect,
render_template,
request,
session,
stream_with_context,
url_for,
)
Expand All @@ -18,7 +19,7 @@

from app import (
current_service,
format_datetime_short,
format_datetime_table,
notification_api_client,
service_api_client,
)
Expand Down Expand Up @@ -93,7 +94,7 @@ def view_job_csv(service_id, job_id):
mimetype="text/csv",
headers={
"Content-Disposition": 'inline; filename="{} - {}.csv"'.format(
job.template["name"], format_datetime_short(job.created_at)
job.template["name"], format_datetime_table(job.created_at)
)
},
)
Expand Down Expand Up @@ -373,6 +374,13 @@ def get_job_partials(job):
job.template_type
)

if request.referrer is not None:
session["arrived_from_preview_page"] = "check" in request.referrer
else:
session["arrived_from_preview_page"] = False

arrived_from_preview_page_url = session.get("arrived_from_preview_page", False)

return {
"counts": counts,
"notifications": render_template(
Expand All @@ -396,6 +404,7 @@ def get_job_partials(job):
"status": render_template(
"partials/jobs/status.html",
job=job,
arrived_from_preview_page_url=arrived_from_preview_page_url,
),
}

Expand Down
Loading

0 comments on commit 5cee174

Please sign in to comment.