-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This project is now feature-complete!
- Loading branch information
Showing
7 changed files
with
102 additions
and
9 deletions.
There are no files selected for viewing
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 |
---|---|---|
|
@@ -7,3 +7,6 @@ SMTP_HOST=smtp | |
SMTP_PORT=1025 | ||
SMTP_USERNAME=testuser | ||
SMTP_PASSWORD=testpass | ||
|
||
# Comma-separated list of Google Group keys (group's email address, group alias, or the unique group ID) | ||
GOOGLE_GROUPS_WHITELIST="[email protected]" |
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 |
---|---|---|
|
@@ -175,3 +175,4 @@ pyrightconfig.json | |
|
||
# End of https://www.toptal.com/developers/gitignore/api/python | ||
|
||
/secrets/* |
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 |
---|---|---|
@@ -1 +1,27 @@ | ||
This project is still under development. | ||
# mailing-list-gateway | ||
|
||
A simple service to ask for user confirmation before adding them to a mailing list. | ||
Currently, only Google Groups is supported. | ||
|
||
## Getting started | ||
|
||
1. Populate `.env` with your configuration. An example is provided in `.env.example`. The default configuration is suitable for development. | ||
|
||
```bash | ||
cp .env.example .env | ||
``` | ||
|
||
2. Obtain a Google Cloud Service Account key and save it as `./secrets/google-service-account.json`. | ||
1. [Create](https://console.cloud.google.com/projectcreate) a Google Cloud project. | ||
2. Create a service account under the project with no roles. | ||
3. In the [Google Admin console](https://admin.google.com/), give "Groups Editor" role to the service account. | ||
4. Enable the [Admin SDK API](https://console.cloud.google.com/apis/library/admin.googleapis.com) in the Google Cloud project. | ||
|
||
3. Start the service. | ||
|
||
```bash | ||
docker compose up --build | ||
``` | ||
|
||
Now, you can view the API spec at http://localhost:8000/docs. | ||
If you are using the default SMTP configuration, you can view outgoing emails at http://localhost:8025. |
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
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
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,49 @@ | ||
import logging | ||
import os.path | ||
|
||
from google.oauth2 import service_account | ||
from googleapiclient.discovery import build | ||
from googleapiclient.errors import HttpError | ||
|
||
SERVICE_ACCOUNT_FILE = "/secrets/google-service-account.json" | ||
SCOPES = [ | ||
# Required to get group: https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups/get | ||
"https://www.googleapis.com/auth/admin.directory.group.readonly", | ||
# Required to insert member: https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/insert | ||
"https://www.googleapis.com/auth/admin.directory.group.member", | ||
] | ||
|
||
GROUPS_WHITELIST = os.environ["GOOGLE_GROUPS_WHITELIST"].split(",") | ||
|
||
|
||
class DirectoryService: | ||
def __init__(self, logger=logging.getLogger(__name__)): | ||
credentials = service_account.Credentials.from_service_account_file( | ||
SERVICE_ACCOUNT_FILE, scopes=SCOPES | ||
) | ||
self.service = build("admin", "directory_v1", credentials=credentials) | ||
|
||
# Ensure we have permissions to access the groups | ||
for group_key in GROUPS_WHITELIST: | ||
self.get_group(group_key) | ||
|
||
self.logger = logger | ||
|
||
logger.info( | ||
f"DirectoryService initialized with groups whitelist: {GROUPS_WHITELIST}" | ||
) | ||
|
||
def get_group(self, group_key: str): | ||
return self.service.groups().get(groupKey=group_key).execute() | ||
|
||
def insert_member(self, group_key: str, email: str): | ||
try: | ||
self.service.members().insert(groupKey=group_key, body={"email": email}).execute() | ||
except HttpError as e: | ||
if e.resp.status == 409: | ||
self.logger.warning(f"Member {email} already exists in group {group_key}. Ignoring.") | ||
else: | ||
raise | ||
|
||
def is_whitelisted_group(self, group_key: str): | ||
return group_key in GROUPS_WHITELIST |
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