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

Implement full check registration + win gift card flow #25

Merged
merged 19 commits into from
Apr 19, 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
23 changes: 23 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export BASE_URL=http://localhost:8000
export SECRET_KEY=super-sekret
export DEBUG=true
export DATABASE_URL=postgres://<local_username>:password@localhost:5432/postgres
export [email protected]
export [email protected]
export DJANGO_SUPERUSER_PASSWORD=ultrasekret

# Enable these for AGCOD integration. See 1Password.
# export AWS_ACCESS_KEY_ID=
# export AWS_SECRET_ACCESS_KEY=
# export AWS_REGION=us-east-1
# export AGCOD_ENDPOINT_HOST=agcod-v2-gamma.amazon.com
# export AGCOD_PARTNER_ID=

# Enable these for Mandrill integration. See 1Password.
# export EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
# export EMAIL_HOST=smtp.mandrillapp.com
# export EMAIL_HOST_PASSWORD=
# export EMAIL_HOST_USER=VoterBowl
# export EMAIL_PORT=587
# export EMAIL_USE_TLS=true
# export EMAIL_USE_SSL=false
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@
}
},
"[html][django-html]": {
"editor.defaultFormatter": "monosans.djlint",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
}
},
"emmet.includeLanguages": {
"django-html": "html"
},
"files.associations": {
"*.dhtml": "django-html"
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ For code cleanliness, we also use:
1. Create and enable a python virtualenv with `python -m venv .venv; source .venv/bin/activate`
1. Install the python dependencies with `pip install -r requirements.txt` or `pip install ".[dev]"`
1. Get postgres set up. If you've got docker installed, `./scripts/dockerpg.sh up`
1. Configure your environment variables. (See `.env.sample` and `settings.py`)
1. Run the app. `./manage.py runserver` and visit http://localhost:8000/
13 changes: 13 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"checkJs": true,
"allowJs": true,
"noEmit": true
},
"include": [
"server/static/js/surreal.js",
"server/static/js/css-scope-inline.js"
]
}
33 changes: 31 additions & 2 deletions server/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,37 @@
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_REGION = os.getenv("AWS_REGION")
ACGOD_ENDPOINT_HOST = os.getenv("ACGOD_ENDPOINT_HOST")
ACGOD_PARTNER_ID = os.getenv("ACGOD_PARTNER_ID")
AGCOD_ENDPOINT_HOST = os.getenv("AGCOD_ENDPOINT_HOST")
AGCOD_PARTNER_ID = os.getenv("AGCOD_PARTNER_ID")

# Sandbox endpoint: agcod-v2-gamma.amazon.com us-east-1
# Production endpoint: agcod-v2.amazon.com us-east-1


# ----------------------------------------------------------------------------
# Email Settings
# ----------------------------------------------------------------------------

# The email address that emails are sent from unless explicitly overridden
# when invoking Django's `send_mail` function
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", "[email protected]")

# The *sending* email address used when Django emails admins about errors.
# For now, we make this the same as DEFAULT_FROM_EMAIL
SERVER_EMAIL = DEFAULT_FROM_EMAIL

# The email addresses of our administrators.
ADMINS = [("Frontseat Developers", "[email protected]")]

# How to send email. We default to console-based email, which simply prints
# emails to the console. This is useful for local development. In production,
# we'll configure SMTP.
EMAIL_BACKEND = os.getenv(
"EMAIL_BACKEND", "django.core.mail.backends.console.EmailBackend"
)
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", None)
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", None)
EMAIL_HOST = os.getenv("EMAIL_HOST", None)
EMAIL_PORT = os.getenv("EMAIL_PORT", None)
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "false").lower() == "true"
EMAIL_USE_SSL = os.getenv("EMAIL_USE_SSL", "false").lower() == "true"
2 changes: 0 additions & 2 deletions server/static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
html {
font-size: 16px;
font-family: var(--font-sans);
background-color: black;
color: white;
}


Expand Down
8 changes: 8 additions & 0 deletions server/static/js/fireworks.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions server/utils/agcod.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ def from_settings(cls) -> t.Self:
aws_access_key_id = t.cast(str | None, settings.AWS_ACCESS_KEY_ID)
aws_secret_access_key = t.cast(str | None, settings.AWS_SECRET_ACCESS_KEY)
aws_region = t.cast(str | None, settings.AWS_REGION)
endpoint_host = t.cast(str | None, settings.ACGOD_ENDPOINT_HOST)
parter_id = t.cast(str | None, settings.ACGOD_PARTNER_ID)
endpoint_host = t.cast(str | None, settings.AGCOD_ENDPOINT_HOST)
parter_id = t.cast(str | None, settings.AGCOD_PARTNER_ID)

if aws_access_key_id is None:
logger.warning("Missing AWS_ACCESS_KEY_ID")
Expand All @@ -304,10 +304,10 @@ def from_settings(cls) -> t.Self:
logger.warning("Missing AWS_REGION")

if endpoint_host is None:
logger.warning("Missing ACGOD_ENDPOINT_HOST")
logger.warning("Missing AGCOD_ENDPOINT_HOST")

if parter_id is None:
logger.warning("Missing ACGOD_PARTNER_ID")
logger.warning("Missing AGCOD_PARTNER_ID")

if None in (
aws_access_key_id,
Expand Down
70 changes: 70 additions & 0 deletions server/utils/email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import dataclasses
import logging
import typing as t

from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string

logger = logging.getLogger(__name__)


@dataclasses.dataclass(frozen=True)
Expand Down Expand Up @@ -42,3 +50,65 @@ def normalize_email(
local = local.encode("ascii", "ignore").decode("ascii")
domain = domain.encode("ascii", "ignore").decode("ascii")
return f"{local}@{domain}"


def send_template_email(
to: str | t.Sequence[str],
template_base: str,
context: dict | None = None,
from_email: str | None = None,
) -> bool:
"""
Send a templatized email.

Send an email to the `to` address, using the template files found under
the `template_base` to render contents.

The following named templates must be found underneath `template_base`:

- `subject.txt`: renders the subject line
- `body.txt`: renders the plain-text body
- `body.dhtml`: renders the HTML body

Django's template system is flexible and can load templates from just about
anywhere, provided you write a plugin. But! By default, we're going to load
them from the filesystem; `template_base` is simply the name of the
directory that contains these three files, relative to the `templates`
directory in the app.

For instance, if we have `subject`/`body` templates in
`server/assistant/templates/email/registration`, then `template_base` is
`email/registration`.
"""
to_array = [to] if isinstance(to, str) else to

message = create_message(to_array, template_base, context, from_email)
try:
message.send()
return True
except Exception:
logger.exception(f"failed to send email to {to}")
return False


def create_message(
to: t.Sequence[str],
template_base: str,
context: dict[str, t.Any] | None = None,
from_email: str | None = None,
) -> EmailMultiAlternatives:
"""Create the underlying email message to send."""
context = context or {}
from_email = from_email or settings.DEFAULT_FROM_EMAIL
context.setdefault("BASE_URL", settings.BASE_URL)

subject = render_to_string(f"{template_base}/subject.txt", context).strip()
text = render_to_string(f"{template_base}/body.txt", context)
html = render_to_string(f"{template_base}/body.dhtml", context)

message = EmailMultiAlternatives(
from_email=from_email, to=to, subject=subject, body=text
)
message.attach_alternative(html, "text/html")

return message
Loading