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

List users email #446

Merged
merged 7 commits into from
Aug 22, 2023
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
7 changes: 6 additions & 1 deletion .circleci/docker-compose.test-prod-db.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ version: '3'

services:
db:
image: postgres:latest
# Latest postgres docker image uses the new Debian bookworm and it is incompatible with some
# existing docker implementations. CircleCI runs one of those older implementations.
# Pinning the image to N-bullseye (prior Debian distribution) as a workaround.
# https://github.com/docker-library/postgres/issues/1100
# image: postgres:latest
image: postgres:12-bullseye
expose:
- "5432"
environment:
Expand Down
7 changes: 6 additions & 1 deletion .circleci/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ services:
POSTGRES_PASSWORD: scionlab_rw_passw0rd

coord-db:
image: postgres:latest
# Latest postgres docker image uses the new Debian bookworm and it is incompatible with some
# existing docker implementations. CircleCI runs one of those older implementations.
# Pinning the image to N-bullseye (prior Debian distribution) as a workaround.
# https://github.com/docker-library/postgres/issues/1100
# image: postgres:latest
image: postgres:12-bullseye
networks:
- coord_net
expose:
Expand Down
110 changes: 110 additions & 0 deletions scionlab/management/commands/mass_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright 2023 ETH Zurich
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import sys

from typing import List
from django.conf import settings
from django.core.management.base import BaseCommand, CommandParser
from django.core.mail import EmailMessage

from scionlab.models.user import User


class Command(BaseCommand):
help = 'List or send a message to the unique emails of the users in alphabetical order'

def add_arguments(self, parser: CommandParser) -> None:
parser.add_argument('-a', '--action', type=str, required=True,
choices=['list', 'send'],
help='Action of the command: list or send')
parser.add_argument('--subject', type=str, required=False,
help='Subject of the email to send')
parser.add_argument('--body', type=argparse.FileType('r'), default='-',
help='Input file to read the body of the email from')
parser.add_argument('--skip_blocks', type=int, default=0,
help='skip N initial blocks of recipients. Useful to continue ' +
'sending after a crash')

def handle(self, *args, **kwargs):
action = kwargs['action']
if action == 'list':
self.list()
elif action == 'send':
self.send(**kwargs)

def list(self):
# print active users emails:
for email in self._obtain_active_emails():
print(email)

# report user stats:
inactive = []
active = []
for u in User.objects.all():
if not u.is_active:
inactive.append(u)
else:
active.append(u)
print(f'--------------------------- inactive: {len(inactive)}')
print(f'--------------------------- active: {len(active)}')

def send(self, **kwargs):
# retrieve the email parameters, or complain
if 'subject' not in kwargs or kwargs['subject'] is None:
exit('Need a subject')
subject = kwargs['subject']
if kwargs['body'] == sys.stdin:
print('Type the body of the email, end with ^D')
with kwargs['body'] as f:
body = f.read()
skip_blocks = kwargs['skip_blocks']

self._send(
subject=subject,
body=body,
skip_blocks=skip_blocks,
)

def _send(self, subject: str, body: str, skip_blocks: int):
recipients = self._obtain_active_emails()
block_count = (len(recipients) - 1) // settings.MAX_EMAIL_RECIPIENTS + 1
for b in range(skip_blocks, block_count):
# the recipients are a subset of the total
dest = recipients[
b*settings.MAX_EMAIL_RECIPIENTS:
(b + 1) * settings.MAX_EMAIL_RECIPIENTS]
# prepare the email and send it
msg = EmailMessage(
subject,
body,
settings.DEFAULT_FROM_EMAIL, # From
[], # To
bcc=dest,
)
msg.send()
print(f'sent {b+1}/{block_count} -> {dest}')
print('done')

def _obtain_active_emails(self) -> List[str]:
emails = User.objects.filter(
is_active=True,
).values_list('email', flat=True).order_by('email').distinct()
return emails


def exit(msg: str):
print(msg)
sys.exit(1)
3 changes: 3 additions & 0 deletions scionlab/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ class VPNKeygenConf:
# Location of the scion-pki command to generate TRCs.
SCION_PKI_COMMAND = os.path.join(BASE_DIR, 'static_bin', 'scion-pki')

# Maximum number of recipients that the SMTP server we have can handle at once.
MAX_EMAIL_RECIPIENTS = 100

# ##### DEBUG CONFIGURATION ###############################
ALLOWED_HOSTS = []
DEBUG = False
Expand Down