From a5ffcfdc90a5462d2e7bc683ac2181dfeca85ba7 Mon Sep 17 00:00:00 2001 From: Pierre Jaury Date: Sat, 20 Feb 2016 13:57:26 +0100 Subject: [PATCH] Setup a basic flask-admin interface --- admin/empty | 0 admin/freeposte/__init__.py | 16 +++++++++ .../__pycache__/__init__.cpython-35.pyc | Bin 0 -> 421 bytes .../__pycache__/models.cpython-35.pyc | Bin 0 -> 1770 bytes .../__pycache__/views.cpython-35.pyc | Bin 0 -> 997 bytes admin/freeposte/models.py | 34 ++++++++++++++++++ admin/freeposte/views.py | 26 ++++++++++++++ admin/requirements.txt | 2 ++ admin/run.py | 5 +++ admin/testdb.py | 7 ++++ config/dovecot/dovecot-sql.conf.ext | 10 ++++-- config/postfix/sqlite-virtual_alias_maps.cf | 6 +++- .../postfix/sqlite-virtual_mailbox_domains.cf | 2 +- 13 files changed, 104 insertions(+), 4 deletions(-) delete mode 100644 admin/empty create mode 100644 admin/freeposte/__init__.py create mode 100644 admin/freeposte/__pycache__/__init__.cpython-35.pyc create mode 100644 admin/freeposte/__pycache__/models.cpython-35.pyc create mode 100644 admin/freeposte/__pycache__/views.cpython-35.pyc create mode 100644 admin/freeposte/models.py create mode 100644 admin/freeposte/views.py create mode 100644 admin/requirements.txt create mode 100644 admin/run.py create mode 100644 admin/testdb.py diff --git a/admin/empty b/admin/empty deleted file mode 100644 index e69de29b..00000000 diff --git a/admin/freeposte/__init__.py b/admin/freeposte/__init__.py new file mode 100644 index 00000000..78dd88c1 --- /dev/null +++ b/admin/freeposte/__init__.py @@ -0,0 +1,16 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy + + + +# Create application +app = Flask(__name__) + +app.config.update({ + 'SQLALCHEMY_DATABASE_URI': 'sqlite:////tmp/freeposte.db' +}) + +# Create the database +db = SQLAlchemy(app) + +from freeposte import views diff --git a/admin/freeposte/__pycache__/__init__.cpython-35.pyc b/admin/freeposte/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a4047b0ca42562905d9c6370f45ba919d637ba5 GIT binary patch literal 421 zcmYk3OHRWu5QfKjwGFA%6)ZSGHqE|5hyX<(6(lGik&Q{~DRmnsArDa5avE-eI6}6p zxB@H2MS_m(@jo8VH@3Xp?YbZL@3$TU_=F8JNgvQGC*%YT1_^*-5HVmnHXt!TnGl)4 zkO5loN=X~ghJ^!*76=oB1(NA~hNe#F6YVw4hNJ_^g~%nE17pASMSZ|$jeU~D<&uOu zz8r>3%#=rbRzqV;}p2i9}Z_GH)8)urOGx^XsbuQuxBSTD@&L6+9 zsN@X_mzK5r9t87DVX%zlDyxGEMW$-?f1w~2N~Rkz=Q5QQ=ly)uwD(jd>IC=c8=&;a O^;pmLj1KEsp78_uTWgU3 literal 0 HcmV?d00001 diff --git a/admin/freeposte/__pycache__/models.cpython-35.pyc b/admin/freeposte/__pycache__/models.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b21c3eb543034b74ba00760266c24efae1ec3fa GIT binary patch literal 1770 zcmc(f&2G~`5XWbo*v@y;qLvnM=`j}qHx39D6;UBXgw(>pm(@1jv`+nz?mB|B^i*B} z@eG`J4W41Iocan}U}l}R2Fiy75>7m}XJ&WD`~P`X+U>?$@$rRU1^5J|1D|07PtDPU z_-7CUBn$!uY%6pitiT&|S3oitJ8)WopaNTA6++hr+)|*50S`jo2K-XMg|G(Oz4{q0 z0zGD&aCb4fmibTRNE<|e^4v=UF)g;;Ay}` z?LiZ;-0hxkyoXsLqSQ1eDoTW!@dG*AIeUi14B5O!y3)Ccr}ojj1{ed5W&?boYAO;* zS1sewdr&n@_ODPJT&OFOpS9|mvhtL97j)Mx^HoQI2CabQ8e0kn^`_9WP*21wKGjm`ph>qPj)az4Q3dvGN~TV}3L274Q$~xe;%|v9Io5x* zwjVI@UujERptcPddsci0P)u^R$XO^%q_j)=BPm5PlF}*pkrc47ED*W~D)Jt5A*`dg z4O4xNo1*AVca)3P_`70wpyViU?RK4gLFYG=(9Ue)sn^gTv`7iD!mM>*jJP^DwKF*K zk8huB9N#(VRgE{wR3dUyqe)3R;~_4{q?M<~6e0J$2DJ4nw9*`r7S(zQ$f9b}pca`n z8A?+fG7Dt7WERQLB&P8wQ!?61pU9b2(bS6yII_}GG8TE1rFuV_sOywon+UC6W-1Jt zhtn(X^bWWFC|C8DKhAJrhd^4i$>)>r5;!;Nl@6t686+r74;ue UyH_;4`_z;*^{{Sbt+Cen3Rq}GPyhe` literal 0 HcmV?d00001 diff --git a/admin/freeposte/__pycache__/views.cpython-35.pyc b/admin/freeposte/__pycache__/views.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3525948a75f43322f7f0ca23ca78a60bae132a45 GIT binary patch literal 997 zcmb7C%Wl&^6uslO9XkoFgoMZsWRomdutBJm5Ul8?qKny>NoOjYdSch(fXX)gnf?ji zFk4pq01~XY*H$7UbrUCZa_^kvoI5A;Jj;?lpMPA99e|%Ocmk}?aGBo-65k9;0M5GF zfzko(0(XHC=R)a$_JRAL1Kj~@}H0mcn4waCbKFOf~a?k$f z@VJ-r@h?0(T+EsE%v~wwu60FSTSu;Jpew0LW4(>g>U;XWQL3&?s}@DYvsUT46s^kX zOFUUsRcqQt)UU2dZ~rhX&TyG2g4$=x9g6yL?%2t@N{eFik&Lbi_3Z-vqdX_WJhw?s z>f4g)G|%t0qU@PRXhta5!Qa=*FO^oyTT$Fs+hwa{rMG%{v!8Y;q%Jmt{ww;JMSb6d zC_yp??**i+>yMf~`(#uzoV|%?s+b@lI1JfWDeYwl6I^>&>W^|ApO=L&$J&n3=5%07 z{rrTFZc1Tp^DZOq_aCQ&y~TC4X`5ozP)0UBq}sUHHy(kH!2NSdna78*x-`4PHe|&k zA!Sa{^PvCFZD^D+MYZ7`#c2KRSWiV}qc{CEcuUvGoFJrZ>dd^C?h6lJ{*2AoKk(no AApigX literal 0 HcmV?d00001 diff --git a/admin/freeposte/models.py b/admin/freeposte/models.py new file mode 100644 index 00000000..98bbddc4 --- /dev/null +++ b/admin/freeposte/models.py @@ -0,0 +1,34 @@ +from freeposte import db + + +class Domain(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(80)) + max_users = db.Column(db.Integer) + max_aliases = db.Column(db.Integer) + + def __str__(self): + return self.name + + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(80)) + domain_id = db.Column(db.Integer, db.ForeignKey(Domain.id)) + domain = db.relationship(Domain, backref='users') + password = db.Column(db.String(255)) + quota_bytes = db.Column(db.Integer()) + + def __str__(self): + return '{0}@{1}'.format(self.username, self.domain.name) + + +class Alias(db.Model): + id = db.Column(db.Integer, primary_key=True) + localpart = db.Column(db.String(80)) + domain_id = db.Column(db.Integer, db.ForeignKey(Domain.id)) + domain = db.relationship(Domain, backref='aliases') + destination = db.Column(db.String()) + + def __str__(self): + return '{0}@{1}'.format(self.username, self.domain.name) diff --git a/admin/freeposte/views.py b/admin/freeposte/views.py new file mode 100644 index 00000000..2f9e53c0 --- /dev/null +++ b/admin/freeposte/views.py @@ -0,0 +1,26 @@ +import flask_admin as admin +from flask_admin.contrib import sqla + +from freeposte import app, db, models + + +# Flask admin +admin = admin.Admin(app, name='Freeposte.io', template_mode='bootstrap3') + + +class DomainModelView(sqla.ModelView): + pass + + +class UserModelView(sqla.ModelView): + pass + + +class AliasModelView(sqla.ModelView): + pass + + +# Add views +admin.add_view(DomainModelView(models.Domain, db.session)) +admin.add_view(UserModelView(models.User, db.session)) +admin.add_view(AliasModelView(models.Alias, db.session)) diff --git a/admin/requirements.txt b/admin/requirements.txt new file mode 100644 index 00000000..fb675a95 --- /dev/null +++ b/admin/requirements.txt @@ -0,0 +1,2 @@ +Flask +Flask-SQLAlchemy diff --git a/admin/run.py b/admin/run.py new file mode 100644 index 00000000..c9cfd78e --- /dev/null +++ b/admin/run.py @@ -0,0 +1,5 @@ +from freeposte import app + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/admin/testdb.py b/admin/testdb.py new file mode 100644 index 00000000..c7417c4c --- /dev/null +++ b/admin/testdb.py @@ -0,0 +1,7 @@ +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 97610abb..320da098 100644 --- a/config/dovecot/dovecot-sql.conf.ext +++ b/config/dovecot/dovecot-sql.conf.ext @@ -3,8 +3,14 @@ connect = /data/freeposte.db # Return the user hashed password password_query = \ - SELECT password FROM users, domains WHERE username = '%n' AND domain = '%d' + SELECT password \ + FROM users INNER JOIN domains ON users.domain_id = domains.id \ + WHERE domains.name = '%d' \ + AND users.username = '%n' # Mostly get the user quota user_query = \ - SELECT '*:bytes=' || quota_bytes AS quota_rule FROM users WHERE username = '%n' AND domain = '%d' + 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' diff --git a/config/postfix/sqlite-virtual_alias_maps.cf b/config/postfix/sqlite-virtual_alias_maps.cf index 1d80e00c..009c6fe1 100644 --- a/config/postfix/sqlite-virtual_alias_maps.cf +++ b/config/postfix/sqlite-virtual_alias_maps.cf @@ -1,2 +1,6 @@ dbpath = /data/freeposte.db -query = SELECT destination FROM aliases WHERE localpart = '%u' AND domain = '%d' +query = \ + SELECT destination \ + FROM aliases INNER JOIN domains ON aliases.domain_id = domains.id \ + WHERE domains.name = '%d' \ + AND aliases.localpart = '%n' diff --git a/config/postfix/sqlite-virtual_mailbox_domains.cf b/config/postfix/sqlite-virtual_mailbox_domains.cf index 91002d8e..4134a848 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 domain FROM domains WHERE domain='%s' +query = SELECT name FROM domains WHERE domain='%s'