From 48fbf737ce062ea45c4cac1ad3d34a3b82d23563 Mon Sep 17 00:00:00 2001 From: Pierre Jaury Date: Sat, 20 Feb 2016 20:11:59 +0100 Subject: [PATCH] Actually bind flask-admin to the mail servers --- admin/freeposte/__init__.py | 14 ++++++++-- admin/freeposte/models.py | 1 + admin/freeposte/views.py | 15 ++++++++-- admin/requirements.txt | 2 ++ admin/run.py | 7 ++++- admin/testdb.py | 7 ----- config/dovecot/dovecot-sql.conf.ext | 14 +++++----- config/nginx/nginx.conf | 28 +++++++++++++++++++ config/postfix/main.cf | 2 ++ config/postfix/sqlite-virtual_alias_maps.cf | 10 +++---- .../postfix/sqlite-virtual_mailbox_domains.cf | 2 +- config/supervisor/supervisord.conf | 7 +++++ config/uwsgi/apps-enabled/freeposte.yml | 16 +++++++++++ 13 files changed, 98 insertions(+), 27 deletions(-) delete mode 100644 admin/testdb.py create mode 100644 config/nginx/nginx.conf create mode 100644 config/uwsgi/apps-enabled/freeposte.yml diff --git a/admin/freeposte/__init__.py b/admin/freeposte/__init__.py index 78dd88c1..89753f79 100644 --- a/admin/freeposte/__init__.py +++ b/admin/freeposte/__init__.py @@ -1,14 +1,22 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy +import os # Create application app = Flask(__name__) -app.config.update({ - 'SQLALCHEMY_DATABASE_URI': 'sqlite:////tmp/freeposte.db' -}) +default_config = { + 'SQLALCHEMY_DATABASE_URI': 'sqlite:////data/freeposte.db', + 'SQLALCHEMY_TRACK_MODIFICATIONS': False, + 'SECRET_KEY': None +} + +# Load configuration from the environment if available +for key, value in default_config.items(): + app.config[key] = os.environ.get(key, value) + # Create the database db = SQLAlchemy(app) diff --git a/admin/freeposte/models.py b/admin/freeposte/models.py index 98bbddc4..7cfa5fb9 100644 --- a/admin/freeposte/models.py +++ b/admin/freeposte/models.py @@ -1,6 +1,7 @@ from freeposte import db + class Domain(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80)) diff --git a/admin/freeposte/views.py b/admin/freeposte/views.py index 2f9e53c0..25c47159 100644 --- a/admin/freeposte/views.py +++ b/admin/freeposte/views.py @@ -8,15 +8,24 @@ from freeposte import app, db, models admin = admin.Admin(app, name='Freeposte.io', template_mode='bootstrap3') -class DomainModelView(sqla.ModelView): +class BaseModelView(sqla.ModelView): + + def after_model_change(self, form, model, is_created): + db.session.commit() + + def after_model_delete(self, model): + db.session.commit() + + +class DomainModelView(BaseModelView): pass -class UserModelView(sqla.ModelView): +class UserModelView(BaseModelView): pass -class AliasModelView(sqla.ModelView): +class AliasModelView(BaseModelView): pass diff --git a/admin/requirements.txt b/admin/requirements.txt index fb675a95..b170d9ee 100644 --- a/admin/requirements.txt +++ b/admin/requirements.txt @@ -1,2 +1,4 @@ Flask +Flask-Admin Flask-SQLAlchemy +uwsgi diff --git a/admin/run.py b/admin/run.py index c9cfd78e..389791c7 100644 --- a/admin/run.py +++ b/admin/run.py @@ -1,4 +1,9 @@ -from freeposte import app +from freeposte import app, db + + +# Initialize the database if required (first launch) +db.create_all() +db.session.commit() if __name__ == '__main__': diff --git a/admin/testdb.py b/admin/testdb.py deleted file mode 100644 index c7417c4c..00000000 --- a/admin/testdb.py +++ /dev/null @@ -1,7 +0,0 @@ -from freeposte import db, models - - -if __name__ == "__main__": - db.drop_all() - db.create_all() - db.session.commit() diff --git a/config/dovecot/dovecot-sql.conf.ext b/config/dovecot/dovecot-sql.conf.ext index 320da098..a0673e5a 100644 --- a/config/dovecot/dovecot-sql.conf.ext +++ b/config/dovecot/dovecot-sql.conf.ext @@ -4,13 +4,13 @@ connect = /data/freeposte.db # Return the user hashed password password_query = \ SELECT password \ - FROM users INNER JOIN domains ON users.domain_id = domains.id \ - WHERE domains.name = '%d' \ - AND users.username = '%n' + FROM user INNER JOIN domain ON user.domain_id = domains.id \ + WHERE domain.name = '%d' \ + AND user.username = '%n' # Mostly get the user quota user_query = \ - SELECT '*:bytes=' || users.quota_bytes AS quota_rule \ - FROM users INNER JOIN domains ON users.domain_id = domains.id \ - WHERE domains.name = '%d' \ - AND users.username = '%n' + SELECT '*:bytes=' || user.quota_bytes AS quota_rule \ + FROM user INNER JOIN domain ON user.domain_id = domain.id \ + WHERE domain.name = '%d' \ + AND user.username = '%n' diff --git a/config/nginx/nginx.conf b/config/nginx/nginx.conf new file mode 100644 index 00000000..a77523eb --- /dev/null +++ b/config/nginx/nginx.conf @@ -0,0 +1,28 @@ +user www-data; +worker_processes 1; + +error_log /var/log/nginx/error.log info; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /var/log/nginx/access.log; + sendfile on; + keepalive_timeout 65; + server_tokens off; + + server { + listen 80; + + location /admin { + include uwsgi_params; + uwsgi_modifier1 30; + uwsgi_pass unix:/var/run/freeposte.sock; + } + } +} diff --git a/config/postfix/main.cf b/config/postfix/main.cf index 5ecab047..8b55fb58 100644 --- a/config/postfix/main.cf +++ b/config/postfix/main.cf @@ -8,6 +8,8 @@ mynetworks = /data/relaynets alias_maps = hash:/etc/aliases # SQLite configuration sql = sqlite:${config_directory}/ +# Only accept virtual emails +mydestination = ############### # TLS diff --git a/config/postfix/sqlite-virtual_alias_maps.cf b/config/postfix/sqlite-virtual_alias_maps.cf index 009c6fe1..f178f496 100644 --- a/config/postfix/sqlite-virtual_alias_maps.cf +++ b/config/postfix/sqlite-virtual_alias_maps.cf @@ -1,6 +1,6 @@ dbpath = /data/freeposte.db -query = \ - SELECT destination \ - FROM aliases INNER JOIN domains ON aliases.domain_id = domains.id \ - WHERE domains.name = '%d' \ - AND aliases.localpart = '%n' +query = + SELECT destination + FROM alias INNER JOIN domain ON alias.domain_id = domain.id + WHERE domain.name = '%d' + AND alias.localpart = '%u' diff --git a/config/postfix/sqlite-virtual_mailbox_domains.cf b/config/postfix/sqlite-virtual_mailbox_domains.cf index 4134a848..a2316d0b 100644 --- a/config/postfix/sqlite-virtual_mailbox_domains.cf +++ b/config/postfix/sqlite-virtual_mailbox_domains.cf @@ -1,2 +1,2 @@ dbpath = /data/freeposte.db -query = SELECT name FROM domains WHERE domain='%s' +query = SELECT name FROM domain WHERE name='%s' diff --git a/config/supervisor/supervisord.conf b/config/supervisor/supervisord.conf index f3cf3e3d..fafabffd 100644 --- a/config/supervisor/supervisord.conf +++ b/config/supervisor/supervisord.conf @@ -1,5 +1,6 @@ [supervisord] nodaemon = true +logfile = /var/log/supervisor/supervisord.log [program:postfix] command = /usr/lib/postfix/master -d @@ -12,3 +13,9 @@ command = /usr/sbin/spamd [program:rsyslog] command = rsyslogd -n + +[program:admin] +command = uwsgi --yaml /etc/uwsgi/apps-enabled/freeposte.yml + +[program:nginx] +command = nginx -g 'daemon off;' diff --git a/config/uwsgi/apps-enabled/freeposte.yml b/config/uwsgi/apps-enabled/freeposte.yml new file mode 100644 index 00000000..1ea57b28 --- /dev/null +++ b/config/uwsgi/apps-enabled/freeposte.yml @@ -0,0 +1,16 @@ +uwsgi: + socket: /var/run/freeposte.sock + chown-socket: www-data:www-data + pidfile: /var/run/freeposte.pid + master: true + workers: 2 + + vacuum: true + plugins: python + wsgi-file: /admin/run.py + callable: app + processes: 1 + pythonpath: /usr/lib/python2.7/site-packages + pythonpath: /admin + catch-exceptions: true + post-buffering: 8192