Update to 5.4

This commit is contained in:
Copium-Snorter
2023-06-20 20:23:44 +01:00
parent 2991096ba7
commit 7b6f07ed6e
47 changed files with 138 additions and 89 deletions

View File

@@ -1,3 +1,14 @@
# 5.4
* RESTful API:
+ `GET /api/users/<domain>`: Export used quota info.
* Fixed issues:
- [API] Disabling domain causes losing inbound BCC email address.
- Can not save few per-admin privileges.
- Not respect server wide min/max password lengths while adding new user.
- tools/cleanup_amavisd_db.py: Can not clean up old SQL records if
column "quar_type" value is null.
# 5.3
+ Ship Python module web.py (github.com/webpy/webpy, public domain).
* RESTful API:

16
EULA Normal file
View File

@@ -0,0 +1,16 @@
* What's included within iRedAdmin-Pro license
- Free upgrade with valid license.
* Restrictions
- One license per server. Customer must purchase license for each server.
- Customer has to renew the license of iRedAdmin-Pro to continue using
iRedAdmin-Pro before license expired.
- After license expired, customer has to purchase a new license to continue
using iRedAdmin-Pro.
- NOT allowed to redistribute and/or resell original iRedAdmin-Pro source
code and the copy you modified based on iRedAdmin-Pro.

0
controllers/sql/urls.py Normal file → Executable file
View File

Binary file not shown.

View File

@@ -9,11 +9,11 @@ msgstr ""
"Last-Translator: Shafeek SUMSER <shafeeks@gmail.com>\n"
"Language: fr_FR\n"
"Language-Team: fr_FR <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
"Generated-By: Babel 2.11.0\n"
#, python-format
msgid "%d admin(s) found."
@@ -118,7 +118,7 @@ msgid "Account is disabled."
msgstr "Compte désactivé."
msgid "Account is domain admin"
msgstr "Compte désactivé."
msgstr "Compte administrateur du domaine."
msgid "Account is global admin"
msgstr "Le compte est un administrateur global."

View File

@@ -1,5 +1,5 @@
__author__ = "Zhang Huangbin"
__author_mail__ = "zhb@iredmail.org"
__version_ldap__ = "5.4"
__version_sql__ = "5.3"
__version_ldap__ = "5.5"
__version_sql__ = "5.4"
__url_license_terms__ = "http://www.iredmail.org/pricing.html#EULA"

View File

@@ -7,30 +7,36 @@ from libs import iredutils
# - Amavisd-new-2.6.x: [ A-Z, a-z, 0-9, +, - ]
MAIL_ID_CHARACTERS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-_'
WBLIST_FORM_INPUT_NAMES = {'wl_sender': 'whitelistSender',
'bl_sender': 'blacklistSender',
'wl_rcpt': 'whitelistRecipient',
'bl_rcpt': 'blacklistRecipient'}
WBLIST_FORM_INPUT_NAMES = {
'wl_sender': 'whitelistSender',
'bl_sender': 'blacklistSender',
'wl_rcpt': 'whitelistRecipient',
'bl_rcpt': 'blacklistRecipient',
}
# Available quarantined types in iRedAdmin web interface, and the short code
# in `amavisd.msgs` sql table.
QUARANTINE_TYPES = {'spam': 'S',
'virus': 'V',
'banned': 'B',
'clean': 'C',
'badheader': 'H',
'badmime': 'M'}
QUARANTINE_TYPES = {
'spam': 'S',
'virus': 'V',
'banned': 'B',
'clean': 'C',
'badheader': 'H',
'badmime': 'M',
}
# Value of `msgs.content` and comment.
CONTENT_TYPES = {'B': 'Banned',
'C': 'Clean',
'H': 'Bad header',
'M': 'Bad mime',
'O': 'Oversized',
'S': 'Spam',
'T': 'MTA error',
'V': 'Virus',
'U': 'Unchecked'}
CONTENT_TYPES = {
'B': 'Banned',
'C': 'Clean',
'H': 'Bad header',
'M': 'Bad mime',
'O': 'Oversized',
'S': 'Spam',
'T': 'MTA error',
'V': 'Virus',
'U': 'Unchecked',
}
def get_wblist_from_form(form, form_input_name):

View File

@@ -98,7 +98,7 @@ def get_quarantined_mails(page=1,
elif account_type == 'user':
if session.get('is_normal_admin'):
# Make sure account is under managed domains
if not account.split('@', 1)[-1] in all_domains:
if account.split('@', 1)[-1] not in all_domains:
# PERMISSION_DENIED
return True, (0, {})
elif session.get('account_is_mail_user'):

View File

@@ -371,7 +371,7 @@ def get_account_status(form,
to_integer=False):
status = get_single_value(form, input_name=input_name, to_string=True)
if not (status in ['active', 'disabled']):
if status not in ['active', 'disabled']:
status = default_value
# SQL backends store the account status as `active=[1|0]`

View File

@@ -31,7 +31,7 @@ def delete_throttle_setting(account, inout_type):
if not iredutils.is_valid_amavisd_address(account):
return False, 'INVALID_ACCOUNT'
if not (inout_type in ['inbound', 'outbound']):
if inout_type not in ['inbound', 'outbound']:
return False, 'INVALID_INOUT_TYPE'
if account and inout_type:

0
libs/iredbase.py Normal file → Executable file
View File

View File

@@ -677,7 +677,7 @@ def generate_random_strings(length=10) -> str:
"23456789"
s = ""
for x in range(length):
for _ in range(length):
s += random.choice(chars)
return s

0
libs/l10n.py Normal file → Executable file
View File

View File

@@ -52,7 +52,11 @@ def list_logs(event='all', domain='all', admin='all', cur_page=1):
listed_only=True,
conn=None)
if qr[0]:
sql_vars["managed_domains"] = qr[1]
managed_domains = qr[1]
if not managed_domains:
return 0, []
sql_vars["managed_domains"] = managed_domains
sql_wheres += ["domain IN $managed_domains"]
else:
return qr

View File

@@ -1129,7 +1129,7 @@ def update(conn, mail, profile_type, form):
# If marked as normal domain admin, allow to create new domains
#
if 'allowed_to_create_domain' in form:
_new_settings = {'create_new_domains': 'yes'}
_new_settings['create_new_domains'] = 'yes'
for i in ['create_max_domains',
'create_max_quota',
@@ -2257,14 +2257,17 @@ def get_basic_user_profiles(domain,
for row in rows:
email = row.username
used_bytes = 0
used_messages = 0
_bytes = 0
_messages = 0
if email in used_quota_info:
used_bytes = used_quota_info[email]["bytes"]
used_messages = used_quota_info[email]["messages"]
_bytes = used_quota_info[email]["bytes"]
_messages = used_quota_info[email]["messages"]
row["used_quota"] = {"bytes": used_bytes, "messages": used_messages}
row["used_quota"] = {
"bytes": _bytes,
"messages": _messages,
}
return True, rows
except Exception as e:

View File

@@ -264,7 +264,7 @@ def search(search_string,
# Add new, remove duplicate records.
for i in _records:
if not (i in result['user']):
if i not in result['user']:
result['user'] += [i]
if qr_user_forwarding:
@@ -272,7 +272,7 @@ def search(search_string,
# Add new, remove duplicate records.
for i in _records:
if not (i in result['user']):
if i not in result['user']:
result['user'] += [i]
# Get email addresses of returned user accounts

0
rc_scripts/iredadmin.debian Normal file → Executable file
View File

0
rc_scripts/iredadmin.freebsd Normal file → Executable file
View File

0
rc_scripts/iredadmin.openbsd Normal file → Executable file
View File

0
rc_scripts/iredadmin.rhel Normal file → Executable file
View File

View File

@@ -1,3 +1,5 @@
* Please read file 'EULA' for End User License Agreement.
* If you already have iRedAdmin open source edition or old iRedAdmin-Pro
release installed, please follow below tutorial to upgrade it to the latest
iRedAdmin-Pro, it's the easiest way with minimal steps:

8
static/.htaccess Executable file
View File

@@ -0,0 +1,8 @@
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
</IfModule>

0
static/default/css/spectre-icons.min.css vendored Normal file → Executable file
View File

0
static/default/css/spectre.min.css vendored Normal file → Executable file
View File

File diff suppressed because one or more lines are too long

2
static/js/jquery-3.6.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
static/js/jquery.quickfilter.js Normal file → Executable file
View File

0
static/js/stupidtable.min.js vendored Normal file → Executable file
View File

View File

@@ -5,7 +5,6 @@
{% set token = token |e %}
{% endif %}
<!--suppress ALL -->
<input type="hidden" name="csrf_token" value="{{ token }}"/>
{%- endmacro %}

View File

@@ -6,7 +6,7 @@
{# ------------ Load JS files ------------- #}
{% macro load_jquery() -%}
<script type="text/javascript" src="{{ctx.homepath}}/static/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="{{ctx.homepath}}/static/js/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="{{ctx.homepath}}/static/js/jquery.tooltip.js"></script>
<script type="text/javascript" src="{{ctx.homepath}}/static/js/jquery.idtabs.js"></script>
<script type="text/javascript" src="{{ctx.homepath}}/static/js/jquery.fancybox.js"></script>

View File

@@ -330,36 +330,39 @@
{% endif %}
{# profile_type: throttling #}
{% if session.get('is_global_admin') or 'throttle' not in disabled_domain_profiles %}
{% if (session.get('is_global_admin') or 'throttle' not in disabled_domain_profiles) and session.get('iredapd_enabled') %}
<div id="profile_throttle">
<form name="throttle" method="post" action="{{ctx.homepath}}/profile/domain/throttle/{{cur_domain}}">
<form name="throttle"
method="post"
action="{{ctx.homepath}}/profile/domain/throttle/{{cur_domain}}"
>
{{ input_csrf_token() }}
{% if session.get('iredapd_enabled') %}
{# Throttling with iRedAPD #}
<div class="columns clear">
{{ input_csrf_token() }}
{% if session.get('iredapd_enabled') %}
{# Throttling with iRedAPD #}
<div class="columns clear">
{{ input_csrf_token() }}
{{ display_throttle_setting(account='@' + cur_domain,
setting=outbound_throttle_setting,
inout_type='outbound') }}
{{ display_throttle_setting(account='@' + cur_domain,
setting=inbound_throttle_setting,
inout_type='inbound',
with_left_border=true) }}
{{ display_throttle_setting(account='@' + cur_domain,
setting=outbound_throttle_setting,
inout_type='outbound') }}
<div class="col1-3 lastcol">
<div class="mark_blue bt-space10">
<ul class="standard clean-padding bt-space10">
<li class="bt-space5">{{ _('This throttle setting will be applied to all individual accounts under domain %s.') |format(cur_domain) }}</li>
<li class="bt-space5">{{ _('You can set per-user throttling in account profile page.') }}</li>
<li class="bt-space5">{{ _('Per-user throttle setting has higher priority.') }}</li>
</ul>
</div>
</div>{#-- .col1-3 --#}
</div>{# .columns #}
{% endif %}
{{ display_throttle_setting(account='@' + cur_domain,
setting=inbound_throttle_setting,
inout_type='inbound',
with_left_border=true) }}
<div class="col1-3 lastcol">
<div class="mark_blue bt-space10">
<ul class="standard clean-padding bt-space10">
<li class="bt-space5">{{ _('This throttle setting will be applied to all individual accounts under domain %s.') |format(cur_domain) }}</li>
<li class="bt-space5">{{ _('You can set per-user throttling in account profile page.') }}</li>
<li class="bt-space5">{{ _('Per-user throttle setting has higher priority.') }}</li>
</ul>
</div>
</div>{#-- .col1-3 --#}
</div>{# .columns #}
{% endif %}
{{ input_submit() }}
</form>

View File

@@ -31,13 +31,13 @@
import os
import sys
import time
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from libs import iredutils
from tools import ira_tool_lib

View File

@@ -27,13 +27,13 @@
import os
import sys
import time
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools.ira_tool_lib import debug, logger, sql_dbn, get_db_conn, sql_count_id

View File

@@ -40,13 +40,13 @@ import time
import logging
import shutil
import pwd
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
from libs import iredutils
from tools import ira_tool_lib
import settings

View File

@@ -6,13 +6,13 @@
import os
import sys
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
from tools import ira_tool_lib
web.config.debug = ira_tool_lib.debug

View File

@@ -26,9 +26,6 @@
import os
import sys
import web
web.config.debug = False
# Directory used to store disclaimer files.
# Default directory is /etc/postfix/disclaimer/.
@@ -43,11 +40,14 @@ os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from libs import iredutils
from tools import ira_tool_lib
logger = ira_tool_lib.logger
web.config.debug = False
if settings.backend == 'ldap':
import ldap
elif settings.backend == 'mysql':

View File

@@ -9,7 +9,6 @@
import os
import sys
import time
import web
output_dir = sys.argv[1]
if not os.path.isdir(output_dir):
@@ -20,6 +19,7 @@ os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
from tools.ira_tool_lib import debug, get_db_conn
web.config.debug = debug

View File

@@ -14,13 +14,13 @@ Usage:
import os
import sys
import time
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools import ira_tool_lib
from libs.iredutils import epoch_seconds_to_gmt

View File

@@ -5,21 +5,21 @@
import os
import sys
import logging
import web
debug = False
# Set True to print SQL queries.
web.config.debug = debug
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from libs import iredutils
# Set True to print SQL queries.
web.config.debug = debug
backend = settings.backend
if backend in ['ldap', 'mysql']:
sql_dbn = 'mysql'

View File

@@ -8,13 +8,13 @@
import os
import sys
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from libs.iredutils import is_valid_amavisd_address
from libs.amavisd import wblist

View File

@@ -93,7 +93,6 @@ import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
import web
os.environ['LC_ALL'] = 'C'
@@ -103,6 +102,7 @@ sys.path.insert(0, rootdir)
now = int(time.time())
import web
import settings
from libs import iredutils
from libs.ireddate import utc_to_timezone

View File

@@ -15,13 +15,13 @@ def usage():
import os
import sys
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools.ira_tool_lib import debug, get_db_conn
from libs.iredutils import is_email

View File

@@ -14,13 +14,13 @@ def usage():
import os
import sys
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools.ira_tool_lib import debug, get_db_conn
from libs.iredutils import is_email

View File

@@ -32,13 +32,13 @@ def usage():
import os
import sys
import web
os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools.ira_tool_lib import debug, logger, get_db_conn
from libs.iredutils import is_email

View File

@@ -5,7 +5,6 @@
import os
import sys
import web
def usage():
@@ -33,6 +32,7 @@ os.environ['LC_ALL'] = 'C'
rootdir = os.path.abspath(os.path.dirname(__file__)) + '/../'
sys.path.insert(0, rootdir)
import web
import settings
from tools.ira_tool_lib import debug, logger, get_db_conn
from libs.iredutils import is_email

0
web/utils.py Normal file → Executable file
View File