mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-12-22 10:29:59 +00:00
Update email verification, add Mailgun backend (#380)
Changes config.example.py!
This commit is contained in:
parent
19eaa2c532
commit
6d09920abd
|
@ -19,6 +19,8 @@ MAINTENANCE_MODE_LOGINS = True
|
|||
|
||||
# What the site identifies itself as. This affects templates, not database stuff.
|
||||
SITE_NAME = 'Nyaa'
|
||||
# What the both sites are labeled under (used for eg. email subjects)
|
||||
GLOBAL_SITE_NAME = 'Nyaa.si'
|
||||
|
||||
# General prefix for running multiple sites, eg. most database tables are site-prefixed
|
||||
SITE_FLAVOR = 'nyaa' # 'nyaa' or 'sukebei'
|
||||
|
@ -49,13 +51,25 @@ else:
|
|||
SQLALCHEMY_DATABASE_URI = (
|
||||
'sqlite:///' + os.path.join(BASE_DIR, 'test.db') + '?check_same_thread=False')
|
||||
|
||||
# Email server settings
|
||||
###########
|
||||
## EMAIL ##
|
||||
###########
|
||||
|
||||
# 'smtp' or 'mailgun'
|
||||
MAIL_BACKEND = 'mailgun'
|
||||
MAIL_FROM_ADDRESS = 'Sender Name <sender@domain.com>'
|
||||
|
||||
# Mailgun settings
|
||||
MAILGUN_API_BASE = 'https://api.mailgun.net/v3/YOUR_DOMAIN_NAME'
|
||||
MAILGUN_API_KEY = 'YOUR_API_KEY'
|
||||
|
||||
# SMTP settings
|
||||
SMTP_SERVER = '***'
|
||||
SMTP_PORT = 587
|
||||
MAIL_FROM_ADDRESS = '***'
|
||||
SMTP_USERNAME = '***'
|
||||
SMTP_PASSWORD = '***'
|
||||
|
||||
|
||||
# The maximum number of files a torrent can contain
|
||||
# until the site says "Too many files to display."
|
||||
MAX_FILES_VIEW = 1000
|
||||
|
|
83
nyaa/email.py
Normal file
83
nyaa/email.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from flask import current_app as app
|
||||
|
||||
import requests
|
||||
|
||||
from nyaa import models
|
||||
|
||||
|
||||
class EmailHolder(object):
|
||||
''' Holds email subject, recipient and content, so we have a general class for
|
||||
all mail backends. '''
|
||||
def __init__(self, subject=None, recipient=None, text=None, html=None):
|
||||
self.subject = subject
|
||||
self.recipient = recipient # models.User or string
|
||||
self.text = text
|
||||
self.html = html
|
||||
|
||||
def format_recipient(self):
|
||||
if isinstance(self.recipient, models.User):
|
||||
return '{} <{}>'.format(self.recipient.username, self.recipient.email)
|
||||
else:
|
||||
return self.recipient
|
||||
|
||||
def recipient_email(self):
|
||||
if isinstance(self.recipient, models.User):
|
||||
return self.recipient.email
|
||||
else:
|
||||
return self.recipient.email
|
||||
|
||||
def as_mimemultipart(self):
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = self.subject
|
||||
msg['From'] = app.config['MAIL_FROM_ADDRESS']
|
||||
msg['To'] = self.format_recipient()
|
||||
|
||||
msg.attach(MIMEText(self.text, 'plain'))
|
||||
if self.html:
|
||||
msg.attach(MIMEText(self.html, 'html'))
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def send_email(email_holder):
|
||||
mail_backend = app.config.get('MAIL_BACKEND')
|
||||
if mail_backend == 'mailgun':
|
||||
_send_mailgun(email_holder)
|
||||
elif mail_backend == 'smtp':
|
||||
_send_smtp(email_holder)
|
||||
elif mail_backend:
|
||||
# TODO: Do this in logging.error when we have that set up
|
||||
print('Unknown mail backend:', mail_backend)
|
||||
|
||||
|
||||
def _send_mailgun(email_holder):
|
||||
mailgun_endpoint = app.config['MAILGUN_API_BASE'] + '/messages'
|
||||
auth = ('api', app.config['MAILGUN_API_KEY'])
|
||||
data = {
|
||||
'from': app.config['MAIL_FROM_ADDRESS'],
|
||||
'to': email_holder.format_recipient(),
|
||||
'subject': email_holder.subject,
|
||||
'text': email_holder.text,
|
||||
'html': email_holder.html
|
||||
}
|
||||
r = requests.post(mailgun_endpoint, data=data, auth=auth)
|
||||
# TODO real error handling?
|
||||
assert r.status_code == 200
|
||||
|
||||
|
||||
def _send_smtp(email_holder):
|
||||
# NOTE: Unused, most likely untested! Should work, however.
|
||||
msg = email_holder.as_mimemultipart()
|
||||
|
||||
server = smtplib.SMTP(app.config['SMTP_SERVER'], app.config['SMTP_PORT'])
|
||||
server.set_debuglevel(1)
|
||||
server.ehlo()
|
||||
server.starttls()
|
||||
server.ehlo()
|
||||
server.login(app.config['SMTP_USERNAME'], app.config['SMTP_PASSWORD'])
|
||||
server.sendmail(app.config['SMTP_USERNAME'], email_holder.recipient_email(), msg.as_string())
|
||||
server.quit()
|
24
nyaa/templates/email/verify.html
Normal file
24
nyaa/templates/email/verify.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Verify your {{ config.GLOBAL_SITE_NAME }} account</title>
|
||||
<style type="text/css">
|
||||
.well {
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
background-color: rgb(240, 240, 240)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
{{ user.username }}, please verify your email by clicking the link below:
|
||||
</div>
|
||||
<div class="well">
|
||||
<a href="{{ activation_link }}">{{ activation_link }}</a>
|
||||
</div>
|
||||
<div>
|
||||
If you did not sign up for {{ config.GLOBAL_SITE_NAME }}, feel free to ignore this email.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
6
nyaa/templates/email/verify.txt
Normal file
6
nyaa/templates/email/verify.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
{{ user.username }}, please verify your email by clicking the link below:
|
||||
|
||||
{{ activation_link }}
|
||||
(if you can't click on the link, copy and paste it to your browser's address bar)
|
||||
|
||||
If you did not sign up for {{ config.GLOBAL_SITE_NAME }}, feel free to ignore this email.
|
|
@ -1,12 +1,9 @@
|
|||
import smtplib
|
||||
from datetime import datetime
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from ipaddress import ip_address
|
||||
|
||||
import flask
|
||||
|
||||
from nyaa import forms, models
|
||||
from nyaa import email, forms, models
|
||||
from nyaa.extensions import db
|
||||
from nyaa.views.users import get_activation_link
|
||||
|
||||
|
@ -83,8 +80,7 @@ def register():
|
|||
db.session.commit()
|
||||
|
||||
if app.config['USE_EMAIL_VERIFICATION']: # force verification, enable email
|
||||
activ_link = get_activation_link(user)
|
||||
send_verification_email(user.email, activ_link)
|
||||
send_verification_email(user)
|
||||
return flask.render_template('waiting.html')
|
||||
else: # disable verification, set user as active and auto log in
|
||||
user.status = models.UserStatusType.ACTIVE
|
||||
|
@ -150,25 +146,19 @@ def redirect_url():
|
|||
return url
|
||||
|
||||
|
||||
def send_verification_email(to_address, activ_link):
|
||||
''' this is until we have our own mail server, obviously.
|
||||
This can be greatly cut down if on same machine.
|
||||
probably can get rid of all but msg formatting/building,
|
||||
init line and sendmail line if local SMTP server '''
|
||||
def send_verification_email(user):
|
||||
activation_link = get_activation_link(user)
|
||||
|
||||
msg_body = 'Please click on: ' + activ_link + ' to activate your account.\n\n\nUnsubscribe:'
|
||||
tmpl_context = {
|
||||
'activation_link': activation_link,
|
||||
'user': user
|
||||
}
|
||||
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = 'Verification Link'
|
||||
msg['From'] = app.config['MAIL_FROM_ADDRESS']
|
||||
msg['To'] = to_address
|
||||
msg.attach(MIMEText(msg_body, 'plain'))
|
||||
email_msg = email.EmailHolder(
|
||||
subject='Verify your {} account'.format(app.config['GLOBAL_SITE_NAME']),
|
||||
recipient=user,
|
||||
text=flask.render_template('email/verify.txt', **tmpl_context),
|
||||
html=flask.render_template('email/verify.html', **tmpl_context),
|
||||
)
|
||||
|
||||
server = smtplib.SMTP(app.config['SMTP_SERVER'], app.config['SMTP_PORT'])
|
||||
server.set_debuglevel(1)
|
||||
server.ehlo()
|
||||
server.starttls()
|
||||
server.ehlo()
|
||||
server.login(app.config['SMTP_USERNAME'], app.config['SMTP_PASSWORD'])
|
||||
server.sendmail(app.config['SMTP_USERNAME'], to_address, msg.as_string())
|
||||
server.quit()
|
||||
email.send_email(email_msg)
|
||||
|
|
|
@ -202,15 +202,23 @@ def activate_user(payload):
|
|||
|
||||
user = models.User.by_id(user_id)
|
||||
|
||||
if not user:
|
||||
# Only allow activating inactive users
|
||||
if not user or user.status != models.UserStatusType.INACTIVE:
|
||||
flask.abort(404)
|
||||
|
||||
# Set user active
|
||||
user.status = models.UserStatusType.ACTIVE
|
||||
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
return flask.redirect(flask.url_for('account.login'))
|
||||
# Log user in
|
||||
flask.g.user = user
|
||||
flask.session['user_id'] = user.id
|
||||
flask.session.permanent = True
|
||||
flask.session.modified = True
|
||||
|
||||
flask.flash(flask.Markup("You've successfully verified your account!"), 'success')
|
||||
return flask.redirect(flask.url_for('main.home'))
|
||||
|
||||
|
||||
def _create_user_class_choices(user):
|
||||
|
|
|
@ -41,6 +41,7 @@ pytest==3.1.1
|
|||
python-dateutil==2.6.0
|
||||
python-editor==1.0.3
|
||||
python-utils==2.1.0
|
||||
requests==2.18.4
|
||||
six==1.10.0
|
||||
SQLAlchemy==1.1.10
|
||||
SQLAlchemy-FullText-Search==0.2.3
|
||||
|
|
Loading…
Reference in a new issue