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..e76a218 --- /dev/null +++ b/ttadmin/common/mailing.py @@ -0,0 +1,32 @@ +import logging + +import requests + +from django.conf import settings + +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( + settings.MAILGUN_URL, + auth=('api', settings.MAILGUN_KEY), + data={ + 'from': frum, + 'to': to, + 'subject': subject, + 'text': body + } + ) + + success = response.status_code == 200 + + if not success: + logger.error('{}: failed to send email "{}" to {}'.format( + response.status_code, + subject, + to)) + + return success 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" diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index 3212471..2ff3ce9 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -9,9 +9,20 @@ admin.site.unregister(Group) class PubkeyInline(admin.TabularInline): model = Pubkey + extra = 1 + +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') + list_display = ('username', 'reviewed', 'email') ordering = ('reviewed',) + exclude = ('first_name', 'last_name', 'password', 'groups', 'user_permissions', 'last_login') + actions = (bulk_review,) + search_fields = ('username', 'email', 'displayname') 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}}