Skip to content

Commit

Permalink
Merge pull request #1947 from GSA/main
Browse files Browse the repository at this point in the history
9/18/24 production deploy
  • Loading branch information
ccostino authored Sep 25, 2024
2 parents 1a9931a + 49ec3dc commit 804f65e
Show file tree
Hide file tree
Showing 84 changed files with 1,252 additions and 5,050 deletions.
18 changes: 5 additions & 13 deletions .ds.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,7 @@
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 65,
"is_secret": false
},
{
"type": "Basic Auth Credentials",
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 99,
"line_number": 66,
"is_secret": false
}
],
Expand Down Expand Up @@ -169,7 +161,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 117,
"line_number": 118,
"is_secret": false
}
],
Expand Down Expand Up @@ -601,15 +593,15 @@
"filename": "tests/app/main/views/test_user_profile.py",
"hashed_secret": "8072d7aad32964ec43fbcb699c75dc38890792f7",
"is_verified": false,
"line_number": 350,
"line_number": 336,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_user_profile.py",
"hashed_secret": "4c9dbb972da179e4f66f023eaa5fb9451d835030",
"is_verified": false,
"line_number": 351,
"line_number": 337,
"is_secret": false
}
],
Expand Down Expand Up @@ -692,5 +684,5 @@
}
]
},
"generated_at": "2024-08-15T16:29:15Z"
"generated_at": "2024-09-03T17:36:57Z"
}
60 changes: 12 additions & 48 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,64 +89,28 @@ jobs:
- uses: ./.github/actions/setup-project
- uses: jwalton/gh-find-current-pr@v1
id: findPr
- name: Clone API
uses: actions/checkout@v4
with:
repository: GSA/notifications-api
path: "notifications-api"
- name: Install API dependencies
working-directory: "notifications-api"
run: make bootstrap
env:
DATABASE_URL: postgresql://user:password@localhost:5432/test_notification_api
SQLALCHEMY_DATABASE_TEST_URI: postgresql://user:password@localhost:5432/test_notification_api
REDIS_URL: redis://localhost:6379
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_ENVIRONMENT: development
- name: Run API server
working-directory: "notifications-api"
run: make run-procfile &
env:
DATABASE_URL: postgresql://user:password@localhost:5432/test_notification_api
SQLALCHEMY_DATABASE_TEST_URI: postgresql://user:password@localhost:5432/test_notification_api
REDIS_URL: redis://localhost:6379
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_ENVIRONMENT: development
- name: Check API Server availability
run: |
curl --fail -v https://notify-api-staging.app.cloud.gov || exit 1
- name: Run Admin server
run: make run-flask &
env:
# API_HOST_NAME: https://notify-api-staging.app.cloud.gov
API_HOST_NAME: http://localhost:6011
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: notify-admin
NOTIFY_ENVIRONMENT: e2etest
NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_E2E_TEST_URI: http://localhost:6012
- name: Run E2E tests
# Run the E2E tests against the code found in this PR.
# run: poetry run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end
# --browser webkit doesn't work at this time.
run: make e2e-test
# Debugging for now to troubleshoot a connectivity issue to the local servers
# run: curl --request GET --url "http://localhost:6012"
# If we want to log stuff and see what's broken,
# insert this line:
# tail -f admin-server.log &
# above make e2e-test
run: |
make run-flask > admin-server.log 2>&1 &
make e2e-test
env:
API_HOST_NAME: http://localhost:6011
API_HOST_NAME: https://notify-api-staging.app.cloud.gov/
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: notify-admin

NOTIFY_ENVIRONMENT: e2etest
NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_E2E_TEST_URI: http://localhost:6012
NOTIFY_E2E_TEST_URI: http://localhost:6012/

validate-new-relic-config:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ dead-code: ## 60% is our aspirational goal, but currently breaks the build
.PHONY: e2e-test
e2e-test: export NEW_RELIC_ENVIRONMENT=test
e2e-test: ## Run end-to-end integration tests; note that --browser webkit isn't currently working
poetry run pytest -vv --browser chromium --browser firefox tests/end_to_end
DEBUG=pw:api,pw:browser poetry run pytest -vv --browser chromium --browser firefox tests/end_to_end

.PHONY: js-lint
js-lint: ## Run javascript linting scanners
Expand Down
2 changes: 1 addition & 1 deletion app/assets/error_pages/5xx.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
href="/static/images/apple-touch-icon.png?a0f7e1b728a42016b247dc54ee40d055">
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicon-16x16.png">
<link rel="manifest" href="/static/images/site.webmanifest">
<link rel="manifest" href="{{ asset_url('images/site.webmanifest') }}">

<link rel="stylesheet" media="screen" href="/static/stylesheets/main.css?d077f86473501ab244de0b30600536ee" />
<link rel="stylesheet" media="print" href="/static/stylesheets/print.css?28010888ca5719dc83d7c2c80f6ed2b2" />
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/activityChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
.padding(0.1);
// Adjust the y-axis domain to add some space above the tallest bar
const maxY = d3.max(deliveredData.map((d, i) => d + (failedData[i] || 0)));
const y = d3.scaleLinear()
const y = d3.scaleSqrt()
.domain([0, maxY + 2]) // Add 2 units of space at the top
.nice()
.range([height, 0]);
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/totalMessagesChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
document.getElementById('message').innerText = `${sms_sent.toLocaleString()} sent / ${sms_remaining_messages.toLocaleString()} remaining`;

// Calculate minimum width for "Messages Sent" as 1% of the total chart width
var minSentPercentage = 0.02; // Minimum width as a percentage of total messages (1% in this case)
var minSentPercentage = (sms_sent === 0) ? 0 : 0.02;
var minSentValue = totalMessages * minSentPercentage;
var displaySent = Math.max(sms_sent, minSentValue);
var displayRemaining = totalMessages - displaySent;
Expand Down
4 changes: 4 additions & 0 deletions app/assets/js/setTimezone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
document.addEventListener('DOMContentLoaded', function() {
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
document.cookie = `timezone=${timeZone}; path=/`;
})
5 changes: 5 additions & 0 deletions app/assets/stylesheets/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ $path: '/static/images/';
// Dependencies from GOV.UK Frontend, packaged to be specific to this application
@import './govuk-frontend/all';

// Custom overrides
.govuk-link {
font-weight: bold;
}

// Specific to this application
@import 'local/typography';
@import 'grids';
Expand Down
1 change: 1 addition & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


class Config(object):
SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167")
NOTIFY_APP_NAME = "admin"
NOTIFY_ENVIRONMENT = getenv("NOTIFY_ENVIRONMENT", "development")
API_HOST_NAME = getenv("API_HOST_NAME", "localhost")
Expand Down
18 changes: 15 additions & 3 deletions app/main/views/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from app.formatters import format_date_numeric, format_datetime_numeric, get_time_left
from app.main import main
from app.main.views.user_profile import set_timezone
from app.statistics_utils import get_formatted_percentage
from app.utils import (
DELIVERED_STATUSES,
Expand All @@ -39,6 +40,7 @@ def old_service_dashboard(service_id):
@main.route("/services/<uuid:service_id>")
@user_has_permissions()
def service_dashboard(service_id):

if session.get("invited_user_id"):
session.pop("invited_user_id", None)
session["service_id"] = service_id
Expand Down Expand Up @@ -323,13 +325,19 @@ def aggregate_template_usage(template_statistics, sort_key="count"):
key=lambda x: x["template_id"],
):
template_stats = list(v)

first_stat = template_stats[0] if template_stats else None
templates.append(
{
"template_id": k,
"template_name": template_stats[0]["template_name"],
"template_type": template_stats[0]["template_type"],
"template_name": first_stat.get("template_name"),
"template_type": first_stat.get("template_type"),
"count": sum(s["count"] for s in template_stats),
"created_by": first_stat.get("created_by"),
"created_by_id": first_stat.get("created_by_id"),
"last_used": first_stat.get("last_used"),
"status": first_stat.get("status"),
"template_folder": first_stat.get("template_folder"),
"template_folder_id": first_stat.get("template_folder_id"),
}
)

Expand Down Expand Up @@ -402,11 +410,13 @@ def get_dashboard_partials(service_id):


def get_dashboard_totals(statistics):

for msg_type in statistics.values():
msg_type["failed_percentage"] = get_formatted_percentage(
msg_type["failed"], msg_type["requested"]
)
msg_type["show_warning"] = float(msg_type["failed_percentage"]) > 3

return statistics


Expand Down Expand Up @@ -465,6 +475,8 @@ def get_months_for_financial_year(year, time_format="%B"):


def get_current_month_for_financial_year(year):
# Setting the timezone here because we need to set it somewhere.
set_timezone()
current_month = datetime.now().month
return current_month

Expand Down
89 changes: 88 additions & 1 deletion app/main/views/platform_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@
from datetime import datetime
from io import StringIO

from flask import Response, abort, flash, render_template, request, url_for
from flask import (
Response,
abort,
current_app,
flash,
render_template,
request,
session,
url_for,
)
from notifications_python_client.errors import HTTPError

from app import (
Expand All @@ -25,6 +34,7 @@
DateFilterForm,
RequiredDateFilterForm,
)
from app.main.views.send import _send_notification
from app.statistics_utils import (
get_formatted_percentage,
get_formatted_percentage_two_dp,
Expand Down Expand Up @@ -771,3 +781,80 @@ def _get_user_row(r):
row.append(r["password_changed_at"])
row.append(r["state"])
return row


@main.route(
"/platform-admin/load-test",
methods=["POST", "GET"],
)
@user_is_platform_admin
def load_test():
"""
The load test assumes that a service called 'Test service' exists. It will make
the platform admin a member of this service if the platform is not already. All
messagese will be sent in this service.
"""
service = _find_load_test_service()
_prepare_load_test_service(service)
example_template = _find_example_template(service)

# Simulated success
for _ in range(0, 250):
session["recipient"] = current_app.config["SIMULATED_SMS_NUMBERS"][0]
session["placeholders"] = {
"day of week": "Monday",
"color": "blue",
"phone number": current_app.config["SIMULATED_SMS_NUMBERS"][0],
}
_send_notification(service["id"], example_template["id"])
# Simulated failure
for _ in range(0, 250):
session["recipient"] = current_app.config["SIMULATED_SMS_NUMBERS"][1]
session["placeholders"] = {
"day of week": "Wednesday",
"color": "orange",
"phone number": current_app.config["SIMULATED_SMS_NUMBERS"][1],
}
_send_notification(service["id"], example_template["id"])

# For now, just redirect to the splash page so we know it's done
return render_template(
"views/platform-admin/splash-page.html",
)


def _find_example_template(service):
templates = service_api_client.get_service_templates(service["id"])
templates = templates["data"]
for template in templates:
# template = json.loads(template)
if template["name"] == "Example text message template":
return template

raise Exception("Could not find example template for load test")


def _find_load_test_service():
services = service_api_client.find_services_by_name("Test service")
services = services["data"]

for service in services:
if service["name"] == "Test service":
return service

raise Exception("Could not find 'Test service' for load test")


def _prepare_load_test_service(service):
users = user_api_client.get_all_users()
for user in users:
if user["platform_admin"] == "t":
try:
user_api_client.add_user_to_service(
service["id"], user["id"], ["send messages"]
)
except Exception:
current_app.logger.exception(
"Couldnt add user, may already be part of service"
)
pass
Loading

0 comments on commit 804f65e

Please sign in to comment.