Commit c3e74361 authored by buttle's avatar buttle

Added per Site SMTP config

parent b16adaac
......@@ -31,8 +31,8 @@ babel = Babel(app)
csrf = CSRFProtect()
csrf.init_app(app)
app.config['APP_VERSION'] = 21
app.config['SCHEMA_VERSION'] = 10
app.config['APP_VERSION'] = 22
app.config['SCHEMA_VERSION'] = 11
app.config['RESERVED_SLUGS'] = ['static', 'admin', 'admins', 'user', 'users', 'form', 'forms', 'site', 'sites', 'update']
# DPL = Data Protection Law
......
......@@ -4,9 +4,6 @@ ROOT_USERS = ['[email protected]']
DEFAULT_LANGUAGE = 'en'
TMP_DIR = '/tmp'
## Your SMTP server
SMTP_SERVER = 'locahost'
## MongoDB config
MONGO_URI = "mongodb://localhost:27017/GNGforms"
......
......@@ -24,23 +24,33 @@ from GNGforms.persistence import Site
import smtplib, socket
def createSmtpObj():
config=g.site.data["smtpConfig"]
try:
smtpObj = smtplib.SMTP(app.config['SMTP_SERVER'])
return smtpObj
if config["encryption"] == "SSL":
server = smtplib.SMTP_SSL(config["host"], port=config["port"], timeout=2)
server.login(config["user"], config["password"])
else:
server = smtplib.SMTP(config["host"], port=config["port"])
if config["user"] and config["password"]:
server.login(config["user"], config["password"])
return server
except socket.error as e:
if g.isAdmin:
flash(gettext("Could not connect to SMTP server"), 'error')
flash(str(e), 'error')
return False
def sendMail(email, message):
smtpObj = createSmtpObj()
if smtpObj:
server = createSmtpObj()
if server:
try:
smtpObj.sendmail(Site().noreplyEmailAddress, email, message.encode('utf-8'))
header='To: ' + email + '\n' + 'From: ' + g.site.data["smtpConfig"]["noreplyAddress"] + '\n'
message=header + message
server.sendmail(g.site.data["smtpConfig"]["noreplyAddress"], email, message.encode('utf-8'))
return True
except:
pass
except Exception as e:
if g.isAdmin:
flash(str(e) , 'error')
return False
......@@ -48,7 +58,6 @@ def smtpSendConfirmEmail(user, newEmail=None):
link="%suser/validate-email/%s" % (Site().host_url, user.token['token'])
message=gettext("Hello %s\n\nPlease confirm your email\n\n%s") % (user.username, link)
message = 'Subject: {}\n\n{}'.format(gettext("GNGforms. Confirm email"), message)
if newEmail:
return sendMail(newEmail, message)
else:
......@@ -76,7 +85,6 @@ def smtpSendRecoverPassword(user):
def smtpSendNewFormEntryNotification(emails, entry, slug):
message=gettext("New form entry in %s at %s\n" % (slug, Site().hostname))
for data in entry:
print(data)
message="%s\n%s: %s" % (message, data[0], data[1])
message="%s\n" % message
......
......@@ -129,6 +129,20 @@ def migrateMongoSchema(schemaVersion):
schemaVersion=10
if schemaVersion < 11:
# Added smtp config per Site.
for site in mongo.db.sites.find():
smtpConfig={
"host": "smtp.%s" % site["hostname"],
"port": 25,
"encryption": "",
"user": "",
"password": "",
"noreplyAddress": site["noreplyEmailAddress"]
}
mongo.db.sites.update_one({"_id": site["_id"]}, {"$unset": {'noreplyEmailAddress' :1},"$set": {"smtpConfig": smtpConfig} })
schemaVersion=11
# this can't be a good migration setup :(
return schemaVersion
......@@ -644,8 +644,15 @@ class Site(object):
"blurb": blurb,
"invitationOnly": True,
"siteName": "gng-forms!",
"noreplyEmailAddress": "[email protected]%s" % hostname,
"personalDataConsent": {"markdown": "", "html": "", "enabled": False }
"personalDataConsent": {"markdown": "", "html": "", "enabled": False },
"smtpConfig": {
"host": "smtp.%s" % hostname,
"port": 25,
"encryption": "",
"user": "",
"password": "",
"noreplyAddress": "[email protected]%s" % hostname
}
}
mongo.db.sites.insert_one(newSiteData)
#create the Installation if it doesn't exist
......@@ -709,14 +716,9 @@ class Site(object):
def personalDataConsent(self):
return self.site['personalDataConsent']
@property
def noreplyEmailAddress(self):
return self.site['noreplyEmailAddress']
@noreplyEmailAddress.setter
def noreplyEmailAddress(self, email):
self.site["noreplyEmailAddress"] = email
mongo.db.sites.save(self.site)
def saveSMTPconfig(self, **kwargs):
self.site["smtpConfig"]=kwargs
self.save()
@property
def invitationOnly(self):
......
......@@ -22,8 +22,9 @@
<br />
<input type=file name=file><br />
<p></p>
<input class="btn-danger btn" type="button" value="{%trans%}Reset{%endtrans%}" onClick="location.href='/site/reset-favicon'">
<input class="btn-success btn" type="submit" value="{%trans%}Submit{%endtrans%}">
<input class="btn-success btn" type="submit" value="{%trans%}Upload{%endtrans%}">
<input class="btn-primary btn" type="button" value="{%trans%}Use default{%endtrans%}" onClick="location.href='/site/reset-favicon'">
<input class="btn-primary btn" type="button" value="{%trans%}Cancel{%endtrans%}" onClick="location.href='/user/{{g.current_user.username}}#site_settings'">
</form>
</div>
......
......@@ -33,10 +33,6 @@
<td>{%trans%}Invitation only{%endtrans%}</td>
<td>{{ site.invitationOnly }}</td>
</tr>
<tr>
<td>{%trans%}Email address{%endtrans%}</td>
<td>{{ site.noreplyEmailAddress }}</td>
</tr>
</table>
<div style="font-size:1.25em; padding-bottom:0.5em;">
......
......@@ -19,7 +19,7 @@
<br />
<label>{%trans%}Email{%endtrans%}</label><br />
<input type="text" name="email" class="form-control" required ><br />
<input type="email" name="email" class="form-control" required ><br />
<br />
<label>{%trans%}Password{%endtrans%}</label><br />
......
{% extends "base.html" %}
{% block content %}
<style>
label { margin-top:0.25em }
</style>
<div class="container">
<div class="row col-md-4"></div>
<div class="row col-md-4">
<div style="font-size:1.5em">{%trans%}Email server configuration{%endtrans%}</div>
<hr />
<form method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<label>{%trans%}Email server{%endtrans%}</label>
<span class='required'></span>
<br />
<input type="text" name="host" class="form-control" value="{{host}}" required />
<label>{%trans%}Port{%endtrans%}</label>
<span class='required'></span>
<br />
<input type="number" name="port" class="form-control" value="{{port}}" required />
<label>{%trans%}Encryption{%endtrans%}</label>
<span class='required'></span>
<br />
<select type="number" name="encryption" class="form-control" value="{{encryption}}" >
<option class="form-control" name="hello" {% if not encryption == "SSL" %}selected=True{% endif %} >{%trans%}None{%endtrans%}</option>
<option class="form-control" name="SSL" {% if encryption == "SSL" %}selected=True{% endif %} >SSL</option>
</select>
<label>{%trans%}User{%endtrans%}</label>
<br />
<input type="text" name="user" class="form-control" value="{{user}}" />
<label>{%trans%}Password{%endtrans%}</label>
<br />
<input type="password" name="password" class="form-control" value="{{password}}" />
<label>{%trans%}Sender address{%endtrans%}</label>
<span class='required'></span>
<br />
<input type="email" name="noreplyAddress" class="form-control" value="{{noreplyAddress}}" required />
<p></p>
<input class="btn-success btn" type="submit" value="{%trans%}Save changes{%endtrans%}">
<input class="btn-primary btn" type="button" value="{%trans%}Cancel{%endtrans%}" onClick="location.href='/user/{{g.current_user.username}}#site_settings'">
</form>
<p>&nbsp;</p>
<div style="font-size:1.25em">{%trans%}Test server configuration{%endtrans%}</div>
<table class="table">
<tr>
<td>
<input id="test-email" name="email" type="email" placeholder="[email protected]" class="form-control" required >
</td>
<td class="text-right">
<input id="test-email-button" class="btn-primary btn btn-md" type="button" value="{%trans%}Send{%endtrans%}" >
</td>
</tr>
</table>
</div>
<div class="row col-md-4"></div>
</div>
<script>
document.getElementById('test-email-button').addEventListener('click', function(evt){
var email = $("#test-email").val();
if (email){
location.href="/site/email/test-config/"+email
}
});
</script>
{% endblock %}
......@@ -115,7 +115,7 @@
<hr />
<p></p>
<div style="font-size:1.5em; padding-bottom:0.5em;">
<div id="admin_settings" style="font-size:1.5em; padding-bottom:0.5em;">
{%trans%}My admin settings{%endtrans%}
</div>
<p></p>
......@@ -142,7 +142,7 @@
</table>
<p></p>
<div style="font-size:1.5em; padding-bottom:0.5em;">
<div id="site_settings" style="font-size:1.5em; padding-bottom:0.5em;">
{%trans%}Site settings{%endtrans%}
</div>
<p></p>
......@@ -167,12 +167,10 @@
</td>
</tr>
<tr>
<td>{%trans%}Email address{%endtrans%}</td>
<td>
{{ site.noreplyEmailAddress }}
</td>
<td>{%trans%}Email server{%endtrans%}</td>
<td></td>
<td class="text-right">
<input class="btn-primary btn btn-xs" type="button" value="{%trans%}Change{%endtrans%}" onClick="location.href='/site/email/change-noreply'">
<input class="btn-primary btn btn-xs" type="button" value="{%trans%}Configure{%endtrans%}" onClick="location.href='/site/email/config'">
</td>
</tr>
<tr>
......@@ -268,17 +266,6 @@
</tr>
</table>
<table class="table">
<tr>
<td>{%trans%}Test SMTP config.{%endtrans%}</td>
<td>
<input id="test-email" type="text" placeholder="[email protected]" class="form-control" required >
</td>
<td class="text-right">
<input id="test-email-button" class="btn-primary btn btn-md" type="button" value="{%trans%}Send email{%endtrans%}" >
</td>
</tr>
</table>
{% endif %}
</div>
<div class="row col-md-3"></div>
......@@ -408,15 +395,6 @@ $(document).ready(function() {
});
});
{% if g.isRootUser %}
document.getElementById('test-email-button').addEventListener('click', function(evt){
var email = $("#test-email").val();
if (email){
location.href="/site/test-smtp/"+email
}
});
{% endif %}
</script>
{% endblock %}
......@@ -1016,19 +1016,43 @@ def save_data_consent():
flash(gettext("Text saved OK"), 'success')
return redirect(make_url_for('user_settings', username=g.current_user.username))
@app.route('/site/email/change-noreply', methods=['GET', 'POST'])
@app.route('/site/email/config', methods=['GET', 'POST'])
@admin_required
def change_noreply_email():
def smtp_config():
config=g.site.data["smtpConfig"]
if request.method == 'POST':
if 'email' in request.form and isValidEmail(request.form['email']):
g.site.noreplyEmailAddress=request.form['email']
flash(gettext("Site email address updated OK"), 'success')
return redirect(make_url_for('user_settings', username=g.current_user.username))
return render_template('change-email.html')
config['host'] = request.form['host']
config['port'] = request.form['port']
config['encryption']=request.form['encryption'] if not request.form['encryption']=="None" else ""
config['user'] = request.form['user']
config['password'] = request.form['password']
config['noreplyAddress'] = request.form['noreplyAddress']
if not config['host']:
flash(gettext("We need a host"), 'warning')
return render_template('smtp-config.html', **config)
if not config['port']:
flash(gettext("We need a port"), 'warning')
return render_template('smtp-config.html', **config)
if not isValidEmail(config['noreplyAddress']):
flash(gettext("We need a valid sender address"), 'warning')
return render_template('smtp-config.html', **config)
g.site.saveSMTPconfig(**config)
flash(gettext("Confguration saved OK"), 'success')
return render_template('smtp-config.html', **config)
return render_template('smtp-config.html', **config)
@app.route('/site/email/test-config/<string:email>', methods=['GET'])
@admin_required
def test_smtp(email):
if isValidEmail(email):
if smtpSendTestEmail(email):
flash(gettext("SMTP config works!"), 'success')
else:
flash("Email not valid", 'warning')
return redirect(make_url_for('smtp_config'))
@app.route('/site/change-sitename', methods=['GET', 'POST'])
@admin_required
......@@ -1066,18 +1090,6 @@ def reset_site_favicon():
flash(gettext("Favicon reset OK. Refresh with &lt;F5&gt;"), 'success')
return redirect(make_url_for('user_settings', username=g.current_user.username))
@app.route('/site/test-smtp/<string:email>', methods=['GET'])
@rootuser_required
def test_smtp(email):
if isValidEmail(email):
if smtpSendTestEmail(email):
flash(gettext("SMTP config works!"), 'success')
else:
flash("Email not valid", 'warning')
return redirect(make_url_for('user_settings', username=g.current_user.username))
@app.route('/site/update', methods=['GET', 'POST'])
def schema_update():
installation=Installation()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment