We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Internal Server Error in admin page
Looks like a reference to the auto-forward page was left behind when Settings / Forwarding were merged.  Clicking the link on /ui/user/list page results in an ISE.

Will submit a PR to fix shortly.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `core/admin/mailu/models.py`
Content:
```
1 from mailu import app, db, dkim, login_manager
2 
3 from sqlalchemy.ext import declarative
4 from passlib import context, hash
5 from datetime import datetime, date
6 from email.mime import text
7 
8 
9 import re
10 import time
11 import os
12 import glob
13 import smtplib
14 
15 
16 # Many-to-many association table for domain managers
17 managers = db.Table('manager',
18     db.Column('domain_name', db.String(80), db.ForeignKey('domain.name')),
19     db.Column('user_email', db.String(255), db.ForeignKey('user.email'))
20 )
21 
22 
23 class CommaSeparatedList(db.TypeDecorator):
24     """ Stores a list as a comma-separated string, compatible with Postfix.
25     """
26 
27     impl = db.String
28 
29     def process_bind_param(self, value, dialect):
30         if type(value) is not list:
31             raise TypeError("Shoud be a list")
32         for item in value:
33             if "," in item:
34                 raise ValueError("No item should contain a comma")
35         return ",".join(value)
36 
37     def process_result_value(self, value, dialect):
38         return filter(bool, value.split(","))
39 
40 
41 class Base(db.Model):
42     """ Base class for all models
43     """
44 
45     __abstract__ = True
46 
47     created_at = db.Column(db.Date, nullable=False, default=datetime.now)
48     updated_at = db.Column(db.Date, nullable=True, onupdate=datetime.now)
49     comment = db.Column(db.String(255), nullable=True)
50 
51 
52 class Domain(Base):
53     """ A DNS domain that has mail addresses associated to it.
54     """
55     __tablename__ = "domain"
56 
57     name = db.Column(db.String(80), primary_key=True, nullable=False)
58     managers = db.relationship('User', secondary=managers,
59         backref=db.backref('manager_of'), lazy='dynamic')
60     max_users = db.Column(db.Integer, nullable=False, default=0)
61     max_aliases = db.Column(db.Integer, nullable=False, default=0)
62     max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0)
63     signup_enabled = db.Column(db.Boolean(), nullable=False, default=False)
64 
65     @property
66     def dkim_key(self):
67         file_path = app.config["DKIM_PATH"].format(
68             domain=self.name, selector=app.config["DKIM_SELECTOR"])
69         if os.path.exists(file_path):
70             with open(file_path, "rb") as handle:
71                 return handle.read()
72 
73     @dkim_key.setter
74     def dkim_key(self, value):
75         file_path = app.config["DKIM_PATH"].format(
76             domain=self.name, selector=app.config["DKIM_SELECTOR"])
77         with open(file_path, "wb") as handle:
78             handle.write(value)
79 
80     @property
81     def dkim_publickey(self):
82         dkim_key = self.dkim_key
83         if dkim_key:
84             return dkim.strip_key(self.dkim_key).decode("utf8")
85 
86     def generate_dkim_key(self):
87         self.dkim_key = dkim.gen_key()
88 
89     def has_email(self, localpart):
90         for email in self.users + self.aliases:
91             if email.localpart == localpart:
92                 return True
93         else:
94             return False
95 
96     def __str__(self):
97         return self.name
98 
99     def __eq__(self, other):
100         try:
101             return self.name == other.name
102         except AttributeError:
103             return False
104 
105 
106 class Alternative(Base):
107     """ Alternative name for a served domain.
108     The name "domain alias" was avoided to prevent some confusion.
109     """
110 
111     __tablename__ = "alternative"
112 
113     name = db.Column(db.String(80), primary_key=True, nullable=False)
114     domain_name = db.Column(db.String(80), db.ForeignKey(Domain.name))
115     domain = db.relationship(Domain,
116         backref=db.backref('alternatives', cascade='all, delete-orphan'))
117 
118     def __str__(self):
119         return self.name
120 
121 
122 class Relay(Base):
123     """ Relayed mail domain.
124     The domain is either relayed publicly or through a specified SMTP host.
125     """
126 
127     __tablename__ = "relay"
128 
129     name = db.Column(db.String(80), primary_key=True, nullable=False)
130     smtp = db.Column(db.String(80), nullable=True)
131 
132     def __str__(self):
133         return self.name
134 
135 
136 class Email(object):
137     """ Abstraction for an email address (localpart and domain).
138     """
139 
140     localpart = db.Column(db.String(80), nullable=False)
141 
142     @declarative.declared_attr
143     def domain_name(cls):
144         return db.Column(db.String(80), db.ForeignKey(Domain.name),
145             nullable=False)
146 
147     # This field is redundant with both localpart and domain name.
148     # It is however very useful for quick lookups without joining tables,
149     # especially when the mail server il reading the database.
150     @declarative.declared_attr
151     def email(cls):
152         updater = lambda context: "{0}@{1}".format(
153             context.current_parameters["localpart"],
154             context.current_parameters["domain_name"],
155         )
156         return db.Column(db.String(255, collation="NOCASE"),
157             primary_key=True, nullable=False,
158             default=updater)
159 
160     def sendmail(self, subject, body):
161         """ Send an email to the address.
162         """
163         from_address = '{}@{}'.format(
164             app.config['POSTMASTER'], app.config['DOMAIN'])
165         with smtplib.SMTP('smtp', port=10025) as smtp:
166             msg = text.MIMEText(body)
167             msg['Subject'] = subject
168             msg['From'] = from_address
169             msg['To'] = self.email
170             smtp.sendmail(from_address, [self.email], msg.as_string())
171 
172     def __str__(self):
173         return self.email
174 
175 
176 class User(Base, Email):
177     """ A user is an email address that has a password to access a mailbox.
178     """
179     __tablename__ = "user"
180 
181     domain = db.relationship(Domain,
182         backref=db.backref('users', cascade='all, delete-orphan'))
183     password = db.Column(db.String(255), nullable=False)
184     quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9)
185     global_admin = db.Column(db.Boolean(), nullable=False, default=False)
186 
187     # Features
188     enable_imap = db.Column(db.Boolean(), nullable=False, default=True)
189     enable_pop = db.Column(db.Boolean(), nullable=False, default=True)
190 
191     # Filters
192     forward_enabled = db.Column(db.Boolean(), nullable=False, default=False)
193     forward_destination = db.Column(db.String(255), nullable=True, default=None)
194     forward_keep = db.Column(db.Boolean(), nullable=False, default=True)
195     reply_enabled = db.Column(db.Boolean(), nullable=False, default=False)
196     reply_subject = db.Column(db.String(255), nullable=True, default=None)
197     reply_body = db.Column(db.Text(), nullable=True, default=None)
198     reply_enddate = db.Column(db.Date, nullable=False,
199         default=date(2999, 12, 31))
200 
201     # Settings
202     displayed_name = db.Column(db.String(160), nullable=False, default="")
203     spam_enabled = db.Column(db.Boolean(), nullable=False, default=True)
204     spam_threshold = db.Column(db.Integer(), nullable=False, default=80.0)
205 
206     # Flask-login attributes
207     is_authenticated = True
208     is_active = True
209     is_anonymous = False
210 
211     def get_id(self):
212         return self.email
213 
214     scheme_dict = {'SHA512-CRYPT': "sha512_crypt",
215                    'SHA256-CRYPT': "sha256_crypt",
216                    'MD5-CRYPT': "md5_crypt",
217                    'CRYPT': "des_crypt"}
218     pw_context = context.CryptContext(
219         schemes = scheme_dict.values(),
220         default=scheme_dict[app.config['PASSWORD_SCHEME']],
221     )
222 
223     def check_password(self, password):
224         reference = re.match('({[^}]+})?(.*)', self.password).group(2)
225         return User.pw_context.verify(password, reference)
226 
227     def set_password(self, password, hash_scheme=app.config['PASSWORD_SCHEME'], raw=False):
228         """Set password for user with specified encryption scheme
229            @password: plain text password to encrypt (if raw == True the hash itself)
230         """
231         # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes
232         if raw:
233             self.password = '{'+hash_scheme+'}' + password
234         else:
235             self.password = '{'+hash_scheme+'}' + User.pw_context.encrypt(password, self.scheme_dict[hash_scheme])
236 
237     def get_managed_domains(self):
238         if self.global_admin:
239             return Domain.query.all()
240         else:
241             return self.manager_of
242 
243     def get_managed_emails(self, include_aliases=True):
244         emails = []
245         for domain in self.get_managed_domains():
246             emails.extend(domain.users)
247             if include_aliases:
248                 emails.extend(domain.aliases)
249         return emails
250 
251     def send_welcome(self):
252         if app.config["WELCOME"].lower() == "true":
253             self.sendmail(app.config["WELCOME_SUBJECT"],
254                 app.config["WELCOME_BODY"])
255 
256     @classmethod
257     def login(cls, email, password):
258         user = cls.query.get(email)
259         return user if (user and user.check_password(password)) else None
260 
261 login_manager.user_loader(User.query.get)
262 
263 
264 class Alias(Base, Email):
265     """ An alias is an email address that redirects to some destination.
266     """
267     __tablename__ = "alias"
268 
269     domain = db.relationship(Domain,
270         backref=db.backref('aliases', cascade='all, delete-orphan'))
271     wildcard = db.Column(db.Boolean(), nullable=False, default=False)
272     destination = db.Column(CommaSeparatedList, nullable=False, default=[])
273 
274 
275 class Token(Base):
276     """ A token is an application password for a given user.
277     """
278     __tablename__ = "token"
279 
280     id = db.Column(db.Integer(), primary_key=True)
281     user_email = db.Column(db.String(255), db.ForeignKey(User.email),
282         nullable=False)
283     user = db.relationship(User,
284         backref=db.backref('tokens', cascade='all, delete-orphan'))
285     password = db.Column(db.String(255), nullable=False)
286     ip = db.Column(db.String(255))
287 
288     def check_password(self, password):
289         return hash.sha256_crypt.verify(password, self.password)
290 
291     def set_password(self, password):
292         self.password = hash.sha256_crypt.using(rounds=1000).hash(password)
293 
294     def __str__(self):
295         return self.comment
296 
297 
298 class Fetch(Base):
299     """ A fetched account is a repote POP/IMAP account fetched into a local
300     account.
301     """
302     __tablename__ = "fetch"
303 
304     id = db.Column(db.Integer(), primary_key=True)
305     user_email = db.Column(db.String(255), db.ForeignKey(User.email),
306         nullable=False)
307     user = db.relationship(User,
308         backref=db.backref('fetches', cascade='all, delete-orphan'))
309     protocol = db.Column(db.Enum('imap', 'pop3'), nullable=False)
310     host = db.Column(db.String(255), nullable=False)
311     port = db.Column(db.Integer(), nullable=False)
312     tls = db.Column(db.Boolean(), nullable=False)
313     username = db.Column(db.String(255), nullable=False)
314     password = db.Column(db.String(255), nullable=False)
315     keep = db.Column(db.Boolean(), nullable=False)
316     last_check = db.Column(db.DateTime, nullable=True)
317     error = db.Column(db.String(1023), nullable=True)
318
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py
--- a/core/admin/mailu/models.py
+++ b/core/admin/mailu/models.py
@@ -162,7 +162,7 @@
         """
         from_address = '{}@{}'.format(
             app.config['POSTMASTER'], app.config['DOMAIN'])
-        with smtplib.SMTP('smtp', port=10025) as smtp:
+        with smtplib.SMTP(app.config['HOST_AUTHSMTP'], port=10025) as smtp:
             msg = text.MIMEText(body)
             msg['Subject'] = subject
             msg['From'] = from_address

{"golden_diff": "diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py\n--- a/core/admin/mailu/models.py\n+++ b/core/admin/mailu/models.py\n@@ -162,7 +162,7 @@\n         \"\"\"\n         from_address = '{}@{}'.format(\n             app.config['POSTMASTER'], app.config['DOMAIN'])\n-        with smtplib.SMTP('smtp', port=10025) as smtp:\n+        with smtplib.SMTP(app.config['HOST_AUTHSMTP'], port=10025) as smtp:\n             msg = text.MIMEText(body)\n             msg['Subject'] = subject\n             msg['From'] = from_address\n", "issue": "Internal Server Error in admin page\nLooks like a reference to the auto-forward page was left behind when Settings / Forwarding were merged.  Clicking the link on /ui/user/list page results in an ISE.\r\n\r\nWill submit a PR to fix shortly.\n", "before_files": [{"content": "from mailu import app, db, dkim, login_manager\n\nfrom sqlalchemy.ext import declarative\nfrom passlib import context, hash\nfrom datetime import datetime, date\nfrom email.mime import text\n\n\nimport re\nimport time\nimport os\nimport glob\nimport smtplib\n\n\n# Many-to-many association table for domain managers\nmanagers = db.Table('manager',\n    db.Column('domain_name', db.String(80), db.ForeignKey('domain.name')),\n    db.Column('user_email', db.String(255), db.ForeignKey('user.email'))\n)\n\n\nclass CommaSeparatedList(db.TypeDecorator):\n    \"\"\" Stores a list as a comma-separated string, compatible with Postfix.\n    \"\"\"\n\n    impl = db.String\n\n    def process_bind_param(self, value, dialect):\n        if type(value) is not list:\n            raise TypeError(\"Shoud be a list\")\n        for item in value:\n            if \",\" in item:\n                raise ValueError(\"No item should contain a comma\")\n        return \",\".join(value)\n\n    def process_result_value(self, value, dialect):\n        return filter(bool, value.split(\",\"))\n\n\nclass Base(db.Model):\n    \"\"\" Base class for all models\n    \"\"\"\n\n    __abstract__ = True\n\n    created_at = db.Column(db.Date, nullable=False, default=datetime.now)\n    updated_at = db.Column(db.Date, nullable=True, onupdate=datetime.now)\n    comment = db.Column(db.String(255), nullable=True)\n\n\nclass Domain(Base):\n    \"\"\" A DNS domain that has mail addresses associated to it.\n    \"\"\"\n    __tablename__ = \"domain\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    managers = db.relationship('User', secondary=managers,\n        backref=db.backref('manager_of'), lazy='dynamic')\n    max_users = db.Column(db.Integer, nullable=False, default=0)\n    max_aliases = db.Column(db.Integer, nullable=False, default=0)\n    max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0)\n    signup_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n\n    @property\n    def dkim_key(self):\n        file_path = app.config[\"DKIM_PATH\"].format(\n            domain=self.name, selector=app.config[\"DKIM_SELECTOR\"])\n        if os.path.exists(file_path):\n            with open(file_path, \"rb\") as handle:\n                return handle.read()\n\n    @dkim_key.setter\n    def dkim_key(self, value):\n        file_path = app.config[\"DKIM_PATH\"].format(\n            domain=self.name, selector=app.config[\"DKIM_SELECTOR\"])\n        with open(file_path, \"wb\") as handle:\n            handle.write(value)\n\n    @property\n    def dkim_publickey(self):\n        dkim_key = self.dkim_key\n        if dkim_key:\n            return dkim.strip_key(self.dkim_key).decode(\"utf8\")\n\n    def generate_dkim_key(self):\n        self.dkim_key = dkim.gen_key()\n\n    def has_email(self, localpart):\n        for email in self.users + self.aliases:\n            if email.localpart == localpart:\n                return True\n        else:\n            return False\n\n    def __str__(self):\n        return self.name\n\n    def __eq__(self, other):\n        try:\n            return self.name == other.name\n        except AttributeError:\n            return False\n\n\nclass Alternative(Base):\n    \"\"\" Alternative name for a served domain.\n    The name \"domain alias\" was avoided to prevent some confusion.\n    \"\"\"\n\n    __tablename__ = \"alternative\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    domain_name = db.Column(db.String(80), db.ForeignKey(Domain.name))\n    domain = db.relationship(Domain,\n        backref=db.backref('alternatives', cascade='all, delete-orphan'))\n\n    def __str__(self):\n        return self.name\n\n\nclass Relay(Base):\n    \"\"\" Relayed mail domain.\n    The domain is either relayed publicly or through a specified SMTP host.\n    \"\"\"\n\n    __tablename__ = \"relay\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    smtp = db.Column(db.String(80), nullable=True)\n\n    def __str__(self):\n        return self.name\n\n\nclass Email(object):\n    \"\"\" Abstraction for an email address (localpart and domain).\n    \"\"\"\n\n    localpart = db.Column(db.String(80), nullable=False)\n\n    @declarative.declared_attr\n    def domain_name(cls):\n        return db.Column(db.String(80), db.ForeignKey(Domain.name),\n            nullable=False)\n\n    # This field is redundant with both localpart and domain name.\n    # It is however very useful for quick lookups without joining tables,\n    # especially when the mail server il reading the database.\n    @declarative.declared_attr\n    def email(cls):\n        updater = lambda context: \"{0}@{1}\".format(\n            context.current_parameters[\"localpart\"],\n            context.current_parameters[\"domain_name\"],\n        )\n        return db.Column(db.String(255, collation=\"NOCASE\"),\n            primary_key=True, nullable=False,\n            default=updater)\n\n    def sendmail(self, subject, body):\n        \"\"\" Send an email to the address.\n        \"\"\"\n        from_address = '{}@{}'.format(\n            app.config['POSTMASTER'], app.config['DOMAIN'])\n        with smtplib.SMTP('smtp', port=10025) as smtp:\n            msg = text.MIMEText(body)\n            msg['Subject'] = subject\n            msg['From'] = from_address\n            msg['To'] = self.email\n            smtp.sendmail(from_address, [self.email], msg.as_string())\n\n    def __str__(self):\n        return self.email\n\n\nclass User(Base, Email):\n    \"\"\" A user is an email address that has a password to access a mailbox.\n    \"\"\"\n    __tablename__ = \"user\"\n\n    domain = db.relationship(Domain,\n        backref=db.backref('users', cascade='all, delete-orphan'))\n    password = db.Column(db.String(255), nullable=False)\n    quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9)\n    global_admin = db.Column(db.Boolean(), nullable=False, default=False)\n\n    # Features\n    enable_imap = db.Column(db.Boolean(), nullable=False, default=True)\n    enable_pop = db.Column(db.Boolean(), nullable=False, default=True)\n\n    # Filters\n    forward_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n    forward_destination = db.Column(db.String(255), nullable=True, default=None)\n    forward_keep = db.Column(db.Boolean(), nullable=False, default=True)\n    reply_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n    reply_subject = db.Column(db.String(255), nullable=True, default=None)\n    reply_body = db.Column(db.Text(), nullable=True, default=None)\n    reply_enddate = db.Column(db.Date, nullable=False,\n        default=date(2999, 12, 31))\n\n    # Settings\n    displayed_name = db.Column(db.String(160), nullable=False, default=\"\")\n    spam_enabled = db.Column(db.Boolean(), nullable=False, default=True)\n    spam_threshold = db.Column(db.Integer(), nullable=False, default=80.0)\n\n    # Flask-login attributes\n    is_authenticated = True\n    is_active = True\n    is_anonymous = False\n\n    def get_id(self):\n        return self.email\n\n    scheme_dict = {'SHA512-CRYPT': \"sha512_crypt\",\n                   'SHA256-CRYPT': \"sha256_crypt\",\n                   'MD5-CRYPT': \"md5_crypt\",\n                   'CRYPT': \"des_crypt\"}\n    pw_context = context.CryptContext(\n        schemes = scheme_dict.values(),\n        default=scheme_dict[app.config['PASSWORD_SCHEME']],\n    )\n\n    def check_password(self, password):\n        reference = re.match('({[^}]+})?(.*)', self.password).group(2)\n        return User.pw_context.verify(password, reference)\n\n    def set_password(self, password, hash_scheme=app.config['PASSWORD_SCHEME'], raw=False):\n        \"\"\"Set password for user with specified encryption scheme\n           @password: plain text password to encrypt (if raw == True the hash itself)\n        \"\"\"\n        # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes\n        if raw:\n            self.password = '{'+hash_scheme+'}' + password\n        else:\n            self.password = '{'+hash_scheme+'}' + User.pw_context.encrypt(password, self.scheme_dict[hash_scheme])\n\n    def get_managed_domains(self):\n        if self.global_admin:\n            return Domain.query.all()\n        else:\n            return self.manager_of\n\n    def get_managed_emails(self, include_aliases=True):\n        emails = []\n        for domain in self.get_managed_domains():\n            emails.extend(domain.users)\n            if include_aliases:\n                emails.extend(domain.aliases)\n        return emails\n\n    def send_welcome(self):\n        if app.config[\"WELCOME\"].lower() == \"true\":\n            self.sendmail(app.config[\"WELCOME_SUBJECT\"],\n                app.config[\"WELCOME_BODY\"])\n\n    @classmethod\n    def login(cls, email, password):\n        user = cls.query.get(email)\n        return user if (user and user.check_password(password)) else None\n\nlogin_manager.user_loader(User.query.get)\n\n\nclass Alias(Base, Email):\n    \"\"\" An alias is an email address that redirects to some destination.\n    \"\"\"\n    __tablename__ = \"alias\"\n\n    domain = db.relationship(Domain,\n        backref=db.backref('aliases', cascade='all, delete-orphan'))\n    wildcard = db.Column(db.Boolean(), nullable=False, default=False)\n    destination = db.Column(CommaSeparatedList, nullable=False, default=[])\n\n\nclass Token(Base):\n    \"\"\" A token is an application password for a given user.\n    \"\"\"\n    __tablename__ = \"token\"\n\n    id = db.Column(db.Integer(), primary_key=True)\n    user_email = db.Column(db.String(255), db.ForeignKey(User.email),\n        nullable=False)\n    user = db.relationship(User,\n        backref=db.backref('tokens', cascade='all, delete-orphan'))\n    password = db.Column(db.String(255), nullable=False)\n    ip = db.Column(db.String(255))\n\n    def check_password(self, password):\n        return hash.sha256_crypt.verify(password, self.password)\n\n    def set_password(self, password):\n        self.password = hash.sha256_crypt.using(rounds=1000).hash(password)\n\n    def __str__(self):\n        return self.comment\n\n\nclass Fetch(Base):\n    \"\"\" A fetched account is a repote POP/IMAP account fetched into a local\n    account.\n    \"\"\"\n    __tablename__ = \"fetch\"\n\n    id = db.Column(db.Integer(), primary_key=True)\n    user_email = db.Column(db.String(255), db.ForeignKey(User.email),\n        nullable=False)\n    user = db.relationship(User,\n        backref=db.backref('fetches', cascade='all, delete-orphan'))\n    protocol = db.Column(db.Enum('imap', 'pop3'), nullable=False)\n    host = db.Column(db.String(255), nullable=False)\n    port = db.Column(db.Integer(), nullable=False)\n    tls = db.Column(db.Boolean(), nullable=False)\n    username = db.Column(db.String(255), nullable=False)\n    password = db.Column(db.String(255), nullable=False)\n    keep = db.Column(db.Boolean(), nullable=False)\n    last_check = db.Column(db.DateTime, nullable=True)\n    error = db.Column(db.String(1023), nullable=True)\n", "path": "core/admin/mailu/models.py"}], "after_files": [{"content": "from mailu import app, db, dkim, login_manager\n\nfrom sqlalchemy.ext import declarative\nfrom passlib import context, hash\nfrom datetime import datetime, date\nfrom email.mime import text\n\n\nimport re\nimport time\nimport os\nimport glob\nimport smtplib\n\n\n# Many-to-many association table for domain managers\nmanagers = db.Table('manager',\n    db.Column('domain_name', db.String(80), db.ForeignKey('domain.name')),\n    db.Column('user_email', db.String(255), db.ForeignKey('user.email'))\n)\n\n\nclass CommaSeparatedList(db.TypeDecorator):\n    \"\"\" Stores a list as a comma-separated string, compatible with Postfix.\n    \"\"\"\n\n    impl = db.String\n\n    def process_bind_param(self, value, dialect):\n        if type(value) is not list:\n            raise TypeError(\"Shoud be a list\")\n        for item in value:\n            if \",\" in item:\n                raise ValueError(\"No item should contain a comma\")\n        return \",\".join(value)\n\n    def process_result_value(self, value, dialect):\n        return filter(bool, value.split(\",\"))\n\n\nclass Base(db.Model):\n    \"\"\" Base class for all models\n    \"\"\"\n\n    __abstract__ = True\n\n    created_at = db.Column(db.Date, nullable=False, default=datetime.now)\n    updated_at = db.Column(db.Date, nullable=True, onupdate=datetime.now)\n    comment = db.Column(db.String(255), nullable=True)\n\n\nclass Domain(Base):\n    \"\"\" A DNS domain that has mail addresses associated to it.\n    \"\"\"\n    __tablename__ = \"domain\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    managers = db.relationship('User', secondary=managers,\n        backref=db.backref('manager_of'), lazy='dynamic')\n    max_users = db.Column(db.Integer, nullable=False, default=0)\n    max_aliases = db.Column(db.Integer, nullable=False, default=0)\n    max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0)\n    signup_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n\n    @property\n    def dkim_key(self):\n        file_path = app.config[\"DKIM_PATH\"].format(\n            domain=self.name, selector=app.config[\"DKIM_SELECTOR\"])\n        if os.path.exists(file_path):\n            with open(file_path, \"rb\") as handle:\n                return handle.read()\n\n    @dkim_key.setter\n    def dkim_key(self, value):\n        file_path = app.config[\"DKIM_PATH\"].format(\n            domain=self.name, selector=app.config[\"DKIM_SELECTOR\"])\n        with open(file_path, \"wb\") as handle:\n            handle.write(value)\n\n    @property\n    def dkim_publickey(self):\n        dkim_key = self.dkim_key\n        if dkim_key:\n            return dkim.strip_key(self.dkim_key).decode(\"utf8\")\n\n    def generate_dkim_key(self):\n        self.dkim_key = dkim.gen_key()\n\n    def has_email(self, localpart):\n        for email in self.users + self.aliases:\n            if email.localpart == localpart:\n                return True\n        else:\n            return False\n\n    def __str__(self):\n        return self.name\n\n    def __eq__(self, other):\n        try:\n            return self.name == other.name\n        except AttributeError:\n            return False\n\n\nclass Alternative(Base):\n    \"\"\" Alternative name for a served domain.\n    The name \"domain alias\" was avoided to prevent some confusion.\n    \"\"\"\n\n    __tablename__ = \"alternative\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    domain_name = db.Column(db.String(80), db.ForeignKey(Domain.name))\n    domain = db.relationship(Domain,\n        backref=db.backref('alternatives', cascade='all, delete-orphan'))\n\n    def __str__(self):\n        return self.name\n\n\nclass Relay(Base):\n    \"\"\" Relayed mail domain.\n    The domain is either relayed publicly or through a specified SMTP host.\n    \"\"\"\n\n    __tablename__ = \"relay\"\n\n    name = db.Column(db.String(80), primary_key=True, nullable=False)\n    smtp = db.Column(db.String(80), nullable=True)\n\n    def __str__(self):\n        return self.name\n\n\nclass Email(object):\n    \"\"\" Abstraction for an email address (localpart and domain).\n    \"\"\"\n\n    localpart = db.Column(db.String(80), nullable=False)\n\n    @declarative.declared_attr\n    def domain_name(cls):\n        return db.Column(db.String(80), db.ForeignKey(Domain.name),\n            nullable=False)\n\n    # This field is redundant with both localpart and domain name.\n    # It is however very useful for quick lookups without joining tables,\n    # especially when the mail server il reading the database.\n    @declarative.declared_attr\n    def email(cls):\n        updater = lambda context: \"{0}@{1}\".format(\n            context.current_parameters[\"localpart\"],\n            context.current_parameters[\"domain_name\"],\n        )\n        return db.Column(db.String(255, collation=\"NOCASE\"),\n            primary_key=True, nullable=False,\n            default=updater)\n\n    def sendmail(self, subject, body):\n        \"\"\" Send an email to the address.\n        \"\"\"\n        from_address = '{}@{}'.format(\n            app.config['POSTMASTER'], app.config['DOMAIN'])\n        with smtplib.SMTP(app.config['HOST_AUTHSMTP'], port=10025) as smtp:\n            msg = text.MIMEText(body)\n            msg['Subject'] = subject\n            msg['From'] = from_address\n            msg['To'] = self.email\n            smtp.sendmail(from_address, [self.email], msg.as_string())\n\n    def __str__(self):\n        return self.email\n\n\nclass User(Base, Email):\n    \"\"\" A user is an email address that has a password to access a mailbox.\n    \"\"\"\n    __tablename__ = \"user\"\n\n    domain = db.relationship(Domain,\n        backref=db.backref('users', cascade='all, delete-orphan'))\n    password = db.Column(db.String(255), nullable=False)\n    quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9)\n    global_admin = db.Column(db.Boolean(), nullable=False, default=False)\n\n    # Features\n    enable_imap = db.Column(db.Boolean(), nullable=False, default=True)\n    enable_pop = db.Column(db.Boolean(), nullable=False, default=True)\n\n    # Filters\n    forward_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n    forward_destination = db.Column(db.String(255), nullable=True, default=None)\n    forward_keep = db.Column(db.Boolean(), nullable=False, default=True)\n    reply_enabled = db.Column(db.Boolean(), nullable=False, default=False)\n    reply_subject = db.Column(db.String(255), nullable=True, default=None)\n    reply_body = db.Column(db.Text(), nullable=True, default=None)\n    reply_enddate = db.Column(db.Date, nullable=False,\n        default=date(2999, 12, 31))\n\n    # Settings\n    displayed_name = db.Column(db.String(160), nullable=False, default=\"\")\n    spam_enabled = db.Column(db.Boolean(), nullable=False, default=True)\n    spam_threshold = db.Column(db.Integer(), nullable=False, default=80.0)\n\n    # Flask-login attributes\n    is_authenticated = True\n    is_active = True\n    is_anonymous = False\n\n    def get_id(self):\n        return self.email\n\n    scheme_dict = {'SHA512-CRYPT': \"sha512_crypt\",\n                   'SHA256-CRYPT': \"sha256_crypt\",\n                   'MD5-CRYPT': \"md5_crypt\",\n                   'CRYPT': \"des_crypt\"}\n    pw_context = context.CryptContext(\n        schemes = scheme_dict.values(),\n        default=scheme_dict[app.config['PASSWORD_SCHEME']],\n    )\n\n    def check_password(self, password):\n        reference = re.match('({[^}]+})?(.*)', self.password).group(2)\n        return User.pw_context.verify(password, reference)\n\n    def set_password(self, password, hash_scheme=app.config['PASSWORD_SCHEME'], raw=False):\n        \"\"\"Set password for user with specified encryption scheme\n           @password: plain text password to encrypt (if raw == True the hash itself)\n        \"\"\"\n        # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes\n        if raw:\n            self.password = '{'+hash_scheme+'}' + password\n        else:\n            self.password = '{'+hash_scheme+'}' + User.pw_context.encrypt(password, self.scheme_dict[hash_scheme])\n\n    def get_managed_domains(self):\n        if self.global_admin:\n            return Domain.query.all()\n        else:\n            return self.manager_of\n\n    def get_managed_emails(self, include_aliases=True):\n        emails = []\n        for domain in self.get_managed_domains():\n            emails.extend(domain.users)\n            if include_aliases:\n                emails.extend(domain.aliases)\n        return emails\n\n    def send_welcome(self):\n        if app.config[\"WELCOME\"].lower() == \"true\":\n            self.sendmail(app.config[\"WELCOME_SUBJECT\"],\n                app.config[\"WELCOME_BODY\"])\n\n    @classmethod\n    def login(cls, email, password):\n        user = cls.query.get(email)\n        return user if (user and user.check_password(password)) else None\n\nlogin_manager.user_loader(User.query.get)\n\n\nclass Alias(Base, Email):\n    \"\"\" An alias is an email address that redirects to some destination.\n    \"\"\"\n    __tablename__ = \"alias\"\n\n    domain = db.relationship(Domain,\n        backref=db.backref('aliases', cascade='all, delete-orphan'))\n    wildcard = db.Column(db.Boolean(), nullable=False, default=False)\n    destination = db.Column(CommaSeparatedList, nullable=False, default=[])\n\n\nclass Token(Base):\n    \"\"\" A token is an application password for a given user.\n    \"\"\"\n    __tablename__ = \"token\"\n\n    id = db.Column(db.Integer(), primary_key=True)\n    user_email = db.Column(db.String(255), db.ForeignKey(User.email),\n        nullable=False)\n    user = db.relationship(User,\n        backref=db.backref('tokens', cascade='all, delete-orphan'))\n    password = db.Column(db.String(255), nullable=False)\n    ip = db.Column(db.String(255))\n\n    def check_password(self, password):\n        return hash.sha256_crypt.verify(password, self.password)\n\n    def set_password(self, password):\n        self.password = hash.sha256_crypt.using(rounds=1000).hash(password)\n\n    def __str__(self):\n        return self.comment\n\n\nclass Fetch(Base):\n    \"\"\" A fetched account is a repote POP/IMAP account fetched into a local\n    account.\n    \"\"\"\n    __tablename__ = \"fetch\"\n\n    id = db.Column(db.Integer(), primary_key=True)\n    user_email = db.Column(db.String(255), db.ForeignKey(User.email),\n        nullable=False)\n    user = db.relationship(User,\n        backref=db.backref('fetches', cascade='all, delete-orphan'))\n    protocol = db.Column(db.Enum('imap', 'pop3'), nullable=False)\n    host = db.Column(db.String(255), nullable=False)\n    port = db.Column(db.Integer(), nullable=False)\n    tls = db.Column(db.Boolean(), nullable=False)\n    username = db.Column(db.String(255), nullable=False)\n    password = db.Column(db.String(255), nullable=False)\n    keep = db.Column(db.Boolean(), nullable=False)\n    last_check = db.Column(db.DateTime, nullable=True)\n    error = db.Column(db.String(1023), nullable=True)\n", "path": "core/admin/mailu/models.py"}]}