1
0
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:
Rainulf Pineda
2016-01-05 16:05:45 -05:00
parent cb162da5fe
commit 590321fcb7
7 changed files with 138 additions and 16 deletions

View File

@@ -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():

View File

@@ -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

View File

@@ -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');