mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-11-25 02:47:04 +00:00
in the admin, show user mailbox sizes, fixes #210
This commit is contained in:
parent
443b084a17
commit
06a8ce1c9d
@ -98,7 +98,7 @@ def me():
|
|||||||
@authorized_personnel_only
|
@authorized_personnel_only
|
||||||
def mail_users():
|
def mail_users():
|
||||||
if request.args.get("format", "") == "json":
|
if request.args.get("format", "") == "json":
|
||||||
return json_response(get_mail_users_ex(env, with_archived=True))
|
return json_response(get_mail_users_ex(env, with_archived=True, with_slow_info=True))
|
||||||
else:
|
else:
|
||||||
return "".join(x+"\n" for x in get_mail_users(env))
|
return "".join(x+"\n" for x in get_mail_users(env))
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ def get_mail_users(env):
|
|||||||
users = [ row[0] for row in c.fetchall() ]
|
users = [ row[0] for row in c.fetchall() ]
|
||||||
return utils.sort_email_addresses(users, env)
|
return utils.sort_email_addresses(users, env)
|
||||||
|
|
||||||
def get_mail_users_ex(env, with_archived=False):
|
def get_mail_users_ex(env, with_archived=False, with_slow_info=False):
|
||||||
# Returns a complex data structure of all user accounts, optionally
|
# Returns a complex data structure of all user accounts, optionally
|
||||||
# including archived (status="inactive") accounts.
|
# including archived (status="inactive") accounts.
|
||||||
#
|
#
|
||||||
@ -86,15 +86,20 @@ def get_mail_users_ex(env, with_archived=False):
|
|||||||
c.execute('SELECT email, privileges FROM users')
|
c.execute('SELECT email, privileges FROM users')
|
||||||
for email, privileges in c.fetchall():
|
for email, privileges in c.fetchall():
|
||||||
active_accounts.add(email)
|
active_accounts.add(email)
|
||||||
users.append({
|
|
||||||
|
user = {
|
||||||
"email": email,
|
"email": email,
|
||||||
"privileges": parse_privs(privileges),
|
"privileges": parse_privs(privileges),
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"aliases": [
|
}
|
||||||
|
users.append(user)
|
||||||
|
|
||||||
|
if with_slow_info:
|
||||||
|
user["aliases"] = [
|
||||||
(alias, sorted(evaluate_mail_alias_map(alias, aliases, env)))
|
(alias, sorted(evaluate_mail_alias_map(alias, aliases, env)))
|
||||||
for alias in aliases.get(email.lower(), [])
|
for alias in aliases.get(email.lower(), [])
|
||||||
]
|
]
|
||||||
})
|
user["mailbox_size"] = utils.du(os.path.join(env['STORAGE_ROOT'], 'mail/mailboxes', *reversed(email.split("@"))))
|
||||||
|
|
||||||
# Add in archived accounts.
|
# Add in archived accounts.
|
||||||
if with_archived:
|
if with_archived:
|
||||||
@ -102,13 +107,17 @@ def get_mail_users_ex(env, with_archived=False):
|
|||||||
for domain in os.listdir(root):
|
for domain in os.listdir(root):
|
||||||
for user in os.listdir(os.path.join(root, domain)):
|
for user in os.listdir(os.path.join(root, domain)):
|
||||||
email = user + "@" + domain
|
email = user + "@" + domain
|
||||||
|
mbox = os.path.join(root, domain, user)
|
||||||
if email in active_accounts: continue
|
if email in active_accounts: continue
|
||||||
users.append({
|
user = {
|
||||||
"email": email,
|
"email": email,
|
||||||
"privileges": "",
|
"privileges": "",
|
||||||
"status": "inactive",
|
"status": "inactive",
|
||||||
"mailbox": os.path.join(root, domain, user),
|
"mailbox": mbox,
|
||||||
})
|
}
|
||||||
|
users.append(user)
|
||||||
|
if with_slow_info:
|
||||||
|
user["mailbox_size"] = utils.du(mbox)
|
||||||
|
|
||||||
# Group by domain.
|
# Group by domain.
|
||||||
domains = { }
|
domains = { }
|
||||||
|
@ -39,7 +39,12 @@ function nice_size(bytes) {
|
|||||||
bytes /= 1024;
|
bytes /= 1024;
|
||||||
powers.shift();
|
powers.shift();
|
||||||
}
|
}
|
||||||
return (Math.round(bytes*10)/10) + " " + powers[0];
|
// round to have three significant figures but at most one decimal place
|
||||||
|
if (bytes >= 100)
|
||||||
|
bytes = Math.round(bytes)
|
||||||
|
else
|
||||||
|
bytes = Math.round(bytes*10)/10;
|
||||||
|
return bytes + " " + powers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_system_backup() {
|
function show_system_backup() {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<h2>Users</h2>
|
<h2>Users</h2>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#user_table tr.account_inactive td .address { color: #888; text-decoration: line-through; }
|
#user_table tr.account_inactive td.address { color: #888; text-decoration: line-through; }
|
||||||
#user_table .aliases { margin-top: .33em; font-size: 95%; }
|
#user_table .aliases { font-size: 90%; }
|
||||||
#user_table .aliases div:before { content: "⇖ "; }
|
#user_table .aliases div:before { content: "⇖ "; }
|
||||||
#user_table .aliases div { }
|
#user_table .aliases div { }
|
||||||
#user_table .actions { margin-top: .33em; font-size: 95%; }
|
#user_table .actions { margin-top: .33em; font-size: 95%; }
|
||||||
@ -38,6 +38,13 @@
|
|||||||
|
|
||||||
<h3>Existing mail users</h3>
|
<h3>Existing mail users</h3>
|
||||||
<table id="user_table" class="table" style="width: auto">
|
<table id="user_table" class="table" style="width: auto">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50%">Email Address</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
<th>Mailbox Size</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -45,10 +52,9 @@
|
|||||||
<div style="display: none">
|
<div style="display: none">
|
||||||
<table>
|
<table>
|
||||||
<tr id="user-template">
|
<tr id="user-template">
|
||||||
<td class='email'>
|
<td class='address'>
|
||||||
<div class='address'> </div>
|
</td>
|
||||||
|
<td class='actions'>
|
||||||
<div class='actions'>
|
|
||||||
<span class='privs'>
|
<span class='privs'>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@ -65,9 +71,13 @@
|
|||||||
<a href="#" onclick="users_remove(this); return false;" class='if_active' title="Archive Account">
|
<a href="#" onclick="users_remove(this); return false;" class='if_active' title="Archive Account">
|
||||||
archive account
|
archive account
|
||||||
</a>
|
</a>
|
||||||
|
</td>
|
||||||
<div class='if_inactive restore_info' style='color: #888; font-size: 90%'>To restore account, create a new account with this email address. Or to permanently delete the mailbox, delete the directory <tt></tt> on the machine.</div>
|
<td class='mailboxsize'>
|
||||||
</div>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="user-extra-template">
|
||||||
|
<td colspan="3" style="border-top: 0; padding-top: 0">
|
||||||
|
<div class='if_inactive restore_info' style='color: #888; font-size: 90%'>To restore account, create a new account with this email address. Or to permanently delete the mailbox, delete the directory <tt></tt> on the machine.</div>
|
||||||
|
|
||||||
<div class='aliases' style='display: none'> </div>
|
<div class='aliases' style='display: none'> </div>
|
||||||
</td>
|
</td>
|
||||||
@ -94,13 +104,19 @@ function show_users() {
|
|||||||
var user = r[i].users[k];
|
var user = r[i].users[k];
|
||||||
|
|
||||||
var n = $("#user-template").clone();
|
var n = $("#user-template").clone();
|
||||||
|
var n2 = $("#user-extra-template").clone();
|
||||||
n.attr('id', '');
|
n.attr('id', '');
|
||||||
|
n2.attr('id', '');
|
||||||
|
$('#user_table tbody').append(n);
|
||||||
|
$('#user_table tbody').append(n2);
|
||||||
|
|
||||||
n.addClass("account_" + user.status);
|
n.addClass("account_" + user.status);
|
||||||
|
n2.addClass("account_" + user.status);
|
||||||
|
|
||||||
n.attr('data-email', user.email);
|
n.attr('data-email', user.email);
|
||||||
n.find('td.email .address').text(user.email)
|
n.find('.address').text(user.email)
|
||||||
$('#user_table tbody').append(n);
|
n.find('.mailboxsize').text(nice_size(user.mailbox_size))
|
||||||
n.find('.restore_info tt').text(user.mailbox);
|
n2.find('.restore_info tt').text(user.mailbox);
|
||||||
|
|
||||||
if (user.status == 'inactive') continue;
|
if (user.status == 'inactive') continue;
|
||||||
|
|
||||||
@ -121,9 +137,9 @@ function show_users() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user.aliases && user.aliases.length > 0) {
|
if (user.aliases && user.aliases.length > 0) {
|
||||||
n.find('.aliases').show();
|
n2.find('.aliases').show();
|
||||||
for (var j = 0; j < user.aliases.length; j++) {
|
for (var j = 0; j < user.aliases.length; j++) {
|
||||||
n.find('td.email .aliases').append($("<div/>").text(
|
n2.find('.aliases').append($("<div/>").text(
|
||||||
user.aliases[j][0]
|
user.aliases[j][0]
|
||||||
+ (user.aliases[j][1].length > 0 ? " ⇐ " + user.aliases[j][1].join(", ") : "")
|
+ (user.aliases[j][1].length > 0 ? " ⇐ " + user.aliases[j][1].join(", ") : "")
|
||||||
))
|
))
|
||||||
|
@ -165,3 +165,22 @@ def create_syslog_handler():
|
|||||||
handler = logging.handlers.SysLogHandler(address='/dev/log')
|
handler = logging.handlers.SysLogHandler(address='/dev/log')
|
||||||
handler.setLevel(logging.WARNING)
|
handler.setLevel(logging.WARNING)
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
def du(path):
|
||||||
|
# Computes the size of all files in the path, like the `du` command.
|
||||||
|
# Based on http://stackoverflow.com/a/17936789. Takes into account
|
||||||
|
# soft and hard links.
|
||||||
|
total_size = 0
|
||||||
|
seen = set()
|
||||||
|
for dirpath, dirnames, filenames in os.walk(path):
|
||||||
|
for f in filenames:
|
||||||
|
fp = os.path.join(dirpath, f)
|
||||||
|
try:
|
||||||
|
stat = os.lstat(fp)
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
if stat.st_ino in seen:
|
||||||
|
continue
|
||||||
|
seen.add(stat.st_ino)
|
||||||
|
total_size += stat.st_size
|
||||||
|
return total_size
|
||||||
|
Loading…
Reference in New Issue
Block a user