diff --git a/app.py b/app.py
index 3f72d3cd0..ea52822ee 100644
--- a/app.py
+++ b/app.py
@@ -3,15 +3,19 @@ import logging
from flask import Flask
from flask.ext.principal import Principal
from flask.ext.login import LoginManager
-
+from flask.ext.mail import Mail
+from config import ProductionConfig
app = Flask(__name__)
+app.config.from_object(ProductionConfig())
+
logger = logging.getLogger(__name__)
Principal(app, use_sessions=True)
-app.secret_key = '1cb18882-6d12-440d-a4cc-b7430fb5f884'
-
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'signin'
+
+mail = Mail()
+mail.init_app(app)
diff --git a/config.py b/config.py
new file mode 100644
index 000000000..fdb96fdf9
--- /dev/null
+++ b/config.py
@@ -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
\ No newline at end of file
diff --git a/data/database.py b/data/database.py
index c8c5aab5a..50ca6055a 100644
--- a/data/database.py
+++ b/data/database.py
@@ -66,6 +66,14 @@ class AccessToken(BaseModel):
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):
# This class is intentionally denormalized. Even though images are supposed
# to be globally unique we can't treat them as such for permissions and
diff --git a/data/model.py b/data/model.py
index ec9d85bb8..24f1279b7 100644
--- a/data/model.py
+++ b/data/model.py
@@ -28,9 +28,14 @@ def create_user(username, password, email):
try:
new_user = User.create(username=username, password_hash=pw_hash,
email=email)
+ return new_user
except Exception as ex:
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):
diff --git a/endpoints/index.py b/endpoints/index.py
index 8a02c70bd..4fb52cb7f 100644
--- a/endpoints/index.py
+++ b/endpoints/index.py
@@ -11,6 +11,7 @@ from app import app
from auth.auth import (process_auth, get_authenticated_user,
get_validated_token)
from util.names import parse_namespace_repository, parse_repository_name
+from util.email import send_confirmation_email
from auth.permissions import (ModifyRepositoryPermission,
ReadRepositoryPermission, UserPermission)
@@ -46,8 +47,10 @@ def generate_headers(f):
@app.route('/v1/users/', methods=['POST'])
def create_user():
user_data = request.get_json()
- model.create_user(user_data['username'], user_data['password'],
- user_data['email'])
+ new_user = model.create_user(user_data['username'], user_data['password'],
+ 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)
diff --git a/endpoints/web.py b/endpoints/web.py
index c7564bb1f..c2a549b5d 100644
--- a/endpoints/web.py
+++ b/endpoints/web.py
@@ -56,6 +56,16 @@ def signin():
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'])
def render_signin_page():
return send_file('templates/signin.html')
diff --git a/requirements.txt b/requirements.txt
index 9b80bab6d..560d03df5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,4 +2,5 @@ peewee
flask
py-bcrypt
Flask-Principal
-Flask-Login
\ No newline at end of file
+Flask-Login
+Flask-Mail
\ No newline at end of file
diff --git a/util/email.py b/util/email.py
new file mode 100644
index 000000000..2d7dc950e
--- /dev/null
+++ b/util/email.py
@@ -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 Quay.io.
+
+To confirm this email address, please click the following link:
+http://quay.io/confirm?token=%s
+"""
+
+
+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)