This commit is contained in:
Adrian Amaglio 2020-05-02 17:32:08 +02:00
parent df035b7f9f
commit 4be346cbf1
2 changed files with 34 additions and 13 deletions

37
main.py
View File

@ -12,9 +12,10 @@ import pymongo # database
from dotenv import load_dotenv
import random, string # for tokens
import html # for sanitization
import datetime # to name unsent mails
##################################################### Bottle stuff ############################################$
##################################################### Bottle stuff ############################################
# The exception that is thrown when an argument is missing
class MissingParameterException (Exception):
@ -35,7 +36,7 @@ class StripPathMiddleware(object):
app = application = bottle.Bottle(catchall=False)
##################################################### Configuration ############################################$
##################################################### Configuration ############################################
def get_env(var, default=None):
"""var is an env var name, default is the value to return if var does not exist. If no default and no value, an exception is raised."""
if var in os.environ:
@ -51,7 +52,7 @@ token_chars = string.ascii_lowercase+string.ascii_uppercase+string.digits
token_len = 50
# form template regex
form_regex = '\{\{(\w+)(\|\w+)?\}\}'
form_regex = '\{\{(\w+)(\|[\w\s,\.\?\'\"\!\[\]]+)?\}\}'
# Load file from .env file.
load_dotenv(os.path.dirname(__file__) + '.env')
@ -87,7 +88,7 @@ mongodb_client = pymongo.MongoClient("mongodb://{}:{}/".format(mongodb_host, mon
mongodb_database = mongodb_client[mongodb_dbname]
##################################################### main route: mail submission ############################################$
##################################################### main route: mail submission ############################################
@app.post('/submit')
def submission ():
@ -123,23 +124,35 @@ def submission ():
subject = re.sub(form_regex, r'{\1}', form['subject']).format(**subject_fields)
content = re.sub(form_regex, r'{\1}', form['content']).format(**content_fields)
print(subject)
print(content)
try:
if not send_mail(from_address, form['mail'], subject, content):
response.status = 500
return 'Le mail na pas pu être envoyé.'
except SMTPDataError as e:
except smtplib.SMTPDataError as e:
save_mail (token, form['mail'], from_address, subject, content)
response.status = 500
return 'Le mail a été refusé.'
error = 'Le mail a été refusé. Votre message a été enregistré, il sera remis manuellement à son destinataire.'
except smtplib.SMTPRecipientsRefused as e:
save_mail (token, form['mail'], from_address, subject, content)
response.status = 500
error = 'Impossible de trouver le destinataire du mail. Votre message a été enregistré, il sera remis manuellement à son destinataire.'
# Redirection
#redirect(success_redirect_default)
origin = request.headers.get('origin')
return '<p>Mail envoyé !</p>' + ('<p>Retour au <a href="{}">formulaire de contact</a></p>'.format(origin) if origin else '')
##################################################### Helpers ############################################$
##################################################### Helpers ############################################
def save_mail (token, to, from_address, subject, content):
with open('unsent/unsent_{}_{}_{}.txt'.format(str(datetime.datetime.now()), token, to), 'w') as f:
f.write("Unsent mail\nSubject: {}\nFrom: {}Content:\n{}".format(
subject,
from_address,
content
))
def get_fields (string):
""" Parse the string looking for template elements and create an array with template to fill and their default values. None if mandatory. """
result = {}
@ -206,7 +219,7 @@ def login(request):
return {'_privilege': 1000} # anonymous
##################################################### Forms ############################################$
##################################################### Forms ############################################
@app.post('/form')
def create_form ():
@ -304,7 +317,7 @@ def delete_form(token):
return 'Privilèges insufisants'
##################################################### Users ############################################$
##################################################### Users ############################################
@app.post('/user/list')
def list_users ():
@ -365,7 +378,7 @@ def delete_user (username):
##################################################### app startup ############################################$
##################################################### app startup ############################################
if __name__ == '__main__':
bottle.run(app=StripPathMiddleware(app), host=listen_address, port=listen_port, debug=True)
else:

View File

@ -12,6 +12,7 @@ But the first limitation is… No interractions… So no contact form… That wo
- Create or reuse an existing contact form
- Add the `action` parameter to the mailer address + `/submit`
- Get a token from this mailer app and place it in your form like :
```
<form action="https://mailer.jean-cloud.net/submit" method="POST">
<input type="mail" name="mail" />
@ -67,6 +68,13 @@ UID=1000
```
You can store them in a `.env` file. The python app will read it or you can pass it to the docker container with `run` option `--env-file`.
- `SMTP_*` are used to connect to the smtp server that will send the mail.
- `SMTP_SSL` is used to enable SSL
- `SMTP_STARTTLS` is used to enable STARTTLS if `SMTP_SSL` is not defined. In no ssl and starttls are defined the app wont connect.
- `MONGODB_HOST` the host to connect to mongodb
- `ADMIN_PASSWORD` password used to manage users
- `UID` used to set the uwsg socket ownership in production
## Roadmap
### Near future
- go on docker hub
@ -78,4 +86,4 @@ You can store them in a `.env` file. The python app will read it or you can pass
### Ameliorations
- Use real user/passwords accounts
- Créate a gui client