From 756fffa3d814fc3cf73964d615744e9660a57522 Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Thu, 19 Jan 2017 23:41:57 -0800 Subject: [PATCH 1/7] note about mailgun --- ttadmin/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ttadmin/settings.py b/ttadmin/settings.py index 2212071..205312b 100644 --- a/ttadmin/settings.py +++ b/ttadmin/settings.py @@ -6,6 +6,7 @@ To run this For Real, you'll want to: * set a different SECRET_KEY * change the password for the database or delete the password and use ident * change DEBUG to False + * set mailgun api info """ import os @@ -99,3 +100,6 @@ STATIC_URL = '/static/' # Not used during local development, but used in staging+live environments STATIC_ROOT = 'static' + +MAILGUN_URL = "OVERWRITE THIS" +MAILGUN_KEY = "OVERWRITE THIS" From 7d2417814893a083994d30e60b4003144a69987a Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Fri, 20 Jan 2017 00:40:18 -0800 Subject: [PATCH 2/7] totally untested email function --- setup.py | 3 ++- ttadmin/common/mailing.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 ttadmin/common/mailing.py diff --git a/setup.py b/setup.py index 494e73d..68f1f0c 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ setup( packages=['ttadmin'], install_requires = ['Django==1.10.2', 'sshpubkeys==2.2.0', - 'psycopg2==2.6.2',], + 'psycopg2==2.6.2', + 'requests==2.12.5'], include_package_data = True, ) diff --git a/ttadmin/common/mailing.py b/ttadmin/common/mailing.py new file mode 100644 index 0000000..faab1c1 --- /dev/null +++ b/ttadmin/common/mailing.py @@ -0,0 +1,25 @@ +import logging + +import requests + +from django.conf.settings import MAILGUN_URL, MAILGUN_KEY + +logger = logging.getLogger() + +FROM='root@tilde.town' + +def send_email(to, body, subject='a message from tilde.town', frum=FROM,): + """Sends an email using mailgun. Logs on failure.""" + response = requests.post( + MAILGUN_URL, + auth=('api', MAILGUN_KEY), + data={ + 'from': frum, + 'to': to, + 'subject': subject, + 'text': body + } + ) + + if response.status_code != 200: + logger.error('failed to send email "{}" to {}'.format(subject, to)) From cecc9deeb49aca90a1b7232390b58a47040a1092 Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Fri, 20 Jan 2017 22:53:17 -0800 Subject: [PATCH 3/7] fix email function --- ttadmin/common/mailing.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ttadmin/common/mailing.py b/ttadmin/common/mailing.py index faab1c1..677218c 100644 --- a/ttadmin/common/mailing.py +++ b/ttadmin/common/mailing.py @@ -2,7 +2,7 @@ import logging import requests -from django.conf.settings import MAILGUN_URL, MAILGUN_KEY +from django.conf import settings logger = logging.getLogger() @@ -11,8 +11,8 @@ FROM='root@tilde.town' def send_email(to, body, subject='a message from tilde.town', frum=FROM,): """Sends an email using mailgun. Logs on failure.""" response = requests.post( - MAILGUN_URL, - auth=('api', MAILGUN_KEY), + settings.MAILGUN_URL, + auth=('api', settings.MAILGUN_KEY), data={ 'from': frum, 'to': to, @@ -22,4 +22,7 @@ def send_email(to, body, subject='a message from tilde.town', frum=FROM,): ) if response.status_code != 200: - logger.error('failed to send email "{}" to {}'.format(subject, to)) + logger.error('{}: failed to send email "{}" to {}'.format( + response.status_code, + subject, + to)) From 1a111be0d59075736d7396114af6a168f0584c06 Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Sat, 21 Jan 2017 00:34:17 -0800 Subject: [PATCH 4/7] signal email sending success --- ttadmin/common/mailing.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ttadmin/common/mailing.py b/ttadmin/common/mailing.py index 677218c..e76a218 100644 --- a/ttadmin/common/mailing.py +++ b/ttadmin/common/mailing.py @@ -21,8 +21,12 @@ def send_email(to, body, subject='a message from tilde.town', frum=FROM,): } ) - if response.status_code != 200: + success = response.status_code == 200 + + if not success: logger.error('{}: failed to send email "{}" to {}'.format( response.status_code, subject, to)) + + return success From ba05ec340cbfa43c8793c743a6f964c4fdded49c Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Sat, 21 Jan 2017 00:35:00 -0800 Subject: [PATCH 5/7] implement user welcome emails emails trigger when they're marked as reviewed --- ttadmin/users/admin.py | 8 ++++ ttadmin/users/models.py | 43 ++++++++++++------- .../users/templates/users/welcome_email.txt | 13 ++++++ 3 files changed, 48 insertions(+), 16 deletions(-) create mode 100644 ttadmin/users/templates/users/welcome_email.txt diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index 3212471..899e6a0 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -10,8 +10,16 @@ admin.site.unregister(Group) class PubkeyInline(admin.TabularInline): model = Pubkey +def bulk_review(madmin, req, qs): + for townie in qs: + townie.reviewed = True + townie.save() + +bulk_review.short_description = 'mark selected townies as reviewed' + @admin.register(Townie) class TownieAdmin(admin.ModelAdmin): inlines = [PubkeyInline] list_display = ('reviewed', 'username', 'email') ordering = ('reviewed',) + actions = (bulk_review,) diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 3bf5aeb..af1b6cc 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -1,11 +1,14 @@ import re from django.db.models import Model -from django.db.models.signals import post_save +from django.db.models.signals import pre_save from django.dispatch import receiver from django.contrib.auth.models import User from django.db.models import TextField, BooleanField, CharField, ForeignKey +from django.template.loader import get_template +from common.mailing import send_email +from help.models import Ticket SSH_TYPE_CHOICES = ( ('ssh-rsa', 'ssh-rsa',), @@ -24,14 +27,22 @@ class Townie(User): reasons = TextField(blank=True, null=False, default='') displayname = CharField(max_length=100, blank=False, null=False) - # TODO consider a generic ensure method that syncs this model with the - # system. there will likely be things besides shell that we want to keep - # track of in the DB. - def ensure_shell(self): - """Runs chsh for the user to set their shell to whatever self.shell - is.""" - raise NotImplementedError() - + def send_welcome_email(self, admin_name='vilmibm'): + welcome_tmpl = get_template('users/welcome_email.txt') + context = { + 'username': self.username, + 'admin_name': admin_name, + } + text = welcome_tmpl.render(context) + from_address = '{}@tilde.town'.format(admin_name) + success = send_email(self.email, text, subject='tilde.town!', frum=from_address) + if not success: + Ticket.objects.create(name='system', + email='root@tilde.town', + issue_type='other', + issue_text='was not able to send welcome email to {} ({})'.format( + self.username, + self.email)) class Pubkey(Model): key_type = CharField(max_length=50, @@ -43,11 +54,11 @@ class Pubkey(Model): townie = ForeignKey(Townie) -@receiver(post_save, sender=Townie) -def sync_system_state(sender, instance, created, **kwargs): - if created: - print('TODO would create new user on system') - else: - print('TODO would update existing user on system') +@receiver(pre_save, sender=Townie) +def on_townie_pre_save(sender, instance, **kwargs): + existing = Townie.objects.filter(username=instance.username) + if not existing: # we're making a new user + return - return + if not existing[0].reviewed and instance.reviewed == True: + instance.send_welcome_email() diff --git a/ttadmin/users/templates/users/welcome_email.txt b/ttadmin/users/templates/users/welcome_email.txt new file mode 100644 index 0000000..b782a20 --- /dev/null +++ b/ttadmin/users/templates/users/welcome_email.txt @@ -0,0 +1,13 @@ +Welcome to tilde.town, ~{{username}}! + +Please take a moment to review our code of conduct: https://tilde.town/~wiki/conduct.html + +and login with: + +ssh -i /path/to/private/key {{username}}@tilde.town + +File a help ticket if you have problems logging in (or other issues): https://cgi.tilde.town/help/tickets + +See you on the server!! + +~{{admin_name}} From 5532ee7745e7cbf96c7f2927961adf3a2430da13 Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Sat, 21 Jan 2017 01:06:35 -0800 Subject: [PATCH 6/7] clean up townie admin some --- ttadmin/users/admin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index 899e6a0..5be424b 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -9,6 +9,7 @@ admin.site.unregister(Group) class PubkeyInline(admin.TabularInline): model = Pubkey + extra = 1 def bulk_review(madmin, req, qs): for townie in qs: @@ -20,6 +21,7 @@ bulk_review.short_description = 'mark selected townies as reviewed' @admin.register(Townie) class TownieAdmin(admin.ModelAdmin): inlines = [PubkeyInline] - list_display = ('reviewed', 'username', 'email') + list_display = ('username', 'reviewed', 'email') ordering = ('reviewed',) + exclude = ('first_name', 'last_name', 'password', 'groups', 'user_permissions', 'last_login') actions = (bulk_review,) From 2b46bef4609422191707c0baabb5f229c078cbe2 Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Sat, 21 Jan 2017 01:25:02 -0800 Subject: [PATCH 7/7] add search fields for townie --- ttadmin/users/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index 5be424b..2ff3ce9 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -25,3 +25,4 @@ class TownieAdmin(admin.ModelAdmin): ordering = ('reviewed',) exclude = ('first_name', 'last_name', 'password', 'groups', 'user_permissions', 'last_login') actions = (bulk_review,) + search_fields = ('username', 'email', 'displayname')