mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-26 01:04:00 -04:00
Merge main
This commit is contained in:
@@ -6,6 +6,7 @@ from itertools import groupby
|
||||
|
||||
from flask import Response, abort, jsonify, render_template, request, session, url_for
|
||||
from flask_login import current_user
|
||||
from flask_socketio import emit
|
||||
from werkzeug.utils import redirect
|
||||
|
||||
from app import (
|
||||
@@ -14,6 +15,7 @@ from app import (
|
||||
job_api_client,
|
||||
notification_api_client,
|
||||
service_api_client,
|
||||
socketio,
|
||||
template_statistics_client,
|
||||
)
|
||||
from app.formatters import format_date_numeric, format_datetime_numeric, get_time_left
|
||||
@@ -32,6 +34,18 @@ from app.utils.user import user_has_permissions
|
||||
from notifications_utils.recipients import format_phone_number_human_readable
|
||||
|
||||
|
||||
@socketio.on("fetch_daily_stats")
|
||||
def handle_fetch_daily_stats(service_id):
|
||||
if service_id:
|
||||
date_range = get_stats_date_range()
|
||||
daily_stats = service_api_client.get_service_notification_statistics_by_day(
|
||||
service_id, start_date=date_range["start_date"], days=date_range["days"]
|
||||
)
|
||||
emit("daily_stats_update", daily_stats)
|
||||
else:
|
||||
emit("error", {"error": "No service_id provided"})
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/dashboard")
|
||||
@user_has_permissions("view_activity", "send_messages")
|
||||
def old_service_dashboard(service_id):
|
||||
@@ -84,6 +98,7 @@ def service_dashboard(service_id):
|
||||
partials=get_dashboard_partials(service_id),
|
||||
job_and_notifications=job_and_notifications,
|
||||
service_data_retention_days=service_data_retention_days,
|
||||
service_id=service_id,
|
||||
)
|
||||
|
||||
|
||||
@@ -434,6 +449,24 @@ def get_months_for_financial_year(year, time_format="%B"):
|
||||
return [month.strftime(time_format) for month in (get_months_for_year(1, 13, year))]
|
||||
|
||||
|
||||
def get_current_month_for_financial_year(year):
|
||||
current_month = datetime.now().month
|
||||
return current_month
|
||||
|
||||
|
||||
def get_stats_date_range():
|
||||
current_financial_year = get_current_financial_year()
|
||||
current_month = get_current_month_for_financial_year(current_financial_year)
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
days = 7
|
||||
return {
|
||||
"current_financial_year": current_financial_year,
|
||||
"current_month": current_month,
|
||||
"start_date": start_date,
|
||||
"days": days,
|
||||
}
|
||||
|
||||
|
||||
def get_months_for_year(start, end, year):
|
||||
return [datetime(year, month, 1) for month in range(start, end)]
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from app.main.views import sign_in
|
||||
from app.main.views.verify import activate_user
|
||||
from app.models.user import InvitedOrgUser, InvitedUser, User
|
||||
from app.utils import hide_from_search_engines, hilite
|
||||
from app.utils.user import is_gov_user
|
||||
|
||||
|
||||
@main.route("/register", methods=["GET", "POST"])
|
||||
@@ -147,6 +148,11 @@ def check_invited_user_email_address_matches_expected(
|
||||
flash("You cannot accept an invite for another person.")
|
||||
abort(403)
|
||||
|
||||
if not is_gov_user(user_email):
|
||||
debug_msg("invited user has a non-government email address.")
|
||||
flash("You must use a government email address.")
|
||||
abort(403)
|
||||
|
||||
|
||||
@main.route("/set-up-your-profile", methods=["GET", "POST"])
|
||||
@hide_from_search_engines
|
||||
@@ -245,10 +251,21 @@ def get_invited_user_email_address(invited_user_id):
|
||||
|
||||
def invited_user_accept_invite(invited_user_id):
|
||||
invited_user = InvitedUser.by_id(invited_user_id)
|
||||
|
||||
if invited_user.status == "expired":
|
||||
current_app.logger.error("User invitation has expired")
|
||||
flash("Your invitation has expired.")
|
||||
flash(
|
||||
"Your invitation has expired; please contact the person who invited you for additional help."
|
||||
)
|
||||
abort(401)
|
||||
|
||||
if invited_user.status == "cancelled":
|
||||
current_app.logger.error("User invitation has been cancelled")
|
||||
flash(
|
||||
"Your invitation is no longer valid; please contact the person who invited you for additional help."
|
||||
)
|
||||
abort(401)
|
||||
|
||||
invited_user.accept_invite()
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,16 @@ import uuid
|
||||
from string import ascii_uppercase
|
||||
from zipfile import BadZipFile
|
||||
|
||||
from flask import abort, flash, redirect, render_template, request, session, url_for
|
||||
from flask import (
|
||||
abort,
|
||||
current_app,
|
||||
flash,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
session,
|
||||
url_for,
|
||||
)
|
||||
from flask_login import current_user
|
||||
from markupsafe import Markup
|
||||
from notifications_python_client.errors import HTTPError
|
||||
@@ -31,12 +40,18 @@ from app.s3_client.s3_csv_client import (
|
||||
s3upload,
|
||||
set_metadata_on_csv_upload,
|
||||
)
|
||||
from app.utils import PermanentRedirect, should_skip_template_page, unicode_truncate
|
||||
from app.utils import (
|
||||
PermanentRedirect,
|
||||
hilite,
|
||||
should_skip_template_page,
|
||||
unicode_truncate,
|
||||
)
|
||||
from app.utils.csv import Spreadsheet, get_errors_for_csv
|
||||
from app.utils.templates import get_template
|
||||
from app.utils.user import user_has_permissions
|
||||
from notifications_utils import SMS_CHAR_COUNT_LIMIT
|
||||
from notifications_utils.insensitive_dict import InsensitiveDict
|
||||
from notifications_utils.logging import scrub
|
||||
from notifications_utils.recipients import RecipientCSV, first_column_headings
|
||||
from notifications_utils.sanitise_text import SanitiseASCII
|
||||
|
||||
@@ -938,6 +953,9 @@ def send_notification(service_id, template_id):
|
||||
)
|
||||
)
|
||||
|
||||
current_app.logger.info(
|
||||
hilite(scrub(f"Recipient for the one-off will be {recipient}"))
|
||||
)
|
||||
keys = []
|
||||
values = []
|
||||
for k, v in session["placeholders"].items():
|
||||
@@ -948,7 +966,9 @@ def send_notification(service_id, template_id):
|
||||
vals = ",".join(values)
|
||||
data = f"{data}\r\n{vals}"
|
||||
|
||||
filename = f"one-off-{current_user.name}-{uuid.uuid4()}.csv"
|
||||
filename = (
|
||||
f"one-off-{uuid.uuid4()}.csv" # {current_user.name} removed from filename
|
||||
)
|
||||
my_data = {"filename": filename, "template_id": template_id, "data": data}
|
||||
upload_id = s3upload(service_id, my_data)
|
||||
form = CsvUploadForm()
|
||||
@@ -969,6 +989,19 @@ def send_notification(service_id, template_id):
|
||||
valid="True",
|
||||
)
|
||||
|
||||
# Here we are attempting to cleverly link the job id to the one-off recipient
|
||||
# If we know the partial phone number of the recipient, we can search
|
||||
# on that initially and find this, which will give us the job_id
|
||||
# And once we know the job_id, we can search on that and it might tell us something
|
||||
# about report generation.
|
||||
current_app.logger.info(
|
||||
hilite(
|
||||
scrub(
|
||||
f"Created job to send one-off, recipient is {recipient}, job_id is {upload_id}"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
session.pop("recipient")
|
||||
session.pop("placeholders")
|
||||
|
||||
|
||||
@@ -4,7 +4,16 @@ import uuid
|
||||
|
||||
import jwt
|
||||
import requests
|
||||
from flask import Response, current_app, redirect, render_template, request, url_for
|
||||
from flask import (
|
||||
Response,
|
||||
abort,
|
||||
current_app,
|
||||
flash,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
url_for,
|
||||
)
|
||||
from flask_login import current_user
|
||||
|
||||
from app import login_manager, user_api_client
|
||||
@@ -15,6 +24,7 @@ from app.models.user import User
|
||||
from app.utils import hide_from_search_engines
|
||||
from app.utils.login import is_safe_redirect_url
|
||||
from app.utils.time import is_less_than_days_ago
|
||||
from app.utils.user import is_gov_user
|
||||
from notifications_utils.url_safe_token import generate_token
|
||||
|
||||
|
||||
@@ -88,6 +98,12 @@ def _do_login_dot_gov():
|
||||
try:
|
||||
access_token = _get_access_token(code, state)
|
||||
user_email, user_uuid = _get_user_email_and_uuid(access_token)
|
||||
if not is_gov_user(user_email):
|
||||
current_app.logger.error(
|
||||
"invited user has a non-government email address."
|
||||
)
|
||||
flash("You must use a government email address.")
|
||||
abort(403)
|
||||
redirect_url = request.args.get("next")
|
||||
user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ def using_notify_nav():
|
||||
"link": "main.trial_mode_new",
|
||||
},
|
||||
{
|
||||
"name": "Pricing",
|
||||
"name": "Tracking usage",
|
||||
"link": "main.pricing",
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user