-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add contributing workflow * add contributing script * sds * add contributing script * quick save * fix workflow * fix trigger * remove example user * remove temp code * fix triggers * rename job * fetch main branch * keep .venv * setup python scripts dir * update pipeline * house keeping * test * fix new line * fix fetch main * replace logging with print * test * fetch branch * set cwd * fix prints and paths * fix print * show response json * test * fix dd auth * test * test * test * test * test * remove test * test * test * test echo env var * test open * test multi env vars * keep venv * test send-email action * use action_path * cat file * cat file * fix action * set env vars * add comments * test json loads * test json loads pt2 * test json loads pt3 * send test email * house keeping * use send-email action * fix pipeline * rename file * fix module doc string * use html url * test * try review trigger * on pull_request_target * test * add env var * checkout * reviews * verify new contributor test * top level workflow * remove gh token secret * test * rename file * rename file * fix ref * rename file * test * test * fix ref * test * pipe output * print latest state * fix assertion * add .venv file * root dir per script * checkout: false * pass values * duplicate workflow * test * output email address * test * test * echo event name * test * not pull request * fix pr checkout * test * test * ref * force * test * test * test * test * test * test * set pr num * no secret * workflow call outputs * validate new contributor * test * test * test * rename * test * test * test * fix script * fix script * fix * test * fix * fix * fix * fix * tidy up * fix * feeback
- Loading branch information
Showing
20 changed files
with
1,745 additions
and
15 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[[source]] | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
name = "pypi" | ||
|
||
[packages] | ||
requests = "==2.31.0" | ||
|
||
[dev-packages] | ||
black = "==23.1.0" | ||
pytest = "==7.2.1" | ||
mypy = "==1.6.1" | ||
pylint = "==3.0.2" | ||
types-requests = "==2.31.0.10" | ||
|
||
[requires] | ||
python_version = "3.11" |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
""" | ||
© Ocado Group | ||
Created on 29/12/2023 at 11:30:49(+00:00). | ||
Using DotDigital, send a transactional email using a triggered campaign as its | ||
content. | ||
https://developer.dotdigital.com/reference/send-transactional-email-using-a-triggered-campaign | ||
""" | ||
|
||
import json | ||
import os | ||
import typing as t | ||
|
||
import requests | ||
|
||
JsonBody = t.Dict[str, t.Any] | ||
|
||
|
||
def get_settings(): | ||
"""Gets the general settings from environment variables. Variables are | ||
parsed to the correct type. | ||
Returns: | ||
A tuple with the values (region, auth, timeout). | ||
""" | ||
|
||
region = os.getenv("REGION", "") | ||
assert region != "", "Region path parameter not set." | ||
|
||
auth = os.getenv("AUTH", "") | ||
assert auth != "", "Authorization header not set." | ||
|
||
timeout = int(os.getenv("TIMEOUT", "-1")) | ||
assert timeout != -1, "Request timeout not set." | ||
|
||
return region, auth, timeout | ||
|
||
|
||
def get_json_body() -> JsonBody: | ||
"""Gets the JSON body from environment variables. Variables are parsed to | ||
the correct type. | ||
Returns: | ||
A dictionary containing the request's JSON body. | ||
""" | ||
|
||
body: JsonBody = {} | ||
|
||
def set_value( | ||
env_key: str, | ||
body_key: str, | ||
required: bool, | ||
json_loads: bool = True, | ||
): | ||
"""Helper to parse environment variables into body parameters. | ||
Args: | ||
env_key: The key of the environment variable. | ||
body_key: The key of the body parameter. | ||
required: If this value is required in the request. | ||
json_loads: If the value should be parsed as a JSON object. Strings | ||
don't need to be parsed as JSON. | ||
""" | ||
|
||
raw_value = os.getenv(env_key, "") | ||
|
||
if required: | ||
assert raw_value != "", f'"{env_key}" environment variable not set.' | ||
|
||
if raw_value != "": | ||
body[body_key] = json.loads(raw_value) if json_loads else raw_value | ||
|
||
set_value( | ||
env_key="TO_ADDRESSES", | ||
body_key="toAddresses", | ||
required=True, | ||
) | ||
set_value( | ||
env_key="CC_ADDRESSES", | ||
body_key="ccAddresses", | ||
required=False, | ||
) | ||
set_value( | ||
env_key="BCC_ADDRESSES", | ||
body_key="bccAddresses", | ||
required=False, | ||
) | ||
set_value( | ||
env_key="FROM_ADDRESS", | ||
body_key="fromAddress", | ||
required=False, | ||
json_loads=False, | ||
) | ||
set_value( | ||
env_key="CAMPAIGN_ID", | ||
body_key="campaignId", | ||
required=True, | ||
) | ||
set_value( | ||
env_key="PERSONALIZATION_VALUES", | ||
body_key="personalizationValues", | ||
required=False, | ||
) | ||
set_value( | ||
env_key="METADATA", | ||
body_key="metadata", | ||
required=False, | ||
json_loads=False, | ||
) | ||
set_value( | ||
env_key="ATTACHMENTS", | ||
body_key="attachments", | ||
required=False, | ||
) | ||
|
||
return body | ||
|
||
|
||
def send_email(region: str, auth: str, timeout: int, body: JsonBody): | ||
"""Sends the email. | ||
Args: | ||
region: The API region to use. | ||
auth: The authorization header used to authenticate with the API. | ||
timeout: The number of seconds to wait before the request times out. | ||
body: The request's JSON body. | ||
""" | ||
|
||
response = requests.post( | ||
url=f"https://{region}-api.dotdigital.com/v2/email/triggered-campaign", | ||
json=body, | ||
headers={ | ||
"accept": "text/plain", | ||
"authorization": auth, | ||
}, | ||
timeout=timeout, | ||
) | ||
|
||
assert response.ok, response.json() | ||
|
||
|
||
def main(): | ||
"""Entry point.""" | ||
|
||
region, auth, timeout = get_settings() | ||
|
||
body = get_json_body() | ||
|
||
send_email(region, auth, timeout, body) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
name: "Code for Life - Email - Send" | ||
description: "Using DotDigital, send a transactional email using a triggered campaign as its content." | ||
inputs: | ||
region: | ||
description: "The Dotdigital region id your account belongs to e.g. r1, r2 or r3." | ||
required: true | ||
default: "r1" | ||
auth: | ||
description: "The authorization header used to authenticate with the api." | ||
required: true | ||
timeout: | ||
description: "The number of seconds to wait for a response before timing out." | ||
required: true | ||
default: "60" | ||
to-addresses: | ||
description: "The email address(es) to send to." | ||
required: true | ||
cc-addresses: | ||
description: "The CC email address or address to to send to. separate email addresses with a comma. Maximum: 100." | ||
required: false | ||
bcc-addresses: | ||
description: "The BCC email address or address to to send to. separate email addresses with a comma. Maximum: 100." | ||
required: false | ||
from-address: | ||
description: "The From address for your email. Note: The From address must already be added to your account. Otherwise, your account's default From address is used." | ||
required: false | ||
campaign-id: | ||
description: "The ID of the triggered campaign, which needs to be included within the request body." | ||
required: true | ||
personalization-values: | ||
description: "Each personalisation value is a key-value pair; the placeholder name of the personalization value needs to be included in the request body." | ||
required: false | ||
metadata: | ||
description: "The metadata for your email. It can be either a single value or a series of values in a JSON object." | ||
required: false | ||
attachments: | ||
description: "A Base64 encoded string. All attachment types are supported. Maximum file size: 15 MB." | ||
required: false | ||
runs: | ||
using: composite | ||
steps: | ||
- uses: ocadotechnology/codeforlife-workspace/.github/actions/python/setup-environment@main | ||
with: | ||
python-version: 3.11 | ||
working-directory: ${{ github.action_path }} | ||
|
||
- name: 📧 Send Email | ||
shell: bash | ||
working-directory: ${{ github.action_path }} | ||
run: pipenv run python . | ||
env: | ||
REGION: ${{ inputs.region }} | ||
AUTH: ${{ inputs.auth }} | ||
TIMEOUT: ${{ inputs.timeout }} | ||
TO_ADDRESSES: ${{ inputs.to-addresses }} | ||
CC_ADDRESSES: ${{ inputs.cc-addresses }} | ||
BCC_ADDRESSES: ${{ inputs.bcc-addresses }} | ||
FROM_ADDRESS: ${{ inputs.from-address }} | ||
CAMPAIGN_ID: ${{ inputs.campaign-id }} | ||
PERSONALIZATION_VALUES: ${{ inputs.personalization-values }} | ||
METADATA: ${{ inputs.metadata }} | ||
ATTACHMENTS: ${{ inputs.attachments }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
name: "Code for Life - Python - Setup Environment" | ||
description: "Set up a python environment." | ||
inputs: | ||
checkout: | ||
description: "A flag to designate if the code should be checked out." | ||
required: true | ||
default: "true" | ||
python-version: | ||
description: "The python version to set up." | ||
required: true | ||
default: "3.8" | ||
working-directory: | ||
description: "The current working directory." | ||
required: true | ||
default: "." | ||
install-args: | ||
description: "Arguments to pass to pipenv install." | ||
required: false | ||
runs: | ||
using: composite | ||
steps: | ||
- name: 🛫 Checkout | ||
if: ${{ inputs.checkout == 'true' }} | ||
uses: actions/checkout@v4 | ||
|
||
- name: 🐍 Set up Python ${{ inputs.python-version }} | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ inputs.python-version }} | ||
|
||
- name: ⬆️ Upgrade pip | ||
shell: bash | ||
run: python -m pip install --upgrade pip | ||
|
||
- name: 🛠 Install pipenv | ||
shell: bash | ||
run: python -m pip install pipenv | ||
|
||
- name: 🛠 Install Dependencies | ||
shell: bash | ||
working-directory: ${{ inputs.working-directory }} | ||
run: pipenv install ${{ inputs.install-args }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[[source]] | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
name = "pypi" | ||
|
||
[packages] | ||
|
||
[dev-packages] | ||
black = "==23.1.0" | ||
pytest = "==7.2.1" | ||
mypy = "==1.6.1" | ||
pylint = "==3.0.2" | ||
|
||
[requires] | ||
python_version = "3.11" |
Oops, something went wrong.