Add percentage used and update tools/mail.py to set quotas

This commit is contained in:
John Supplee 2019-02-01 15:36:27 +02:00
parent fa66585b6b
commit 7874683618
5 changed files with 94 additions and 17 deletions

View File

@ -56,6 +56,19 @@ Todo
Changes Changes
------- -------
### v0.40-quota-0.13-alpha
* Add a `default-quota` setting in `settings.yaml`
* Add input for setting quota when entering a new user in control panel
* Modify `tools/mail.py` to allow for setting and getting the default system quota
* Modify `tools/mail.py` to allow for getting a user's quota setting
* Modify the mail users list in control panel to display percentage used
### v0.40-quota-0.12-alpha ### v0.40-quota-0.12-alpha
* Update README * Update README

View File

@ -9,7 +9,7 @@ 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, remove_mail_user
from mailconfig import get_mail_user_privileges, add_remove_mail_user_privilege 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 from mailconfig import get_mail_aliases, get_mail_aliases_ex, get_mail_domains, add_mail_alias, remove_mail_alias
from mailconfig import set_mail_quota, get_default_quota, validate_quota from mailconfig import get_mail_quota, set_mail_quota, get_default_quota, validate_quota
env = utils.load_environment() env = utils.load_environment()
auth_service = auth.KeyAuthService() auth_service = auth.KeyAuthService()
@ -153,11 +153,26 @@ def mail_users():
@app.route('/mail/users/add', methods=['POST']) @app.route('/mail/users/add', methods=['POST'])
@authorized_personnel_only @authorized_personnel_only
def mail_users_add(): def mail_users_add():
quota = request.form.get('quota', get_default_quota(env))
try: try:
return add_mail_user(request.form.get('email', ''), request.form.get('password', ''), request.form.get('privileges', ''), request.form.get('quota', ''), env) return add_mail_user(request.form.get('email', ''), request.form.get('password', ''), request.form.get('privileges', ''), quota, env)
except ValueError as e: except ValueError as e:
return (str(e), 400) return (str(e), 400)
@app.route('/mail/users/quota', methods=['GET'])
@authorized_personnel_only
def get_mail_users_quota():
email = request.values.get('email', '')
quota = get_mail_quota(email, env)
if request.values.get('text'):
return quota
return json_response({
"email": email,
"quota": quota
})
@app.route('/mail/users/quota', methods=['POST']) @app.route('/mail/users/quota', methods=['POST'])
@authorized_personnel_only @authorized_personnel_only
def mail_users_quota(): def mail_users_quota():
@ -531,8 +546,11 @@ def privacy_status_set():
@app.route('/system/default-quota', methods=["GET"]) @app.route('/system/default-quota', methods=["GET"])
@authorized_personnel_only @authorized_personnel_only
def default_quota_get(): def default_quota_get():
if request.values.get('text'):
return get_default_quota(env)
else:
return json_response({ return json_response({
"default-quota": get_default_quota(env) "default-quota": get_default_quota(env),
}) })
@app.route('/system/default-quota', methods=["POST"]) @app.route('/system/default-quota', methods=["POST"])
@ -540,7 +558,7 @@ def default_quota_get():
def default_quota_set(): def default_quota_set():
config = utils.load_settings(env) config = utils.load_settings(env)
try: try:
config["default-quota"] = validate_quota(request.form.get('default_quota')) config["default-quota"] = validate_quota(request.values.get('default_quota'))
utils.write_settings(config, env) utils.write_settings(config, env)
except ValueError as e: except ValueError as e:

View File

@ -147,18 +147,30 @@ def get_mail_users_ex(env, with_archived=False):
(user, domain) = email.split('@') (user, domain) = email.split('@')
box_size = 0 box_size = 0
box_count = 0 box_count = 0
box_quota = '' box_quota = 0
percent = ''
try: try:
dirsize_file = os.path.join(env['STORAGE_ROOT'], 'mail/mailboxes/%s/%s/maildirsize' % (domain, user)) dirsize_file = os.path.join(env['STORAGE_ROOT'], 'mail/mailboxes/%s/%s/maildirsize' % (domain, user))
with open(dirsize_file, 'r') as f: with open(dirsize_file, 'r') as f:
box_quota = f.readline() box_quota = int(f.readline().split('S')[0])
for line in f.readlines(): for line in f.readlines():
(size, count) = line.split(' ') (size, count) = line.split(' ')
box_size += int(size) box_size += int(size)
box_count += int(count) box_count += int(count)
try:
percent = (box_size / box_quota) * 100
except:
percent = 'Error'
except: except:
box_size = '?' box_size = '?'
box_count = '?' box_count = '?'
box_quota = '?'
percent = '?'
if quota == '0':
percent = ''
user = { user = {
"email": email, "email": email,
@ -166,6 +178,7 @@ def get_mail_users_ex(env, with_archived=False):
"quota": quota, "quota": quota,
"box_quota": box_quota, "box_quota": box_quota,
"box_size": sizeof_fmt(box_size) if box_size != '?' else box_size, "box_size": sizeof_fmt(box_size) if box_size != '?' else box_size,
"percent": '%3.0f%%' % percent if type(percent) != str else percent,
"box_count": box_count, "box_count": box_count,
"status": "active", "status": "active",
} }
@ -324,6 +337,9 @@ def add_mail_user(email, pw, privs, quota, env):
validation = validate_privilege(p) validation = validate_privilege(p)
if validation: return validation if validation: return validation
if quota is None:
quota = get_default_quota()
try: try:
quota = validate_quota(quota) quota = validate_quota(quota)
except ValueError as e: except ValueError as e:
@ -338,7 +354,7 @@ def add_mail_user(email, pw, privs, quota, env):
# add the user to the database # add the user to the database
try: try:
c.execute("INSERT INTO users (email, password, privileges, quota) VALUES (?, ?, ?, ?)", c.execute("INSERT INTO users (email, password, privileges, quota) VALUES (?, ?, ?, ?)",
(email, pw, "\n".join(privs)), quota) (email, pw, "\n".join(privs), quota))
except sqlite3.IntegrityError: except sqlite3.IntegrityError:
return ("User already exists.", 400) return ("User already exists.", 400)
@ -369,6 +385,15 @@ def hash_password(pw):
# http://wiki2.dovecot.org/Authentication/PasswordSchemes # http://wiki2.dovecot.org/Authentication/PasswordSchemes
return utils.shell('check_output', ["/usr/bin/doveadm", "pw", "-s", "SHA512-CRYPT", "-p", pw]).strip() return utils.shell('check_output', ["/usr/bin/doveadm", "pw", "-s", "SHA512-CRYPT", "-p", pw]).strip()
def get_mail_quota(email, env):
conn, c = open_database(env, with_connection=True)
c.execute("SELECT quota FROM users WHERE email=?", (email,))
rows = c.fetchall()
if len(rows) != 1:
return ("That's not a user (%s)." % email, 400)
return rows[0][0]
def set_mail_quota(email, quota, env): def set_mail_quota(email, quota, env):
# validate that password is acceptable # validate that password is acceptable
quota = validate_quota(quota) quota = validate_quota(quota)

View File

@ -7,6 +7,7 @@
#user_table .account_inactive .if_active { display: none; } #user_table .account_inactive .if_active { display: none; }
#user_table .account_active .if_inactive { display: none; } #user_table .account_active .if_inactive { display: none; }
#user_table .account_active.if_inactive { display: none; } #user_table .account_active.if_inactive { display: none; }
.row-center { text-align: center; }
</style> </style>
<h3>Add a mail user</h3> <h3>Add a mail user</h3>
@ -47,9 +48,10 @@
<thead> <thead>
<tr> <tr>
<th width="35%">Email Address</th> <th width="35%">Email Address</th>
<th>Messages</th> <th class="row-center">Messages</th>
<th>Size</th> <th class="row-center">Size</th>
<th>Quota</th> <th class="row-center">Used</th>
<th class="row-center">Quota</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
@ -62,9 +64,10 @@
<tr id="user-template"> <tr id="user-template">
<td class='address'> <td class='address'>
</td> </td>
<td class="box-count"></td> <td class="box-count row-center"></td>
<td class="box-size"></td> <td class="box-size row-center"></td>
<td class="quota"> <td class="percent row-center"></td>
<td class="quota row-center">
</td> </td>
<td class='actions'> <td class='actions'>
<span class='privs'> <span class='privs'>
@ -159,7 +162,7 @@ function show_users() {
function(r) { function(r) {
$('#user_table tbody').html(""); $('#user_table tbody').html("");
for (var i = 0; i < r.length; i++) { for (var i = 0; i < r.length; i++) {
var hdr = $("<tr><td colspan='3'><h4/></td></tr>"); var hdr = $("<tr><td colspan='6'><h4/></td></tr>");
hdr.find('h4').text(r[i].domain); hdr.find('h4').text(r[i].domain);
$('#user_table tbody').append(hdr); $('#user_table tbody').append(hdr);
@ -180,7 +183,14 @@ function show_users() {
n.attr('data-quota', user.quota); n.attr('data-quota', user.quota);
n.find('.address').text(user.email); n.find('.address').text(user.email);
n.find('.box-count').text(user.box_count); n.find('.box-count').text(user.box_count);
if (user.box_count == '?') {
n.find('.box-count').attr('title', 'Message count is unkown')
}
n.find('.box-size').text(user.box_size); n.find('.box-size').text(user.box_size);
if (user.box_size == '?') {
n.find('.box-size').attr('title', 'Mailbox size is unkown')
}
n.find('.percent').text(user.percent)
n.find('.quota').text((user.quota == '0') ? 'unlimited' : user.quota); n.find('.quota').text((user.quota == '0') ? 'unlimited' : user.quota);
n2.find('.restore_info tt').text(user.mailbox); n2.find('.restore_info tt').text(user.mailbox);

View File

@ -57,10 +57,11 @@ def setup_key_auth(mgmt_uri):
if len(sys.argv) < 2: if len(sys.argv) < 2:
print("Usage: ") print("Usage: ")
print(" tools/mail.py system default-quota [new default]")
print(" tools/mail.py user (lists users with quotas)") print(" tools/mail.py user (lists users with quotas)")
print(" tools/mail.py user add user@domain.com [password]") print(" tools/mail.py user add user@domain.com [password]")
print(" tools/mail.py user password user@domain.com [password]") print(" tools/mail.py user password user@domain.com [password]")
print(" tools/mail.py user quota user@domain new-quota") print(" tools/mail.py user quota user@domain [new-quota]")
print(" tools/mail.py user remove user@domain.com") print(" tools/mail.py user remove user@domain.com")
print(" tools/mail.py user make-admin user@domain.com") print(" tools/mail.py user make-admin user@domain.com")
print(" tools/mail.py user remove-admin user@domain.com") print(" tools/mail.py user remove-admin user@domain.com")
@ -121,6 +122,10 @@ elif sys.argv[1] == "user" and sys.argv[2] == "admins":
if "admin" in user['privileges']: if "admin" in user['privileges']:
print(user['email']) print(user['email'])
elif sys.argv[1] == "user" and sys.argv[2] == "quota" and len(sys.argv) == 4:
# Set a user's quota
print(mgmt("/mail/users/quota?text=1&email=%s" % sys.argv[3]))
elif sys.argv[1] == "user" and sys.argv[2] == "quota" and len(sys.argv) == 5: elif sys.argv[1] == "user" and sys.argv[2] == "quota" and len(sys.argv) == 5:
# Set a user's quota # Set a user's quota
users = mgmt("/mail/users/quota", { "email": sys.argv[3], "quota": sys.argv[4] }) users = mgmt("/mail/users/quota", { "email": sys.argv[3], "quota": sys.argv[4] })
@ -134,6 +139,12 @@ elif sys.argv[1] == "alias" and sys.argv[2] == "add" and len(sys.argv) == 5:
elif sys.argv[1] == "alias" and sys.argv[2] == "remove" and len(sys.argv) == 4: elif sys.argv[1] == "alias" and sys.argv[2] == "remove" and len(sys.argv) == 4:
print(mgmt("/mail/aliases/remove", { "address": sys.argv[3] })) print(mgmt("/mail/aliases/remove", { "address": sys.argv[3] }))
elif sys.argv[1] == "system" and sys.argv[2] == "default-quota" and len(sys.argv) == 3:
print(mgmt("/system/default-quota?text=1"))
elif sys.argv[1] == "system" and sys.argv[2] == "default-quota" and len(sys.argv) == 4:
print(mgmt("/system/default-quota", { "default_quota": sys.argv[3]}))
else: else:
print("Invalid command-line arguments.") print("Invalid command-line arguments.")
sys.exit(1) sys.exit(1)