mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2026-04-19 00:17:23 +02:00
Implemented quota.
- Implemented quota to management. - Quota to have 0 as default, added more description.
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
<label class="sr-only" for="adduserPassword">Password</label>
|
||||
<input type="password" class="form-control" id="adduserPassword" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="adduserQuota">Quota (MB)</label>
|
||||
<input type="text" class="form-control" id="adduserQuota" placeholder="Quota (MB)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select class="form-control" id="adduserPrivs">
|
||||
<option value="">Normal User</option>
|
||||
@@ -31,6 +35,7 @@
|
||||
<button type="submit" class="btn btn-primary">Add User</button>
|
||||
</form>
|
||||
<ul style="margin-top: 1em; padding-left: 1.5em; font-size: 90%;">
|
||||
<li>Enter blank or 0 for no quota (unlimited) accounts.</li>
|
||||
<li>Passwords must be at least eight characters and may not contain spaces. For best results, <a href="#" onclick="return generate_random_password()">generate a random password</a>.</li>
|
||||
<li>Use <a href="#" onclick="return show_panel('aliases')">aliases</a> to create email addresses that forward to existing accounts.</li>
|
||||
<li>Administrators get access to this control panel.</li>
|
||||
@@ -44,6 +49,7 @@
|
||||
<th width="50%">Email Address</th>
|
||||
<th>Actions</th>
|
||||
<th>Mailbox Size</th>
|
||||
<th>Mailbox Quota</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -66,6 +72,13 @@
|
||||
|
|
||||
</span>
|
||||
|
||||
<span class="if_active">
|
||||
<a href="#" onclick="users_set_quota(this); return false;" class='setquota' title="Set Quota">
|
||||
set quota
|
||||
</a>
|
||||
|
|
||||
</span>
|
||||
|
||||
<span class='add-privs'>
|
||||
</span>
|
||||
|
||||
@@ -75,6 +88,8 @@
|
||||
</td>
|
||||
<td class='mailboxsize'>
|
||||
</td>
|
||||
<td class='mailboxquota'>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="user-extra-template" class="if_inactive">
|
||||
<td colspan="3" style="border: 0; padding-top: 0">
|
||||
@@ -157,6 +172,7 @@ function show_users() {
|
||||
n.attr('data-email', user.email);
|
||||
n.find('.address').text(user.email)
|
||||
n.find('.mailboxsize').text(nice_size(user.mailbox_size))
|
||||
n.find('.mailboxquota').text(''+user.quota + " MB")
|
||||
n2.find('.restore_info tt').text(user.mailbox);
|
||||
|
||||
if (user.status == 'inactive') continue;
|
||||
@@ -185,13 +201,15 @@ function do_add_user() {
|
||||
var email = $("#adduserEmail").val();
|
||||
var pw = $("#adduserPassword").val();
|
||||
var privs = $("#adduserPrivs").val();
|
||||
var quota = $("#adduserQuota").val();
|
||||
api(
|
||||
"/mail/users/add",
|
||||
"POST",
|
||||
{
|
||||
email: email,
|
||||
password: pw,
|
||||
privileges: privs
|
||||
privileges: privs,
|
||||
quota: quota
|
||||
},
|
||||
function(r) {
|
||||
// Responses are multiple lines of pre-formatted text.
|
||||
@@ -233,6 +251,33 @@ function users_set_password(elem) {
|
||||
});
|
||||
}
|
||||
|
||||
function users_set_quota(elem) {
|
||||
var email = $(elem).parents('tr').attr('data-email');
|
||||
|
||||
var quota = "";
|
||||
|
||||
show_modal_confirm(
|
||||
"User Quota",
|
||||
$("<p>Set a new quota for <b>" + email + "</b>?</p> <p><label for='quota_value' style='display: block; font-weight: normal'>New Quota (MB):</label><input type='text' id='quota_value'></p><p><small>Quota must be positive integer. Enter 0 or blank for no quota.</small></p>"),
|
||||
"Set Quota",
|
||||
function() {
|
||||
api(
|
||||
"/mail/users/quota",
|
||||
"POST",
|
||||
{
|
||||
email: email,
|
||||
quota: $('#quota_value').val()
|
||||
},
|
||||
function(r) {
|
||||
// Responses are multiple lines of pre-formatted text.
|
||||
show_modal_error("Set Quota", $("<pre/>").text(r));
|
||||
},
|
||||
function(r) {
|
||||
show_modal_error("Set Quota", r);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function users_remove(elem) {
|
||||
var email = $(elem).parents('tr').attr('data-email');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user