diff --git a/management/daemon.py b/management/daemon.py index 2e23c8aa..c956bb9a 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -6,7 +6,7 @@ from functools import wraps from flask import Flask, request, render_template, abort, Response, send_from_directory, make_response import auth, utils, multiprocessing.pool -from mailconfig import get_mail_users, get_mail_users_ex, get_admins, add_mail_user, set_mail_password, remove_mail_user +from mailconfig import get_mail_users, get_mail_users_ex, get_admins, add_mail_user, set_mail_password, set_mail_quota, remove_mail_user from mailconfig import get_mail_user_privileges, add_remove_mail_user_privilege from mailconfig import get_mail_aliases, get_mail_aliases_ex, get_mail_domains, add_mail_alias, remove_mail_alias @@ -154,7 +154,11 @@ def mail_users(): @authorized_personnel_only def mail_users_add(): try: - return add_mail_user(request.form.get('email', ''), request.form.get('password', ''), request.form.get('privileges', ''), env) + return add_mail_user( + request.form.get('email', ''), + request.form.get('password', ''), + request.form.get('privileges', ''), + request.form.get('quota', ''), env) except ValueError as e: return (str(e), 400) @@ -166,6 +170,14 @@ def mail_users_password(): except ValueError as e: return (str(e), 400) +@app.route('/mail/users/quota', methods=['POST']) +@authorized_personnel_only +def mail_users_quota(): + try: + return set_mail_quota(request.form.get('email', ''), request.form.get('quota', ''), env) + except ValueError as e: + return (str(e), 400) + @app.route('/mail/users/remove', methods=['POST']) @authorized_personnel_only def mail_users_remove(): diff --git a/management/mailconfig.py b/management/mailconfig.py index 82c922e4..04baf296 100755 --- a/management/mailconfig.py +++ b/management/mailconfig.py @@ -128,14 +128,15 @@ def get_mail_users_ex(env, with_archived=False, with_slow_info=False): users = [] active_accounts = set() c = open_database(env) - c.execute('SELECT email, privileges FROM users') - for email, privileges in c.fetchall(): + c.execute('SELECT email, privileges, quota FROM users') + for email, privileges, quota in c.fetchall(): active_accounts.add(email) user = { "email": email, "privileges": parse_privs(privileges), "status": "active", + "quota": quota, } users.append(user) @@ -156,6 +157,7 @@ def get_mail_users_ex(env, with_archived=False, with_slow_info=False): "privileges": "", "status": "inactive", "mailbox": mbox, + "quota": "?", } users.append(user) if with_slow_info: @@ -271,7 +273,7 @@ def get_mail_domains(env, filter_aliases=lambda alias : True): + [get_domain(address, as_unicode=False) for address, *_ in get_mail_aliases(env) if filter_aliases(address) ] ) -def add_mail_user(email, pw, privs, env): +def add_mail_user(email, pw, privs, quota, env): # validate email if email.strip() == "": return ("No email address provided.", 400) @@ -285,8 +287,13 @@ def add_mail_user(email, pw, privs, env): # during box setup the user won't know the rules. return ("You may not make a user account for that address because it is frequently used for domain control validation. Use an alias instead if necessary.", 400) + if not quota: + quota = 0 + # validate password validate_password(pw) + # validate quota + validate_quota(quota) # validate privileges if privs is None or privs.strip() == "": @@ -305,8 +312,8 @@ def add_mail_user(email, pw, privs, env): # add the user to the database try: - c.execute("INSERT INTO users (email, password, privileges) VALUES (?, ?, ?)", - (email, pw, "\n".join(privs))) + c.execute("INSERT INTO users (email, password, quota, privileges) VALUES (?, ?, ?, ?)", + (email, pw, quota, "\n".join(privs))) except sqlite3.IntegrityError: return ("User already exists.", 400) @@ -331,6 +338,20 @@ def set_mail_password(email, pw, env): conn.commit() return "OK" +def set_mail_quota(email, quota, env): + if not quota: + quota = 0 + # validate quota + validate_quota(quota) + + # update the database + conn, c = open_database(env, with_connection=True) + c.execute("UPDATE users SET quota=? WHERE email=?", (quota, email)) + if c.rowcount != 1: + return ("That's not a user (%s)." % email, 400) + conn.commit() + return "OK" + def hash_password(pw): # Turn the plain password into a Dovecot-format hashed password, meaning # something like "{SCHEME}hashedpassworddata". @@ -613,6 +634,13 @@ def validate_password(pw): if len(pw) < 8: raise ValueError("Passwords must be at least eight characters.") +def validate_quota(quota): + # validate quota + quota = str(quota) + if not quota.isdigit(): + raise ValueError("Quota must be a number.") + if int(quota) < 0: + raise ValueError("Quota must be a positive number.") if __name__ == "__main__": import sys diff --git a/management/templates/users.html b/management/templates/users.html index cf944c86..2e40f104 100644 --- a/management/templates/users.html +++ b/management/templates/users.html @@ -22,6 +22,10 @@ +