You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			117 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
from freeposte import db
 | 
						|
 | 
						|
from sqlalchemy.ext import declarative
 | 
						|
from passlib import context
 | 
						|
from datetime import datetime
 | 
						|
 | 
						|
 | 
						|
# Many-to-many association table for domain administrators
 | 
						|
admins = db.Table('admin',
 | 
						|
    db.Column('domain_name', db.String(80), db.ForeignKey('domain.name')),
 | 
						|
    db.Column('user_domain_name', db.String(80)),
 | 
						|
    db.Column('user_localpart', db.String(80)),
 | 
						|
    db.ForeignKeyConstraint(
 | 
						|
        ('user_domain_name', 'user_localpart'),
 | 
						|
        ('user.domain_name', 'user.localpart')
 | 
						|
    )
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
class Base(db.Model):
 | 
						|
    """ Base class for all models
 | 
						|
    """
 | 
						|
 | 
						|
    __abstract__ = True
 | 
						|
 | 
						|
    created_at = db.Column(db.Date, nullable=False, default=datetime.now)
 | 
						|
    updated_at = db.Column(db.Date, nullable=True, onupdate=datetime.now)
 | 
						|
    comment = db.Column(db.String(255), nullable=True)
 | 
						|
 | 
						|
 | 
						|
class Domain(Base):
 | 
						|
    """ A DNS domain that has mail addresses associated to it.
 | 
						|
    """
 | 
						|
    name = db.Column(db.String(80), primary_key=True, nullable=False)
 | 
						|
    admins = db.relationship('User', secondary=admins,
 | 
						|
        backref=db.backref('admin_of'), lazy='dynamic')
 | 
						|
    max_users = db.Column(db.Integer, nullable=True)
 | 
						|
    max_aliases = db.Column(db.Integer, nullable=True)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.name
 | 
						|
 | 
						|
 | 
						|
class Address(Base):
 | 
						|
    """ Abstraction for a mail address (localpart and domain).
 | 
						|
    """
 | 
						|
    __abstract__ = True
 | 
						|
 | 
						|
    localpart = db.Column(db.String(80), primary_key=True, nullable=False)
 | 
						|
 | 
						|
    @declarative.declared_attr
 | 
						|
    def domain_name(cls):
 | 
						|
        return db.Column(db.String(80), db.ForeignKey(Domain.name),
 | 
						|
            primary_key=True, nullable=False)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return '{0}@{1}'.format(self.localpart, self.domain_name)
 | 
						|
 | 
						|
    def get_id(self):
 | 
						|
        return str(self)
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def get_by_email(cls, email):
 | 
						|
        localpart, domain = email.split('@', maxsplit=1)
 | 
						|
        # Get the user object
 | 
						|
        return cls.query.filter_by(domain_name=domain, localpart=localpart).first()
 | 
						|
 | 
						|
 | 
						|
class User(Address):
 | 
						|
    """ A user is a mail address that has a password to access a mailbox.
 | 
						|
    """
 | 
						|
    domain = db.relationship(Domain, backref='users')
 | 
						|
    password = db.Column(db.String(255), nullable=False)
 | 
						|
    quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9)
 | 
						|
    global_admin = db.Column(db.Boolean(), nullable=False, default=False)
 | 
						|
 | 
						|
    # Filters
 | 
						|
    forward = db.Column(db.String(160), nullable=True, default=None)
 | 
						|
    reply_subject = db.Column(db.String(255), nullable=True, default=None)
 | 
						|
    reply_body = db.Column(db.Text(), nullable=True, default=None)
 | 
						|
 | 
						|
    # Settings
 | 
						|
    displayed_name = db.Column(db.String(160), nullable=False, default="")
 | 
						|
    spam_enabled = db.Column(db.Boolean(), nullable=False, default=True)
 | 
						|
    spam_threshold = db.Column(db.Numeric(), nullable=False, default=5.0)
 | 
						|
 | 
						|
    # Flask-login attributes
 | 
						|
    is_authenticated = True
 | 
						|
    is_active = True
 | 
						|
    is_anonymous = False
 | 
						|
 | 
						|
    pw_context = context.CryptContext(["sha512_crypt", "sha256_crypt"])
 | 
						|
 | 
						|
    def check_password(self, password):
 | 
						|
        return User.pw_context.verify(password, self.password)
 | 
						|
 | 
						|
    def set_password(self, password):
 | 
						|
        self.password = User.pw_context.encrypt(password)
 | 
						|
 | 
						|
    def get_managed_domains(self):
 | 
						|
        if self.global_admin:
 | 
						|
            return Domain.query.all()
 | 
						|
        else:
 | 
						|
            return self.admin_of
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def login(cls, email, password):
 | 
						|
        user = cls.get_by_email(email)
 | 
						|
        return user if (user and user.check_password(password)) else None
 | 
						|
 | 
						|
 | 
						|
class Alias(Address):
 | 
						|
    """ An alias is a mail address that redirects to some other addresses.
 | 
						|
    """
 | 
						|
    domain = db.relationship(Domain, backref='aliases')
 | 
						|
    destination = db.Column(db.String(), nullable=False)
 |