Send a confirmation email when an account is created. Links don't do anything yet.
This commit is contained in:
parent
87dc3b6344
commit
99341f7d53
8 changed files with 73 additions and 7 deletions
10
app.py
10
app.py
|
@ -3,15 +3,19 @@ import logging
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask.ext.principal import Principal
|
from flask.ext.principal import Principal
|
||||||
from flask.ext.login import LoginManager
|
from flask.ext.login import LoginManager
|
||||||
|
from flask.ext.mail import Mail
|
||||||
|
from config import ProductionConfig
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(ProductionConfig())
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
Principal(app, use_sessions=True)
|
Principal(app, use_sessions=True)
|
||||||
|
|
||||||
app.secret_key = '1cb18882-6d12-440d-a4cc-b7430fb5f884'
|
|
||||||
|
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
login_manager.init_app(app)
|
login_manager.init_app(app)
|
||||||
login_manager.login_view = 'signin'
|
login_manager.login_view = 'signin'
|
||||||
|
|
||||||
|
mail = Mail()
|
||||||
|
mail.init_app(app)
|
||||||
|
|
15
config.py
Normal file
15
config.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class FlaskConfig(object):
|
||||||
|
SECRET_KEY = '1cb18882-6d12-440d-a4cc-b7430fb5f884'
|
||||||
|
|
||||||
|
class MailConfig(object):
|
||||||
|
MAIL_SERVER = 'email-smtp.us-east-1.amazonaws.com'
|
||||||
|
MAIL_USE_TLS = True
|
||||||
|
MAIL_PORT = 587
|
||||||
|
MAIL_USERNAME = 'AKIAIXV5SDGCPVMU3N4Q'
|
||||||
|
MAIL_PASSWORD = 'AhmX/vWE91uQ2RtcEKTkfNrzZehEjPNXOXeOXgQNfLao'
|
||||||
|
DEFAULT_MAIL_SENDER = 'support@fluxmonkey.io'
|
||||||
|
MAIL_FAIL_SILENTLY = False
|
||||||
|
TESTING = False
|
||||||
|
|
||||||
|
class ProductionConfig(FlaskConfig, MailConfig):
|
||||||
|
pass
|
|
@ -66,6 +66,14 @@ class AccessToken(BaseModel):
|
||||||
created = DateTimeField(default=datetime.now)
|
created = DateTimeField(default=datetime.now)
|
||||||
|
|
||||||
|
|
||||||
|
class EmailConfirmation(BaseModel):
|
||||||
|
code = CharField(default=random_string_generator())
|
||||||
|
user = ForeignKeyField(User)
|
||||||
|
pw_reset = BooleanField(default=False)
|
||||||
|
email_confirm = BooleanField(default=False)
|
||||||
|
created = DateTimeField(default=datetime.now)
|
||||||
|
|
||||||
|
|
||||||
class Image(BaseModel):
|
class Image(BaseModel):
|
||||||
# This class is intentionally denormalized. Even though images are supposed
|
# This class is intentionally denormalized. Even though images are supposed
|
||||||
# to be globally unique we can't treat them as such for permissions and
|
# to be globally unique we can't treat them as such for permissions and
|
||||||
|
|
|
@ -28,9 +28,14 @@ def create_user(username, password, email):
|
||||||
try:
|
try:
|
||||||
new_user = User.create(username=username, password_hash=pw_hash,
|
new_user = User.create(username=username, password_hash=pw_hash,
|
||||||
email=email)
|
email=email)
|
||||||
|
return new_user
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
raise DataModelException(ex.message)
|
raise DataModelException(ex.message)
|
||||||
return new_user
|
|
||||||
|
|
||||||
|
def create_confirm_email_code(user):
|
||||||
|
code = EmailConfirmation(user=user, email_confirm=True)
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
def get_user(username):
|
def get_user(username):
|
||||||
|
|
|
@ -11,6 +11,7 @@ from app import app
|
||||||
from auth.auth import (process_auth, get_authenticated_user,
|
from auth.auth import (process_auth, get_authenticated_user,
|
||||||
get_validated_token)
|
get_validated_token)
|
||||||
from util.names import parse_namespace_repository, parse_repository_name
|
from util.names import parse_namespace_repository, parse_repository_name
|
||||||
|
from util.email import send_confirmation_email
|
||||||
from auth.permissions import (ModifyRepositoryPermission,
|
from auth.permissions import (ModifyRepositoryPermission,
|
||||||
ReadRepositoryPermission, UserPermission)
|
ReadRepositoryPermission, UserPermission)
|
||||||
|
|
||||||
|
@ -46,8 +47,10 @@ def generate_headers(f):
|
||||||
@app.route('/v1/users/', methods=['POST'])
|
@app.route('/v1/users/', methods=['POST'])
|
||||||
def create_user():
|
def create_user():
|
||||||
user_data = request.get_json()
|
user_data = request.get_json()
|
||||||
model.create_user(user_data['username'], user_data['password'],
|
new_user = model.create_user(user_data['username'], user_data['password'],
|
||||||
user_data['email'])
|
user_data['email'])
|
||||||
|
code = model.create_confirm_email_code(new_user)
|
||||||
|
send_confirmation_email(new_user.username, new_user.email, code.code)
|
||||||
return make_response('Created', 201)
|
return make_response('Created', 201)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,16 @@ def signin():
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/confirm', methods=['GET'])
|
||||||
|
def confirm_email():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/reset', methods=['GET'])
|
||||||
|
def password_reset():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@app.route('/signin', methods=['GET'])
|
@app.route('/signin', methods=['GET'])
|
||||||
def render_signin_page():
|
def render_signin_page():
|
||||||
return send_file('templates/signin.html')
|
return send_file('templates/signin.html')
|
||||||
|
|
|
@ -3,3 +3,4 @@ flask
|
||||||
py-bcrypt
|
py-bcrypt
|
||||||
Flask-Principal
|
Flask-Principal
|
||||||
Flask-Login
|
Flask-Login
|
||||||
|
Flask-Mail
|
20
util/email.py
Normal file
20
util/email.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from flask.ext.mail import Message
|
||||||
|
|
||||||
|
from app import mail, app
|
||||||
|
|
||||||
|
|
||||||
|
CONFIRM_MESSAGE = """
|
||||||
|
This email address was recently used to register the username '%s'
|
||||||
|
at <a href="http://quay.io">Quay.io</a>.<br>
|
||||||
|
<br>
|
||||||
|
To confirm this email address, please click the following link:<br>
|
||||||
|
<a href="http://quay.io/confirm?token=%s">http://quay.io/confirm?token=%s</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def send_confirmation_email(username, email, token):
|
||||||
|
msg = Message('Welcome to Quay! Please confirm your email.',
|
||||||
|
sender='support@fluxmonkey.io', # Why do I need this?
|
||||||
|
recipients=[email])
|
||||||
|
msg.html = CONFIRM_MESSAGE % (username, token, token)
|
||||||
|
mail.send(msg)
|
Reference in a new issue