Skip to content

Commit c07646d

Browse files
committed
Command contact_owners: add support to filter by usernames
Add `--usernames` argument to be able to filter by usernames when sending contacting users. This can be used as: ``` django-admin contact_owners --notification notification.md --sticky --usernames usernames.txt ``` ``` humitos santos anthony ``` ``` Read the Docs is going to force email verification to be able to login accounts in the following weeks. We've noticed **your account doesn't have any email verified**. Please, go to [your email settings](/accounts/email/) and verify your email now. ``` In this case, it will send a sticky notification with that content to these 3 users. Required by #9865
1 parent fef866e commit c07646d

File tree

1 file changed

+39
-15
lines changed

1 file changed

+39
-15
lines changed

readthedocs/core/management/commands/contact_owners.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import structlog
21
import sys
32
from pathlib import Path
43
from pprint import pprint
54

5+
import structlog
66
from django.conf import settings
77
from django.contrib.auth import get_user_model
88
from django.core.management.base import BaseCommand
@@ -31,10 +31,16 @@ class Command(BaseCommand):
3131
3232
Email and send an ephemeral (disappears after shown once) notification to all owners of the "readthedocs" organization::
3333
34-
django-admin contact_owners --email email.md --notification notification.md --organization readthedocs # noqa
34+
django-admin contact_owners --email email.md --notification notification.md --organization readthedocs
35+
36+
Send a sticky notifications to multiple users::
3537
36-
Where ``email.md`` is a markdown file with the first line as the subject, and the rest is the content.
37-
``user`` and ``domain`` are available in the context.
38+
django-admin contact_owners --notification notification.md --sticky --usernames usernames.txt
39+
40+
* ``usernames.txt`` is a text file containing one username per line.
41+
* ``notifications.md`` is a Markdown file containing the message to be included in the notification.
42+
* ``email.md`` is a Markdown file with the first line as the subject, and the rest is the content.
43+
Note that ``user`` and ``domain`` are available in the context.
3844
3945
.. code:: markdown
4046
@@ -50,7 +56,7 @@ class Command(BaseCommand):
5056
add the ``--production`` flag to actually send the email/notification.
5157
"""
5258

53-
help = 'Send an email or sticky notification from a file (markdown) to all owners.'
59+
help = "Send an email or sticky notification from a file (Markdown) to users."
5460

5561
def add_arguments(self, parser):
5662
parser.add_argument(
@@ -92,16 +98,24 @@ def add_arguments(self, parser):
9298
'--project',
9399
help='Project slug to filter by.',
94100
)
101+
parser.add_argument(
102+
"--usernames",
103+
help="Path to a file with the one username per line to filter by.",
104+
)
95105

96106
def handle(self, *args, **options):
97107
if not options['email'] and not options['notification']:
98108
print("--email or --notification is required.")
99109
sys.exit(1)
100110

101-
project = options['project']
102-
organization = options['organization']
103-
if project and organization:
104-
print("--project and --organization can\'t be used together.")
111+
project = options["project"]
112+
organization = options["organization"]
113+
usernames = options["usernames"]
114+
if (
115+
len([item for item in [project, organization, usernames] if bool(item)])
116+
>= 2
117+
):
118+
print("--project, --organization and --usernames can't be used together.")
105119
sys.exit(1)
106120

107121
if project:
@@ -116,6 +130,15 @@ def handle(self, *args, **options):
116130
.filter(organizationowner__organization__disabled=False)
117131
.distinct()
118132
)
133+
elif usernames:
134+
file = Path(usernames)
135+
with file.open() as f:
136+
usernames = f.readlines()
137+
138+
# remove "\n" from lines
139+
usernames = [line.strip() for line in usernames]
140+
141+
users = User.objects.filter(username__in=usernames)
119142
else:
120143
users = (
121144
User.objects
@@ -124,16 +147,17 @@ def handle(self, *args, **options):
124147
)
125148

126149
print(
127-
'len(owners)={} production={} email={} notification={}'.format(
150+
"len(owners)={} production={} email={} notification={} sticky={}".format(
128151
users.count(),
129-
bool(options['production']),
130-
options['email'],
131-
options['notification'],
152+
bool(options["production"]),
153+
options["email"],
154+
options["notification"],
155+
options["sticky"],
132156
)
133157
)
134158

135-
if input('Continue? y/n: ') != 'y':
136-
print('Aborting run.')
159+
if input("Continue? y/N: ") != "y":
160+
print("Aborting run.")
137161
return
138162

139163
notification_content = ''

0 commit comments

Comments
 (0)