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

Initial TemplateCategory client #1884

Merged
merged 15 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
86 changes: 44 additions & 42 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,38 @@


class Config(object):
# for waffles: pull out the routes into a flat list of the form ['/home', '/accueil', '/why-gc-notify', ...]
EXTRA_ROUTES = [item for sublist in map(lambda x: x.values(), GC_ARTICLES_ROUTES.values()) for item in sublist]

ACTIVITY_STATS_LIMIT_DAYS = 7
if os.environ.get("HEROKU_APP_NAME", "") != "":
ADMIN_BASE_URL = "https://" + os.environ.get("HEROKU_APP_NAME", "") + ".herokuapp.com"
else:
ADMIN_BASE_URL = os.environ.get("ADMIN_BASE_URL", "http://localhost:6012")
ADMIN_CLIENT_USER_NAME = "notify-admin"
ADMIN_CLIENT_SECRET = os.environ.get("ADMIN_CLIENT_SECRET")
ANTIVIRUS_API_HOST = os.environ.get("ANTIVIRUS_API_HOST")
ANTIVIRUS_API_KEY = os.environ.get("ANTIVIRUS_API_KEY")
ALLOW_DEBUG_ROUTE = env.bool("ALLOW_DEBUG_ROUTE", False)

# List of allowed service IDs that are allowed to send HTML through their templates.
ALLOW_HTML_SERVICE_IDS: List[str] = [id.strip() for id in os.getenv("ALLOW_HTML_SERVICE_IDS", "").split(",")]

ADMIN_BASE_URL = (
"https://" + os.environ.get("HEROKU_APP_NAME", "") + ".herokuapp.com"
if os.environ.get("HEROKU_APP_NAME", "") != ""
else os.environ.get("ADMIN_BASE_URL", "http://localhost:6012")
)
ADMIN_CLIENT_SECRET = os.environ.get("ADMIN_CLIENT_SECRET")
ADMIN_CLIENT_USER_NAME = "notify-admin"
ANTIVIRUS_API_HOST = os.environ.get("ANTIVIRUS_API_HOST")
ANTIVIRUS_API_KEY = os.environ.get("ANTIVIRUS_API_KEY")
API_HOST_NAME = os.environ.get("API_HOST_NAME")
ASSET_DOMAIN = os.getenv("ASSET_DOMAIN", "assets.notification.canada.ca")
ASSET_PATH = "/static/"
ASSETS_DEBUG = False
AWS_REGION = os.environ.get("AWS_REGION", "us-east-1")

# Bounce Rate parameters
BR_DISPLAY_VOLUME_MINIMUM = 1000

BULK_SEND_AWS_BUCKET = os.getenv("BULK_SEND_AWS_BUCKET")
BULK_SEND_TEST_SERVICE_ID = os.getenv("BULK_SEND_TEST_SERVICE_ID")

CHECK_PROXY_HEADER = False
CONTACT_EMAIL = os.environ.get("CONTACT_EMAIL", "[email protected]")
CRM_GITHUB_PERSONAL_ACCESS_TOKEN = os.getenv("CRM_GITHUB_PERSONAL_ACCESS_TOKEN")
CRM_ORG_LIST_URL = os.getenv("CRM_ORG_LIST_URL")
CSV_MAX_ROWS = env.int("CSV_MAX_ROWS", 50_000)
CSV_MAX_ROWS_BULK_SEND = env.int("CSV_MAX_ROWS_BULK_SEND", 100_000)
CSV_UPLOAD_BUCKET_NAME = os.getenv("CSV_UPLOAD_BUCKET_NAME", "notification-alpha-canada-ca-csv-upload")
CRM_GITHUB_PERSONAL_ACCESS_TOKEN = os.getenv("CRM_GITHUB_PERSONAL_ACCESS_TOKEN")
CRM_ORG_LIST_URL = os.getenv("CRM_ORG_LIST_URL")
DANGEROUS_SALT = os.environ.get("DANGEROUS_SALT")
DEBUG = False
DEBUG_KEY = os.environ.get("DEBUG_KEY", "")
Expand All @@ -74,8 +73,21 @@ class Config(object):
DOCUMENTATION_DOMAIN = os.getenv("DOCUMENTATION_DOMAIN", "documentation.notification.canada.ca")
EMAIL_2FA_EXPIRY_SECONDS = 1_800 # 30 Minutes
EMAIL_EXPIRY_SECONDS = 3600 # 1 hour
FREE_YEARLY_SMS_LIMIT = env.int("FREE_YEARLY_SMS_LIMIT", 25_000)

# for waffles: pull out the routes into a flat list of the form ['/home', '/accueil', '/why-gc-notify', ...]
EXTRA_ROUTES = [item for sublist in map(lambda x: x.values(), GC_ARTICLES_ROUTES.values()) for item in sublist]

# FEATURE FLAGS
FF_NEW_BRANDING = env.bool("FF_NEW_BRANDING", False)
FF_SALESFORCE_CONTACT = env.bool("FF_SALESFORCE_CONTACT", True)
FF_TEMPLATE_CATEGORY = env.bool("FF_TEMPLATE_CATEGORY", False)
FF_TOU = env.bool("FF_TOU", False)

FREE_YEARLY_EMAIL_LIMIT = env.int("FREE_YEARLY_EMAIL_LIMIT", 10_000_000)
FREE_YEARLY_SMS_LIMIT = env.int("FREE_YEARLY_SMS_LIMIT", 25_000)
GC_ARTICLES_API = os.environ.get("GC_ARTICLES_API", "articles.alpha.canada.ca/notification-gc-notify")
GC_ARTICLES_API_AUTH_PASSWORD = os.environ.get("GC_ARTICLES_API_AUTH_PASSWORD")
GC_ARTICLES_API_AUTH_USERNAME = os.environ.get("GC_ARTICLES_API_AUTH_USERNAME")
GOOGLE_ANALYTICS_ID = os.getenv("GOOGLE_ANALYTICS_ID", "UA-102484926-14")
GOOGLE_TAG_MANAGER_ID = os.getenv("GOOGLE_TAG_MANAGER_ID", "GTM-KRKRZQV")
HC_EN_SERVICE_ID = os.getenv("HC_EN_SERVICE_ID")
Expand All @@ -84,40 +96,38 @@ class Config(object):
HTTP_PROTOCOL = "http"
INVITATION_EXPIRY_SECONDS = 3_600 * 24 * 2 # 2 days - also set on api
IP_GEOLOCATE_SERVICE = os.environ.get("IP_GEOLOCATE_SERVICE", "").rstrip("/")
GC_ARTICLES_API = os.environ.get("GC_ARTICLES_API", "articles.alpha.canada.ca/notification-gc-notify")
GC_ARTICLES_API_AUTH_USERNAME = os.environ.get("GC_ARTICLES_API_AUTH_USERNAME")
GC_ARTICLES_API_AUTH_PASSWORD = os.environ.get("GC_ARTICLES_API_AUTH_PASSWORD")

LANGUAGES = ["en", "fr"]
LOGO_UPLOAD_BUCKET_NAME = os.getenv("ASSET_UPLOAD_BUCKET_NAME", "notification-alpha-canada-ca-asset-upload")
MAX_FAILED_LOGIN_COUNT = 10
MOU_BUCKET_NAME = os.getenv("MOU_BUCKET_NAME", "")

NOTIFY_APP_NAME = "admin"
NOTIFY_BAD_FILLER_UUID = "00000000-0000-0000-0000-000000000000"
NOTIFY_ENVIRONMENT = "development"
NOTIFY_LOG_LEVEL = "DEBUG"
NOTIFY_LOG_PATH = os.getenv("NOTIFY_LOG_PATH", "")
NOTIFY_SERVICE_ID = "d6aa2c68-a2d9-4437-ab19-3ae8eb202553"

NOTIFY_TEMPLATE_PREFILL_SERVICE_ID = "93305b36-b0a0-4a34-9ab2-c1b7bb5ca489"
NOTIFY_USER_ID = "6af522d0-2915-4e52-83a3-3690455a5fe6"
PERMANENT_SESSION_LIFETIME = 8 * 60 * 60 # 8 hours

REDIS_URL = os.environ.get("REDIS_URL")
PERMANENT_SESSION_LIFETIME = 8 * 60 * 60 # 8 hours
REDIS_ENABLED = env.bool("REDIS_ENABLED", False)

REDIS_URL = os.environ.get("REDIS_URL")
ROUTE_SECRET_KEY_1 = os.environ.get("ROUTE_SECRET_KEY_1", "")
ROUTE_SECRET_KEY_2 = os.environ.get("ROUTE_SECRET_KEY_2", "")
WAF_SECRET = os.environ.get("WAF_SECRET", "waf-secret")

# Scan files integration
SCANFILES_AUTH_TOKEN = os.environ.get("SCANFILES_AUTH_TOKEN", "")
SCANFILES_URL = os.environ.get("SCANFILES_URL", "")

SECRET_KEY = env.list("SECRET_KEY", [])
SECURITY_EMAIL = os.environ.get("SECURITY_EMAIL", "[email protected]")
SEND_FILE_MAX_AGE_DEFAULT = 365 * 24 * 60 * 60 # 1 year
SENDING_DOMAIN = os.environ.get("SENDING_DOMAIN", "notification.alpha.canada.ca")
SENSITIVE_SERVICES = os.environ.get("SENSITIVE_SERVICES", "")
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_NAME = "notify_admin_session"
SESSION_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_SECURE = True
SESSION_REFRESH_EACH_REQUEST = True
SESSION_COOKIE_SAMESITE = "Lax"
SENSITIVE_SERVICES = os.environ.get("SENSITIVE_SERVICES", "")
SHOW_STYLEGUIDE = env.bool("SHOW_STYLEGUIDE", True)

# Hosted graphite statsd prefix
Expand All @@ -128,24 +138,16 @@ class Config(object):

TEMPLATE_PREVIEW_API_HOST = os.environ.get("TEMPLATE_PREVIEW_API_HOST", "http://localhost:6013")
TEMPLATE_PREVIEW_API_KEY = os.environ.get("TEMPLATE_PREVIEW_API_KEY", "my-secret-key")

WAF_SECRET = os.environ.get("WAF_SECRET", "waf-secret")
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = None

ZENDESK_API_KEY = os.environ.get("ZENDESK_API_KEY")

# Bounce Rate parameters
BR_DISPLAY_VOLUME_MINIMUM = 1000

# Scan files integration
SCANFILES_URL = os.environ.get("SCANFILES_URL", "")
SCANFILES_AUTH_TOKEN = os.environ.get("SCANFILES_AUTH_TOKEN", "")
# Various IDs
BULK_SEND_TEST_SERVICE_ID = os.getenv("BULK_SEND_TEST_SERVICE_ID")

# FEATURE FLAGS
FF_SALESFORCE_CONTACT = env.bool("FF_SALESFORCE_CONTACT", True)
FF_NEW_BRANDING = env.bool("FF_NEW_BRANDING", False)
FF_TEMPLATE_CATEGORY = env.bool("FF_TEMPLATE_CATEGORY", False)
FF_TOU = env.bool("FF_TOU", False)
NOTIFY_USER_ID = "6af522d0-2915-4e52-83a3-3690455a5fe6"
NOTIFY_SERVICE_ID = "d6aa2c68-a2d9-4437-ab19-3ae8eb202553"
NO_BRANDING_ID = os.environ.get("NO_BRANDING_ID", "0af93cf1-2c49-485f-878f-f3e662e651ef")

@classmethod
Expand Down
20 changes: 10 additions & 10 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1911,24 +1911,24 @@ class BrandingRequestForm(StripWhitespaceForm):
class TemplateCategoryForm(StripWhitespaceForm):
name_en = StringField("Name EN", validators=[DataRequired(message=_l("This cannot be empty"))])
name_fr = StringField("Name FR", validators=[DataRequired(message=_l("This cannot be empty"))])
desc_en = StringField("Desc EN", validators=[DataRequired(message=_l("This cannot be empty"))])
desc_fr = StringField("Desc FR", validators=[DataRequired(message=_l("This cannot be empty"))])
description_en = StringField("Desc EN", validators=[DataRequired(message=_l("This cannot be empty"))])
description_fr = StringField("Desc FR", validators=[DataRequired(message=_l("This cannot be empty"))])
hidden = RadioField(_l("Hide category"), choices=[("True", _l("Hide")), ("False", _l("Show"))])
email_priority = RadioField(
email_process_type = RadioField(
_l("Email Priority"),
choices=[
("high", _l("High")),
("medium", _l("Medium")),
("low", _l("Low")),
("priority", _l("High")),
("normal", _l("Medium")),
("bulk", _l("Low")),
],
validators=[DataRequired(message=_l("This cannot be empty"))],
)
sms_priority = RadioField(
sms_process_type = RadioField(
_l("Text message priority"),
choices=[
("high", _l("High")),
("medium", _l("Medium")),
("low", _l("Low")),
("priority", _l("High")),
("normal", _l("Medium")),
("bulk", _l("Low")),
],
validators=[DataRequired(message=_l("This cannot be empty"))],
)
64 changes: 54 additions & 10 deletions app/main/views/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
"letter": LetterTemplateForm,
}

# Todo: Remove this once the process_types in the backend are updated to use low/med/high
category_mapping = {
"bulk": "low",
"normal": "medium",
"priority": "high",
}

form_objects_with_category = {
"email": EmailTemplateFormWithCategory,
"sms": SMSTemplateFormWithCategory,
Expand Down Expand Up @@ -840,15 +847,11 @@ def abort_403_if_not_admin_user():
def _get_categories_and_prepare_form(template, template_type):
categories = template_category_api_client.get_all_template_categories()

# TODO: Remove this, this will come from the DB
if "/edit" in request.path:
template["template_category"] = "1"

form = form_objects_with_category[template_type](**template)

# alphabetize choices
name_col = "name_en" if get_current_locale(current_app) == "en" else "name_fr"
desc_col = "desc_en" if get_current_locale(current_app) == "en" else "desc_fr"
desc_col = "description_en" if get_current_locale(current_app) == "en" else "description_fr"
categories = sorted(categories, key=lambda x: x[name_col])
form.template_category.choices = [(cat["id"], cat[name_col]) for cat in categories]

Expand Down Expand Up @@ -1239,26 +1242,67 @@ def add_recipients(service_id, template_id):
def template_categories():
template_category_list = template_category_api_client.get_all_template_categories()

# Todo: Remove this once the process_types in the backend are updated to use low/med/high
# Maps bulk/normal/priority to low/med/high for display in the front end.
for cat in template_category_list:
if cat["sms_process_type"] in category_mapping:
cat["sms_process_type"] = category_mapping[cat["sms_process_type"]]

if cat["email_process_type"] in category_mapping:
cat["email_process_type"] = category_mapping[cat["email_process_type"]]

return render_template(
"views/templates/template_categories.html", search_form=SearchByNameForm(), template_categories=template_category_list
)


@main.route("/template-categories/add", methods=["GET", "POST"])
def add_template_category():
form = TemplateCategoryForm()

if form.validate_on_submit():
template_category_api_client.create_template_category(
name_en=form.data["name_en"],
name_fr=form.data["name_fr"],
description_en=form.data["description_en"],
description_fr=form.data["description_fr"],
hidden=form.data["hidden"],
email_process_type=form.data["email_process_type"],
sms_process_type=form.data["sms_process_type"],
)

return redirect(url_for(".template_categories"))

return render_template("views/templates/template_category.html", search_form=SearchByNameForm(), form=form)


@main.route("/template-categories/<template_category_id>", methods=["GET", "POST"])
@user_is_platform_admin
def template_category(template_category_id):
template_category = template_category_api_client.get_template_category(template_category_id)
form = TemplateCategoryForm(
name_en=template_category["name_en"],
name_fr=template_category["name_fr"],
desc_en=template_category["desc_en"],
desc_fr=template_category["desc_fr"],
description_en=template_category["description_en"],
description_fr=template_category["description_fr"],
hidden=template_category["hidden"],
email_priority=template_category["email_priority"],
sms_priority=template_category["sms_priority"],
email_process_type=template_category["email_process_type"],
sms_process_type=template_category["sms_process_type"],
)

form.validate_on_submit()
if form.validate_on_submit():
template_category_api_client.update_template_category(
template_category_id,
name_en=form.data["name_en"],
name_fr=form.data["name_fr"],
description_en=form.data["description_en"],
description_fr=form.data["description_fr"],
hidden=form.data["hidden"],
email_process_type=form.data["email_process_type"],
sms_process_type=form.data["sms_process_type"],
)

return redirect(url_for(".template_categories"))

return render_template(
"views/templates/template_category.html", search_form=SearchByNameForm(), template_category=template_category, form=form
Expand Down
Loading
Loading