Compare commits

...

52 Commits

Author SHA1 Message Date
Patrick Schult 0303dbc1d2
Merge pull request from mailcow/feat/domain-wide-footer
[Rspamd] add domain wide footer
2023-09-13 15:11:33 +02:00
FreddleSpl0it acee742822
[Web] move domain-wide-footer vars info to lang files 2023-09-13 15:08:07 +02:00
FreddleSpl0it 8d792fbd62
[Rspamd] domain-wide-footer update description 2023-09-13 13:03:46 +02:00
FreddleSpl0it d132a51a4d
Merge remote-tracking branch 'origin/staging' into feat/domain-wide-footer 2023-09-13 12:44:41 +02:00
FreddleSpl0it 2111115a73
[Rspamd] domain-wide-footer add more template vars 2023-09-13 12:42:12 +02:00
renovate[bot] 160c9caee3
Update docker/setup-buildx-action action to v3 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:16 +02:00
renovate[bot] 33de788453
Update docker/setup-qemu-action action to v3 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:09 +02:00
renovate[bot] f86f5657d9
Update docker/login-action action to v3 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:00 +02:00
renovate[bot] e02a92a0d0
Update docker/build-push-action action to v5 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:40:44 +02:00
FreddleSpl0it 5ae9605e77
[Rspamd] domain-wide-footer add jinja templating 2023-09-12 12:19:46 +02:00
Christian Schmitt 89bc11ce0f
Fix typo in German translation: ()
"gibt Aufschluss darüber"
2023-09-11 15:44:24 +02:00
Patrick Schult 4b096962a9
Merge pull request from mailcow/feat/backup_action
Update rebuild_backup_image.yml
2023-09-08 16:01:34 +02:00
Patrick Schult c64fdf9aa3
Merge pull request from FELDSAM-INC/feldsam/enhancements
[Web] apple config app passwords enhancements + translations
2023-09-08 15:41:25 +02:00
Patrick Schult 9caaaa6498
Merge pull request from FELDSAM-INC/feldsam/css-fixes
[Web] BS5 styling fixes and enhancements
2023-09-08 15:29:47 +02:00
Patrick Schult 105a7a4c74
Merge pull request from FELDSAM-INC/feldsam/filter-by-domain
[Web] Filter tables by Domain where possible
2023-09-08 15:01:15 +02:00
Patrick Schult 09782e5b47
Merge pull request from FELDSAM-INC/feldsam/dark-mode-logo
[Web] dark mode logo support
2023-09-08 14:57:43 +02:00
milkmaker 21121f9827
Translations update from Weblate ()
* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.en-gb.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Peter <magic@kthx.at>

---------

Co-authored-by: Peter <magic@kthx.at>
2023-09-04 19:56:42 +02:00
renovate[bot] 8e87e76dcf
Update actions/checkout action to v4 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-04 18:49:38 +02:00
Patrick Schult 2629f3d865
Merge pull request from FELDSAM-INC/feldsam/datatables-sk-cz-translations
[Web] translated datatables to CZ and SK
2023-09-04 07:59:01 +02:00
Kristian Feldsam 8e5cd90707 [Web] Filter tables by Domain where possible
This feature was standard in Mailcow in pre-BS5 releases

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:55:51 +02:00
Kristian Feldsam 9ffa810054 [Web] Edit Domain/Mailbox - added collapsible tabs for mobile devices
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:41:25 +02:00
Kristian Feldsam db9562e843 [Web] mailboxes - remove tab dropdown, if not admin
there are no domain and mailbox templates available, so no need to have dropdown in tabs

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:05:24 +02:00
Kristian Feldsam 3540075b61 [Web] dark mode logo support
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:49:12 +02:00
Kristian Feldsam d0ba061f7a [Web] mobile devices - scroll window to opened tab
This feature was in versions before BS5

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:36:39 +02:00
Kristian Feldsam 871ae5d7d2 [Web] mobile devices styling fixes and enhancements
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:36:32 +02:00
Kristian Feldsam 633ebe5e8d [Web] fixed add domain save action button group styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam 1b7cc830ca [Web] standarize select box dropdown buttons
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam d48193fd0e [Web] edit object - added space after heaading
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam bb69f39976 [Web] domain and alias domain edit - translated dkim “domain”
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam f059db54d0 [Web] edit mailbox template - fixed settigns buttons styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam e4e8abb1b9 [Web] Ratelimit settings as input group
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam 1a207f4d88 [Web] translated datatables to CZ and SK
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 12:38:50 +02:00
Kristian Feldsam 8e5323023a [Web] checkbox styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:45 +02:00
Kristian Feldsam 6d9805109a [Web] styling enhancements
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:39 +02:00
Kristian Feldsam 1822d56efb [Web] fixed new mailbox settings buttons styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>

Fixed input with btn in input group styling

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:33 +02:00
Kristian Feldsam 1e3766e2f1 [Web] revisited dark mode theme, enhanced colors
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:25 +02:00
Patrick Schult 372b1c7bbc
Merge pull request from Dexus-Forks/Dexus-patch-1
Update config for nginx >=1.25.1 (http2, server_names_hash_max_size, server_names_hash_bucket_size)
2023-08-29 12:05:44 +02:00
Patrick Schult 9ba5c13702
Merge pull request from mstilkerich/fix_dockerapi_cpuload
Fix CPU load of dockerapi container
2023-08-28 16:23:27 +02:00
milkmaker 30e241babe
Translations update from Weblate ()
* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.es-es.json

Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.hu-hu.json

[Web] Updated lang.hu-hu.json

[Web] Updated lang.hu-hu.json

Co-authored-by: 0xAndrewBlack <0xandrewblack@gmail.com>
Co-authored-by: Kántor Attila <attilalaci300@gmail.com>
Co-authored-by: Mihály Szilágyi <szimih90@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ro-ro.json

Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.gr-gr.json

[Web] Added lang.gr-gr.json

Co-authored-by: Nik Beaver <nik@beavers.forsale>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Adrien Kara <mailcow-translate@iglou.eu>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.en-gb.json

Co-authored-by: Philipp E <ph.ecker@philipp-dev.info>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ca-es.json

Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.it-it.json

Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.si-si.json

[Web] Updated lang.si-si.json

[Web] Updated lang.si-si.json

[Web] Added lang.si-si.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: gomiunik <boris@gomiunik.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* Add Greek + Slovenian

---------

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: 0xAndrewBlack <0xandrewblack@gmail.com>
Co-authored-by: Kántor Attila <attilalaci300@gmail.com>
Co-authored-by: Mihály Szilágyi <szimih90@gmail.com>
Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: Nik Beaver <nik@beavers.forsale>
Co-authored-by: Adrien Kara <mailcow-translate@iglou.eu>
Co-authored-by: Philipp E <ph.ecker@philipp-dev.info>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: gomiunik <boris@gomiunik.net>
2023-08-19 21:47:23 +02:00
Niklas Meyer 956b170674
Merge pull request from mailcow/renovate/nextcloud-server-27.x 2023-08-14 18:11:36 +02:00
renovate[bot] 2c52753adb
Update dependency nextcloud/server to v27.0.2
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-08-14 15:21:07 +00:00
Josef Fröhle 095d59c01b Update listen_ssl.template deprecated http2 on listener 2023-08-12 16:59:15 +02:00
Josef Fröhle 1a2f145b28 Update site.conf: server_names_hash_bucket_size 128 2023-08-12 16:58:26 +02:00
Michael Stilkerich 930473a980 Set asyncio timeout to 0 for yielding 2023-08-12 07:20:56 +02:00
DerLinkman 1db8990271 Fixed Branch checkout in generate_config.sh 2023-08-10 13:51:40 +02:00
FreddleSpl0it 025fd03310
[Rspamd] remove X-Moo-Tag header if unnecessary 2023-08-07 14:26:30 +02:00
renovate[bot] e468c59dfc
Update thollander/actions-comment-pull-request action to v2.4.2 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-07 06:46:07 +02:00
renovate[bot] 340ef866d2
Update thollander/actions-comment-pull-request action to v2.4.1 ()
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-06 16:39:26 +02:00
Michael Stilkerich 533bd36572 Fix CPU load of dockerapi container
Previously the handle_pubsub_messages() loop was executing every 10ms
when there was no message available. Now reading from the redis network
socket will block (the coroutine) for up to 30s before it returns when
no message is available.

Using channel.listen() would be even better, but it lacks the
ignore_subscribe_messages option and I could not figure out how to
filter the returned messages.
2023-08-05 20:58:34 +02:00
Peter d8fd023cdb
Update rebuild_backup_image.yml 2023-07-24 17:39:41 +02:00
FreddleSpl0it f295b8cd91
[Rspamd] add domain wide footer 2023-05-08 12:55:38 +02:00
Kristian Feldsam 2eafd89412 [web] apple config app passwords enhancements + translations
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-03-18 16:29:11 +01:00
99 changed files with 2582 additions and 1331 deletions
.github/workflows
data
Dockerfiles/dockerapi
conf
web
generate_config.sh
helper-scripts

View File

@ -10,7 +10,7 @@ jobs:
if: github.event.pull_request.base.ref != 'staging' #check if the target branch is not staging
steps:
- name: Send message
uses: thollander/actions-comment-pull-request@v2.4.0
uses: thollander/actions-comment-pull-request@v2.4.2
with:
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
message: |

View File

@ -28,7 +28,7 @@ jobs:
- "watchdog-mailcow"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Docker
run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh

View File

@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run the Action

View File

@ -11,24 +11,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }}
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
file: data/Dockerfiles/backup/Dockerfile
push: true
tags: mailcow/backup:latest

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Generate postscreen_access.cidr
run: |

View File

@ -198,8 +198,8 @@ async def handle_pubsub_messages(channel: aioredis.client.PubSub):
while True:
try:
async with async_timeout.timeout(1):
message = await channel.get_message(ignore_subscribe_messages=True)
async with async_timeout.timeout(60):
message = await channel.get_message(ignore_subscribe_messages=True, timeout=30)
if message is not None:
# Parse message
data_json = json.loads(message['data'].decode('utf-8'))
@ -244,7 +244,7 @@ async def handle_pubsub_messages(channel: aioredis.client.PubSub):
else:
dockerapi.logger.error("Unknwon PubSub recieved - %s" % json.dumps(data_json))
await asyncio.sleep(0.01)
await asyncio.sleep(0.0)
except asyncio.TimeoutError:
pass

View File

@ -1,5 +1,6 @@
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
server_names_hash_bucket_size 64;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
map $http_x_forwarded_proto $client_req_scheme {
default $scheme;

View File

@ -1,2 +1,3 @@
listen ${HTTPS_PORT} ssl http2;
listen [::]:${HTTPS_PORT} ssl http2;
listen ${HTTPS_PORT} ssl;
listen [::]:${HTTPS_PORT} ssl;
http2 on;

View File

@ -221,6 +221,16 @@ rspamd_config:register_symbol({
local tagged_rcpt = task:get_symbol("TAGGED_RCPT")
local mailcow_domain = task:get_symbol("RCPT_MAILCOW_DOMAIN")
local function remove_moo_tag()
local moo_tag_header = task:get_header('X-Moo-Tag', false)
if moo_tag_header then
task:set_milter_reply({
remove_headers = {['X-Moo-Tag'] = 0},
})
end
return true
end
if tagged_rcpt and tagged_rcpt[1].options and mailcow_domain then
local tag = tagged_rcpt[1].options[1]
rspamd_logger.infox("found tag: %s", tag)
@ -229,6 +239,7 @@ rspamd_config:register_symbol({
if action ~= 'no action' and action ~= 'greylist' then
rspamd_logger.infox("skipping tag handler for action: %s", action)
remove_moo_tag()
return true
end
@ -243,6 +254,7 @@ rspamd_config:register_symbol({
local function tag_callback_subfolder(err, data)
if err or type(data) ~= 'string' then
rspamd_logger.infox(rspamd_config, "subfolder tag handler for rcpt %s returned invalid or empty data (\"%s\") or error (\"%s\")", body, data, err)
remove_moo_tag()
else
rspamd_logger.infox("Add X-Moo-Tag header")
task:set_milter_reply({
@ -261,6 +273,7 @@ rspamd_config:register_symbol({
)
if not redis_ret_subfolder then
rspamd_logger.infox(rspamd_config, "cannot make request to load tag handler for rcpt")
remove_moo_tag()
end
else
@ -268,7 +281,10 @@ rspamd_config:register_symbol({
local sbj = task:get_header('Subject')
new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
task:set_milter_reply({
remove_headers = {['Subject'] = 1},
remove_headers = {
['Subject'] = 1,
['X-Moo-Tag'] = 0
},
add_headers = {['Subject'] = new_sbj}
})
end
@ -284,6 +300,7 @@ rspamd_config:register_symbol({
)
if not redis_ret_subject then
rspamd_logger.infox(rspamd_config, "cannot make request to load tag handler for rcpt")
remove_moo_tag()
end
end
@ -295,6 +312,7 @@ rspamd_config:register_symbol({
if #rcpt_split == 2 then
if rcpt_split[1] == 'postmaster' then
rspamd_logger.infox(rspamd_config, "not expanding postmaster alias")
remove_moo_tag()
else
rspamd_http.request({
task=task,
@ -307,7 +325,8 @@ rspamd_config:register_symbol({
end
end
end
else
remove_moo_tag()
end
end,
priority = 19
@ -503,3 +522,146 @@ rspamd_config:register_symbol({
end
end
})
rspamd_config:register_symbol({
name = 'MOO_FOOTER',
type = 'prefilter',
callback = function(task)
local lua_mime = require "lua_mime"
local lua_util = require "lua_util"
local rspamd_logger = require "rspamd_logger"
local rspamd_redis = require "rspamd_redis"
local ucl = require "ucl"
local redis_params = rspamd_parse_redis_server('footer')
local envfrom = task:get_from(1)
local uname = task:get_user()
if not envfrom or not uname then
return false
end
local uname = uname:lower()
local env_from_domain = envfrom[1].domain:lower() -- get smtp from domain in lower case
local function newline(task)
local t = task:get_newlines_type()
if t == 'cr' then
return '\r'
elseif t == 'lf' then
return '\n'
end
return '\r\n'
end
local function redis_cb_footer(err, data)
if err or type(data) ~= 'string' then
rspamd_logger.infox(rspamd_config, "domain wide footer request for user %s returned invalid or empty data (\"%s\") or error (\"%s\")", uname, data, err)
else
-- parse json string
local parser = ucl.parser()
local res,err = parser:parse_string(data)
if not res then
rspamd_logger.infox(rspamd_config, "parsing domain wide footer for user %s returned invalid or empty data (\"%s\") or error (\"%s\")", uname, data, err)
else
local footer = parser:get_object()
if footer and type(footer) == "table" and (footer.html or footer.plain) then
rspamd_logger.infox(rspamd_config, "found domain wide footer for user %s: html=%s, plain=%s", uname, footer.html, footer.plain)
local envfrom_mime = task:get_from(2)
local from_name = ""
if envfrom_mime and envfrom_mime[1].name then
from_name = envfrom_mime[1].name
elseif envfrom and envfrom[1].name then
from_name = envfrom[1].name
end
local replacements = {
auth_user = uname,
from_user = envfrom[1].user,
from_name = from_name,
from_addr = envfrom[1].addr,
from_domain = envfrom[1].domain:lower()
}
if footer.html then
footer.html = lua_util.jinja_template(footer.html, replacements, true)
end
if footer.plain then
footer.plain = lua_util.jinja_template(footer.plain, replacements, true)
end
-- add footer
local out = {}
local rewrite = lua_mime.add_text_footer(task, footer.html, footer.plain) or {}
local seen_cte
local newline_s = newline(task)
local function rewrite_ct_cb(name, hdr)
if rewrite.need_rewrite_ct then
if name:lower() == 'content-type' then
local nct = string.format('%s: %s/%s; charset=utf-8',
'Content-Type', rewrite.new_ct.type, rewrite.new_ct.subtype)
out[#out + 1] = nct
return
elseif name:lower() == 'content-transfer-encoding' then
out[#out + 1] = string.format('%s: %s',
'Content-Transfer-Encoding', 'quoted-printable')
seen_cte = true
return
end
end
out[#out + 1] = hdr.raw:gsub('\r?\n?$', '')
end
task:headers_foreach(rewrite_ct_cb, {full = true})
if not seen_cte and rewrite.need_rewrite_ct then
out[#out + 1] = string.format('%s: %s', 'Content-Transfer-Encoding', 'quoted-printable')
end
-- End of headers
out[#out + 1] = newline_s
if rewrite.out then
for _,o in ipairs(rewrite.out) do
out[#out + 1] = o
end
else
out[#out + 1] = task:get_rawbody()
end
local out_parts = {}
for _,o in ipairs(out) do
if type(o) ~= 'table' then
out_parts[#out_parts + 1] = o
out_parts[#out_parts + 1] = newline_s
else
out_parts[#out_parts + 1] = o[1]
if o[2] then
out_parts[#out_parts + 1] = newline_s
end
end
end
task:set_message(out_parts)
else
rspamd_logger.infox(rspamd_config, "domain wide footer request for user %s returned invalid or empty data (\"%s\")", uname, data)
end
end
end
end
local redis_ret_footer = rspamd_redis_make_request(task,
redis_params, -- connect params
env_from_domain, -- hash key
false, -- is write
redis_cb_footer, --callback
'HGET', -- command
{"DOMAIN_WIDE_FOOTER", env_from_domain} -- arguments
)
if not redis_ret_footer then
rspamd_logger.infox(rspamd_config, "cannot make request to load footer for domain")
end
return true
end,
priority = 1
})

View File

@ -108,6 +108,7 @@ $template_data = [
'rsettings' => $rsettings,
'rspamd_regex_maps' => $rspamd_regex_maps,
'logo_specs' => customize('get', 'main_logo_specs'),
'logo_dark_specs' => customize('get', 'main_logo_dark_specs'),
'ip_check' => customize('get', 'ip_check'),
'password_complexity' => password_complexity('get'),
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],

View File

@ -42,11 +42,6 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
table.dataTable td.dt-control:before {
background-color: #979797 !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background-color: #fbfbfb;
}
table.dataTable.table-striped>tbody>tr>td {
vertical-align: middle;
}

View File

@ -357,6 +357,7 @@ button[aria-expanded='true'] > .caret {
}
.progress {
height: 16px;
background-color: #d5d5d5;
}
@ -370,3 +371,22 @@ button[aria-expanded='true'] > .caret {
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #f0f0f0 !important;
}
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
color: #fff;
background-color: #555;
background-image: none;
border-color: #4d4d4d;
}
.btn-check:checked+.btn-light:focus, .btn-check:active+.btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show>.btn-light.dropdown-toggle:focus,
.btn-check:focus+.btn-light, .btn-light:focus {
box-shadow: none;
}
.btn-group>.btn:not(:last-of-type) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.badge.bg-info > a,
.badge.bg-danger > a {
color: #fff !important;
text-decoration: none;
}

View File

@ -38,7 +38,7 @@
@media (max-width: 767px) {
.responsive-tabs .tab-pane {
.responsive-tabs .tab-pane:not(.rsettings) {
display: block !important;
opacity: 1;
}
@ -206,6 +206,19 @@
.senders-mw220 {
max-width: 100% !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
table.dataTable td.dt-control:before {
height: 2rem;
width: 2rem;
line-height: 2rem;
margin-top: -15px;
}
li .dtr-data {
padding: 0;
}
}
@media (max-width: 350px) {

View File

@ -1,90 +1,128 @@
body {
background-color: #414141;
color: #e0e0e0;
background-color: #1c1c1e;
color: #f2f2f7;
}
.card {
border: 1px solid #1c1c1c;
background-color: #3a3a3a;
border: 1px solid #2c2c2e;
background-color: #2c2c2e;
}
legend {
color: #f5f5f5;
color: #f2f2f7;
}
.card-header {
color: #bbb;
background-color: #2c2c2c;
color: #8e8e93;
background-color: #1c1c1e;
border-color: transparent;
}
.card-body {
--bs-card-color: #bbb;
}
.btn-secondary, .paginate_button, .page-link, .btn-light {
color: #fff !important;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
color: #f2f2f7 !important;
background-color: #5e5e5e !important;
border-color: #4c4c4e !important;
}
.btn-dark {
color: #000 !important;;
background-color: #f6f6f6 !important;;
border-color: #ddd !important;;
}
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
border-color: #7a7a7a !important;
}
.alert-secondary {
color: #fff !important;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
}
.bg-secondary {
color: #fff !important;
background-color: #7a7a7a !important;
}
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
color: #fff;
}
.page-item.active .page-link {
background-color: #158cba !important;
border-color: #127ba3 !important;
color: #f2f2f7 !important;
background-color: #242424 !important;
border-color: #1c1c1e !important;
}
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
background-color: #7a7a7a;
border-color: #5c5c5c !important;
color: #fff;
background-color: #444444;
border-color: #4c4c4e !important;
color: #f2f2f7;
}
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
border-color: #5e5e5e !important;
}
.alert-secondary {
color: #f2f2f7 !important;
background-color: #5e5e5e !important;
border-color: #4c4c4e !important;
}
.bg-secondary {
color: #f2f2f7 !important;
background-color: #5e5e5e !important;
}
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
color: #f2f2f7;
}
.page-item.active .page-link {
background-color: #3e3e3e !important;
border-color: #3e3e3e !important;
}
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
background-color: #5e5e5e;
border-color: #4c4c4e !important;
color: #f2f2f7;
}
.btn-secondary:disabled, .btn-secondary.disabled {
border-color: #7a7a7a !important;
border-color: #5e5e5e !important;
}
.modal-content {
background-color: #414141;
--bs-modal-color: #bbb;
background-color: #2c2c2e;
}
.modal-header {
border-bottom: 1px solid #161616;
border-bottom: 1px solid #999;
}
.modal-title {
color: white;
color: #bbb;
}
.modal .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
.navbar.bg-light {
background-color: #222222 !important;
border-color: #181818;
background-color: #1c1c1e !important;
border-color: #2c2c2e;
}
.nav-link {
color: #ccc !important;
color: #8e8e93 !important;
}
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
background: none;
}
.nav-tabs, .nav-tabs .nav-link {
border-color: #444444 !important;
}
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
border-bottom-color: #414141;
border-bottom-color: #1c1c1e !important;
}
.card .nav-tabs .nav-link:not(.disabled):hover, .card .nav-tabs .nav-link:not(.disabled):focus, .card .nav-tabs .nav-link.active {
border-bottom-color: #2c2c2e !important;
}
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
color: #ccc !important;
color: #f2f2f7 !important;
}
.dropdown-menu {
background-color: #585858;
border: 1px solid #333;
background-color: #424242;
border: 1px solid #282828;
}
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
color: #fafafa;
@ -97,7 +135,7 @@ legend {
color: #d4d4d4 !important;
}
tbody tr {
color: #555;
color: #ccc;
}
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
color: #ccc;
@ -106,18 +144,15 @@ tbody tr {
color: #ccc;
}
.list-group-item {
background-color: #333;
background-color: #282828;
border: 1px solid #555;
}
.table-striped>tbody>tr:nth-of-type(odd) {
background-color: #333;
background-color: #424242;
}
table.dataTable>tbody>tr.child ul.dtr-details>li {
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
}
tbody tr {
color: #ccc;
}
.label.label-last-login {
color: #ccc !important;
background-color: #555 !important;
@ -133,20 +168,20 @@ div.numberedtextarea-number {
}
.well {
border: 1px solid #555;
background-color: #333;
background-color: #282828;
}
pre {
color: #ccc;
background-color: #333;
background-color: #282828;
border: 1px solid #555;
}
input.form-control, textarea.form-control {
color: #e2e2e2 !important;
background-color: #555 !important;
background-color: #424242 !important;
border: 1px solid #999;
}
input.form-control:focus, textarea.form-control {
background-color: #555 !important;
background-color: #424242 !important;
}
input.form-control:disabled, textarea.form-disabled {
color: #a8a8a8 !important;
@ -154,16 +189,14 @@ input.form-control:disabled, textarea.form-disabled {
}
.input-group-addon {
color: #ccc;
background-color: #555 !important;
background-color: #424242 !important;
border: 1px solid #999;
}
.input-group-text {
color: #ccc;
background-color: #242424;
background-color: #1c1c1c;
}
.list-group-item {
color: #ccc;
}
@ -175,11 +208,11 @@ input.form-control:disabled, textarea.form-disabled {
}
.dropdown-item.active:hover {
color: #fff !important;
background-color: #31b1e4;
background-color: #007aff;
}
.form-select {
color: #e2e2e2!important;
background-color: #555!important;
background-color: #424242!important;
border: 1px solid #999;
}
@ -191,31 +224,6 @@ input.form-control:disabled, textarea.form-disabled {
color: #fff !important;
}
.table-secondary {
--bs-table-bg: #7a7a7a;
--bs-table-striped-bg: #e4e4e4;
--bs-table-striped-color: #000;
--bs-table-active-bg: #d8d8d8;
--bs-table-active-color: #000;
--bs-table-hover-bg: #dedede;
--bs-table-hover-color: #000;
color: #000;
border-color: #d8d8d8;
}
.table-light {
--bs-table-bg: #f6f6f6;
--bs-table-striped-bg: #eaeaea;
--bs-table-striped-color: #000;
--bs-table-active-bg: #dddddd;
--bs-table-active-color: #000;
--bs-table-hover-bg: #e4e4e4;
--bs-table-hover-color: #000;
color: #000;
border-color: #dddddd;
}
.form-control-plaintext {
color: #e0e0e0;
}
@ -289,12 +297,12 @@ a:hover {
}
.tag-box {
background-color: #555;
border: 1px solid #999;
background-color: #282828;
border: 1px solid #555;
}
.tag-input {
color: #fff;
background-color: #555;
background-color: #282828;
}
.tag-add {
color: #ccc;
@ -303,43 +311,24 @@ a:hover {
color: #d1d1d1;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
background-color: #7a7a7a !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
background-color: #7a7a7a !important;
border: 1.5px solid #5c5c5c !important;
color: #fff !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
background-color: #949494;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background-color: #444444;
}
.btn-check-label {
color: #fff;
}
.btn-outline-secondary:hover {
background-color: #c3c3c3;
background-color: #5c5c5c;
}
.btn.btn-outline-secondary {
color: #fff !important;
color: #e0e0e0 !important;
border-color: #7a7a7a !important;
}
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #9b9b9b !important;
background-color: #7a7a7a !important;
}
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
color: #f2f2f7 !important;
background-color: #242424 !important;
border-color: #1c1c1e !important;
}
.btn-input-missing,
.btn-input-missing:hover,
.btn-input-missing:active,
@ -347,27 +336,119 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
.btn-input-missing:active:hover,
.btn-input-missing:active:focus {
color: #fff !important;
background-color: #ff2f24 !important;
border-color: #e21207 !important;
background-color: #ff3b30 !important;
border-color: #ff3b30 !important;
}
.inputMissingAttr {
border-color: #FF4136 !important;
border-color: #ff4136 !important;
}
.list-group-details {
background: #444444;
background: #555;
}
.list-group-header {
background: #333;
background: #444;
}
span.mail-address-item {
background-color: #333;
background-color: #444;
border-radius: 4px;
border: 1px solid #555;
padding: 2px 7px;
display: inline-block;
margin: 2px 6px 2px 0;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
background-color: #7a7a7a !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
background-color: #7a7a7a !important;
border: 1.5px solid #5c5c5c !important;
color: #e0e0e0 !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
background-color: #949494;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background-color: #414141;
}
table.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
color: #ccc !important;
}
.table-secondary {
--bs-table-bg: #282828;
--bs-table-striped-bg: #343434;
--bs-table-striped-color: #f2f2f7;
--bs-table-active-bg: #4c4c4c;
--bs-table-active-color: #f2f2f7;
--bs-table-hover-bg: #3a3a3a;
--bs-table-hover-color: #f2f2f7;
color: #ccc;
border-color: #3a3a3a;
}
.table-light {
--bs-table-bg: #3a3a3a;
--bs-table-striped-bg: #444444;
--bs-table-striped-color: #f2f2f7;
--bs-table-active-bg: #5c5c5c;
--bs-table-active-color: #f2f2f7;
--bs-table-hover-bg: #4c4c4c;
--bs-table-hover-color: #f2f2f7;
color: #ccc;
border-color: #4c4c4c;
}
.table-bordered {
border-color: #3a3a3a;
}
.table-bordered th,
.table-bordered td {
border-color: #3a3a3a !important;
}
.table-bordered thead th,
.table-bordered thead td {
border-bottom-width: 2px;
}
.table-striped>tbody>tr:nth-of-type(odd)>td,
.table-striped>tbody>tr:nth-of-type(odd)>th {
background-color: #282828;
}
.table-hover>tbody>tr:hover {
background-color: #343434;
}
.table>:not(caption)>*>* {
border-color: #5c5c5c;
--bs-table-color-state:#bbb;
--bs-table-bg: #3a3a3a;
}
.text-muted {
--bs-secondary-color: #8e8e93;
}
input::placeholder {
color: #8e8e93 !important;
}
.form-select {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%238e8e93' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}
.btn-light, .btn-light:hover {
background-image: none;
}

View File

@ -47,6 +47,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
$quota_notification_bcc = quota_notification_bcc('get', $domain);
$rl = ratelimit('get', 'domain', $domain);
$rlyhosts = relayhost('get');
$domain_footer = mailbox('get', 'domain_wide_footer', $domain);
$template = 'edit/domain.twig';
$template_data = [
'acl' => $_SESSION['acl'],
@ -56,23 +57,26 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'rlyhosts' => $rlyhosts,
'dkim' => dkim('details', $domain),
'domain_details' => $result,
'domain_footer' => $domain_footer,
];
}
}
elseif (isset($_GET["template"])){
$domain_template = mailbox('get', 'domain_templates', $_GET["template"]);
elseif (isset($_GET['template'])){
$domain_template = mailbox('get', 'domain_templates', $_GET['template']);
if ($domain_template){
$template_data = [
'template' => $domain_template
'template' => $domain_template,
'rl' => ['frame' => $domain_template['attributes']['rl_frame']],
];
$template = 'edit/domain-templates.twig';
$result = true;
}
else {
$mailbox_template = mailbox('get', 'mailbox_templates', $_GET["template"]);
$mailbox_template = mailbox('get', 'mailbox_templates', $_GET['template']);
if ($mailbox_template){
$template_data = [
'template' => $mailbox_template
'template' => $mailbox_template,
'rl' => ['frame' => $mailbox_template['attributes']['rl_frame']],
];
$template = 'edit/mailbox-templates.twig';
$result = true;

View File

@ -24,9 +24,10 @@ function customize($_action, $_item, $_data = null) {
}
switch ($_item) {
case 'main_logo':
if (in_array($_data['main_logo']['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
case 'main_logo_dark':
if (in_array($_data[$_item]['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
try {
if (file_exists($_data['main_logo']['tmp_name']) !== true) {
if (file_exists($_data[$_item]['tmp_name']) !== true) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
@ -34,7 +35,7 @@ function customize($_action, $_item, $_data = null) {
);
return false;
}
$image = new Imagick($_data['main_logo']['tmp_name']);
$image = new Imagick($_data[$_item]['tmp_name']);
if ($image->valid() !== true) {
$_SESSION['return'][] = array(
'type' => 'danger',
@ -63,7 +64,7 @@ function customize($_action, $_item, $_data = null) {
return false;
}
try {
$redis->Set('MAIN_LOGO', 'data:' . $_data['main_logo']['type'] . ';base64,' . base64_encode(file_get_contents($_data['main_logo']['tmp_name'])));
$redis->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
@ -201,8 +202,9 @@ function customize($_action, $_item, $_data = null) {
}
switch ($_item) {
case 'main_logo':
case 'main_logo_dark':
try {
if ($redis->del('MAIN_LOGO')) {
if ($redis->del(strtoupper($_item))) {
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
@ -239,8 +241,9 @@ function customize($_action, $_item, $_data = null) {
return ($app_links) ? $app_links : false;
break;
case 'main_logo':
case 'main_logo_dark':
try {
return $redis->get('MAIN_LOGO');
return $redis->get(strtoupper($_item));
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
@ -277,9 +280,14 @@ function customize($_action, $_item, $_data = null) {
}
break;
case 'main_logo_specs':
case 'main_logo_dark_specs':
try {
$image = new Imagick();
$img_data = explode('base64,', customize('get', 'main_logo'));
if($_item == 'main_logo_specs') {
$img_data = explode('base64,', customize('get', 'main_logo'));
} else {
$img_data = explode('base64,', customize('get', 'main_logo_dark'));
}
if ($img_data[1]) {
$image->readImageBlob(base64_decode($img_data[1]));
return $image->identifyImage();

View File

@ -3320,6 +3320,45 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
}
break;
case 'domain_wide_footer':
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'domain_invalid'
);
return false;
}
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied'
);
return false;
}
$footers = array();
$footers['html'] = isset($_data['footer_html']) ? $_data['footer_html'] : '';
$footers['plain'] = isset($_data['footer_plain']) ? $_data['footer_plain'] : '';
try {
$redis->hSet('DOMAIN_WIDE_FOOTER', $domain, json_encode($footers));
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('redis_error', $e)
);
return false;
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('domain_footer_modified', htmlspecialchars($domain))
);
break;
}
break;
case 'get':
@ -4432,6 +4471,40 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
return $resourcedata;
break;
case 'domain_wide_footer':
$domain = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'domain_invalid'
);
return false;
}
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied'
);
return false;
}
try {
$footers = $redis->hGet('DOMAIN_WIDE_FOOTER', $domain);
$footers = json_decode($footers, true);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('redis_error', $e)
);
return false;
}
return $footers;
break;
}
break;
case 'delete':

View File

@ -40,6 +40,7 @@ $globalVariables = [
'ui_texts' => $UI_TEXTS,
'css_path' => '/cache/'.basename($CSSPath),
'logo' => customize('get', 'main_logo'),
'logo_dark' => customize('get', 'main_logo_dark'),
'available_languages' => $AVAILABLE_LANGUAGES,
'lang' => $lang,
'skip_sogo' => (getenv('SKIP_SOGO') == 'y'),

View File

@ -120,10 +120,14 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
if (isset($_POST["submit_main_logo"])) {
if ($_FILES['main_logo']['error'] == 0) {
customize('add', 'main_logo', $_FILES);
}
if ($_FILES['main_logo_dark']['error'] == 0) {
customize('add', 'main_logo_dark', $_FILES);
}
}
if (isset($_POST["reset_main_logo"])) {
customize('delete', 'main_logo');
customize('delete', 'main_logo_dark');
}
// Some actions will not be available via API
if (isset($_POST["license_validate_now"])) {

View File

@ -90,6 +90,7 @@ $AVAILABLE_LANGUAGES = array(
'es-es' => 'Español (Spanish)',
'fi-fi' => 'Suomi (Finish)',
'fr-fr' => 'Français (French)',
'gr-gr' => 'Ελληνικά (Greek)',
'hu-hu' => 'Magyar (Hungarian)',
'it-it' => 'Italiano (Italian)',
'ko-kr' => '한국어 (Korean)',
@ -99,6 +100,7 @@ $AVAILABLE_LANGUAGES = array(
'pt-pt' => 'Português (Portuguese)',
'ro-ro' => 'Română (Romanian)',
'ru-ru' => 'Pусский (Russian)',
'si-si' => 'Slovenščina (Slovenian)',
'sk-sk' => 'Slovenčina (Slovak)',
'sv-se' => 'Svenska (Swedish)',
'tr-tr' => 'Türkçe (Turkish)',

View File

@ -15801,7 +15801,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
paginationEl.empty();
}
else {
paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination');
paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination pagination-sm');
}
attach(

View File

@ -121,10 +121,21 @@ $(document).ready(function() {
if (lastTab) {
$('[data-bs-target="#' + lastTab + '"]').click();
var tab = $('[id^="' + lastTab + '"]');
$(tab).find('.card-body.collapse').collapse('show');
$(tab).find('.card-body.collapse:first').collapse('show');
}
});
})();
// responsive tabs, scroll to opened tab
$(document).on("shown.bs.collapse shown.bs.tab", function (e) {
var target = $(e.target);
if($(window).width() <= 767) {
var offset = target.offset().top - 60;
$("html, body").stop().animate({
scrollTop: offset
}, 100);
}
});
// IE fix to hide scrollbars when table body is empty
$('tbody').filter(function (index) {
@ -314,19 +325,28 @@ $(document).ready(function() {
$('#dark-mode-toggle').click(toggleDarkMode);
if ($('#dark-mode-theme').length) {
$('#dark-mode-toggle').prop('checked', true);
$('.main-logo').addClass('d-none');
$('.main-logo-dark').removeClass('d-none');
if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
} else {
$('.main-logo').removeClass('d-none');
$('.main-logo-dark').addClass('d-none');
}
function toggleDarkMode(){
if($('#dark-mode-theme').length){
$('#dark-mode-theme').remove();
$('#dark-mode-toggle').prop('checked', false);
$('.main-logo').removeClass('d-none');
$('.main-logo-dark').addClass('d-none');
if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png');
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_dark.png');
localStorage.setItem('theme', 'light');
}else{
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
$('#dark-mode-toggle').prop('checked', true);
$('.main-logo').addClass('d-none');
$('.main-logo-dark').removeClass('d-none');
if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
localStorage.setItem('theme', 'dark');

View File

@ -510,14 +510,14 @@ jQuery(function($){
if (table == 'relayhoststable') {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; }
else { item.in_use_by = item.used_by_mailboxes + '<hr style="margin:5px 0px 5px 0px;">' + item.used_by_domains; }
item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
});
} else if (table == 'transportstable') {
$.each(data, function (i, item) {
@ -528,49 +528,49 @@ jQuery(function($){
item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username;
}
item.action = '<div class="btn-group">' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="transports" name="multi_select" value="' + item.id + '" />';
});
} else if (table == 'queuetable') {
$.each(data, function (i, item) {
item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
rcpts = $.map(item.recipients, function(i) {
return escapeHtml(i);
});
item.recipients = rcpts.join('<hr style="margin:1px!important">');
item.action = '<div class="btn-group">' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.queue_show_message + '</a>' +
'<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-xs-lg btn-secondary">' + lang.queue_show_message + '</a>' +
'</div>';
});
} else if (table == 'forwardinghoststable') {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-xs-lg btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
});
} else if (table == 'oauth2clientstable') {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.scope = "profile";
item.grant_types = 'refresh_token password authorization_code';
item.chkbox = '<input type="checkbox" data-id="oauth2_clients" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="oauth2_clients" name="multi_select" value="' + item.id + '" />';
});
} else if (table == 'domainadminstable') {
$.each(data, function (i, item) {
item.selected_domains = escapeHtml(item.selected_domains);
item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>");
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' +
'<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
'<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
'</div>';
});
} else if (table == 'adminstable') {
@ -580,10 +580,10 @@ jQuery(function($){
} else {
item.usr = item.username;
}
item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' +
'<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
});
}

View File

@ -93,10 +93,10 @@ jQuery(function($){
dataSrc: function(data){
$.each(data, function (i, item) {
if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />';
}
});
@ -154,10 +154,10 @@ jQuery(function($){
dataSrc: function(data){
$.each(data, function (i, item) {
if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />';
}
});

View File

@ -466,16 +466,16 @@ jQuery(function($){
item.def_quota_for_mbox = humanFileSize(item.def_quota_for_mbox);
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
item.action = '<div class="btn-group">';
if (role == "admin") {
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-sm btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-sm btn-xs-lg btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
}
else {
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-sm btn-xs-lg btn-xs-half btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
}
if (Array.isArray(item.tags)){
@ -650,7 +650,7 @@ jQuery(function($){
url: "/api/v1/get/domain/template/all",
dataSrc: function(json){
$.each(json, function (i, item) {
item.chkbox = '<input type="checkbox" data-id="domain_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="domain_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.attributes.def_quota_for_mbox = humanFileSize(item.attributes.def_quota_for_mbox);
item.attributes.max_quota_for_mbox = humanFileSize(item.attributes.max_quota_for_mbox);
@ -671,13 +671,13 @@ jQuery(function($){
if (item.template.toLowerCase() == "default"){
item.action = '<div class="btn-group">' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'</div>';
}
else {
item.action = '<div class="btn-group">' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/domain/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/domain/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
}
@ -851,8 +851,9 @@ jQuery(function($){
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables,
initComplete: function(){
initComplete: function(settings, json){
hideTableExpandCollapseBtn('#tab-mailboxes', '#mailbox_table');
filterByDomain(json, 8, table);
},
ajax: {
type: "GET",
@ -880,7 +881,7 @@ jQuery(function($){
}
}
*/
item.chkbox = '<input type="checkbox" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
if (item.attributes.passwd_update != '0') {
var last_pw_change = new Date(item.attributes.passwd_update.replace(/-/g, "/"));
item.last_pw_change = last_pw_change.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
@ -912,18 +913,18 @@ jQuery(function($){
if (acl_data.login_as === 1) {
item.action = '<div class="btn-group">' +
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-success"><i class="bi bi-person-fill"></i> Login</a>';
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-lg btn-xs-half btn-success"><i class="bi bi-person-fill"></i> Login</a>';
if (ALLOW_ADMIN_EMAIL_LOGIN) {
item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-lg btn-xs-half btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
}
item.action += '</div>';
}
else {
item.action = '<div class="btn-group">' +
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
}
item.in_use = {
@ -1148,7 +1149,7 @@ jQuery(function($){
url: "/api/v1/get/mailbox/template/all",
dataSrc: function(json){
$.each(json, function (i, item) {
item.chkbox = '<input type="checkbox" data-id="mailbox_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="mailbox_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.template = escapeHtml(item.template);
if (item.attributes.rl_frame === "s"){
@ -1190,13 +1191,13 @@ jQuery(function($){
if (item.template.toLowerCase() == "default"){
item.action = '<div class="btn-group">' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'</div>';
}
else {
item.action = '<div class="btn-group">' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/mailbox/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/mailbox/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
}
@ -1362,8 +1363,9 @@ jQuery(function($){
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables,
initComplete: function(){
initComplete: function(settings, json){
hideTableExpandCollapseBtn('#tab-resources', '#resource_table');
filterByDomain(json, 5, table);
},
ajax: {
type: "GET",
@ -1378,10 +1380,10 @@ jQuery(function($){
item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
}
item.action = '<div class="btn-group">' +
'<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.name = escapeHtml(item.name);
item.description = escapeHtml(item.description);
});
@ -1509,8 +1511,9 @@ jQuery(function($){
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables,
order: [[2, 'desc']],
initComplete: function(){
initComplete: function(settings, json){
hideTableExpandCollapseBtn('#collapse-tab-bcc', '#bcc_table');
filterByDomain(json, 6, table);
},
ajax: {
type: "GET",
@ -1518,10 +1521,10 @@ jQuery(function($){
dataSrc: function(json){
$.each(json, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="/edit/bcc/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/bcc/' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="bcc" name="multi_select" value="' + item.id + '" />';
item.local_dest = escapeHtml(item.local_dest);
item.bcc_dest = escapeHtml(item.bcc_dest);
if (item.type == 'sender') {
@ -1632,10 +1635,10 @@ jQuery(function($){
item.recipient_map_old = escapeHtml(item.recipient_map_old);
item.recipient_map_new = escapeHtml(item.recipient_map_new);
item.action = '<div class="btn-group">' +
'<a href="/edit/recipient_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/recipient_map/' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
});
return json;
@ -1734,10 +1737,10 @@ jQuery(function($){
item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
}
item.action = '<div class="btn-group">' +
'<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
});
return json;
@ -1823,8 +1826,9 @@ jQuery(function($){
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables,
order: [[2, 'desc']],
initComplete: function(){
initComplete: function(settings, json){
hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table');
filterByDomain(json, 5, table);
},
ajax: {
type: "GET",
@ -1832,10 +1836,10 @@ jQuery(function($){
dataSrc: function(json){
$.each(json, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.goto = escapeHtml(item.goto.replace(/,/g, " "));
if (item.public_comment !== null) {
item.public_comment = escapeHtml(item.public_comment);
@ -1958,7 +1962,7 @@ jQuery(function($){
table.on('responsive-resize', function (e, datatable, columns){
hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table');
});
table.on( 'draw', function (){
$('#alias_table [data-bs-toggle="tooltip"]').tooltip();
});
@ -1991,11 +1995,11 @@ jQuery(function($){
item.alias_domain = escapeHtml(item.alias_domain);
item.action = '<div class="btn-group">' +
'<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-sm btn-xs-third btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
'<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-lg btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-lg btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-sm btn-xs-lg btn-xs-third btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
if(item.parent_is_backupmx == '1') {
item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a> <div class="badge fs-6 bg-warning">' + lang.alias_domain_backupmx + '</div></span>';
} else {
@ -2093,10 +2097,10 @@ jQuery(function($){
}
item.server_w_port = escapeHtml(item.user1) + '@' + escapeHtml(item.host1) + ':' + escapeHtml(item.port1);
item.action = '<div class="btn-group">' +
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
if (item.is_running == 1) {
item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
} else {
@ -2247,10 +2251,10 @@ jQuery(function($){
item.script_data = '<pre class="text-break" style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
item.filter_type = '<div class="badge fs-6 bg-secondary">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
item.action = '<div class="btn-group">' +
'<a href="/edit/filter/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/edit/filter/' + item.id + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-lg btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
});
return json;
@ -2329,6 +2333,40 @@ jQuery(function($){
else
$(tab).find(".table_collapse_option").hide();
}
function filterByDomain(json, column, table){
var tableId = $(table.table().container()).attr('id');
// Create the `select` element
var select = $('<select class="btn btn-sm btn-xs-lg btn-light text-start mx-2"><option value="">'+lang.all_domains+'</option></select>')
.insertBefore(
$('#'+tableId+' .dataTables_filter > label > input')
)
.on( 'change', function(){
table.column(column)
.search($(this).val())
.draw();
});
// get all domains
var domains = [];
json.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
if(key === 'domain') {
domains.push(value)
}
});
});
// get unique domain list
domains = domains.filter(function(value, index, array) {
return array.indexOf(value) === index;
});
// add domains to select
domains.forEach(function(domain) {
select.append($('<option>' + domain + '</option>'));
});
}
// detect element visibility changes
function onVisible(element, callback) {
@ -2344,7 +2382,7 @@ jQuery(function($){
}
});
})
observer.observe(element_object);
});
}

View File

@ -77,7 +77,7 @@ jQuery(function($){
'<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><i class="bi bi-file-earmark-text"></i> ' + lang.show_item + '</a>' +
'</div>';
}
item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="qitems" name="multi_select" value="' + item.id + '" />';
});
return data;

View File

@ -48,7 +48,7 @@ jQuery(function($){
url: "/api/v1/get/mailq/all",
dataSrc: function(data){
$.each(data, function (i, item) {
item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
rcpts = $.map(item.recipients, function(i) {
return escapeHtml(i);
});

View File

@ -127,7 +127,7 @@ jQuery(function($){
}
}
function createSortableDate(td, cellData, date_string = false) {
if (date_string)
var date = new Date(cellData);
@ -169,11 +169,11 @@ jQuery(function($){
item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
item.address = escapeHtml(item.address);
}
else {
item.chkbox = '<input type="checkbox" disabled />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
item.action = '<span>-</span>';
}
});
@ -263,11 +263,11 @@ jQuery(function($){
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
}
else {
item.action = '<span>-</span>';
item.chkbox = '<input type="checkbox" disabled />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
}
if (item.is_running == 1) {
item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
@ -420,11 +420,11 @@ jQuery(function($){
'<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
}
else {
item.action = '<span>-</span>';
item.chkbox = '<input type="checkbox" disabled />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
}
});
@ -503,13 +503,13 @@ jQuery(function($){
console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled title="' + lang.spamfilter_table_domain_policy + '" />';
}
if (acl_data.spam_policy === 0) {
item.chkbox = '<input type="checkbox" disabled />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
}
});
@ -574,13 +574,13 @@ jQuery(function($){
console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />';
}
if (acl_data.spam_policy === 0) {
item.chkbox = '<input type="checkbox" disabled />';
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
}
});

View File

@ -1867,6 +1867,9 @@ if (isset($_GET['query'])) {
case "quota_notification_bcc":
process_edit_return(quota_notification_bcc('edit', $attr));
break;
case "domain-wide-footer":
process_edit_return(mailbox('edit', 'domain_wide_footer', $attr));
break;
case "mailq":
process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));
break;

View File

@ -3,7 +3,23 @@
"bcc_maps": "BCC maps",
"filters": "Filtres",
"recipient_maps": "Recipient maps",
"syncjobs": "Feines de sincronització"
"syncjobs": "Feines de sincronització",
"quarantine_category": "Canvia la categoria de les notificacions de quarantena",
"quarantine_notification": "Canvia les notificacions de quarantena",
"sogo_profile_reset": "Restableix el prefil SOGo",
"alias_domains": "Afegir àlies de domini",
"app_passwds": "Gestiona les contrasenyes de les aplicacions",
"domain_desc": "Canvia la descripció del domini",
"eas_reset": "Restableix els dispositius EAS",
"login_as": "Inicia sessió com a usuari de la bústia de correu",
"prohibited": "Prohibit per ACL",
"protocol_access": "Canvia el protocol d'accés",
"quarantine": "Accions de quarantena",
"quarantine_attachments": "Fitxers adjunts en quarantena",
"spam_alias": "Àlies temporals",
"spam_score": "Puntuació de correu brossa",
"tls_policy": "Política TLS",
"unlimited_quota": "Quota ilimitada per bústies de correo"
},
"add": {
"activate_filter_warn": "All other filters will be deactivated, when active is checked.",
@ -55,7 +71,9 @@
"target_domain": "Domini destí:",
"username": "Username",
"validate": "Validar",
"validation_success": "Validated successfully"
"validation_success": "Validated successfully",
"app_name": "Nom de l'aplicació",
"app_password": "Afegir contrasenya a l'aplicació"
},
"admin": {
"access": "Accés",
@ -259,7 +277,7 @@
},
"footer": {
"cancel": "Cancel·lar",
"confirm_delete": "Confirma l'esborrat ",
"confirm_delete": "Confirma l'esborrat",
"delete_now": "Esborrar ara",
"delete_these_items": "Si et plau confirma els canvis al objecte amb id:",
"loading": "Si et plau espera ...",

View File

@ -41,6 +41,7 @@
"alias_domain": "Doménový alias",
"alias_domain_info": "<small>Platné názvy domén (oddělené čárkami).</small>",
"app_name": "Název aplikace",
"app_passwd_protocols": "Povolené protokoly pro hesla aplikací",
"app_password": "Přidat heslo aplikace",
"automap": "Pokusit se automaticky mapovat složky (\"Sent items\", \"Sent\" => \"Sent\" atd.)",
"backup_mx_options": "Možnosti záložního MX",
@ -459,6 +460,29 @@
"value_missing": "Prosím, uveďte všechny hodnoty",
"yotp_verification_failed": "Yubico OTP ověření selhalo: %s"
},
"datatables": {
"emptyTable": "Tabulka neobsahuje žádná data",
"info": "Zobrazuji _START_ až _END_ z celkem _TOTAL_ záznamů",
"infoEmpty": "Zobrazuji 0 až 0 z 0 záznamů",
"infoFiltered": "(filtrováno z celkem _MAX_ záznamů)",
"loadingRecords": "Načítám...",
"zeroRecords": "Žádné záznamy nebyly nalezeny",
"paginate": {
"first": "První",
"last": "Poslední",
"next": "Další",
"previous": "Předchozí"
},
"aria": {
"sortAscending": ": aktivujte pro seřazení vzestupně",
"sortDescending": ": aktivujte pro seřazení sestupně"
},
"lengthMenu": "Zobrazit _MENU_ výsledků",
"processing": "Zpracovávání...",
"search": "Vyhledávání:",
"decimal": ",",
"thousands": " "
},
"debug": {
"chart_this_server": "Graf (tento server)",
"containers_info": "Informace o kontejnerech",
@ -498,6 +522,7 @@
"optional": "Tento záznam je volitelný."
},
"edit": {
"acl": "ACL (Oprávnění)",
"active": "Aktivní",
"admin": "Upravit administrátora",
"advanced_settings": "Pokročilá nastavení",
@ -507,6 +532,7 @@
"allowed_protocols": "Povolené protokoly",
"app_name": "Název aplikace",
"app_passwd": "Heslo aplikace",
"app_passwd_protocols": "Povolené protokoly pro hesla aplikací",
"automap": "Pokusit se automaticky mapovat složky (\"Sent items\", \"Sent\" => \"Sent\" atd.)",
"backup_mx_options": "Možnosti záložního MX",
"bcc_dest_format": "Cíl kopie musí být jedna platná email adresa. Pokud potřebujete posílat kopie na více adres, vytvořte Alias a použijte jej zde.",
@ -590,6 +616,8 @@
"sieve_desc": "Krátký popis",
"sieve_type": "Typ filtru",
"skipcrossduplicates": "Přeskočit duplicitní zprávy (\"první přijde, první mele\")",
"sogo_access": "Udělit přímý přihlašovací přístup do služby SOGo",
"sogo_access_info": "Jednotné přihlášení (SSO) z mail UI zůstává funkční. Toto nastavení neovlivňuje přístup ke všem ostatním službám ani neodstraňuje či nemění stávající profil uživatele SOGo.",
"sogo_visible": "Alias dostupný v SOGo",
"sogo_visible_info": "Tato volba určuje objekty, jež lze zobrazit v SOGo (sdílené nebo nesdílené aliasy, jež ukazuje alespoň na jednu schránku).",
"spam_alias": "Vytvořit nebo změnit dočasné aliasy",
@ -1027,13 +1055,16 @@
"alias_valid_until": "Platný do",
"aliases_also_send_as": "Smí odesílat také jako uživatel",
"aliases_send_as_all": "Nekontrolovat přístup odesílatele pro následující doménu(y) a jejich aliasy domény:",
"allowed_protocols": "Povolené protokoly",
"app_hint": "Hesla aplikací jsou alternativní heslo pro přihlášení k IMAP, SMTP, CalDAV, CardDAV a EAS. Uživatelské jméno zůstává stejné.<br>SOGo však nelze s heslem aplikace použít.",
"app_name": "Název aplikace",
"app_passwds": "Hesla aplikací",
"apple_connection_profile": "Profil připojení Apple",
"apple_connection_profile_complete": "Tento profil obsahuje parametry připojení k IMAP, SMTP, CalDAV (kalendáře) a CardDAV (kontakty) pro zařízení Apple.",
"apple_connection_profile_mailonly": "Tento profil obsahuje parametry připojení k IMAP a SMTP pro zařízení Apple.",
"apple_connection_profile_with_app_password": "Nové heslo aplikace se vygeneruje a přidá do profilu, takže při nastavování zařízení není třeba zadávat žádné heslo. Soubor nesdílejte, protože poskytuje plný přístup k vaší poštovní schránce.",
"change_password": "Změnit heslo",
"change_password_hint_app_passwords": "Váš účet má %d hesel aplikací, která nebudou změněna. Chcete-li je spravovat, přejděte na kartu Hesla aplikací.",
"clear_recent_successful_connections": "Vymazat nedávné úspěšné přihlášení",
"client_configuration": "Zobrazit průvodce nastavením e-mailových klientů a smartphonů",
"create_app_passwd": "Vytvořit heslo aplikace",
@ -1044,6 +1075,7 @@
"delete_ays": "Potvrďte odstranění.",
"direct_aliases": "Přímé aliasy",
"direct_aliases_desc": "Na přímé aliasy se uplatňuje filtr spamu a nastavení pravidel TLS",
"direct_protocol_access": "Tento uživatel mailové schránky má <b>přímý externí přístup</b> k následujícím protokolům a aplikacím. Toto nastavení je řízeno správcem. Pro udělení přístupu k jednotlivým protokolům a aplikacím lze vytvořit hesla aplikací.<br>Tlačítko \" Přihlaste se do webmailu\" zajišťuje jednotné přihlášení k SOGo a je vždy k dispozici.",
"eas_reset": "Smazat mezipaměť zařízení ActiveSync",
"eas_reset_help": "Obnovení mezipaměti zařízení pomůže zpravidla obnovit poškozený profil služby ActiveSync.<br><b>Upozornění:</b> Všechna data budou opětovně stažena!",
"eas_reset_now": "Smazat",
@ -1137,15 +1169,15 @@
"spamfilter_yellow": "Žlutá: tato zpráva může být spam, bude označena jako spam a přesunuta do složky nevyžádané pošty",
"status": "Stav",
"sync_jobs": "Synchronizační úlohy",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problém s autentifikací",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Chybné uživatelské jméno nebo heslo",
"syncjob_EXIT_CONNECTION_FAILURE": "Problém se spojením",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nelze se připojit ke vzdálenému serveru",
"syncjob_EXIT_OVERQUOTA": "Cílová schránka je plná",
"syncjob_EXIT_TLS_FAILURE": "Problém se šifrovaným spojením",
"syncjob_EX_OK": "Úspěch",
"syncjob_check_log": "Zkontrolujte záznam",
"syncjob_last_run_result": "Výsledek posledního spuštění",
"syncjob_EX_OK": "Úspěch",
"syncjob_EXIT_CONNECTION_FAILURE": "Problém se spojením",
"syncjob_EXIT_TLS_FAILURE": "Problém se šifrovaným spojením",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problém s autentifikací",
"syncjob_EXIT_OVERQUOTA": "Cílová schránka je plná",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nelze se připojit ke vzdálenému serveru",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Chybné uživatelské jméno nebo heslo",
"tag_handling": "Zacházení s označkovanou poštou",
"tag_help_example": "Příklad e-mailové adresy se značkou: me<b>+Facebook</b>@example.org",
"tag_help_explain": "V podsložce: v doručené poště bude vytvořena nová podsložka pojmenovaná po značce zprávy (\"INBOX / Facebook\").<br>\r\nV předmětu: název značky bude přidáván k předmětu mailu, například: \"[Facebook] Moje zprávy\".",
@ -1165,6 +1197,7 @@
"week": "týden",
"weekly": "Každý týden",
"weeks": "týdny",
"with_app_password": "s heslem aplikace",
"year": "rok",
"years": "let"
},

View File

@ -343,7 +343,9 @@
"api_read_only": "Schreibgeschützter Zugriff",
"api_read_write": "Lese-Schreib-Zugriff",
"oauth2_apps": "OAuth2 Apps",
"queue_unban": "entsperren"
"queue_unban": "entsperren",
"allowed_methods": "Access-Control-Allow-Methods",
"allowed_origins": "Access-Control-Allow-Origin"
},
"danger": {
"access_denied": "Zugriff verweigert oder unvollständige/ungültige Daten",
@ -579,6 +581,10 @@
"disable_login": "Login verbieten (Mails werden weiterhin angenommen)",
"domain": "Domain bearbeiten",
"domain_admin": "Domain-Administrator bearbeiten",
"domain_footer": "Domain wide footer",
"domain_footer_html": "HTML footer",
"domain_footer_info": "Domain wide footer werden allen ausgehenden E-Mails hinzugefügt, die einer Adresse innerhalb dieser Domain gehört.<br>Die folgenden Variablen können für den Footer benutzt werden:",
"domain_footer_plain": "PLAIN footer",
"domain_quota": "Domain Speicherplatz gesamt (MiB)",
"domains": "Domains",
"dont_check_sender_acl": "Absender für Domain %s u. Alias-Domain nicht prüfen",
@ -964,7 +970,7 @@
"queue": {
"delete": "Queue löschen",
"flush": "Queue flushen",
"info": "In der Mailqueue befinden sich alle E-Mails, welche auf eine Zustellung warten. Sollte eine E-Mail eine längere Zeit innerhalb der Mailqueue stecken wird diese automatisch vom System gelöscht.<br>Die Fehlermeldung der jeweiligen Mail gibt aufschluss darüber, warum diese nicht zugestellt werden konnte",
"info": "In der Mailqueue befinden sich alle E-Mails, welche auf eine Zustellung warten. Sollte eine E-Mail eine längere Zeit innerhalb der Mailqueue stecken wird diese automatisch vom System gelöscht.<br>Die Fehlermeldung der jeweiligen Mail gibt Aufschluss darüber, warum diese nicht zugestellt werden konnte",
"legend": "Funktionen der Mailqueue Aktionen:",
"ays": "Soll die derzeitige Queue wirklich komplett bereinigt werden?",
"deliver_mail": "Ausliefern",
@ -1015,6 +1021,7 @@
"domain_admin_added": "Domain-Administrator %s wurde angelegt",
"domain_admin_modified": "Änderungen an Domain-Administrator %s wurden gespeichert",
"domain_admin_removed": "Domain-Administrator %s wurde entfernt",
"domain_footer_modified": "Änderungen an Domain Footer %s wurden gespeichert",
"domain_modified": "Änderungen an Domain %s wurden gespeichert",
"domain_removed": "Domain %s wurde entfernt",
"dovecot_restart_success": "Dovecot wurde erfolgreich neu gestartet",
@ -1118,7 +1125,7 @@
"apple_connection_profile_mailonly": "Dieses Verbindungsprofil beinhaltet IMAP- und SMTP-Konfigurationen für ein Apple-Gerät.",
"apple_connection_profile_with_app_password": "Es wird ein neues App-Passwort erzeugt und in das Profil eingefügt, damit bei der Einrichtung kein Passwort eingegeben werden muss. Geben Sie das Profil nicht weiter, da es einen vollständigen Zugriff auf Ihr Postfach ermöglicht.",
"change_password": "Passwort ändern",
"change_password_hint_app_passwords": "Ihre Mailbox hat {{number_of_app_passwords}} App-Passwörter, die nicht geändert werden. Um diese zu verwalten, gehen Sie bitte zum App-Passwörter-Tab.",
"change_password_hint_app_passwords": "Ihre Mailbox hat %d App-Passwörter, die nicht geändert werden. Um diese zu verwalten, gehen Sie bitte zum App-Passwörter-Tab.",
"clear_recent_successful_connections": "Alle erfolgreichen Verbindungen bereinigen",
"client_configuration": "Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen",
"create_app_passwd": "Erstelle App-Passwort",

View File

@ -149,6 +149,8 @@
"ays": "Are you sure you want to proceed?",
"ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
"change_logo": "Change logo",
"logo_normal_label": "Normal",
"logo_dark_label": "Inverted for dark mode",
"configuration": "Configuration",
"convert_html_to_text": "Convert HTML to plain text",
"cors_settings": "CORS Settings",
@ -581,6 +583,17 @@
"disable_login": "Disallow login (incoming mail is still accepted)",
"domain": "Edit domain",
"domain_admin": "Edit domain administrator",
"domain_footer": "Domain wide footer",
"domain_footer_html": "HTML footer",
"domain_footer_info": "Domain-wide footers are added to all outgoing emails associated with an address within this domain. <br> The following variables can be used for the footer:",
"domain_footer_info_vars": {
"auth_user": "{= auth_user =} - Authenticated Username specified by an MTA",
"from_user": "{= from_user =} - From user part of envelope, e.g for \"moo@mailcow.tld\" it returns \"moo\"",
"from_name": "{= from_name =} - From name of envelope, e.g for \"Mailcow &lt;moo@mailcow.tld&gt;\" it returns \"Mailcow\"",
"from_addr": "{= from_addr =} - From address part of envelope",
"from_domain": "{= from_domain =} - From domain part of envelope"
},
"domain_footer_plain": "PLAIN footer",
"domain_quota": "Domain quota",
"domains": "Domains",
"dont_check_sender_acl": "Disable sender check for domain %s (+ alias domains)",
@ -1024,6 +1037,7 @@
"domain_admin_added": "Domain administrator %s has been added",
"domain_admin_modified": "Changes to domain administrator %s have been saved",
"domain_admin_removed": "Domain administrator %s has been removed",
"domain_footer_modified": "Changes to domain footer %s have been saved",
"domain_modified": "Changes to domain %s have been saved",
"domain_removed": "Domain %s has been removed",
"dovecot_restart_success": "Dovecot was restarted successfully",
@ -1127,7 +1141,7 @@
"apple_connection_profile_mailonly": "This connection profile includes IMAP and SMTP configuration parameters for an Apple device.",
"apple_connection_profile_with_app_password": "A new app password is generated and added to the profile so that no password needs to be entered when setting up your device. Please do not share the file as it grants full access to your mailbox.",
"change_password": "Change password",
"change_password_hint_app_passwords": "Your account has {{number_of_app_passwords}} app passwords that will not be changed. To manage these, go to the App passwords tab.",
"change_password_hint_app_passwords": "Your account has %d app passwords that will not be changed. To manage these, go to the App passwords tab.",
"clear_recent_successful_connections": "Clear seen successful connections",
"client_configuration": "Show configuration guides for email clients and smartphones",
"create_app_passwd": "Create app password",

View File

@ -20,7 +20,9 @@
"tls_policy": "Póliza de TLS",
"unlimited_quota": "Cuota ilimitada para buzones",
"app_passwds": "Gestionar las contraseñas de aplicaciones",
"domain_desc": "Cambiar descripción del dominio"
"domain_desc": "Cambiar descripción del dominio",
"protocol_access": "Cambiar protocolo de acceso",
"quarantine_category": "Cambiar categoría de las notificaciones de cuarentena"
},
"add": {
"activate_filter_warn": "Todos los demás filtros se desactivarán cuando este filtro se active.",
@ -85,7 +87,13 @@
"timeout2": "Tiempo de espera para la conexión al host local",
"username": "Usuario",
"validate": "Validar",
"validation_success": "Validado exitosamente"
"validation_success": "Validado exitosamente",
"inactive": "Inactivo",
"app_name": "Nombre de la App",
"app_password": "Añadir contraseña para la app",
"public_comment": "Comentarios públicos",
"disable_login": "Desactivar login (el correo entrante seguirá activo)",
"comment_info": "Los comentarios privados no son visibles al usuario, mientras que los comentarios públicos aparecerán sobre la información general del usuario"
},
"admin": {
"access": "Acceso",
@ -114,7 +122,7 @@
"app_name": "Nombre de la app",
"apps_name": "Nombre \"mailcow Apps\"",
"arrival_time": "Tiempo de llegada (hora del servidor)",
"ban_list_info": "La lista de IPs bloqueadas sigue a continuación: <b> red (tiempo de prohibición restante) - [acciones]</b>.<br/> Las IPs en cola para ser desbloquadas se eliminarán de la lista de bloqueos en unos pocos segundos. <br/> Las etiquetas rojas indican bloqueos permanentes permanentes mediante la inclusión en una lista negra.",
"ban_list_info": "Lista de IPs bloqueadas: <b>red (tiempo de prohibición restante) - [acciones]</b>.<br />Las IPs en cola para ser desbloqueadas se eliminarán de la lista de bloqueos en unos pocos segundos.<br />Las etiquetas rojas indican bloqueos permanentes mediante la inclusión en la lista negra.",
"change_logo": "Cambiar logo",
"configuration": "Configuración",
"credentials_transport_warning": "<b>Advertencia</b>: al agregar una nueva entrada de ruta de transporte se actualizarán las credenciales para todas las entradas con una columna de \"siguiente destino\" coincidente.",
@ -432,7 +440,7 @@
},
"header": {
"administration": "Administración",
"debug": "Información del sistema",
"debug": "Información",
"email": "E-Mail",
"mailcow_config": "Configuración",
"quarantine": "Cuarentena",

View File

@ -1096,7 +1096,8 @@
"weeks": "semaines",
"months": "mois",
"year": "année",
"years": "années"
"years": "années",
"with_app_password": "avec le mot de passe de l'application"
},
"warning": {
"cannot_delete_self": "Impossible de supprimer lutilisateur connecté",

View File

@ -0,0 +1,20 @@
{
"user": {
"verify": "Επαλήθευση",
"week": "εβδομάδα",
"weekly": "Εβδομαδιαία",
"weeks": "Εβδομάδες",
"with_app_password": "με κωδικό εφαρμογής",
"year": "χρόνος",
"years": "χρόνια"
},
"warning": {
"cannot_delete_self": "Αδυναμία διαγραφής συνδεδεμένου χρήστη",
"dovecot_restart_failed": "Απέτυχε η επανεκκίνηση του Dovecot, παρακαλώ ελέγξτε τα αρχεία καταγραφής.",
"no_active_admin": "Αδυναμία απενεργοποίησης του τελευταίου ενεργού διαχειριστή",
"domain_added_sogo_failed": "Προστέθηκε το όνομα χώρου αλλά απέτυχε η επανεκκίνηση του SOGo.",
"hash_not_found": "Η κατακερματισμένη τιμή (hash value) δεν βρέθηκε ή έχει είδη διαγραφεί.",
"ip_invalid": "Παραλείφθηκε μη έγκυρη διεύθυνση IP: %s",
"is_not_primary_alias": "Παραλείφθηκε μη πρωτεύον ψευδώνυμο %s"
}
}

View File

@ -18,7 +18,11 @@
"transport_dest_format": "Szintaxis: pelda.hu, .pelda.hu, *, fiok@pelda.hu (több érték esetén vesszővel elválasztva)",
"upload": "Feltöltés",
"username": "Felhasználónév",
"verify": "Ellenőrzés"
"verify": "Ellenőrzés",
"activate_api": "API aktiválása",
"activate_send": "Küldés gomb aktiválása",
"add": "Hozzáad",
"active": "Aktív"
},
"edit": {
"active": "Aktív",
@ -385,9 +389,18 @@
"acl": {
"delimiter_action": "Elhatárolás",
"alias_domains": "Alias domainek hozzáadása",
"app_passwds": "Alkalmazás jelszavak kezelése"
"app_passwds": "Alkalmazás jelszavak kezelése",
"domain_desc": "Domain leírás módosítása",
"filters": "Szűrők",
"login_as": "Bejelentkezés mint",
"quarantine": "Karantén műveletek",
"bcc_maps": "BCC címek"
},
"diagnostics": {
"dns_records": "DNS bejegyzések"
},
"add": {
"username": "Felhasználónév",
"validation_success": "Sikeres ellenőrzés"
}
}

View File

@ -134,10 +134,10 @@
"admins_ldap": "Amministratori LDAP",
"advanced_settings": "Impostazioni avanzate",
"api_allow_from": "Allow API access from these IPs/CIDR network notations",
"api_info": "The API is a work in progress. The documentation can be found at <a href=\"/api\">/api</a>",
"api_info": "Questa API è in modifica. La documentazione può essere trovata su <a href=\"/api\">/api</a>",
"api_key": "Chiave API",
"api_skip_ip_check": "Salta il controllo dell'IP per l'API",
"app_links": "App links",
"app_links": "Link dell'app",
"app_name": "Nome dell'app",
"apps_name": "Nome \"mailcow Apps\"",
"arrival_time": "Ora di arrivo (ora del server)",
@ -338,7 +338,8 @@
"oauth2_apps": "App OAuth2",
"oauth2_add_client": "Aggiungere il client OAuth2",
"rsettings_preset_4": "Disattivare Rspamd per un dominio",
"options": "Opzioni"
"options": "Opzioni",
"cors_settings": "Impostazioni CORS"
},
"danger": {
"access_denied": "Accesso negato o form di login non corretto",
@ -1194,7 +1195,7 @@
"weeks": "settimane",
"year": "anno",
"years": "anni",
"change_password_hint_app_passwords": "Il tuo account ha {{number_of_app_passwords}} password delle app che non verranno modificate. Per gestirle, vai alla scheda App passwords.",
"change_password_hint_app_passwords": "Il tuo account ha %d password delle app che non verranno modificate. Per gestirle, vai alla scheda App passwords.",
"syncjob_check_log": "Controlla i log",
"syncjob_last_run_result": "Risultato dell'ultima esecuzione",
"open_logs": "Apri i log",

View File

@ -106,7 +106,8 @@
"timeout2": "Timeout pentru conectarea la gazda locală",
"username": "Nume de utilizator",
"validate": "Validează",
"validation_success": "Validat cu succes"
"validation_success": "Validat cu succes",
"tags": "Etichete"
},
"admin": {
"access": "Acces",
@ -334,7 +335,15 @@
"username": "Nume de utilizator",
"validate_license_now": "Validează GUID cu serverul de licență",
"verify": "Verifică",
"yes": "&#10003;"
"yes": "&#10003;",
"cors_settings": "Setări CORS",
"f2b_ban_time_increment": "Timpul de blocare creşte cu fiecare blocare",
"f2b_max_ban_time": "Max. timp de blocare (s)",
"ip_check": "Verificaţie IP",
"ip_check_disabled": "Verificarea IP este dezactivată. Puteţi activa la<br> <strong>Sistem > Configuraţie > Opţiuni > Personalizează</strong>",
"ip_check_opt_in": "Alegeţi să folosiţi servicile <strong>ipv4.mailcow.email</strong> şi <strong>ipv6.mailcow.email</strong> să rezolvaţi addrese IP externale.",
"options": "Opţiuni",
"queue_unban": "retractează interzicere"
},
"danger": {
"access_denied": "Accesul a fost respins sau datele formularului sunt invalide",
@ -453,7 +462,16 @@
"username_invalid": "Numele de utilizator %s nu poate fi utilizat",
"validity_missing": "Atribuie o perioadă de valabilitate",
"value_missing": "Furnizează toate valorile",
"yotp_verification_failed": "Verificarea Yubico OTP a eșuat: %s"
"yotp_verification_failed": "Verificarea Yubico OTP a eșuat: %s",
"cors_invalid_method": "Aveţi specificaţi 'Allow-Method' invalid",
"webauthn_authenticator_failed": "Authentificator selectat nu a fost găsit",
"webauthn_publickey_failed": "Nici-o cheie publică a fost salvată pentru authenticatorul selectat",
"webauthn_username_failed": "Authenticatorul selectat aparţine la alt cont",
"demo_mode_enabled": "Mod de demonstraţie este activ",
"extended_sender_acl_denied": "lipseşte ACL pentru setarea adrese externe",
"template_exists": "Şablon %s deja există",
"template_id_invalid": "Şablon ID %s este invalid",
"template_name_invalid": "Nume de şablon este invalid"
},
"debug": {
"chart_this_server": "Grafic (acest server)",
@ -641,7 +659,7 @@
"header": {
"administration": "Configurație și detalii",
"apps": "Aplicații",
"debug": "Informații Sistem",
"debug": "Informaţie",
"email": "E-Mail",
"mailcow_config": "Configurație",
"quarantine": "Carantină",
@ -1038,7 +1056,7 @@
"apple_connection_profile_mailonly": "Acest profil de conexiune include parametrii de configurare IMAP și SMTP pentru dispozitivele Apple.",
"apple_connection_profile_with_app_password": "O nouă parolă pentru aplicație este generată și adăugată la profil, astfel încât să nu fie necesară introducerea unei parole la configurarea dispozitivului. Vă rugăm să nu partajați fișierul, deoarece oferă acces deplin la căsuța dvs. poștală.",
"change_password": "Schimbă parola",
"change_password_hint_app_passwords": "Contul dvs. are {{number_of_app_passwords}} parole de aplicație care nu vor fi modificate. Pentru a le gestiona, accesați secțiunea Parole aplicație.",
"change_password_hint_app_passwords": "Contul dvs. are %d parole de aplicație care nu vor fi modificate. Pentru a le gestiona, accesați secțiunea Parole aplicație.",
"clear_recent_successful_connections": "Ștergeți conexiunile reușite văzute",
"client_configuration": "Afișează ghidurile de configurare pentru clienții de email și smartphone-uri",
"create_app_passwd": "Crează parola aplicației",
@ -1187,5 +1205,9 @@
"quota_exceeded_scope": "Cota de spațiu a domeniului depășită: Numai căsuțe poștale nelimitate pot fi create pe acest domeniu.",
"session_token": "Token formular invalid: Nepotrivire token",
"session_ua": "Token formular invalid: Eroare validare utilizator-agent"
},
"datatables": {
"expand_all": "Expandează tot",
"decimal": ","
}
}

View File

@ -338,7 +338,13 @@
"yes": "&#10003;",
"queue_unban": "разблокировать",
"f2b_ban_time_increment": "Время бана увеличивается с каждым баном",
"f2b_max_ban_time": "Максимальное время блокировки"
"f2b_max_ban_time": "Максимальное время блокировки",
"allowed_origins": "Access-Control-Allow-Origin",
"cors_settings": "Настройки CORS",
"allowed_methods": "Access-Control-Allow-Methods",
"ip_check": "Проверить IP",
"ip_check_disabled": "Проверка IP отключена. Вы можете включить его в разделе <br> <strong>Система > Конфигурация > Параметры > Настроить</strong>.",
"ip_check_opt_in": "Согласие на использование сторонних служб <strong>ipv4.mailcow.email</strong> и <strong>ipv6.mailcow.email</strong> для разрешения внешних IP-адресов."
},
"danger": {
"access_denied": "Доступ запрещён, или указаны неверные данные",
@ -457,7 +463,10 @@
"username_invalid": "Имя пользователя %s нельзя использовать",
"validity_missing": "Пожалуйста, назначьте срок действия",
"value_missing": "Пожалуйста заполните все поля",
"yotp_verification_failed": "Ошибка валидации Yubico OTP: %s"
"yotp_verification_failed": "Ошибка валидации Yubico OTP: %s",
"cors_invalid_method": "Указан недопустимый метод разрешения",
"demo_mode_enabled": "Демонстрационный режим включен",
"cors_invalid_origin": "Указан неверный Allow-Origin"
},
"debug": {
"chart_this_server": "Диаграмма (текущий сервер)",
@ -542,7 +551,7 @@
"inactive": "Неактивный",
"kind": "Тип",
"last_modified": "Последние изменения",
"lookup_mx": "Назначение на основе резовинга MX записи по регулярному выражению (<code>.*\\.example\\.com$</code> для маршрутизации всей почты через этот хост, если MX заканчивающийся на example.com)",
"lookup_mx": "Назначение на основе резолвинга MX записи по регулярному выражению (<code>.*\\.example\\.com$</code> для маршрутизации всей почты через этот хост, если MX заканчивающийся на example.com)",
"mailbox": "Изменение почтового аккаунта",
"mailbox_quota_def": "Квота по умолчанию",
"mailbox_relayhost_info": "Применяется только к почтовому ящику и личным псевдонимам, вне зависимости от настроек маршрутизации на уровне домена.",
@ -607,7 +616,9 @@
"title": "Изменение объекта",
"unchanged_if_empty": "Если без изменений - оставьте пустым",
"username": "Имя пользователя",
"validate_save": "Подтвердить и сохранить"
"validate_save": "Подтвердить и сохранить",
"sogo_access_info": "Единый вход из интерфейса почты продолжает работать. Эта настройка не влияет на доступ ко всем другим службам, а также не удаляет или изменяет существующий профиль пользователя SOGo.",
"app_passwd_protocols": "Разрешенные протоколы для пароля приложения"
},
"fido2": {
"confirm": "Подтвердить",
@ -987,7 +998,8 @@
"verified_fido2_login": "Авторизация FIDO2 пройдена",
"verified_totp_login": "Авторизация TOTP пройдена",
"verified_webauthn_login": "Авторизация WebAuthn пройдена",
"verified_yotp_login": "Авторизация Yubico OTP пройдена"
"verified_yotp_login": "Авторизация Yubico OTP пройдена",
"cors_headers_edited": "Настройки CORS сохранены"
},
"tfa": {
"api_register": "%s использует Yubico Cloud API. Пожалуйста, получите ключ API для вашего ключа <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">здесь</a>",
@ -1169,7 +1181,12 @@
"weekly": "Раз в неделю",
"weeks": "недели",
"year": "год",
"years": "лет"
"years": "лет",
"allowed_protocols": "Разрешенные протоколы",
"apple_connection_profile_with_app_password": "Новый пароль приложения генерируется и добавляется в профиль, поэтому при настройке устройства не требуется вводить пароль. Не предоставляйте доступ к файлу, поскольку он предоставляет полный доступ к вашему почтовому ящику.",
"direct_protocol_access": "Этот пользователь почтового ящика имеет <b>прямой, внешний доступ</b> к следующим протоколам и приложениям. Эта настройка контролируется вашим администратором. Для предоставления доступа к отдельным протоколам и приложениям могут быть созданы пароли приложений.<br> Кнопка \"Вход в веб-почту\" обеспечивает единый вход в SOGo и всегда доступна.",
"with_app_password": "с паролем приложения",
"change_password_hint_app_passwords": "В вашей учетной записи есть {{number_of_app_passwords}} паролей приложений, которые не будут изменены. Чтобы управлять ими, перейдите на вкладку \"Пароли приложений\"."
},
"warning": {
"cannot_delete_self": "Вы не можете удалить сами себя",
@ -1183,5 +1200,8 @@
"quota_exceeded_scope": "Квота домена превышена: могут быть созданы только почтовые ящики без лимита.",
"session_token": "Неверный токен формы: несоответствие токена",
"session_ua": "Неверный токен формы: ошибка проверки User-Agent"
},
"datatables": {
"infoPostFix": ""
}
}

View File

@ -0,0 +1,396 @@
{
"acl": {
"app_passwds": "Upravljaj gesla aplikacij",
"bcc_maps": "Preslikave SKP (BCC)",
"delimiter_action": "Dejanje ločila",
"domain_relayhost": "Spremeni gostitelja relay za domeno",
"eas_reset": "Ponastavi EAS naprave",
"filters": "Filtri",
"login_as": "Prijavi se kot uporabnik poštnega predala",
"mailbox_relayhost": "Spremeni gostitelja relay za poštni predal",
"prohibited": "Prepovedano z ACL",
"protocol_access": "Spremeni dostop do protokola",
"pushover": "Pushover",
"quarantine": "Dejanja karantene",
"quarantine_attachments": "Priponke v karanteno",
"quarantine_notification": "Spremeni obvestila o karanteni",
"ratelimit": "Omejitev pošiljanja",
"recipient_maps": "Preslikave prejemnikov",
"smtp_ip_access": "Spremeni dovoljene gostitelje za SMTP",
"sogo_access": "Dovoli upravljanje SOGo dostopov",
"sogo_profile_reset": "Ponastavi SOGo profil",
"spam_alias": "Začasni aliasi",
"spam_policy": "Blacklist/Whitelist",
"spam_score": "Ocena neželene pošte",
"tls_policy": "Politika TLS",
"unlimited_quota": "Neomejena kvota za poštne predale",
"alias_domains": "Dodaj alias domene",
"domain_desc": "Spremeni opis domene",
"extend_sender_acl": "Dovoli razširitev pošiljateljevega ACL z zunanjimi e-poštnimi naslovi",
"quarantine_category": "Spremeni kategorijo obvestil o karanteni",
"syncjobs": "Opravila sinhronizacije"
},
"add": {
"active": "Aktivno",
"add": "Dodaj",
"add_domain_only": "Dodaj samo domeno",
"add_domain_restart": "Dodaj domeno in ponovno zaženi SOGo",
"alias_address": "Alias naslov/i",
"alias_domain": "Alias domena",
"alias_domain_info": "<small>Samo veljavne domene (ločene z vejico).</small>",
"app_name": "Ime aplikacije",
"app_password": "Dodaj geslo aplikacije",
"app_passwd_protocols": "Dovoljeni protokoli za geslo aplikacije",
"automap": "Poskusi samodejno preslikati mape (\"Sent items\", \"Sent\" => \"Poslano\" ipd.)",
"backup_mx_options": "Možnosti posredovanja (relay)",
"comment_info": "Zasebni komentarji niso vidni uporabnikom, javni komentarji pa so prikazani kot tooltip, ko se z miško postavimo nad uporabnika v pregledu",
"custom_params": "Parametri po meri",
"custom_params_hint": "Pravilno: --param=xy, napačno: --param xy",
"delete1": "Izbriši na viru, ko je končano",
"delete2": "Izbriši sporočila na cilju, ki niso na viru",
"delete2duplicates": "Izbriši dvojnike na cilju",
"description": "Opis",
"destination": "Cilj",
"domain": "Domena",
"domain_matches_hostname": "Domena %s se ujema z nazivom gostitelja (hostname)",
"domain_quota_m": "Kvota za celotno domeno (MiB)",
"enc_method": "Metoda kriptiranja",
"exclude": "Izključi objekte (regex)",
"full_name": "Polno ime",
"gal": "Globalni seznam stikov (GAL)",
"generate": "generiraj",
"goto_ham": "Prepoznaj kot <span class=\"text-success\"><b>ham</b></span>",
"goto_null": "Odstrani e-poštno sporočilo brez obvestila",
"goto_spam": "Prepoznaj kot <span class=\"text-danger\"><b>spam</b></span>",
"hostname": "Gostitelj",
"inactive": "Neaktivno",
"kind": "Tip",
"mailbox_quota_def": "Privzeta kvota za poštni predal",
"mailbox_username": "Uporabniško ime (levi del e-poštnega naslova)",
"max_aliases": "Največje število dovoljenih aliasov",
"max_mailboxes": "Največje dovoljeno število poštnih predalov",
"mins_interval": "Interval preverjanja (minute)",
"multiple_bookings": "Več rezervacij",
"nexthop": "Naslednji korak",
"password_repeat": "Potrditev gesla (ponovi)",
"port": "Vrata (port)",
"private_comment": "Zasebni komentar",
"public_comment": "Javni komentar",
"quota_mb": "Kvota (MiB)",
"relay_all": "Posreduj vse prejemnike (relay)",
"relay_all_info": "↪ Če izberete da <b>ne</b> posredujete vse prejemnike, morate ustvariti (\"slepi\") poštni predal za vsakega prejemnika, za katerega želite posredovati e-pošto.",
"relay_domain": "Posreduj to domeno (relay)",
"relay_unknown_only": "Posreduj samo neobstoječe poštne predale. V obstoječe poštne predale bo e-pošta dostavljena lokalno.",
"relayhost_wrapped_tls_info": "Prosim <b>ne</b> uporabljajte TLS-wrapped vrata (večinoma uporabljeno na vratih 465).<br>\nUporabite katera koli non-wrapped vrata in ustvarite STARTTLS. TLS politika za obvezno uporabo TLS se lahko ustvari pod \"Preslikave TLS politik\"",
"select": "Prosim izberite...",
"select_domain": "Prosim najprej izberite domeno",
"sieve_desc": "Kratek opis",
"sieve_type": "Vrsta filtra",
"skipcrossduplicates": "Preskoči podvojena sporočila po mapah (prvi pride, prvi melje)",
"subscribeall": "Prijavi vse mape",
"syncjob": "Dodaj opravilo sinhronizacije",
"tags": "Oznake",
"target_address": "Goto naslov",
"target_address_info": "<small>Polni e-poštni naslov/i (ločeni z vejico).</small>",
"target_domain": "Ciljna domena",
"timeout1": "Časovna omejitev za povezavo do oddaljenega gostitelja",
"username": "Uporabniško ime",
"validate": "Preveri",
"validation_success": "Uspešno preverjeno",
"activate_filter_warn": "Ko je aktivni izbran, bodo vsi ostali filtri deaktivirani.",
"alias_address_info": "<small>Polni email naslov/i oziroma @example.com za zajem vseh sporočil domene (ločeno z vejico), <b>samo domene mailcow</b>.</small>",
"bcc_dest_format": "BCC naslov mora biti en veljaven e-poštni naslov.<br>Če morate poslati kopijo na več naslov, ustvarite alias in ga uporabite tukaj.",
"disable_login": "Prepovej vpis (vhodna e-pošta je še vedno sprejeta)",
"gal_info": "GAL vsebuje vse objekte domene in ga uporabniki ne morejo urejati. Informacija o zasedenosti v SOGo ni na voljo, če je onemogočena! <b>Ponovno zaženi SOGo za uveljavitev sprememb.</b>",
"mailbox_quota_m": "Najvišja kvota na poštni predal (MiB)",
"password": "Geslo",
"post_domain_add": "SOGo container \"sogo-mailcow\" mora biti ponovno zagnan po dodajanju nove domene!<br><br>Dodatno se mora preveriti DNS konfiguracija domene. Ko je DNS konfiguracija domene odobrena, ponovno zaženite \"acme-mailcow\" za samodejno generiranje certifikatov za novo domeno (autoconfig.&lt;domain&gt;, autodiscover.&lt;domain&gt;).<br>Ta korak je opcijski in se ponovno poskuša vsakih 24 ur.",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Definirate lahko preslikave transportov za cilj po meri za to domeno. Če ni nastavljena, se ustvari MX poizvedba.",
"syncjob_hint": "Pozor! Gesla se morajo shraniti v plain-text!",
"timeout2": "Časovna omejitev za povezavo do lokalnega gostitelja"
},
"admin": {
"access": "Dostop",
"action": "Dejanje",
"activate_api": "Aktiviraj API",
"activate_send": "Aktiviraj gumb \"Pošlji\"",
"active": "Aktivno",
"active_rspamd_settings_map": "Aktivna preslikava nastavitev",
"add": "Dodaj",
"add_domain_admin": "Dodaj skrbnika domene",
"add_forwarding_host": "Dodaj gostitelja za posredovanje",
"add_relayhost": "Dodaj transport odvisen od pošiljatelja",
"add_row": "Dodaj vrstico",
"add_settings_rule": "Dodaj pravilo nastavitev",
"add_transport": "Dodaj transport",
"add_transports_hint": "Prosimo zavedajte se, da se podatki za avtentikacijo, če obstajajo, shranijo v plain text.",
"additional_rows": " nove vrstice so bile dodane",
"admin_details": "Uredi podrobnosti skrbnika",
"admin_domains": "Dodeljene domene",
"admins": "Skrbniki",
"admins_ldap": "LDAP skrbniki",
"advanced_settings": "Napredne nastavitve",
"api_info": "API je v razvoju. Dokumentacija je na voljo na naslovu <a href=\"/api\">/api</a>",
"api_key": "API ključ",
"api_read_only": "Dostop samo za branje",
"api_read_write": "Dostop za branje in urejanje",
"api_skip_ip_check": "Preskoči preverjanje IP za API",
"app_links": "Povezave aplikacij",
"app_name": "Ime aplikacije",
"arrival_time": "Čas prispetja (strežniški čas)",
"authed_user": "Prij. uporabnik",
"ays": "Ste prepričani, da želite nadaljevati?",
"change_logo": "Zamenjaj logotip",
"configuration": "Konfiguracija",
"convert_html_to_text": "Pretvori HTML v golo besedilo",
"credentials_transport_warning": "<b>Opozorilo</b>: Dodajanje nove preslikave transporta bo posodobilo poverilnice za vse vnose, ki imajo enako vrednost v stolpcu naslednji skok.",
"customer_id": "ID stranke",
"customize": "Prilagodi",
"destination": "Cilj",
"dkim_add_key": "Dodaj ARC/DKIM ključ",
"dkim_domains_selector": "Izbira",
"dkim_domains_wo_keys": "Izberi domene z manjkajočimi ključi",
"dkim_from": "Od",
"dkim_from_title": "Izvorna domena od katere prekopiram podatke",
"dkim_key_missing": "Manjka ključ",
"dkim_key_unused": "Ključ ni v rabi",
"dkim_key_valid": "Veljaven ključ",
"dkim_keys": "ARC/DKIM ključi",
"dkim_overwrite_key": "Prepiši obstoječi DKIM ključ",
"dkim_private_key": "Zasebni ključ",
"dkim_to": "Za",
"domain": "Domena",
"domain_admin": "Skrbnik domene",
"domain_admins": "Skrbniki domene",
"domain_s": "Domena/e",
"duplicate": "Podvoji",
"duplicate_dkim": "Podvoji DKIM zapis",
"edit": "Uredi",
"empty": "Ni rezultatov",
"excludes": "Izključuje te prejemnike",
"f2b_ban_time": "Čas blokade (s)",
"f2b_ban_time_increment": "Čas blokade se poveča z vsako blokado",
"f2b_blacklist": "Mreže/gostitelji na blacklisti",
"f2b_filter": "Regex filtri",
"f2b_max_attempts": "Največ poskusov",
"f2b_max_ban_time": "Maksimalno trajanje blokade (s)",
"f2b_netban_ipv4": "velikost subneta IPv4 za blokiranje (8-32)",
"f2b_netban_ipv6": "Velikost subneta IPv6 za blokiranje (8-128)",
"f2b_parameters": "Fail2ban parametri",
"f2b_regex_info": "Upoštevajo se dnevniki SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Upoštevan čas (s) za največ poskusov",
"f2b_whitelist": "Mreže/gostitelji na whitelisti",
"filter_table": "Filtriraj tabelo",
"from": "Od",
"generate": "ustvari",
"guid": "GUID - enolični ID instance",
"guid_and_license": "GUID & licenca",
"hash_remove_info": "Odstranitev hasha za omejitev (če obstaja) bo povsem ponastavilo njen števec.<br>\n Vsak hash je prikazan z individualno barvo.",
"help_text": "Zamenjaj tekst za pomoč pod masko za prijavo (HTML je dovoljen)",
"host": "Gostitelj",
"html": "HTML",
"import": "Uvozi",
"import_private_key": "Uvozi zasebni ključ",
"in_use_by": "V uporabi",
"inactive": "Neaktivno",
"include_exclude": "Vključi/Izključi",
"include_exclude_info": "Privzeto - če ni izbire - so vključeni <b>vsi poštni predali</b>",
"includes": "Vključi te prejemnike",
"ip_check": "Kontrola IP",
"ip_check_disabled": "Kontrola IP je onemogočena. Lahko jo omogočite pod <br/> <strong>Sistem > Konfiguracija > Možnosti > Prilagodi</strong>",
"ip_check_opt_in": "Opt-in za uporabo zunanje storitve <strong>ipv4.mailcow.email</strong> in <strong>ipv6.mailcow.email</strong> za razreševanje zunanjih IP.",
"is_mx_based": "Glede na MX",
"last_applied": "Nazadnje aplicirano",
"link": "Povezava",
"loading": "Prosim počakajte...",
"login_time": "Čas prijave",
"logo_info": "Vaša slika bo pomanjšana na velikost 40px za zgornjo navigacijo in največjo velikost 250px za začetno stran. Zelo priporočena je uporaba grafike brez izgube kakovosti ob spremembi velikosti.",
"message": "Sporočilo",
"message_size": "Velikost sporočila",
"nexthop": "Naslednji skok",
"no": "&#10005;",
"no_active_bans": "Ni aktivnih blokad",
"no_new_rows": "Ni dodatnih vrstic",
"no_record": "Ni zapisa",
"oauth2_apps": "OAuth2 aplikacije",
"oauth2_add_client": "Dodaj OAuth2 klienta",
"oauth2_client_id": "ID klienta",
"oauth2_client_secret": "Skrivnost (secret)",
"oauth2_redirect_uri": "URI za preusmeritev",
"oauth2_renew_secret": "Generiraj nov client secret",
"oauth2_revoke_tokens": "Zavrni vse tokene klientov",
"optional": "opcijsko",
"options": "Možnosti",
"password": "Geslo",
"password_length": "Dolžina gesla",
"password_policy": "Politika gesel",
"password_policy_chars": "Mora vsebovati vsaj eno črko",
"password_policy_length": "Minimalna dolžina gesla je %d",
"password_policy_lowerupper": "Mora vsebovati male in velike črke",
"password_policy_numbers": "Mora vsebovati vsaj eno številko",
"password_policy_special_chars": "Mora vsebovati posebne znake",
"password_repeat": "Potrditev gesla (ponovite)",
"priority": "Prioriteta",
"private_key": "Zasebni ključ",
"quarantine": "Karantena",
"quarantine_bcc": "Pošlji kopijo vseh obvestil (BCC) temu prejemniku:<br><small>Pustite prazno za izklop te funkcije. <b>Nepodpisana, nepreverjena pošta. Uporabljalo naj bi se samo za interno dostavo.</b></small>",
"quarantine_exclude_domains": "Izključi domene in alias-domene",
"quarantine_max_age": "Maksimalna starost v dnevnih<br><small>Vrednost mora biti večja ali enaka 1 dnevu</small>",
"quarantine_max_score": "Opusti obvestilo, če je ocena spama večja od te vrednosti:<br><small>Privzeto 9999.0</small>",
"quarantine_max_size": "Največja velikost v MiB (Večji elementi so zavrženi):<br><small>0 <b>ne</b> pomeni neomejeno.</small>",
"quarantine_notification_html": "Predloga sporočila za obvestilo:<br><small>Pustite prazno za obnovitev privzete predloge.</small>",
"quarantine_notification_sender": "Pošiljatelj obvestila",
"quarantine_notification_subject": "Naslov obvestila",
"quarantine_release_format": "Oblika sproščenih elementov",
"quarantine_release_format_att": "Kot priponka",
"quarantine_release_format_raw": "Nespremenjen original",
"quarantine_retention_size": "Število zadržanj na poštni predal: <br><small>0 pomeni <b>neaktivno</b>,</small>",
"quota_notification_sender": "Pošiljatelj obvestila",
"quota_notification_subject": "Predmet obvestila",
"quota_notifications": "Obvestila o omejitvi",
"quota_notifications_info": "Obvestila o omejitvi so poslana uporabnikom enkrat, ko presežejo 80% in enkrat ko presežejo 95% zasedenosti.",
"queue_unban": "odblokiraj",
"r_active": "Aktivne omejitve",
"r_inactive": "Neaktivne omejitve",
"rate_name": "Ime omejitve",
"recipients": "Prejemniki",
"refresh": "Osveži",
"regen_api_key": "Ponovno generiraj API ključ",
"regex_maps": "Regex preslikave",
"relay_from": "\"Od:\" naslov",
"relay_rcpt": "\"Za:\" naslov",
"relay_run": "Izvedi test",
"relayhosts": "Transporti glede na pošiljatelja",
"remove": "Odstrani",
"remove_row": "Odstrani vrstico",
"reset_default": "Ponastavi na privzeto",
"reset_limit": "Odstrani hash",
"routing": "Routing",
"rsetting_add_rule": "Dodaj pravilo",
"rsetting_content": "Vsebina pravila",
"rsetting_desc": "Kratek opis",
"rsetting_no_selection": "Prosim izberite pravilo",
"rsetting_none": "Ni pravil na voljo",
"rsettings_insert_preset": "Vstavi prednastavljen primer \"%s\"",
"rsettings_preset_1": "Onemogoči vse razen DKIM in omejitve za prijavljene uporabnike",
"rsettings_preset_2": "Postmasterji želijo spam",
"rsettings_preset_3": "Dovoli samo specifične pošiljatelje za poštni predal (npr. uporaba samo kot interni poštni predal)",
"rsettings_preset_4": "Onemogoči Rspamd za domeno",
"rspamd_com_settings": "Ime nastavitve bo samodejno generirano. Prosim oglejte si primere nastavitev spodaj. Za več informacij si oglejte <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">dokumentacijo Rspamd</a>",
"rspamd_global_filters": "Globalne preslikave filtrov",
"rspamd_global_filters_agree": "Previden bom!",
"rspamd_global_filters_info": "Globalne preslikave filtrov vsebujejo različne vrste globalnih blacklist in whitelist.",
"add_admin": "Dodaj skrbnika",
"add_relayhost_hint": "Prosimo zavedajte se, da se podatki za avtentikacijo, če obstajajo, shranijo v plain text.",
"admin": "Skrbnik",
"api_allow_from": "Dovoli API dostop s teh IP naslovov / CIDR mrežnih zapisov",
"apps_name": "Ime aplikacije v mailcow",
"ban_list_info": "Oglejte si seznam blokiranih IP naslovov spodaj: <b>network (remaining ban time) - [actions]</b>.<br />. IPji v vrsti za odstranitev blokade bodo odstranjeni iz aktivnega seznama blokad v nekaj sekundah.<br />Rdeče oznake prikazujejo trajne blokade z blacklisto.",
"dkim_key_length": "Dolžina DKIM ključa (v bitih)",
"dkim_to_title": "Ciljne domene bodo prepisane",
"f2b_list_info": "Gostitelj ali omrežje na blacklisti bo vedno prevladal zapis na whitelisti. <b>Apliciranje sprememb seznama traja nekaj sekund.</b>",
"forwarding_hosts": "Gostitelji za posredovanje",
"forwarding_hosts_add_hint": "Lahko vpišete IPv4/IPv6 naslove, mreže v CIDR obliki, imena gostiteljev (kateri se prevedejo v IP naslove) ali imena domen (katera se prevedejo v IP naslove glede na poizvedbo po SPF zapisih, v primeru manjkajočih zapisov pa MX zapisih).",
"forwarding_hosts_hint": "Dohodna sporočila so brezpogojno sprejeta od katerih koli gostiteljev v tem seznamu. Ti gostitelji se ne bodo preverjali po DNSBL seznamih in ne bodo dodani v greyliste. Prejeti spam s teh gostiteljev ni nikoli zavrnjen, opcijsko pa se lahko premakne v mapo neželene pošte. Najpogostejša uporaba za to je navedba poštnih strežnikov, iz katerih ste nastavili pravilo za posredovanje pošte na vaš mailcow strežnik.",
"license_info": "Licenca ni zahtevana, a pomaga pri nadaljnjem razvoju. <br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"Naročilo SAL\">Registrirajte svoj GUID tukaj</a> ali <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Naročilo podpora\">Kupite podporo za svojo namestitev Mailcow.</a>",
"lookup_mx": "Cilj je regular expression za ujemanje MX zapisov (<code>.*\\.google\\.com</code> za usmeritev vse pošte na MX, ki se konča z google.com, preko tega skoka)",
"main_name": "Naziv \"mailcow UI\"",
"merged_vars_hint": "Sive vrstice so združene iz <code>vars.(local.)inc.php</code> in jih ni mogoče spremeniti.",
"oauth2_info": "OAuth2 implementacija omogoča grant vrste \"Authorization code\" in izdaja refresh tokene.<br>\nStrežnik prav tako izda nove refresh tokene, ko je bil refresh token uporabljen<br><br>\n&#8226; Privzeti obseg je <i>profile</i>. Samo uporabniki poštnih predalov se lahko prijavijo s pomočjo OAuth2. Če parameter obsega ni vnesen, se nastavi na <i>profile</i>.<br>\n&#8226; Parameter <i>state</i> mora biti poslan s strani klienta kot del zahtevka za avtorizacijo .<br><br>\nPoti za OAuth2 API: <br>\n<ul>\n <li>Endpoint za avtorizacijo: <code>/oauth/authorize</code></li>\n <li>Endpoint za tokene: <code>/oauth/token</code></li>\n <li>Stran vira: <code>/oauth/profile</code></li>\n</ul>\nPonovno generiranje client secret ne bo razveljavilo obstoječih avtorizacijskih kod, ne bodo pa mogle obnoviti svoje tokene.<br><br>\nZavrnitev client tokenov bo povzročilo tekojčno prekinitev aktivnih sej. Vsi klienti se bodo morali ponovno prijaviti.",
"quarantine_redirect": "<b>Preusmeri vsa obvestila</b> k temu prejemniku:<br><small>Pustite prazno, da onemogočite. <b>Nepodpisana, nepreverjena pošta. Uporabljalo bi se naj samo za interno dostavo.</b></small>",
"quota_notification_html": "Predloga sporočila za obvestilo:<br><small>Pustite prazno za obnovitev privzete predloge.</small>",
"quota_notifications_vars": "{{percent}} pomeni trenutna omejitev uporabnika<br>{{username}} je ime poštnega predala",
"r_info": "Sivi/onemogočeni elementi v seznamu aktivnih omejitev niso znane kot veljavne omejitve za mailcow in ne morejo biti premaknjene. Neznane omejitve bodo kljub temu nastavljene po vrstnem redu pojavitve. <br>Nove elemente lahko dodate v <code>inc/vars.local.inc.php</code> da jih lahko vklopite ali izklopite.",
"relayhosts_hint": "Določite transporte glede na pošiljatelja, da jih lahko izberete v konfiguraciji domene.<br>\nTransportni servis je vedno \"smtp:\" in bo poskušal s TLS ko bo na voljo. Wrapped TLS (SMTPS) ni podprto. Upošteva se uporabnikova politika odhodnega TLS.<br>\nVpliva na izbrane domene vključno z alias domenami.",
"transport_dest_format": "Regex ali sintaksa: example.org, .example.org, *, box@example.org (več vrednosti ločite z vejico)",
"transport_test_rcpt_info": "&#8226; Uporabite null@hosted.mailcow.de za testiranje relaya na drugo destinacijo.",
"rspamd_global_filters_regex": "Njihovi nazivi pojasnijo njihov namen. Vsa vsebina mora imeti veljaven regular expression v obliki \"/pattern/options\" (npr. <code>/.+@domain\\.tld/i</code>).<br>\nČeprav se v vsaki vrstici regexa izvedejo osnovni pregledi, je lahko funkcionalnost programa Rspamd motena, če sintaksa ni pravilna.<br>\nRspamd bo poskušal prebrati vsebino preslikave, ko bo spremenjena. Če imate težave, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">ponovno zaženite Rspamd</a>, da prisilite ponovno nalaganje preslikav.<br> Elementi z Blackliste so izključeni iz karantene.",
"rspamd_settings_map": "Preslikava nastavitev Rspamd",
"sal_level": "Moo stopnja",
"save": "Shrani spremembe",
"search_domain_da": "Išči domene",
"send": "Pošlji",
"sender": "Pošiljatelj",
"service": "Servis",
"service_id": "ID servisa",
"source": "Vir",
"spamfilter": "Spam filter",
"subject": "Predmet",
"success": "Uspešno",
"sys_mails": "Sistemska pošta",
"text": "Besedilo",
"time": "Čas",
"title": "Naziv",
"title_name": "Naziv spletnega mesta \"mailcow UI\"",
"to_top": "Nazaj na vrh",
"transport_maps": "Preslikave transportov",
"transports_hint": "&#8226; Vpis preslikave transporta <b>nadredi</b> preslikavo transporta odvisno od pošiljatelja.<br>\n&#8226; Preferenčno se uporabljajo transporti glede na MX zapise.<br>\n&#8226; Izhodne TLS politike na uporabnika so ignorirane in se lahko vsilijo samo s preslikavami TLS politik.<br>\n&#8226; Transportni servis za definirane transporte je vedno \"smtp:\" in bo posledično poskušal TLS ko bo ponujeno. Wrapped TLS (SMTPS) ni podprto.<br>\n&#8226; Naslovi, ki se ujemajo z \"/localhost$/\" bodo vedno preneseni preko \"local:\", in zato destinacija \"*\" ne bo vplivala na te naslove.<br>\n&#8226; Za določitev poverilnic za naslednji skok (npr. \"[host]:25\"), Postfix <b>vedno</b> preveri \"host\" preden išče \"[host]:25\". Zaradi takšnega obnašanja je nemogoče hkrati uporabiti \"host\" in \"[host]:25\".",
"ui_footer": "Noga (HTML dovoljen)",
"ui_header_announcement": "Obvestila",
"ui_header_announcement_active": "Nastavi obvestilo kot aktivno",
"ui_header_announcement_content": "Besedilo (HTML dovoljen)",
"ui_header_announcement_help": "Obvestilo je vidno za vse prijavljene uporabnike in na vmesniku za prijavo.",
"ui_header_announcement_select": "Izberite vrsto obvestila",
"ui_header_announcement_type": "Vrsta",
"ui_header_announcement_type_danger": "Zelo pomembno",
"ui_header_announcement_type_info": "Info",
"ui_header_announcement_type_warning": "Pomembno",
"ui_texts": "Oznake in besedila UI",
"unban_pending": "unban v postopku",
"unchanged_if_empty": "Če je nespremenjeno, pustite prazno",
"upload": "Naloži",
"username": "Uporabniško ime",
"validate_license_now": "Potrdi GUID z licenčnim strežnikom",
"verify": "Preveri",
"yes": "&#10003;"
},
"danger": {
"alias_goto_identical": "Alias in goto naslov morata biti identična",
"aliasd_targetd_identical": "Alias domena ne sme biti enaka ciljni domeni: %s",
"bcc_exists": "BCC preslikava obstaja za vrsto %s",
"dkim_domain_or_sel_exists": "DKIM ključ za \"%s\" obstaja in ne bo prepisan.",
"domain_quota_m_in_use": "Kvota domene mora biti večja ali enaka %s MiB",
"extra_acl_invalid_domain": "Zunanji pošiljatelj \"%s\" uporablja neveljavno domeno",
"global_map_write_error": "Ni mogoče zapisati ID globalne preslikave %s: %s",
"img_tmp_missing": "Ni mogoče preveriti slikovne datoteke: začasne datoteke ni mogoče najti",
"invalid_nexthop": "Oblika naslednjega skoka ni veljavna",
"invalid_nexthop_authenticated": "Naslednji skok obstaja z drugačnimi poverilnicami. Prosim najprej posodobite obstoječe poverilnice za ta naslednji skok.",
"demo_mode_enabled": "Demo način je omogočen",
"access_denied": "Dostop zavrnjen ali pa so podatki obrazca napačni",
"alias_domain_invalid": "Alias domena %s ni veljavna",
"alias_empty": "Alias naslov ne sme biti prazen",
"alias_invalid": "Alias naslov %s ni veljaven",
"aliases_in_use": "Max. aliasov mora biti večje ali enako %d",
"app_name_empty": "Naziv aplikacije ne more biti prazno",
"app_passwd_id_invalid": "ID gesla aplikacije %s je neveljaven",
"bcc_empty": "BCC cilj ne more biti prazen",
"bcc_must_be_email": "BCC cilj %s ni veljaven e-poštni naslov",
"comment_too_long": "Komentar je predolg, dovoljeno je največ 100 znakov.",
"defquota_empty": "Privzeta kvota na poštni predal ne more biti 0",
"description_invalid": "Opis resursa za %s ni veljaven",
"dkim_domain_or_sel_invalid": "Domena ali izbirnik DKIM ni veljaven: %s",
"domain_cannot_match_hostname": "Domena se ne more ujemati z imenom gostitelja",
"domain_exists": "Domena %s že obstaja",
"domain_invalid": "Manjka ali napačno ime domene",
"domain_not_empty": "Ne morem odstraniti ne-prazno domeno %s",
"domain_not_found": "Domene %s ni bilo mogoče najti",
"extended_sender_acl_denied": "manjka ACL za določitev naslovov zunanjih pošiljateljev",
"extra_acl_invalid": "Naslov zunanjega pošiljatelja \"%s\" ni veljaven",
"fido2_verification_failed": "Preverjanje FIDO2 ni uspelo: %s",
"file_open_error": "Datoteka ne more biti odprta za urejanje",
"filter_type": "Napačna vrsta filtra",
"from_invalid": "Pošiljatelj ne sme biti prazno",
"global_filter_write_error": "Ni mogoče zapisati datoteke filtra: %s",
"global_map_invalid": "ID globalne preslikave %s ni veljaven",
"goto_empty": "Alias naslov mora vsebovati vsaj en veljaven goto naslov",
"goto_invalid": "Goto naslov %s ni veljaven",
"ham_learn_error": "Napaka pri učenju Ham: %s",
"imagick_exception": "Napaka: Imagick napaka pri branju slike",
"img_invalid": "Ni možno preveriti slikovne datoteke",
"invalid_bcc_map_type": "Neveljavna vrsta preslikave BCC",
"invalid_destination": "Ciljna oblika \"%s\" ni veljavna",
"invalid_filter_type": "Neveljavna vrsta filtra",
"invalid_host": "Naveden je neveljaven gostitelj (host): %s",
"invalid_mime_type": "Neveljaven mime type"
}
}

View File

@ -41,6 +41,7 @@
"alias_domain": "Alias doména",
"alias_domain_info": "<small>Len platné mená domén (oddelené čiarkou).</small>",
"app_name": "Meno aplikácie",
"app_passwd_protocols": "Povolené protokoly pre heslá aplikácií",
"app_password": "Pridať heslo aplikácie",
"automap": "Skúsiť automaticky mapovať priečinky (\"Sent items\", \"Sent\" => \"Sent\" atd.)",
"backup_mx_options": "Možnosti preposielania",
@ -456,6 +457,29 @@
"value_missing": "Prosím poskytnite všetky hodnoty",
"yotp_verification_failed": "Overenie cez OTP Yubico zlyhalo: %s"
},
"datatables": {
"info": "Záznamy _START_ až _END_ z celkom _TOTAL_",
"infoEmpty": "Záznamy 0 až 0 z celkom 0 ",
"infoFiltered": "(vyfiltrované spomedzi _MAX_ záznamov)",
"lengthMenu": "Zobraz _MENU_ záznamov",
"loadingRecords": "Načítavam...",
"processing": "Spracúvam...",
"search": "Hľadať:",
"zeroRecords": "Nenašli sa žiadne vyhovujúce záznamy",
"paginate": {
"first": "Prvá",
"last": "Posledná",
"next": "Nasledujúca",
"previous": "Predchádzajúca"
},
"aria": {
"sortAscending": ": aktivujte na zoradenie stĺpca vzostupne",
"sortDescending": ": aktivujte na zoradenie stĺpca zostupne"
},
"emptyTable": "Nie sú k dispozícii žiadne dáta.",
"decimal": ",",
"thousands": " "
},
"debug": {
"chart_this_server": "Graf (tento server)",
"containers_info": "Informácie o kontajneroch",
@ -505,6 +529,7 @@
"allowed_protocols": "Povolené protokoly",
"app_name": "Meno aplikácie",
"app_passwd": "Heslo aplikácie",
"app_passwd_protocols": "Povolené protokoly pre heslá aplikácií",
"automap": "Skúsiť automapovať priečinky (\"Sent items\", \"Sent\" => \"Sent\" atd.)",
"backup_mx_options": "Možnosti preposielania",
"bcc_dest_format": "Cieľ kópie musí byť jedna platná emailová adresa. Pokiaľ potrebujete posielať kópie na viac adries, vytvorte Alias a použite ho tu.",
@ -589,6 +614,8 @@
"sieve_desc": "Krátky popis",
"sieve_type": "Typ filtru",
"skipcrossduplicates": "Preskočiť duplikované správy naprieč priečinkami (akceptuje sa prvý nález)",
"sogo_access": "Udeliť priamy prístup k prihláseniu do služby SOGo",
"sogo_access_info": "Jednotné prihlásenie (SSO) z mail UI zostáva funkčné. Toto nastavenie nemá vplyv na prístup k všetkým ostatným službám, ani neodstraňuje alebo nemení existujúci profil používateľa SOGo.",
"sogo_visible": "Alias je viditeľný v SOGo",
"sogo_visible_info": "Táto voľba ovplyvňuje len objekty, ktoré dokážu byť zobrazené v SOGo (zdieľané alebo nezdieľané alias adresy ukazujúc na minimálne jednu lokálnu mailovú schránku). Ak je skrytý, alias nebude prezentovaný ako voliteľný odosielateľ v SOGo.",
"spam_alias": "Vytvoriť alebo zmeniť časovo limitované alias adresy",
@ -1031,13 +1058,16 @@
"alias_valid_until": "Platné do",
"aliases_also_send_as": "Môže odosielať ako používateľ",
"aliases_send_as_all": "Nekontrolovať prístup odosielateľa pre nasledujúcu doménu/y a jej alias domény",
"allowed_protocols": "Povolené protokoly",
"app_hint": "Heslá aplikácií sú alternatívne heslá pre vaše IMAP, SMTP, CalDAV, CardDAV a EAS prihlásenie. Používateľské meno zostáva nezmenené.<br>SOGo nie je momentálne podporovaný.",
"app_name": "Meno aplikácie",
"app_passwds": "Heslá aplikácií",
"apple_connection_profile": "Apple konfiguračný profil",
"apple_connection_profile_complete": "Tento profil zahŕňa IMAP a SMTP parametre, ako aj CalDAV (kalendáre) a CardDAV (kontakty) pre zariadenia Apple.",
"apple_connection_profile_mailonly": "Tento profil zahŕňa IMAP a SMTP konfiguračné parametre pre zariadenia Apple.",
"apple_connection_profile_with_app_password": "Nové heslo aplikácie sa vygeneruje a pridá do profilu, takže pri nastavovaní zariadenia nie je potrebné zadávať žiadne heslo. Súbor nezdieľajte, pretože poskytuje úplný prístup k vašej poštovej schránke.",
"change_password": "Zmeniť heslo",
"change_password_hint_app_passwords": "Váš účet má %d hesiel aplikácií, ktoré nebudú zmenené. Ak ich chcete spravovať, prejdite na kartu Heslá aplikácií.",
"clear_recent_successful_connections": "Vymazať nedávne úspešné prihlásenia",
"client_configuration": "Zobraziť konfiguračné pokyny pre emailových klientov a smartfóny",
"create_app_passwd": "Vytvoriť heslo aplikácie",
@ -1048,6 +1078,7 @@
"delete_ays": "Potvrďte zmazanie.",
"direct_aliases": "Priame alias adresy",
"direct_aliases_desc": "Priame aliasy sú ovplyvnené spam filtrom a nastavením TLS pravidiel.",
"direct_protocol_access": "Tento používateľ mailovej schránky má <b>priamy, externý prístup</b> k nasledujúcim protokolom a aplikáciám. Toto nastavenie má pod kontrolou Váš správca. Na udelenie prístupu k jednotlivým protokolom a aplikáciám je možné vytvoriť heslá aplikácií.<br>Tlačidlo \" Prihláste sa do webmailu\" poskytuje jednotné prihlásenie do systému SOGo a je vždy k dispozícii.",
"eas_reset": "Resetovať medzipamäť u ActiveSync zariadení",
"eas_reset_help": "Vo väčšine prípadov, reset medzipamäte ActiveSync pomôže opravit nefunkčný profil.<br><b>Pozor:</b> Všetky potrebné dáta budú opäť stiahnuté!",
"eas_reset_now": "Reset ActiveSync",
@ -1141,15 +1172,15 @@
"spamfilter_yellow": "Žltá: Táto správa môže byť spam, bude označená ako spam a presunutá do priečinku nevyžiadanej pošty",
"status": "Status",
"sync_jobs": "Synchronizačné úlohy",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problém s autentifikáciou",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Chybné uživateľské meno alebo heslo",
"syncjob_EXIT_CONNECTION_FAILURE": "Problém so spojením",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nedá sa pripojiť k vzdialenému serveru",
"syncjob_EXIT_OVERQUOTA": "Cieľová schránka je plná",
"syncjob_EXIT_TLS_FAILURE": "Problém so šifrovaným spojením",
"syncjob_EX_OK": "Úspech",
"syncjob_check_log": "Skontrolujte záznam",
"syncjob_last_run_result": "Výsledok posledného spustenia",
"syncjob_EX_OK": "Úspech",
"syncjob_EXIT_CONNECTION_FAILURE": "Problém so spojením",
"syncjob_EXIT_TLS_FAILURE": "Problém so šifrovaným spojením",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problém s autentifikáciou",
"syncjob_EXIT_OVERQUOTA": "Cieľová schránka je plná",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nedá sa pripojiť k vzdialenému serveru",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Chybné uživateľské meno alebo heslo",
"tag_handling": "Zaobchádzanie s označenou poštou",
"tag_help_example": "Príklad tagu e-mailovej adresy: me<b>+Facebook</b>@example.org",
"tag_help_explain": "V podadresári: nový podadresár s menom tag-u bude vytvorený nižšie INBOX (\"INBOX/Facebook\").<br>\r\nIn subject: meno štítka bude pridané pred predmet pošty, napríklad: \"[Facebook] My News\".",
@ -1169,10 +1200,11 @@
"week": "týždeň",
"weekly": "Týždenne",
"weeks": "týždne",
"with_app_password": "s heslom aplikácie",
"year": "rok",
"years": "rokov",
"apple_connection_profile_with_app_password": "Nové heslo aplikácie sa vygeneruje a pridá do profilu, takže pri nastavovaní zariadenia nie je potrebné zadávať žiadne heslo. Súbor nezdieľajte, pretože poskytuje úplný prístup k vašej mail schránke.",
"change_password_hint_app_passwords": "Vaše konto má {{number_of_app_passwords}} hesiel aplikácií, ktoré nebudú zmenené. Ak ich chcete spravovať, prejdite na kartu Heslá aplikácií.",
"change_password_hint_app_passwords": "Vaše konto má %d hesiel aplikácií, ktoré nebudú zmenené. Ak ich chcete spravovať, prejdite na kartu Heslá aplikácií.",
"direct_protocol_access": "Tento používateľ mailovej schránky má <b>priamy, externý prístup</b> k nasledujúcim protokolom a aplikáciám. Toto nastavenie kontroluje administrátor. Na udelenie prístupu k jednotlivým protokolom a aplikáciám je možné vytvoriť heslá aplikácií.<br>Tlačidlo \"Prihlásenie do webmailu\" poskytuje jednotné prihlásenie do systému SOGo a je vždy k dispozícii."
},
"warning": {

View File

@ -335,7 +335,17 @@
"transport_test_rcpt_info": "&#8226; Використовуйте null@hosted.mailcow.de для перевірки пересилання на зовнішній пункт призначення.",
"transports_hint": "&#8226; Глобальні правила маршрутизації <b>переважають</b> над маршрутами на основі відправника.<br>\n&#8226; Переважно використовувати транспорти на основі резолвінгу MX.<br>\n&#8226; Користувацькі політики TLS для вихідної пошти будуть проігноровані та використовуватимуть політику TLS, налаштовану тут.<br>\n&#8226; Протокол для доставки завжди \"smtp:\" і тому намагатиметься використовувати TLS, якщо наступний хост підтримує його. SMTPS (TLS, найчастіше порту 465) не підтримується.<br>\n&#8226; Адреси відповідні \"/localhost$/\" завжди будуть доставлені \"local:\", отже політика \"*\" не поширюється на них.<br>\n&#8226; Щоб визначити облікові дані для наступного вузла \"[host]:25\", Postfix <b>завжди</b> шукає дані для \"host\" перед тим як шукати \"[host]:25\". Така поведінка унеможливлює використання \"host\" and \"[host]:25\" одночасно.",
"ui_header_announcement_help": "Оголошення видно на екрані входу в mailcow UI і всім користувачам, що ввійшли в систему.",
"unchanged_if_empty": "Якщо не змінено, залиште порожнім"
"unchanged_if_empty": "Якщо не змінено, залиште порожнім",
"allowed_methods": "Access-Control-Allow-Methods",
"f2b_max_ban_time": "Максимальний час блокування (с)",
"f2b_ban_time_increment": "Час бану збільшується з кожним баном",
"allowed_origins": "Access-Control-Allow-Origin",
"cors_settings": "Налаштування CORS",
"ip_check": "Перевірка IP",
"ip_check_disabled": "Перевірка IP вимкнена. Ви можете ввімкнути його в меню<br> <strong>Система > Конфігурація > Параметри > Налаштувати</strong>",
"ip_check_opt_in": "Згода на використання сторонніх служб <strong>ipv4.mailcow.email</strong> і <strong>ipv6.mailcow.email</strong> для визначення зовнішніх IP-адрес.",
"options": "Параметри",
"queue_unban": "розблокувати"
},
"danger": {
"alias_domain_invalid": "Неприпустимий псевдонім домену: %s",
@ -454,7 +464,17 @@
"tls_policy_map_dest_invalid": "Неприпустиме значення призначення політики",
"tls_policy_map_parameter_invalid": "Неприпустиме значення параметра політики",
"unlimited_quota_acl": "Необмежена квота заборонена політикою доступу",
"yotp_verification_failed": "Помилка валідації Yubico OTP: %s"
"yotp_verification_failed": "Помилка валідації Yubico OTP: %s",
"cors_invalid_method": "Вказано недійсний Allow-Method",
"webauthn_authenticator_failed": "Обраний автентифікатор не знайдено",
"webauthn_publickey_failed": "Для вибраного автентифікатора не було збережено відкритого ключа",
"webauthn_username_failed": "Обраний автентифікатор належить іншому акаунту",
"cors_invalid_origin": "Вказано недійсний Allow-Origin",
"demo_mode_enabled": "Демонстраційний режим увімкнено",
"extended_sender_acl_denied": "відсутній ACL для встановлення зовнішніх адрес відправників",
"template_exists": "Шаблон %s вже існує",
"template_id_invalid": "Ідентифікатор шаблону %s недійсний",
"template_name_invalid": "Ім'я шаблону невірне"
},
"debug": {
"chart_this_server": "Діаграма (цей сервер)",
@ -481,7 +501,21 @@
"username": "Ім'я користувача",
"external_logs": "Зовнішні журнали",
"jvm_memory_solr": "Використання оперативної пам'яті JVM",
"log_info": "<p><b>Журнали контейнерів</b> mailcow зберігаються в Redis, і раз на хвилину рядки журналу за межами <code>LOG_LINES (%d)</code> видаляються, щоб зменшити навантаження на сервер.\n <br>Самі журнали контейнерів не зберігаються після перезавантаження контейнера. Усі контейнери додатково пишуть логи у службу Docker, і, отже, використовують драйвер логування за промовчанням. Журнали контейнерів призначені лише для налагодження дрібних проблем. Для інших завдань, будь ласка, настройте драйвер логування Docker самостійно.</p>\n <p><b>Зовнішні журнали</b> збираються через API програм.</p>\n <p><b>Статичні журнали</b> &ndash; це в основному журнали активності, які не записуються в Dockerd, але все одно повинні бути постійними (за винятком журналів API).</p>"
"log_info": "<p><b>Журнали контейнерів</b> mailcow зберігаються в Redis, і раз на хвилину рядки журналу за межами <code>LOG_LINES (%d)</code> видаляються, щоб зменшити навантаження на сервер.\n <br>Самі журнали контейнерів не зберігаються після перезавантаження контейнера. Усі контейнери додатково пишуть логи у службу Docker, і, отже, використовують драйвер логування за промовчанням. Журнали контейнерів призначені лише для налагодження дрібних проблем. Для інших завдань, будь ласка, настройте драйвер логування Docker самостійно.</p>\n <p><b>Зовнішні журнали</b> збираються через API програм.</p>\n <p><b>Статичні журнали</b> &ndash; це в основному журнали активності, які не записуються в Dockerd, але все одно повинні бути постійними (за винятком журналів API).</p>",
"error_show_ip": "Не вдалося розпізнати публічні IP-адреси",
"no_update_available": "Система працює на останній версії",
"architecture": "Архітектура",
"container_running": "Працює",
"container_disabled": "Контейнер зупинено або вимкнено",
"container_stopped": "Зупинено",
"cores": "Ядра",
"current_time": "Системний час",
"memory": "Пам'ять",
"show_ip": "Показати загальнодоступну IP-адресу",
"timezone": "Часовий пояс",
"update_available": "Доступне оновлення",
"update_failed": "Не вдалося перевірити наявність оновлень",
"wip": "Наразі робота триває"
},
"diagnostics": {
"cname_from_a": "Значення, отримане із запису A/AAAA. Це підтримується, поки запис вказує на правильний ресурс.",
@ -607,7 +641,8 @@
"sender_acl_info": "Врахуйте, що якщо користувачеві поштового облікового запису А дозволено відправляти від імені користувача Б, то адреса користувача Б не з'явиться автоматично у списку \"Відправник\" при написанні листів у SOGo.<br>\n Користувач поштового облікового запису Б повинен створити делегування в SOGo, щоб користувач поштового облікового запису А міг вибрати його адресу як відправника. Делегування знаходиться в меню (три крапки) праворуч від імені поштового облікового запису у вікні пошти SOGo. Ця поведінка не відноситься до псевдонімів.",
"sogo_visible_info": "Впливає лише на об'єкти, які можуть відображатися в SOGo (персональні або загальні псевдоніми, що вказують щонайменше на один локальний поштовий обліковий запис). Зверніть увагу, що якщо функцію вимкнено, користувач не зможе вибрати адресу псевдоніма як відправника в SOGo.",
"target_address": "Власники псевдоніма, <small>(розділені комами)</small>",
"timeout2": "Тайм-аут для підключення до локального хоста"
"timeout2": "Тайм-аут для підключення до локального хоста",
"pushover_sound": "Звук"
},
"fido2": {
"confirm": "Підтвердити",
@ -648,7 +683,8 @@
"restart_netfilter": "Перезапустити netfilter",
"restart_sogo": "Перезапустити SOGo",
"user_settings": "Налаштування користувача",
"mailcow_config": "Конфігурація"
"mailcow_config": "Конфігурація",
"mailcow_system": "Система"
},
"info": {
"no_action": "Дій не передбачено",
@ -831,7 +867,13 @@
"target_address": "Власники псевдоніму",
"tls_map_dest_info": "Приклади: example.org, .example.org, [mail.example.org]:25",
"tls_map_parameters_info": "Залиште поле порожнім або вкажіть параметри, наприклад: protocols=!SSLv2 ciphers=medium exclude=3DES",
"tls_policy_maps_enforced_tls": "Для вихідних повідомлень від користувачів із включеною примусовою політикою шифрування вихідних з'єднань не описані глобальною політикою, будуть застосовані значення за замовчуванням, зазначені в <code>smtp_tls_mandatory_protocols</code> та <code>smtp_tls_mandatory_ciphers</code>."
"tls_policy_maps_enforced_tls": "Для вихідних повідомлень від користувачів із включеною примусовою політикою шифрування вихідних з'єднань не описані глобальною політикою, будуть застосовані значення за замовчуванням, зазначені в <code>smtp_tls_mandatory_protocols</code> та <code>smtp_tls_mandatory_ciphers</code>.",
"add_template": "Додати шаблон",
"domain_templates": "Шаблони доменів",
"relay_unknown": "Ретрансляція невідомих поштових скриньок",
"mailbox_templates": "Шаблони поштових скриньок",
"templates": "Шаблони",
"template": "Шаблон"
},
"oauth2": {
"authorize_app": "Авторизація додатка",
@ -896,7 +938,20 @@
"table_size_show_n": "Відображати %s полів"
},
"queue": {
"queue_manager": "Черга на відправлення"
"queue_manager": "Черга на відправлення",
"delete": "Видалити все",
"info": "Поштова черга містить усі електронні листи, які очікують на доставку. Якщо електронний лист застряг у черзі на тривалий час, він автоматично видаляється системою.<br>Повідомлення про помилку відповідного листа містить інформацію про те, чому лист не може бути доставлено.",
"unhold_mail": "Зняти утримування",
"unhold_mail_legend": "Звільняє вибрані листи для доставки. (Потрібне попереднє утримання)",
"flush": "Очистити чергу",
"legend": "Функції дій з поштовими чергами:",
"ays": "Підтвердьте, що ви хочете видалити всі елементи з поточної черги.",
"deliver_mail": "Доставити",
"deliver_mail_legend": "проби повторної доставки вибраних листів.",
"hold_mail": "Утримати",
"hold_mail_legend": "Утримує вибрані листи. (Запобігає подальшим спробам доставки)",
"show_message": "Показати повідомлення",
"unban": "розблокувати чергу"
},
"ratelimit": {
"disabled": "Вимкнено",
@ -988,7 +1043,12 @@
"settings_map_added": "Правило додано",
"tls_policy_map_entry_deleted": "Політику TLS ID %s видалено",
"verified_totp_login": "Авторизацію TOTP пройдено",
"domain_add_dkim_available": "Ключ DKIM вже існує"
"domain_add_dkim_available": "Ключ DKIM вже існує",
"template_added": "Додано шаблон %s",
"template_modified": "Зміни до шаблону %s збережено",
"cors_headers_edited": "Налаштування CORS збережено",
"ip_check_opt_in_modified": "Перевірка IP-адреси успішно збережено",
"template_removed": "Шаблону із ID %s видалено"
},
"tfa": {
"confirm": "Підтвердьте",
@ -1037,7 +1097,7 @@
"apple_connection_profile_complete": "Цей профіль включає налаштування IMAP та SMTP, а також CalDAV (календарів) та CardDAV (контактів) для пристрою Apple.",
"apple_connection_profile_mailonly": "Цей профіль включає лише налаштування IMAP та SMTP для пристрою Apple.",
"change_password": "Змінити пароль",
"change_password_hint_app_passwords": "Ваш обліковий запис містить {{number_of_app_passwords}} паролів додатків, які не змінюватимуться. Щоб керувати ними, перейдіть на вкладку \"Паролі додатків\".",
"change_password_hint_app_passwords": "Ваш обліковий запис містить %d паролів додатків, які не змінюватимуться. Щоб керувати ними, перейдіть на вкладку \"Паролі додатків\".",
"clear_recent_successful_connections": "Очистити історію успішних підключень",
"create_app_passwd": "Створити новий пароль",
"create_syncjob": "Створити нове завдання синхронізації",
@ -1176,7 +1236,8 @@
"tag_help_explain": "Перемістити до підпапки: буде створено нову підпапку в INBOX з ім'ям тега, наприклад: \"INBOX/Facebook\".<br>\n Додати до теми листа: ім'я тега буде додано до теми листа, наприклад: \"[Facebook] My News\".",
"tls_policy_warning": "<strong>Попередження:</strong> якщо ви увімкнете примусове шифрування пошти, ви можете зіткнутися з втратою листів.<br>Повідомлення, які не відповідають політиці, будуть відкидатися з повідомленням поштовим сервером про серйозний збій.<br>Цей параметр застосовується до вашої основної адреси електронної пошти (логіну), усім особистим псевдонімам та псевдонімам доменів. Маються на увазі лише псевдоніми <b>з однією поштовою скринькою</b>, як одержувач.",
"year": "рік",
"years": "років"
"years": "років",
"pushover_sound": "Звук"
},
"warning": {
"domain_added_sogo_failed": "Домен був доданий, але перезавантажити SOGo не вдалося, будь ласка, перевірте журнали сервера.",
@ -1190,5 +1251,31 @@
"hash_not_found": "Хеш не знайдено або вже видалено",
"ip_invalid": "Пропущено недійсний IP: %s",
"is_not_primary_alias": "Пропущено неосновний псевдонім %s"
},
"datatables": {
"decimal": ".",
"infoPostFix": "",
"zeroRecords": "Відповідних записів не знайдено",
"aria": {
"sortAscending": ": активувати для сортування стовпців за зростанням",
"sortDescending": ": активувати для сортування стовпців за спаданням"
},
"emptyTable": "У таблиці немає даних",
"expand_all": "Розгорнути всі",
"info": "Показано від _START_ до _END_ of _TOTAL_ записів",
"infoEmpty": "Показано від 0 до 0 із 0 записів",
"infoFiltered": "(відфільтровано з _MAX_ всіх записів)",
"thousands": ",",
"lengthMenu": "Показати записи _MENU_",
"loadingRecords": "Завантаження...",
"processing": "Будь ласка, зачекайте...",
"search": "Пошук:",
"paginate": {
"first": "Перший",
"last": "Останній",
"next": "Наступний",
"previous": "Попередній"
},
"collapse_all": "Згорнути все"
}
}

View File

@ -1042,7 +1042,7 @@
"apple_connection_profile_mailonly": "此连接描述文件包括提供给 Apple 设备的 IMAP 和 SMTP 配置参数。",
"apple_connection_profile_with_app_password": "一个新的应用程序密码将会被生成并添加到该配置文件中,因此在设备设置时不需要输入密码。请不要随意分享该文件,因为它包含你的邮箱的完全访问权限。",
"change_password": "更改密码",
"change_password_hint_app_passwords": "你的账户有 {{number_of_app_passwords}} 个应用密码,这些密码将不会被更改。如果需要管理这些密码,请访问应用密码标签。",
"change_password_hint_app_passwords": "你的账户有 %d 个应用密码,这些密码将不会被更改。如果需要管理这些密码,请访问应用密码标签。",
"clear_recent_successful_connections": "清除成功匹配的连接",
"client_configuration": "显示邮箱客户端和智能手机的配置指南",
"create_app_passwd": "添加应用密码",

View File

@ -1036,7 +1036,7 @@
"apple_connection_profile_mailonly": "此連接描述檔案包括提供給 Apple 裝置的 IMAP 和 SMTP 組態參數。",
"apple_connection_profile_with_app_password": "應用程式密碼已產生並加入到連接描述檔案中,因此裝置在設定時不需要輸入密碼。請勿分享這個檔案,因為它擁有存取信箱的所有權限。",
"change_password": "更改密碼",
"change_password_hint_app_passwords": "你的帳號有 {{number_of_app_passwords}} 個應用程式密碼不會被更動。要管理這些密碼,請至應用程式密碼分頁。",
"change_password_hint_app_passwords": "你的帳號有 %d 個應用程式密碼不會被更動。要管理這些密碼,請至應用程式密碼分頁。",
"clear_recent_successful_connections": "中斷成功的連線",
"client_configuration": "顯示電子信箱程式和智慧型手機的設定指南",
"create_app_passwd": "新增應用程式密碼",

View File

@ -0,0 +1,9 @@
<div class="thumbnail mb-4">
<img class="img-thumbnail mb-4{% if dark %} bg-black{% endif %}" src="{{ logo }}" alt="mailcow logo">
<div class="caption">
<span class="badge fs-5 bg-info">{{ logo_specs.geometry.width }}x{{ logo_specs.geometry.height }} px</span>
<span class="badge fs-5 bg-info">{{ logo_specs.mimetype }}</span>
<span class="badge fs-5 bg-info">{{ logo_specs.fileSize }}</span>
</div>
</div>

View File

@ -122,8 +122,8 @@
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-9">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-item="cors" data-api-url="edit/cors" data-id="editcors" data-action="edit_selected" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<div class="offset-sm-2 col-sm-9 d-grid d-sm-block">
<button class="btn btn-sm btn-xs-lg btn-success" data-item="cors" data-api-url="edit/cors" data-id="editcors" data-action="edit_selected" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div>
</div>
</form>
@ -146,7 +146,7 @@
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<label>
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" {% if api.ro.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
<input type="checkbox" class="form-check-input" name="skip_ip_check" id="skip_ip_check_ro" {% if api.ro.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
</label>
</div>
</div>
@ -159,15 +159,15 @@
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<label>
<input type="checkbox" name="active" {% if api.ro.active %}checked{% endif %}> {{ lang.admin.activate_api }}
<input type="checkbox" class="form-check-input" name="active" {% if api.ro.active %}checked{% endif %}> {{ lang.admin.activate_api }}
</label>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success" name="admin_api[ro]" type="submit" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#" {% if not api.ro.api_key %}disabled{% endif %}>{{ lang.admin.regen_api_key }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half d-block d-sm-inline btn-success" name="admin_api[ro]" type="submit" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half d-block d-sm-inline btn-secondary admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#" {% if not api.ro.api_key %}disabled{% endif %}>{{ lang.admin.regen_api_key }}</button>
</div>
</div>
</div>
@ -191,7 +191,7 @@
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<label>
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_rw" {% if api.rw.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
<input type="checkbox" class="form-check-input" name="skip_ip_check" id="skip_ip_check_rw" {% if api.rw.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
</label>
</div>
</div>
@ -204,7 +204,7 @@
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<label>
<input type="checkbox" name="active" {% if api.rw.active %}checked{% endif %}> {{ lang.admin.activate_api }}
<input type="checkbox" class="form-check-input" name="active" {% if api.rw.active %}checked{% endif %}> {{ lang.admin.activate_api }}
</label>
</div>
</div>

View File

@ -10,22 +10,26 @@
<legend><i class="bi bi-file-image"></i> {{ lang.admin.change_logo }}</legend><hr />
<p class="text-muted">{{ lang.admin.logo_info }}</p>
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
<p>
<input class="mb-4" type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml"><br>
<button name="submit_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary"><i class="bi bi-upload"></i> {{ lang.admin.upload }}</button>
</p>
<div class="mb-4">
<label for="main_logo_input" class="form-label">{{ lang.admin.logo_normal_label }}</label>
<input class="form-control" id="main_logo_input" type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
</div>
<div class="mb-4">
<label for="main_logo_dark_input" class="form-label">{{ lang.admin.logo_dark_label }}</label>
<input class="form-control" id="main_logo_dark_input" type="file" name="main_logo_dark" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
</div>
<button name="submit_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary"><i class="bi bi-upload"></i> {{ lang.admin.upload }}</button>
</form>
{% if logo %}
<div class="row">
{% if logo or logo_dark %}
<div class="row mt-4">
<div class="col-sm-4">
<div class="thumbnail">
<img class="img-thumbnail" src="{{ logo }}" alt="mailcow logo">
<div class="caption">
<span class="badge fs-5 bg-info">{{ logo_specs.geometry.width }}x{{ logo_specs.geometry.height }} px</span>
<span class="badge fs-5 bg-info">{{ logo_specs.mimetype }}</span>
<span class="badge fs-5 bg-info">{{ logo_specs.fileSize }}</span>
</div>
</div>
{% if logo %}
{% include 'admin/customize/logo.twig' %}
{% endif %}
{% if logo_dark %}
{% include 'admin/customize/logo.twig' with {'logo': logo_dark, 'logo_specs': logo_dark_specs, 'dark': 1} %}
{% endif %}
<hr>
<form class="form-inline" role="form" method="post">
<p><button name="reset_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary">{{ lang.admin.reset_default }}</button></p>
@ -111,7 +115,7 @@
</div>
</div>
<p><textarea class="form-control" id="ui_announcement_text" name="ui_announcement_text" rows="7">{{ ui_texts.ui_announcement_text }}</textarea></p>
<div class="checkbox">
<div class="form-check">
<label>
<input type="checkbox" name="ui_announcement_active" class="form-check-input" {% if ui_texts.ui_announcement_active == 1 %}checked{% endif %}> {{ lang.admin.ui_header_announcement_active }}
</label>

View File

@ -20,7 +20,7 @@
{% for domain, domain_data in dkim_domains %}
{% if domain_data.dkim %}
<div class="row collapse show dkim_key_valid">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ domain }}"></div>
<div class="col-md-1"><input type="checkbox" class="form-check-input" data-id="dkim" name="multi_select" value="{{ domain }}"></div>
<div class="col-md-3">
<p>{{ lang.admin.domain }}: <strong>{{ domain }}</strong>
<p class="dkim-label"><span class="badge fs-6 bg-success">{{ lang.admin.dkim_key_valid }}</span></p>
@ -31,7 +31,7 @@
<div class="col-md-8">
<textarea class="form-control" rows="6" readonly>{{ domain_data.dkim.dkim_txt }}</textarea>
<small>
<i class="bi bi-arrow-return-right"></i>
<i class="bi bi-arrow-return-right"></i>
<a href="#" data-bs-toggle="modal" data-bs-target="#showDKIMprivKey" id="dkim_priv" data-priv-key="{{ domain_data.dkim.privkey }}"> {{ lang.admin.dkim_private_key }}</a>
</small>
</div>
@ -50,7 +50,7 @@
{% for alias_domain, alias_domain_data in domain_data.alias_domains %}
{% if alias_domain_data.dkim %}
<div class="row collapse in dkim_key_valid">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ alias_domain }}"></div>
<div class="col-md-1"><input type="checkbox" class="form-check-input" data-id="dkim" name="multi_select" value="{{ alias_domain }}"></div>
<div class="col-md-2 offset-md-1">
<p><small>↳ Alias-Domain: <strong>{{ alias_domain }}</strong></small>
<p class="dkim-label"><span class="badge fs-6 bg-success">{{ lang.admin.dkim_key_valid }}</span></p>
@ -78,7 +78,7 @@
{% endfor %}
{% for blind, data in dkim_blind_domains|filter(data => data.dkim is not null) %}
<div class="row collapse in dkim_key_unused">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ blind }}"></div>
<div class="col-md-1"><input type="checkbox" class="form-check-input" data-id="dkim" name="multi_select" value="{{ blind }}"></div>
<div class="col-md-3">
<p>{{ lang.admin.domain }}: <strong>{{ blind }}</strong>
<p class="dkim-label"><span class="badge fs-6 bg-warning">{{ lang.admin.dkim_key_unused }}</span></p>
@ -114,7 +114,7 @@
</div>
<div class="row mb-4">
<div class="col-12 col-md-6 col-lg-4 col-xl-3">
<select data-style="btn btn-secondary btn-sm" class="form-control" id="key_size" name="key_size" title="{{ lang.admin.dkim_key_length }}" required>
<select data-style="btn btn-light btn-sm" class="form-control" id="key_size" name="key_size" title="{{ lang.admin.dkim_key_length }}" required>
<option data-subtext="bits">1024</option>
<option data-subtext="bits">2048</option>
</select>
@ -143,7 +143,7 @@
</div>
<div class="mb-2">
<label>
<input type="checkbox" name="overwrite_existing" value="1"> {{ lang.admin.dkim_overwrite_key }}
<input type="checkbox" class="form-check-input" name="overwrite_existing" value="1"> {{ lang.admin.dkim_overwrite_key }}
</label>
</div>
<button class="btn btn-sm d-block d-sm-inline btn-secondary" data-action="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.import }}</button>
@ -159,7 +159,7 @@
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end" for="from_domain">{{ lang.admin.dkim_from }}:</label>
<div class="col-sm-10 col-md-6 col-lg-4 col-xl-3">
<select data-style="btn btn-secondary btn-sm"
<select data-style="btn btn-light btn-sm"
data-live-search="true"
data-id="dkim_duplicate"
title="{{ lang.admin.dkim_from_title }}"
@ -175,7 +175,7 @@
<div class="col-sm-10 col-md-6 col-lg-4 col-xl-3">
<select
data-live-search="true"
data-style="btn btn-secondary btn-sm"
data-style="btn btn-light btn-sm"
data-id="dkim_duplicate"
title="{{ lang.admin.dkim_to_title }}"
name="to_domain" id="to_domain" class="full-width-select form-control" multiple required>

View File

@ -92,28 +92,29 @@
{% endif %}
{% for active_ban in f2b_data.active_bans %}
<p>
<span class="badge fs-5 bg-info py-0">
<span class="badge fs-7 bg-info d-block d-sm-inline-block">
<i class="bi bi-funnel-fill"></i>
<a href="https://bgp.he.net/ip/{{ active_ban.ip }}" target="_blank" style="color:white">
<a href="https://bgp.he.net/ip/{{ active_ban.ip }}" target="_blank">
{{ active_ban.network }}
</a>
({{ active_ban.banned_until }}) -
({{ active_ban.banned_until }})
</span>
<span class="d-none d-sm-inline"> - </span>
{% if active_ban.queued_for_unban == 0 %}
<a class="btn btn-lg btn-link p-0 text-info" data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[{{ lang.admin.queue_unban }}]</a>
<a class="btn btn-lg btn-link p-0 text-info" data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a>
<a class="btn btn-lg btn-link p-0 text-info" data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist (<b>needs restart</b>)]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[{{ lang.admin.queue_unban }}]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist (<b>needs restart</b>)]</a>
{% else %}
<i>{{ lang.admin.unban_pending }}</i>
{% endif %}
</span>
</p>
{% endfor %}
<hr>
{% for perm_ban in f2b_data.perm_bans %}
<p>
<span class="badge fs-5 bg-danger" style="padding: 0.1em 0.4em 0.1em;">
<span class="badge fs-7 bg-danger d-block d-sm-inline-block">
<i class="bi bi-funnel-fill"></i>
<a href="https://bgp.he.net/ip/{{ perm_ban.ip }}" target="_blank" style="color:white">
<a href="https://bgp.he.net/ip/{{ perm_ban.ip }}" target="_blank">
{{ perm_ban.network }}
</a>
</span>

View File

@ -9,7 +9,7 @@
<div id="collapse-tab-config-fwdhosts" class="card-body collapse" data-bs-parent="#admin-content">
<p style="margin-bottom:40px">{{ lang.admin.forwarding_hosts_hint }}</p>
<table id="forwardinghoststable" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-admin">
<div class="mass-actions-admin mb-4">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary">{{ lang.mailbox.toggle_all }}</button>
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>

View File

@ -21,7 +21,7 @@
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<label>
<input type="checkbox" name="{{ name }}" id="{{ name }}" value="1" {% if value == 1 %}checked{% endif %}> {{ lang.admin['password_policy_'~name] }}
<input type="checkbox" class="form-check-input" name="{{ name }}" id="{{ name }}" value="1" {% if value == 1 %}checked{% endif %}> {{ lang.admin['password_policy_'~name] }}
</label>
</div>
</div>

View File

@ -44,7 +44,7 @@
<p class="text-muted">{{ lang.admin.rsetting_no_selection }}</p>
</div>
{% for rsetting in rsettings %}
<div id="settings_tab{{ rsetting.details.id }}" class="tab-pane">
<div id="settings_tab{{ rsetting.details.id }}" class="tab-pane rsettings">
<form class="form" data-id="rsettings" role="form" method="post">
<input type="hidden" name="active" value="0">
<div>
@ -57,11 +57,13 @@
</div>
<div class="mt-4 mb-2">
<label>
<input type="checkbox" name="active" value="1" {% if rsetting.details.active %}checked{% endif %}> {{ lang.admin.active }}
<input type="checkbox" class="form-check-input" name="active" value="1" {% if rsetting.details.active %}checked{% endif %}> {{ lang.admin.active }}
</label>
</div>
<button class="btn btn-sm btn-success" data-action="edit_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url='edit/rsetting' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-danger" data-action="delete_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url="delete/rsetting" data-api-attr='{}' href="#">{{ lang.admin.remove }}</button>
<div class="btn-group">
<button class="btn btn-sm btn-xs-lg btn-success" data-action="edit_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url='edit/rsetting' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-lg btn-danger" data-action="delete_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url="delete/rsetting" data-api-attr='{}' href="#">{{ lang.admin.remove }}</button>
</div>
</form>
</div>
{% endfor %}

View File

@ -12,7 +12,7 @@
<div class="row">
<div class="offset-sm-2 col-sm-10">
<label>
<input type="checkbox" id="show_rspamd_global_filters"> {{ lang.admin.rspamd_global_filters_agree }}
<input type="checkbox" class="form-check-input" id="show_rspamd_global_filters"> {{ lang.admin.rspamd_global_filters_agree }}
</label>
</div>
</div>

View File

@ -55,7 +55,7 @@
<div id="collapse-tab-maps" class="card-body collapse" data-bs-parent="#admin-content">
<p style="margin-bottom:40px">{{ lang.admin.transports_hint|raw }}</p>
<table id="transportstable" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-admin">
<div class="mass-actions-admin mb-4">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="transports" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary">{{ lang.mailbox.toggle_all }}</button>
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -90,12 +90,12 @@
</div>
<div class="mb-2">
<label>
<input type="checkbox" name="is_mx_based" value="1"> {{ lang.admin.lookup_mx|raw }}
<input type="checkbox" class="form-check-input" name="is_mx_based" value="1"> {{ lang.admin.lookup_mx|raw }}
</label>
</div>
<div class="mb-4">
<label>
<input type="checkbox" name="active" value="1"> {{ lang.admin.active }}
<input type="checkbox" class="form-check-input" name="active" value="1"> {{ lang.admin.active }}
</label>
</div>
<p class="text-muted">{{ lang.admin.credentials_transport_warning|raw }}</p>

View File

@ -60,7 +60,7 @@
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<label>
<input type="checkbox" id="mass_disarm"> {{ lang.admin.activate_send }}
<input type="checkbox" class="form-check-input" id="mass_disarm"> {{ lang.admin.activate_send }}
</label>
</div>
</div>

View File

@ -31,7 +31,10 @@
{% block navbar %}
<nav class="navbar navbar-expand-lg navbar-light bg-light navbar-fixed-top p-0">
<div class="container-fluid">
<a class="navbar-brand" href="/"><img alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}"></a>
<a class="navbar-brand" href="/">
<img class="main-logo" alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}">
<img class="main-logo-dark" alt="mailcow-logo-dark" src="{{ logo_dark|default('/img/cow_mailcow.svg') }}">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-list fs-3"></i>
</button>

View File

@ -37,7 +37,8 @@
<div class="card-body">
<div class="row">
<div class="col-sm-12 col-md-4 d-flex flex-column">
<img class="img-responsive my-auto m-auto" alt="mailcow-logo" style="max-width: 85%; max-height: 85%;" src="{{ logo|default('/img/cow_mailcow.svg') }}">
<img class="main-logo img-responsive my-auto m-auto" alt="mailcow-logo" style="max-width: 85%; max-height: 85%;" src="{{ logo|default('/img/cow_mailcow.svg') }}">
<img class="main-logo-dark img-responsive my-auto m-auto" alt="mailcow-logo-dark" style="max-width: 85%; max-height: 85%;" src="{{ logo_dark|default('/img/cow_mailcow.svg') }}">
</div>
<div class="col-sm-12 col-md-8">
<div class="table-responsive" style="margin-top: 10px;">

View File

@ -27,15 +27,15 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
</div>
</div>
</div>

View File

@ -19,19 +19,19 @@
<label class="control-label col-sm-2" for="goto">{{ lang.edit.target_address|raw }}</label>
<div class="col-sm-10">
<textarea id="textarea_alias_goto" class="form-control mb-4" autocapitalize="none" autocorrect="off" rows="10" id="goto" name="goto" required>{{ goto|replace({',': ', '}) }}</textarea>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null"{% if result.goto == 'null@localhost' %} checked{% endif %}> {{ lang.add.goto_null }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_null"{% if result.goto == 'null@localhost' %} checked{% endif %}> {{ lang.add.goto_null }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam"{% if result.goto == 'spam@localhost' %} checked{% endif %}> {{ lang.add.goto_spam|raw }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_spam"{% if result.goto == 'spam@localhost' %} checked{% endif %}> {{ lang.add.goto_spam|raw }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham"{% if result.goto == 'ham@localhost' %} checked{% endif %}> {{ lang.add.goto_ham|raw }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_ham"{% if result.goto == 'ham@localhost' %} checked{% endif %}> {{ lang.add.goto_ham|raw }}</label>
</div>
{% if not skip_sogo %}
<hr>
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_visible"{% if result.sogo_visible == '1' %} checked{% endif %}> {{ lang.edit.sogo_visible }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible"{% if result.sogo_visible == '1' %} checked{% endif %}> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="text-muted">{{ lang.edit.sogo_visible_info }}</p>
{% endif %}
@ -53,8 +53,8 @@
<hr>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.edit_alias_domain }}</h4>
<h4 class="mb-4">{{ lang.edit.edit_alias_domain }}</h4>
<form class="form-horizontal" data-id="editaliasdomain" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="row mb-2">
@ -17,8 +17,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
@ -31,17 +31,19 @@
<hr>
<form data-id="domratelimit" class="form-inline well" method="post">
<label class="control-label mb-2">{{ lang.acl.ratelimit }}</label>
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
<div class="input-group mb-4">
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</select>
</div>
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="domratelimit" data-item="{{ alias_domain }}" data-api-url='edit/rl-domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</form>
{% if dkim %}
<hr>
<div class="row">
<div class="col-12 col-sm-2">
<p>Domain: <strong>{{ result.alias_domain }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
<p>{{ lang.add.domain }}: <strong>{{ result.alias_domain }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
</div>
<div class="col-12 col-sm-10">
<pre class="p-2">{{ dkim.dkim_txt }}</pre>

View File

@ -26,8 +26,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -24,8 +24,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -64,16 +64,16 @@
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="gal"{% if template.attributes.gal == '1' %} checked{% endif %}> {{ lang.edit.gal }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="gal"{% if template.attributes.gal == '1' %} checked{% endif %}> {{ lang.edit.gal }}</label>
<small class="text-muted">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if template.attributes.active == '1' %} checked{% endif %}{% if mailcow_cc_role != 'admin' %} disabled{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if template.attributes.active == '1' %} checked{% endif %}{% if mailcow_cc_role != 'admin' %} disabled{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
@ -81,13 +81,12 @@
<div class="row">
<label class="control-label col-sm-2">{{ lang.edit.ratelimit }}</label>
<div class="col-sm-10">
<input name="rl_value" type="number" value="{{ template.attributes.rl_value }}" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
<option value="s"{% if template.attributes.rl_frame == 's' %} selected{% endif %}>{{ lang.ratelimit.second }}</option>
<option value="m"{% if template.attributes.rl_frame == 'm' %} selected{% endif %}>{{ lang.ratelimit.minute }}</option>
<option value="h"{% if template.attributes.rl_frame == 'h' %} selected{% endif %}>{{ lang.ratelimit.hour }}</option>
<option value="d"{% if template.attributes.rl_frame == 'd' %} selected{% endif %}>{{ lang.ratelimit.day }}</option>
</select>
<div class="input-group">
<input name="rl_value" type="number" value="{{ template.attributes.rl_value }}" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
</div>
{% endif %}
@ -101,7 +100,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2" for="key_size">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-secondary btn-sm" class="form-control" id="key_size" name="key_size">
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
<option value="1024" data-subtext="bits" {% if template.attributes.key_size == 1024 %} selected{% endif %}>1024</option>
<option value="2048" data-subtext="bits" {% if template.attributes.key_size == 2048 %} selected{% endif %}>2048</option>
</select>
@ -111,12 +110,12 @@
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.edit.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"{% if template.attributes.backupmx == '1' %} checked{% endif %}> {{ lang.edit.relay_domain }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="backupmx"{% if template.attributes.backupmx == '1' %} checked{% endif %}> {{ lang.edit.relay_domain }}</label>
<br>
<label><input type="checkbox" value="1" name="relay_all_recipients"{% if template.attributes.relay_all_recipients == '1' %} checked{% endif %}> {{ lang.edit.relay_all }}</label>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_all_recipients"{% if template.attributes.relay_all_recipients == '1' %} checked{% endif %}> {{ lang.edit.relay_all }}</label>
<p>{{ lang.edit.relay_all_info|raw }}</p>
<label><input type="checkbox" value="1" name="relay_unknown_only"{% if template.attributes.relay_unknown_only == '1' %} checked{% endif %}> {{ lang.edit.relay_unknown_only }}</label>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_unknown_only"{% if template.attributes.relay_unknown_only == '1' %} checked{% endif %}> {{ lang.edit.relay_unknown_only }}</label>
<br>
<p>{{ lang.edit.relay_transport_info|raw }}</p>
</div>

View File

@ -2,233 +2,315 @@
{% block inner_content %}
{% if result %}
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#dedit">{{ lang.edit.domain }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dratelimit">{{ lang.edit.ratelimit }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dspamfilter">{{ lang.edit.spam_filter }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dqwbcc">{{ lang.edit.quota_warning_bcc }}</button></li>
</ul>
<hr>
<div class="tab-content">
<div id="dedit" class="tab-pane fade show active" role="tabpanel" aria-labelledby="domain-edit">
<form data-id="editdomain" class="form-horizontal" role="form" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="backupmx">
<input type="hidden" value="0" name="gal">
<input type="hidden" value="0" name="relay_all_recipients">
<input type="hidden" value="0" name="relay_unknown_only">
<div class="row mb-2" data-acl="{{ acl.domain_desc }}">
<label class="control-label col-sm-2" for="description">{{ lang.edit.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="{{ result.description }}">
<div id="domain-content" class="responsive-tabs">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#dedit">{{ lang.edit.domain }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dratelimit">{{ lang.edit.ratelimit }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dspamfilter">{{ lang.edit.spam_filter }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dqwbcc">{{ lang.edit.quota_warning_bcc }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dfooter">{{ lang.edit.domain_footer }}</button></li>
</ul>
<hr class="d-none d-md-block">
<div class="tab-content">
<div id="dedit" class="tab-pane fade show active" role="tabpanel" aria-labelledby="domain-edit">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-dedit" data-bs-toggle="collapse" aria-controls="collapse-tab-dedit">
{{ lang.edit.domain }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-dedit" class="card-body collapse show" data-bs-parent="#domain-content">
<form data-id="editdomain" class="form-horizontal" role="form" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="backupmx">
<input type="hidden" value="0" name="gal">
<input type="hidden" value="0" name="relay_all_recipients">
<input type="hidden" value="0" name="relay_unknown_only">
<div class="row mb-2" data-acl="{{ acl.domain_desc }}">
<label class="control-label col-sm-2" for="description">{{ lang.edit.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="{{ result.description }}">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
<div class="col-sm-10">
<div class="form-control tag-box">
{% for tag in domain_details.tags %}
<span data-action='delete_selected' data-item="{{ tag|url_encode }}" data-id="domain_tag_{{ tag }}" data-api-url='delete/domain/tag/{{ domain }}' class="badge bg-primary tag-badge btn-badge">
<i class="bi bi-tag-fill"></i>
{{ tag }}
</span>
{% endfor %}
<input type="text" class="tag-input">
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
<input type="hidden" value="" name="tags" class="tag-values" />
</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.domain_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
</div>
</div>
{% if mailcow_cc_role == 'admin' %}
<div class="row mb-2">
<label class="control-label col-sm-2" for="aliases">{{ lang.edit.max_aliases }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="{{ result.max_num_aliases_for_domain }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="mailboxes">{{ lang.edit.max_mailboxes }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="{{ result.max_num_mboxes_for_domain }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="defquota">{{ lang.edit.mailbox_quota_def }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="defquota" value="{{ (result.def_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="maxquota">{{ lang.edit.max_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="{{ (result.max_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.domain_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="{{ (result.max_quota_for_domain / 1048576) }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.edit.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="backupmx"{% if result.backupmx == '1' %} checked{% endif %}> {{ lang.edit.relay_domain }}</label>
<br>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_all_recipients"{% if result.relay_all_recipients == '1' %} checked{% endif %}> {{ lang.edit.relay_all }}</label>
<p>{{ lang.edit.relay_all_info|raw }}</p>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_unknown_only"{% if result.relay_unknown_only == '1' %} checked{% endif %}> {{ lang.edit.relay_unknown_only }}</label>
<br>
<p>{{ lang.edit.relay_transport_info|raw }}</p>
<hr style="margin:25px 0px 0px 0px">
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="gal"{% if result.gal == '1' %} checked{% endif %}> {{ lang.edit.gal }}</label>
<small class="text-muted">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
</div>
<hr>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}{% if mailcow_cc_role != 'admin' %} disabled{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="editdomain" data-item="{{ domain }}" data-api-url='edit/domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<small class="fst-italic d-block">{{ lang.edit.created_on }}: {{ result.created }}</small>
<small class="fst-italic d-block">{{ lang.edit.last_modified }}: {{ result.modified }}</small>
</div>
</div>
</form>
{% if dkim %}
<hr>
<div class="row">
<div class="col-12 col-sm-2">
<p>{{ lang.add.domain }}: <strong>{{ result.domain_name }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
</div>
<div class="col-12 col-sm-10">
<pre class="p-2">{{ dkim.dkim_txt }}</pre>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
<div class="col-sm-10">
<div class="form-control tag-box">
{% for tag in domain_details.tags %}
<span data-action='delete_selected' data-item="{{ tag|url_encode }}" data-id="domain_tag_{{ tag }}" data-api-url='delete/domain/tag/{{ domain }}' class="badge bg-primary tag-badge btn-badge">
<i class="bi bi-tag-fill"></i>
{{ tag }}
</span>
{% endfor %}
<input type="text" class="tag-input">
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
<input type="hidden" value="" name="tags" class="tag-values" />
</div>
<div id="dratelimit" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-ratelimit">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-ratelimit" data-bs-toggle="collapse" aria-controls="collapse-tab-ratelimit">
{{ lang.edit.ratelimit }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-ratelimit" class="card-body collapse" data-bs-parent="#domain-content">
<form data-id="domratelimit" class="well" method="post">
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.edit.ratelimit }}</label>
<div class="col-sm-10">
<div class="input-group">
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<button data-acl="{{ acl.ratelimit }}" class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="domratelimit" data-item="{{ domain }}" data-api-url='edit/rl-domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.domain_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
<div id="dspamfilter" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-spamfilter">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-spamfilter" data-bs-toggle="collapse" aria-controls="collapse-tab-spamfilter">
{{ lang.edit.spam_filter }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-spamfilter" class="card-body collapse" data-bs-parent="#domain-content">
<div class="row">
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_wl }}</h4>
<p>{{ lang.user.spamfilter_wl_desc|raw }}</p>
<form class="form-inline mb-4" data-id="add_wl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<button class="btn btn-secondary" data-action="add_item" data-id="add_wl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"wl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</div>
</form>
<table id="wl_policy_domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-secondary" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_bl }}</h4>
<p>{{ lang.user.spamfilter_bl_desc|raw }}</p>
<form class="form-inline mb-4" data-id="add_bl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<button class="btn btn-secondary" data-action="add_item" data-id="add_bl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"bl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</div>
</form>
<table id="bl_policy_domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-secondary" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a></li>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% if mailcow_cc_role == 'admin' %}
<div class="row mb-2">
<label class="control-label col-sm-2" for="aliases">{{ lang.edit.max_aliases }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="{{ result.max_num_aliases_for_domain }}">
<div id="dqwbcc" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-qwbcc">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-qwbcc" data-bs-toggle="collapse" aria-controls="collapse-tab-qwbcc">
{{ lang.edit.quota_warning_bcc }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-qwbcc" class="card-body collapse" data-bs-parent="#domain-content">
<div class="row">
<div class="col-sm-12">
<h4>{{ lang.edit.quota_warning_bcc }}</h4>
<p>{{ lang.edit.quota_warning_bcc_info|raw }}</p>
<form class="form-horizontal" data-id="quota_bcc">
<input type="hidden" value="0" name="active">
<div class="row mb-2">
<label class="control-label col-sm-2" for="script_data">{{ lang.edit.target_address|raw }}:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="10" id="bcc_rcpt" name="bcc_rcpt">{{ quota_notification_bcc.bcc_rcpts|join("\n") }}</textarea>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if quota_notification_bcc.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="quota_bcc" data-item="quota_bcc" data-api-url='edit/quota_notification_bcc' data-api-attr='{"domain":"{{ domain }}"}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="mailboxes">{{ lang.edit.max_mailboxes }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="{{ result.max_num_mboxes_for_domain }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="defquota">{{ lang.edit.mailbox_quota_def }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="defquota" value="{{ (result.def_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="maxquota">{{ lang.edit.max_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="{{ (result.max_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.domain_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="{{ (result.max_quota_for_domain / 1048576) }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.edit.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"{% if result.backupmx == '1' %} checked{% endif %}> {{ lang.edit.relay_domain }}</label>
<br>
<label><input type="checkbox" value="1" name="relay_all_recipients"{% if result.relay_all_recipients == '1' %} checked{% endif %}> {{ lang.edit.relay_all }}</label>
<p>{{ lang.edit.relay_all_info|raw }}</p>
<label><input type="checkbox" value="1" name="relay_unknown_only"{% if result.relay_unknown_only == '1' %} checked{% endif %}> {{ lang.edit.relay_unknown_only }}</label>
<br>
<p>{{ lang.edit.relay_transport_info|raw }}</p>
<hr style="margin:25px 0px 0px 0px">
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="gal"{% if result.gal == '1' %} checked{% endif %}> {{ lang.edit.gal }}</label>
<small class="text-muted">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
</div>
<hr>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}{% if mailcow_cc_role != 'admin' %} disabled{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="editdomain" data-item="{{ domain }}" data-api-url='edit/domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<small class="fst-italic d-block">{{ lang.edit.created_on }}: {{ result.created }}</small>
<small class="fst-italic d-block">{{ lang.edit.last_modified }}: {{ result.modified }}</small>
</div>
</div>
</form>
{% if dkim %}
<hr>
<div class="row">
<div class="col-12 col-sm-2">
<p>Domain: <strong>{{ result.domain_name }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
</div>
<div class="col-12 col-sm-10">
<pre class="p-2">{{ dkim.dkim_txt }}</pre>
</div>
</div>
{% endif %}
</div>
<div id="dratelimit" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-ratelimit">
<form data-id="domratelimit" class="form-inline well" method="post">
<div class="row">
<div class="col-12">
<label class="control-label mb-2">{{ lang.edit.ratelimit }}</label>
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
<button data-acl="{{ acl.ratelimit }}" class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="domratelimit" data-item="{{ domain }}" data-api-url='edit/rl-domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
</div>
<div id="dspamfilter" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-spamfilter">
<div class="row">
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_wl }}</h4>
<p>{{ lang.user.spamfilter_wl_desc|raw }}</p>
<form class="form-inline mb-4" data-id="add_wl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-secondary" data-action="add_item" data-id="add_wl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"wl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<table id="wl_policy_domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-secondary" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_bl }}</h4>
<p>{{ lang.user.spamfilter_bl_desc|raw }}</p>
<form class="form-inline mb-4" data-id="add_bl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-secondary" data-action="add_item" data-id="add_bl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"bl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<table id="bl_policy_domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-secondary" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half d-block d-sm-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a></li>
</div>
<div id="dfooter" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-footer">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-footer" data-bs-toggle="collapse" aria-controls="collapse-tab-footer">
{{ lang.edit.domain_footer }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-footer" class="card-body collapse" data-bs-parent="#domain-content">
<div class="row">
<div class="col-sm-12">
<h4>{{ lang.edit.domain_footer }}</h4>
<p>{{ lang.edit.domain_footer_info|raw }}</p>
<pre>{{ lang.edit.domain_footer_info_vars.auth_user }}
{{ lang.edit.domain_footer_info_vars.from_user }}
{{ lang.edit.domain_footer_info_vars.from_name }}
{{ lang.edit.domain_footer_info_vars.from_addr }}
{{ lang.edit.domain_footer_info_vars.from_domain }}</pre>
<form class="form-horizontal mt-4" data-id="domain_footer">
<div class="row mb-2">
<label class="control-label col-sm-2" for="domain_footer_html">{{ lang.edit.domain_footer_html }}:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="10" id="domain_footer_html" name="footer_html">{{ domain_footer.html }}</textarea>
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="domain_footer_plain">{{ lang.edit.domain_footer_plain }}:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="10" id="domain_footer_plain" name="footer_plain">{{ domain_footer.plain }}</textarea>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="domain_footer" data-item="domain_footer" data-api-url='edit/domain-wide-footer' data-api-attr='{"domain":"{{ domain }}"}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="dqwbcc" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-qwbcc">
<div class="row">
<div class="col-sm-12">
<h4>{{ lang.edit.quota_warning_bcc }}</h4>
<p>{{ lang.edit.quota_warning_bcc_info|raw }}</p>
<form class="form-horizontal" data-id="quota_bcc">
<input type="hidden" value="0" name="active">
<div class="row mb-2">
<label class="control-label col-sm-2" for="script_data">{{ lang.edit.target_address|raw }}:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="10" id="bcc_rcpt" name="bcc_rcpt">{{ quota_notification_bcc.bcc_rcpts|join("\n") }}</textarea>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if quota_notification_bcc.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="quota_bcc" data-item="quota_bcc" data-api-url='edit/quota_notification_bcc' data-api-attr='{"domain":"{{ domain }}"}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% else %}
{{ parent() }}

View File

@ -40,15 +40,15 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
</div>
</div>
</div>

View File

@ -28,8 +28,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -9,8 +9,8 @@
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access">
<input type="hidden" value="0" name="protocol_access">
<div class="row mb-4">
<label class="control-label col-sm-2" for="template">{{ lang.mailbox.template }}</label>
<div class="col-sm-10">
@ -41,16 +41,16 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_never" autocomplete="off" value="never" {% if template.attributes.quarantine_notification == 'never' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_never">{{ lang.user.never }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_never">{{ lang.user.never }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_hourly" autocomplete="off" value="hourly" {% if template.attributes.quarantine_notification == 'hourly' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_daily" autocomplete="off" value="daily" {% if template.attributes.quarantine_notification == 'daily' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_daily">{{ lang.user.daily }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_daily">{{ lang.user.daily }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_weekly" autocomplete="off" value="weekly" {% if template.attributes.quarantine_notification == 'weekly' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_weekly">{{ lang.user.weekly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_weekly">{{ lang.user.weekly }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
@ -60,13 +60,13 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_reject" autocomplete="off" value="reject" {% if template.attributes.quarantine_category == 'reject' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_reject">{{ lang.user.q_reject }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_reject">{{ lang.user.q_reject }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_add_header" autocomplete="off" value="add_header" {% if template.attributes.quarantine_category == 'add_header' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_all" autocomplete="off" value="all" {% if template.attributes.quarantine_category == 'all' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_all">{{ lang.user.q_all }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_all">{{ lang.user.q_all }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
@ -76,10 +76,10 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="checkbox" class="btn-check" name="tls_enforce_in" id="tls_enforce_in" autocomplete="off" value="1" {% if template.attributes.tls_enforce_in == '1' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<input type="checkbox" class="btn-check" name="tls_enforce_out" id="tls_enforce_out" autocomplete="off" value="1" {% if template.attributes.tls_enforce_out == '1' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
</div>
</div>
</div>
@ -97,7 +97,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2">ACL</label>
<div class="col-sm-10">
<select id="template_user_acl" name="acl" size="10" multiple class="form-control">
<select id="template_user_acl" name="acl" size="10" multiple class="form-control">
<option value="spam_alias" {% if template.attributes.acl_spam_alias == '1' %} selected{% endif %}>{{ lang.acl["spam_alias"] }}</option>
<option value="tls_policy" {% if template.attributes.acl_tls_policy == '1' %} selected{% endif %}>{{ lang.acl["tls_policy"] }}</option>
<option value="spam_score" {% if template.attributes.acl_spam_score == '1' %} selected{% endif %}>{{ lang.acl["spam_score"] }}</option>
@ -118,14 +118,13 @@
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-10">
<input name="rl_value" type="number" autocomplete="off" value="{{ template.attributes.rl_value }}" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
<option value="s"{% if template.attributes.rl_frame == 's' %} selected{% endif %}>{{ lang.ratelimit.second }}</option>
<option value="m"{% if template.attributes.rl_frame == 'm' %} selected{% endif %}>{{ lang.ratelimit.minute }}</option>
<option value="h"{% if template.attributes.rl_frame == 'h' %} selected{% endif %}>{{ lang.ratelimit.hour }}</option>
<option value="d"{% if template.attributes.rl_frame == 'd' %} selected{% endif %}>{{ lang.ratelimit.day }}</option>
</select>
<p class="text-muted mt-3">{{ lang.edit.mbox_rl_info }}</p>
<div class="input-group">
<input name="rl_value" type="number" autocomplete="off" value="{{ template.attributes.rl_value }}" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<p class="text-muted mt-1">{{ lang.edit.mbox_rl_info }}</p>
</div>
</div>
<hr>
@ -140,8 +139,8 @@
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update"{% if template.attributes.force_pw_update == '1' %} checked{% endif %}> {{ lang.edit.force_pw_update }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="force_pw_update"{% if template.attributes.force_pw_update == '1' %} checked{% endif %}> {{ lang.edit.force_pw_update }}</label>
<small class="text-muted">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
@ -149,8 +148,8 @@
{% if not skip_sogo %}
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_access"{% if template.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"{% if template.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>

View File

@ -2,399 +2,443 @@
{% block inner_content %}
{% if result %}
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#medit">{{ lang.edit.mailbox }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#mpushover">{{ lang.edit.pushover }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#macl">{{ lang.edit.acl }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#mrl">{{ lang.edit.ratelimit }}</button></li>
</ul>
<hr>
<div class="tab-content">
<div id="medit" class="tab-pane fade show active" role="tabpanel" aria-labelledby="mailbox-edit">
<form class="form-horizontal" data-id="editmailbox" role="form" method="post">
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access">
<div class="row mb-2">
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" value="{{ result.name }}">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
<div class="col-sm-10">
<div class="form-control tag-box">
{% for tag in mailbox_details.tags %}
<span data-action='delete_selected' data-item="{{ tag }}" data-id="mailbox_tag_{{ tag }}" data-api-url='delete/mailbox/tag/{{ mailbox }}' class="badge bg-primary tag-badge btn-badge">
<i class="bi bi-tag-fill"></i>
{{ tag }}
</span>
{% endfor %}
<input type="text" class="tag-input">
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
<input type="hidden" value="" name="tags" class="tag-values" />
</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
<br><span id="quotaBadge" class="badge bg-info">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
</label>
<div class="col-sm-10">
<input type="number" name="quota" style="width:100%" min="0" max="{{ (result.max_new_quota / 1048576) }}" value="{{ (result.quota / 1048576) }}" class="form-control">
<small class="text-muted">0 = ∞</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.edit.sender_acl }}</label>
<div class="col-sm-10">
<select data-live-search="true" data-width="100%" style="width:100%" id="editSelectSenderACL" name="sender_acl" size="10" multiple>
{% for domain in sender_acl_handles.sender_acl_domains.ro %}
<option data-subtext="Admin" value="{{ domain }}" disabled selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.sender_acl_addresses.ro %}
<option data-subtext="Admin" disabled selected>
{{ alias }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.fixed_sender_aliases %}
<option data-subtext="Alias" disabled selected>{{ alias }}</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.rw %}
<option value="{{ domain }}" selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.selectable %}
<option value="{{ domain }}">
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.rw %}
<option selected>{{ address }}</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.selectable %}
<option>{{ address }}</option>
{% endfor %}
</select>
<div id="sender_acl_disabled"><i class="bi bi-shield-exclamation"></i> {{ lang.edit.sender_acl_disabled|raw }}</div>
<small class="text-muted d-block">{{ lang.edit.sender_acl_info|raw }}</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.mailbox_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control mb-4">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.attributes.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.attributes.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
<p class="d-block d-sm-none" style="margin: 0;padding: 0">&nbsp;</p>
<small class="text-muted d-block">{{ lang.edit.mailbox_relayhost_info }}</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'never' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'hourly' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'daily' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'weekly' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"weekly"}'>{{ lang.user.weekly }}</button>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.quarantine_category }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'reject' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'add_header' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'all' %} btn-dark{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"all"}'>{{ lang.user.q_all }}</button>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.user.tls_policy }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark"{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark"{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_out": {% if get_tls_policy.tls_enforce_out == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_out }}</button>
</div>
</div>
</div>
<div class="row">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="{{ lang.edit.unchanged_if_empty }}" autocomplete="new-password">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div data-acl="{{ acl.extend_sender_acl }}" class="row mb-4">
<label class="control-label col-sm-2" for="extended_sender_acl">{{ lang.edit.extended_sender_acl }}</label>
<div class="col-sm-10">
{% if sender_acl_handles.external_sender_aliases %}
{% set ext_sender_acl = sender_acl_handles.external_sender_aliases|join(', ') %}
{% endif %}
{% if acl.extend_sender_acl and acl.extend_sender_acl == 1 %}
<input type="text" class="form-control" name="extended_sender_acl" value="{{ ext_sender_acl }}" placeholder="user1@example.com, user2@example.org, @example.com, ...">
<small class="text-muted">{{ lang.edit.extended_sender_acl_info|raw }}</small>
{% endif %}
</div>
</div>
<div class="row">
<label class="control-label col-sm-2" for="protocol_access">{{ lang.edit.allowed_protocols }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.protocol_access }}" name="protocol_access" multiple class="form-control">
<option value="imap"{% if result.attributes.imap_access == '1' %} selected{% endif %}>IMAP</option>
<option value="pop3"{% if result.attributes.pop3_access == '1' %} selected{% endif %}>POP3</option>
<option value="smtp"{% if result.attributes.smtp_access == '1' %} selected{% endif %}>SMTP</option>
<option value="sieve"{% if result.attributes.sieve_access == '1' %} selected{% endif %}>Sieve</option>
</select>
</div>
</div>
<div hidden data-acl="{{ acl.smtp_ip_access }}" class="row">
<label class="control-label col-sm-2" for="allow_from_smtp">{{ lang.edit.allow_from_smtp }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="allow_from_smtp" value="{{ allow_from_smtp }}" placeholder="1.1.1.1, 10.2.0.0/24, ...">
<small class="text-muted">{{ lang.edit.allow_from_smtp_info }}</small>
</div>
</div>
<hr>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<select name="active" class="form-control">
<option value="1"{% if result.active == '1' %} selected{% endif %}>{{ lang.edit.active }}</option>
<option value="2"{% if result.active == '2' %} selected{% endif %}>{{ lang.edit.disable_login }}</option>
<option value="0"{% if result.active == '0' %} selected{% endif %}>{{ lang.edit.inactive }}</option>
</select>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update"{% if result.attributes.force_pw_update == '1' %} checked{% endif %}> {{ lang.edit.force_pw_update }}</label>
<small class="text-muted">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
</div>
{% if not skip_sogo %}
<div data-acl="{{ acl.sogo_access }}" class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_access"{% if result.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>
</div>
{% endif %}
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="editmailbox" data-item="{{ result.username }}" data-api-url='edit/mailbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<small class="fst-italic d-block">{{ lang.edit.created_on }}: {{ result.created }}</small>
<small class="fst-italic d-block">{{ lang.edit.last_modified }}: {{ result.modified }}</small>
</div>
</div>
</form>
</div>
<div id="mpushover" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-pushover">
<form data-id="pushover" class="form well" method="post">
<input type="hidden" value="0" name="evaluate_x_prio">
<input type="hidden" value="0" name="only_x_prio">
<input type="hidden" value="0" name="active">
<div class="row">
<div class="col-sm-1">
<p class="text-muted"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAACglBMVEUAAAAAAAEAAAAilecFGigAAAAAAAAAAAAAAAANj+c3n+Ypm+oeYI4KWI4MieAtkdQbleoJcLcjmeswmN4Rit4KgdMKUYQJKUAQSnILL0kMNlMSTngimOoNPF0hlOQBBgkNOlkRS3MHIjUhk+IPf8wKLUYsjM0AAAASTngAAAAAAAAPfckbdLIbdrYUWIgegsgce70knfEAAAAknfENOVkGHi8YaaIjnvEdgMUhkuAQSG8aca0hleQUh9YLjOM4nOEMgtMcbaYWa6YemO02ltkKhNktgLodYZEPXJEyi8kKesktfLUzj84cWYMiluckZ5YJXJYeW4Y0k9YKfs4yjs0pc6YHZaUviskLfMkqmugak+cqkNcViNcqeK4Iaq4XRmYGPmYMKDsFJTstgr0LdL0ti84CCQ4BCQ4Qgc8rlt8XjN8shcQsi8wZSGgEP2cRMEUDKkUAAAD///8dmvEamfExo/EXmPEWl/ERlvElnvEsofEjnfETl/Enn/Ezo/E4pvEvovEfm/E1pPEzpPEvofEOlfEpoPEamPEQlfEYmfE6p/EgnPEVlvEroPE3pfE2pfENk/Ern/E3pPEcmfEfmvEnnvBlufT6/P0soPAknPDd7/zs9vzo9PxBqfItofAqoPD9/f3B4/q43/mx2/l/xfZ6w/Vxv/VtvfVgt/RXtPNTsfNEq/L3+/31+v3a7fvR6vvH5fqs2vmc0/jx+P3v9/3h8fzW7PvV7PvL5/q13fmo1/mh1PiY0fiNy/aHyfZ2wfVou/Vdt/RPsPM3oeoQkuowmeAgjdgcgMQbeLrw9/3k8vy74Pm63/mX0PdYtfNNr/Ikm+4wnOchkuAVjOAfdrMVcrOdoJikAAAAcnRSTlMAIQ8IzzweFwf+/fvw8P79+/Xt7e3p6eji4d7U08y8qZyTiIWDgn53bWxqaWBKQ0JBOjUwMCkoJCEfHBkT/vz8/Pv7+vr69/b29PTy7ezm5ubm5N7e29vQ0M/Pv7+4uLW1pqaWloWDg3x7e21mUVFFRUXdPracAAAEbElEQVRIx4WUZbvaQBCFF+ru7u7u7u7u7t4mvVwSoBC0JIUCLRQolLq7u7vr/+nMLkmQyvlwyfPcd86e3ZldUqwyQ/p329J+XfutPQYOLUP+q55rFtQJRvY79+xxlZTUWbKpz7/xrrMr2+3BoNPpdLn2lJQ4HEeqLOr1d7z7XNkesQed4A848G63Oy4Gmg/6Mz542QvZbqe8C/Ig73CLYiYTrtLmT3zfqbIcAR7y4wIqH/B6M9Fo0+Ldb6sM9ph/v4ozPuz12mxRofaAAr7jCNkuoz/jNf9AGHibkBCm51fsGKvxsAGWx4H+jBcEi6V2birDpCL/9Klrd1KHbiSvPWP8V0tTnTfO03iXi57P6WNHOVUf44IFdFDRz6pV5fw8Zy5z3JVH5+R48OwxqDiGvKJIY9R+9JsCuJ5HPg74OVEMpz+nbdEPUHEWeEk6IDUnTC1l5r+f8uffc0cfxc8fS17kLso24SwUPFDA/6DE82xKDOPliJ7n/GGOOyWK9zD9CdjvOfg9Dv6AH+AX04LW9gj2i8W/APx1UbxwCAu+wPmcpgUKL/EHdvtq4uwaZwCuznPJVY5LHhED15G/isd5Hz4eKui/e/du02YoKFeD5mHzHIN/nxEDe25gQQwKorAid04CfyzwL4XutXvl1Pt1guMOwwKPkU8mYIFT8JHK+vv8prpDScUVL+j8s3lOctw1GIhbWHAS+HgKPk7xPM/4UtNAYmzizJkf6NgTb/gM8jePQLsewMdthS3g95tMpT1IhVm6v1s8fYmLeb13Odwp8Fh5KY048y/d14WUrwrb1e/X/rNp73nkD8kWS+wi/MZ4XuetG4mhKubJm3/WNEvi8SHwB56nPKjUam0LBdp9ARwupFemTYudvgN/L1+A/Ko/LGBuS8pPy+YR1fuCTWNKnUyoeUyYx2o2dyEVGmr5xTD42xzvkD16+Pb9WIIH6fmt1r3mbsTY7Bvw+n23naT8BUWh86bz6G/e259UXPUK3gfAxQDlo7Rpx3Geqb2e3wp83SGEdKpB7zvwYbzvT2n65xLwbH6YP+M9C8vA8E1wxLU8gkCbdhXGUyrMgwVrcbzLHonr78lzDvWM3q/C/HtDlXoSUIe3YkblhRPIX4E8Oo/9siLv8dRjV7SBlkdgTXvKS7nzsA/9AfeEuhKq9T8zWIDv1Sd6ETAP4D6/H/1V+1BojvruNa4SZXz4JhY84dV5MOF5agUvu5OsOo+KRpG30KalEnoeDccFlutPZYs38D5n3zcpr1/0fBhfb3DOY1z2tSAgLxWezz6zuoHhfUmOejf6blHQH/sFuJYfcMZX307ytKvRa3ifoV/586P5j+tICtS77BuJxzxYAPZsntX8k3eSIhlajK4p8b7iefCEKs03kD/I2LnxL9ovH+43y4fAv1YrI/mzDBsavAX/UppfzVOrZT/ydxk6lJ047MfLfVbcb6hS9ZEzWxekKQ5WrtPqZg3rV6tWrX6Tle3KQZj/q6KxQnmDoXwFY0VSrN9e8FRXBCTAvwAAAABJRU5ErkJggg==" class="img img-fluid"></a></p>
</div>
<div class="col-sm-10">
<p class="text-muted">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
<p class="text-muted">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}</code>, <code>{MSG_ID}</code></p>
<div class="row">
<div class="col-sm-6 mb-2">
<label for="token">API Token/Key (Application)</label>
<input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
<div id="mailbox-content" class="responsive-tabs">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#medit">{{ lang.edit.mailbox }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#mpushover">{{ lang.edit.pushover }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#macl">{{ lang.edit.acl }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#mrl">{{ lang.edit.ratelimit }}</button></li>
</ul>
<hr class="d-none d-md-block">
<div class="tab-content">
<div id="medit" class="tab-pane fade show active" role="tabpanel" aria-labelledby="mailbox-edit">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-medit" data-bs-toggle="collapse" aria-controls="collapse-tab-medit">
{{ lang.edit.mailbox }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div class="col-sm-6 mb-2">
<label for="key">User/Group Key</label>
<input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
<div id="collapse-tab-medit" class="card-body collapse show" data-bs-parent="#mailbox-content">
<form class="form-horizontal" data-id="editmailbox" role="form" method="post">
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access">
<div class="row mb-2">
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" value="{{ result.name }}">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
<div class="col-sm-10">
<div class="form-control tag-box">
{% for tag in mailbox_details.tags %}
<span data-action='delete_selected' data-item="{{ tag }}" data-id="mailbox_tag_{{ tag }}" data-api-url='delete/mailbox/tag/{{ mailbox }}' class="badge bg-primary tag-badge btn-badge">
<i class="bi bi-tag-fill"></i>
{{ tag }}
</span>
{% endfor %}
<input type="text" class="tag-input">
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
<input type="hidden" value="" name="tags" class="tag-values" />
</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
<br><span id="quotaBadge" class="badge bg-info">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
</label>
<div class="col-sm-10">
<input type="number" name="quota" style="width:100%" min="0" max="{{ (result.max_new_quota / 1048576) }}" value="{{ (result.quota / 1048576) }}" class="form-control">
<small class="text-muted">0 = ∞</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.edit.sender_acl }}</label>
<div class="col-sm-10">
<select data-live-search="true" data-width="100%" style="width:100%" id="editSelectSenderACL" name="sender_acl" size="10" multiple>
{% for domain in sender_acl_handles.sender_acl_domains.ro %}
<option data-subtext="Admin" value="{{ domain }}" disabled selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.sender_acl_addresses.ro %}
<option data-subtext="Admin" disabled selected>
{{ alias }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.fixed_sender_aliases %}
<option data-subtext="Alias" disabled selected>{{ alias }}</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.rw %}
<option value="{{ domain }}" selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.selectable %}
<option value="{{ domain }}">
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.rw %}
<option selected>{{ address }}</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.selectable %}
<option>{{ address }}</option>
{% endfor %}
</select>
<div id="sender_acl_disabled"><i class="bi bi-shield-exclamation"></i> {{ lang.edit.sender_acl_disabled|raw }}</div>
<small class="text-muted d-block">{{ lang.edit.sender_acl_info|raw }}</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.mailbox_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control mb-4">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.attributes.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.attributes.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
<p class="d-block d-sm-none" style="margin: 0;padding: 0">&nbsp;</p>
<small class="text-muted d-block">{{ lang.edit.mailbox_relayhost_info }}</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'never' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'hourly' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'daily' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'weekly' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"weekly"}'>{{ lang.user.weekly }}</button>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.quarantine_category }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'reject' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'add_header' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'all' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"all"}'>{{ lang.user.q_all }}</button>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.user.tls_policy }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_out": {% if get_tls_policy.tls_enforce_out == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_out }}</button>
</div>
</div>
</div>
<div class="row">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="{{ lang.edit.unchanged_if_empty }}" autocomplete="new-password">
</div>
</div>
<div class="row mb-4">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div data-acl="{{ acl.extend_sender_acl }}" class="row mb-4">
<label class="control-label col-sm-2" for="extended_sender_acl">{{ lang.edit.extended_sender_acl }}</label>
<div class="col-sm-10">
{% if sender_acl_handles.external_sender_aliases %}
{% set ext_sender_acl = sender_acl_handles.external_sender_aliases|join(', ') %}
{% endif %}
{% if acl.extend_sender_acl and acl.extend_sender_acl == 1 %}
<input type="text" class="form-control" name="extended_sender_acl" value="{{ ext_sender_acl }}" placeholder="user1@example.com, user2@example.org, @example.com, ...">
<small class="text-muted">{{ lang.edit.extended_sender_acl_info|raw }}</small>
{% endif %}
</div>
</div>
<div class="row">
<label class="control-label col-sm-2" for="protocol_access">{{ lang.edit.allowed_protocols }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.protocol_access }}" name="protocol_access" multiple class="form-control">
<option value="imap"{% if result.attributes.imap_access == '1' %} selected{% endif %}>IMAP</option>
<option value="pop3"{% if result.attributes.pop3_access == '1' %} selected{% endif %}>POP3</option>
<option value="smtp"{% if result.attributes.smtp_access == '1' %} selected{% endif %}>SMTP</option>
<option value="sieve"{% if result.attributes.sieve_access == '1' %} selected{% endif %}>Sieve</option>
</select>
</div>
</div>
<div hidden data-acl="{{ acl.smtp_ip_access }}" class="row">
<label class="control-label col-sm-2" for="allow_from_smtp">{{ lang.edit.allow_from_smtp }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="allow_from_smtp" value="{{ allow_from_smtp }}" placeholder="1.1.1.1, 10.2.0.0/24, ...">
<small class="text-muted">{{ lang.edit.allow_from_smtp_info }}</small>
</div>
</div>
<hr>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<select name="active" class="form-control">
<option value="1"{% if result.active == '1' %} selected{% endif %}>{{ lang.edit.active }}</option>
<option value="2"{% if result.active == '2' %} selected{% endif %}>{{ lang.edit.disable_login }}</option>
<option value="0"{% if result.active == '0' %} selected{% endif %}>{{ lang.edit.inactive }}</option>
</select>
</div>
</div>
<div class="row mt-2">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="force_pw_update"{% if result.attributes.force_pw_update == '1' %} checked{% endif %}> {{ lang.edit.force_pw_update }}</label>
<small class="text-muted">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
</div>
{% if not skip_sogo %}
<div data-acl="{{ acl.sogo_access }}" class="row">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"{% if result.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>
</div>
{% endif %}
<div class="row mt-2 mb-2">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="editmailbox" data-item="{{ result.username }}" data-api-url='edit/mailbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<small class="fst-italic d-block">{{ lang.edit.created_on }}: {{ result.created }}</small>
<small class="fst-italic d-block">{{ lang.edit.last_modified }}: {{ result.modified }}</small>
</div>
</div>
</form>
</div>
<div class="col-sm-6 mb-4">
<label for="title">{{ lang.edit.pushover_title }}</label>
<input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
</div>
<div class="col-sm-6 mb-4">
<label for="text">{{ lang.edit.pushover_text }}</label>
<input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
</div>
<div class="col-sm-12 mb-4">
<label for="text">{{ lang.edit.pushover_sender_array|raw }}</label>
<input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="sender1@example.com, sender2@example.com">
</div>
<div class="col-sm-12 mb-2">
<div class="form-group">
<label for="sound">{{ lang.edit.pushover_sound }}</label><br>
<select name="sound" class="form-control">
<option value="pushover"{% if pushover_data.attributes.sound == 'pushover' %} selected{% endif %}>Pushover (default)</option>
<option value="bike"{% if pushover_data.attributes.sound == 'bike' %} selected{% endif %}>Bike</option>
<option value="bugle"{% if pushover_data.attributes.sound == 'bugle' %} selected{% endif %}>Bugle</option>
<option value="cashregister"{% if pushover_data.attributes.sound == 'cashregister' %} selected{% endif %}>Cash Register</option>
<option value="classical"{% if pushover_data.attributes.sound == 'classical' %} selected{% endif %}>Classical</option>
<option value="cosmic"{% if pushover_data.attributes.sound == 'cosmic' %} selected{% endif %}>Cosmic</option>
<option value="falling"{% if pushover_data.attributes.sound == 'falling' %} selected{% endif %}>Falling</option>
<option value="gamelan"{% if pushover_data.attributes.sound == 'gamelan' %} selected{% endif %}>Gamelan</option>
<option value="incoming"{% if pushover_data.attributes.sound == 'incoming' %} selected{% endif %}>Incoming</option>
<option value="intermission"{% if pushover_data.attributes.sound == 'intermission' %} selected{% endif %}>Intermission</option>
<option value="magic"{% if pushover_data.attributes.sound == 'magic' %} selected{% endif %}>Magic</option>
<option value="mechanical"{% if pushover_data.attributes.sound == 'mechanical' %} selected{% endif %}>Mechanical</option>
<option value="pianobar"{% if pushover_data.attributes.sound == 'pianobar' %} selected{% endif %}>Piano Bar</option>
<option value="siren"{% if pushover_data.attributes.sound == 'siren' %} selected{% endif %}>Siren</option>
<option value="spacealarm"{% if pushover_data.attributes.sound == 'spacealarm' %} selected{% endif %}>Space Alarm</option>
<option value="tugboat"{% if pushover_data.attributes.sound == 'tugboat' %} selected{% endif %}>Tug Boat</option>
<option value="alien"{% if pushover_data.attributes.sound == 'alien' %} selected{% endif %}>Alien Alarm (long)</option>
<option value="climb"{% if pushover_data.attributes.sound == 'climb' %} selected{% endif %}>Climb (long)</option>
<option value="persistent"{% if pushover_data.attributes.sound == 'persistent' %} selected{% endif %}>Persistent (long)</option>
<option value="echo"{% if pushover_data.attributes.sound == 'echo' %} selected{% endif %}>Pushover Echo (long)</option>
<option value="updown"{% if pushover_data.attributes.sound == 'updown' %} selected{% endif %}>Up Down (long)</option>
<option value="vibrate"{% if pushover_data.attributes.sound == 'vibrate' %} selected{% endif %}>Vibrate Only</option>
<option value="none"{% if pushover_data.attributes.sound == 'none' %} selected{% endif %}> None (silent) </option>
</select>
</div>
</div>
<div class="col-sm-12">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
<div class="col-sm-12">
<legend style="cursor:pointer;margin-top:10px" data-bs-target="#po_advanced" unselectable="on" data-bs-toggle="collapse">
<i class="bi bi-plus"></i> {{ lang.edit.advanced_settings }}
</legend>
<hr />
</div>
<div class="col-sm-12 mb-4">
<div id="po_advanced" class="collapse">
<label for="text">{{ lang.edit.pushover_sender_regex }}</label>
<input type="text" class="form-control mt-2" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
<div class="checkbox mt-4">
<label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_evaluate_x_prio|raw }}</label>
</div>
<div class="checkbox mt-2">
<label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_only_x_prio|raw }}</label>
</div>
</div>
</div>
</div>
<div class="btn-group" data-acl="{{ acl.pushover }}">
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success" data-action="edit_selected" data-id="pushover" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{}' href="#">{{ lang.edit.save }}</a>
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="pushover-test" data-item="{{ mailbox }}" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.edit.pushover_verify }}</a>
<a id="pushover_delete" class="btn btn-sm d-block d-sm-inline btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> {{ lang.edit.remove }}</a>
</div>
</div>
</div>
</form>
</div>
<div id="macl" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-acl">
<form data-id="useracl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="text-muted">ACL</p>
</div>
<div class="col-sm-10">
<select id="user_acl" name="user_acl" size="10" multiple>
{% for acl, val in user_acls %}
<option value="{{ acl }}"{% if val == 1 %} selected{% endif %}>{{ lang.acl[acl] }}</option>
{% endfor %}
</select>
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="useracl" data-item="{{ mailbox }}" data-api-url='edit/user-acl' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
<div id="mpushover" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-pushover">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-mpushover" data-bs-toggle="collapse" aria-controls="collapse-tab-mpushover">
{{ lang.edit.pushover }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-mpushover" class="card-body collapse" data-bs-parent="#mailbox-content">
<form data-id="pushover" class="form well" method="post">
<input type="hidden" value="0" name="evaluate_x_prio">
<input type="hidden" value="0" name="only_x_prio">
<input type="hidden" value="0" name="active">
<div class="row">
<div class="col-sm-1">
<p class="text-muted"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAACglBMVEUAAAAAAAEAAAAilecFGigAAAAAAAAAAAAAAAANj+c3n+Ypm+oeYI4KWI4MieAtkdQbleoJcLcjmeswmN4Rit4KgdMKUYQJKUAQSnILL0kMNlMSTngimOoNPF0hlOQBBgkNOlkRS3MHIjUhk+IPf8wKLUYsjM0AAAASTngAAAAAAAAPfckbdLIbdrYUWIgegsgce70knfEAAAAknfENOVkGHi8YaaIjnvEdgMUhkuAQSG8aca0hleQUh9YLjOM4nOEMgtMcbaYWa6YemO02ltkKhNktgLodYZEPXJEyi8kKesktfLUzj84cWYMiluckZ5YJXJYeW4Y0k9YKfs4yjs0pc6YHZaUviskLfMkqmugak+cqkNcViNcqeK4Iaq4XRmYGPmYMKDsFJTstgr0LdL0ti84CCQ4BCQ4Qgc8rlt8XjN8shcQsi8wZSGgEP2cRMEUDKkUAAAD///8dmvEamfExo/EXmPEWl/ERlvElnvEsofEjnfETl/Enn/Ezo/E4pvEvovEfm/E1pPEzpPEvofEOlfEpoPEamPEQlfEYmfE6p/EgnPEVlvEroPE3pfE2pfENk/Ern/E3pPEcmfEfmvEnnvBlufT6/P0soPAknPDd7/zs9vzo9PxBqfItofAqoPD9/f3B4/q43/mx2/l/xfZ6w/Vxv/VtvfVgt/RXtPNTsfNEq/L3+/31+v3a7fvR6vvH5fqs2vmc0/jx+P3v9/3h8fzW7PvV7PvL5/q13fmo1/mh1PiY0fiNy/aHyfZ2wfVou/Vdt/RPsPM3oeoQkuowmeAgjdgcgMQbeLrw9/3k8vy74Pm63/mX0PdYtfNNr/Ikm+4wnOchkuAVjOAfdrMVcrOdoJikAAAAcnRSTlMAIQ8IzzweFwf+/fvw8P79+/Xt7e3p6eji4d7U08y8qZyTiIWDgn53bWxqaWBKQ0JBOjUwMCkoJCEfHBkT/vz8/Pv7+vr69/b29PTy7ezm5ubm5N7e29vQ0M/Pv7+4uLW1pqaWloWDg3x7e21mUVFFRUXdPracAAAEbElEQVRIx4WUZbvaQBCFF+ru7u7u7u7u7t4mvVwSoBC0JIUCLRQolLq7u7vr/+nMLkmQyvlwyfPcd86e3ZldUqwyQ/p329J+XfutPQYOLUP+q55rFtQJRvY79+xxlZTUWbKpz7/xrrMr2+3BoNPpdLn2lJQ4HEeqLOr1d7z7XNkesQed4A848G63Oy4Gmg/6Mz542QvZbqe8C/Ig73CLYiYTrtLmT3zfqbIcAR7y4wIqH/B6M9Fo0+Ldb6sM9ph/v4ozPuz12mxRofaAAr7jCNkuoz/jNf9AGHibkBCm51fsGKvxsAGWx4H+jBcEi6V2birDpCL/9Klrd1KHbiSvPWP8V0tTnTfO03iXi57P6WNHOVUf44IFdFDRz6pV5fw8Zy5z3JVH5+R48OwxqDiGvKJIY9R+9JsCuJ5HPg74OVEMpz+nbdEPUHEWeEk6IDUnTC1l5r+f8uffc0cfxc8fS17kLso24SwUPFDA/6DE82xKDOPliJ7n/GGOOyWK9zD9CdjvOfg9Dv6AH+AX04LW9gj2i8W/APx1UbxwCAu+wPmcpgUKL/EHdvtq4uwaZwCuznPJVY5LHhED15G/isd5Hz4eKui/e/du02YoKFeD5mHzHIN/nxEDe25gQQwKorAid04CfyzwL4XutXvl1Pt1guMOwwKPkU8mYIFT8JHK+vv8prpDScUVL+j8s3lOctw1GIhbWHAS+HgKPk7xPM/4UtNAYmzizJkf6NgTb/gM8jePQLsewMdthS3g95tMpT1IhVm6v1s8fYmLeb13Odwp8Fh5KY048y/d14WUrwrb1e/X/rNp73nkD8kWS+wi/MZ4XuetG4mhKubJm3/WNEvi8SHwB56nPKjUam0LBdp9ARwupFemTYudvgN/L1+A/Ko/LGBuS8pPy+YR1fuCTWNKnUyoeUyYx2o2dyEVGmr5xTD42xzvkD16+Pb9WIIH6fmt1r3mbsTY7Bvw+n23naT8BUWh86bz6G/e259UXPUK3gfAxQDlo7Rpx3Geqb2e3wp83SGEdKpB7zvwYbzvT2n65xLwbH6YP+M9C8vA8E1wxLU8gkCbdhXGUyrMgwVrcbzLHonr78lzDvWM3q/C/HtDlXoSUIe3YkblhRPIX4E8Oo/9siLv8dRjV7SBlkdgTXvKS7nzsA/9AfeEuhKq9T8zWIDv1Sd6ETAP4D6/H/1V+1BojvruNa4SZXz4JhY84dV5MOF5agUvu5OsOo+KRpG30KalEnoeDccFlutPZYs38D5n3zcpr1/0fBhfb3DOY1z2tSAgLxWezz6zuoHhfUmOejf6blHQH/sFuJYfcMZX307ytKvRa3ifoV/586P5j+tICtS77BuJxzxYAPZsntX8k3eSIhlajK4p8b7iefCEKs03kD/I2LnxL9ovH+43y4fAv1YrI/mzDBsavAX/UppfzVOrZT/ydxk6lJ047MfLfVbcb6hS9ZEzWxekKQ5WrtPqZg3rV6tWrX6Tle3KQZj/q6KxQnmDoXwFY0VSrN9e8FRXBCTAvwAAAABJRU5ErkJggg==" class="img img-fluid"></a></p>
</div>
<div class="col-sm-10">
<p class="text-muted">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
<p class="text-muted">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}</code>, <code>{MSG_ID}</code></p>
<div class="row">
<div class="col-sm-6 mb-2">
<label for="token">API Token/Key (Application)</label>
<input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
</div>
<div class="col-sm-6 mb-2">
<label for="key">User/Group Key</label>
<input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
</div>
<div class="col-sm-6 mb-4">
<label for="title">{{ lang.edit.pushover_title }}</label>
<input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
</div>
<div class="col-sm-6 mb-4">
<label for="text">{{ lang.edit.pushover_text }}</label>
<input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
</div>
<div class="col-sm-12 mb-4">
<label for="text">{{ lang.edit.pushover_sender_array|raw }}</label>
<input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="sender1@example.com, sender2@example.com">
</div>
<div class="col-sm-12 mb-2">
<div class="form-group">
<label for="sound">{{ lang.edit.pushover_sound }}</label><br>
<select name="sound" class="form-control">
<option value="pushover"{% if pushover_data.attributes.sound == 'pushover' %} selected{% endif %}>Pushover (default)</option>
<option value="bike"{% if pushover_data.attributes.sound == 'bike' %} selected{% endif %}>Bike</option>
<option value="bugle"{% if pushover_data.attributes.sound == 'bugle' %} selected{% endif %}>Bugle</option>
<option value="cashregister"{% if pushover_data.attributes.sound == 'cashregister' %} selected{% endif %}>Cash Register</option>
<option value="classical"{% if pushover_data.attributes.sound == 'classical' %} selected{% endif %}>Classical</option>
<option value="cosmic"{% if pushover_data.attributes.sound == 'cosmic' %} selected{% endif %}>Cosmic</option>
<option value="falling"{% if pushover_data.attributes.sound == 'falling' %} selected{% endif %}>Falling</option>
<option value="gamelan"{% if pushover_data.attributes.sound == 'gamelan' %} selected{% endif %}>Gamelan</option>
<option value="incoming"{% if pushover_data.attributes.sound == 'incoming' %} selected{% endif %}>Incoming</option>
<option value="intermission"{% if pushover_data.attributes.sound == 'intermission' %} selected{% endif %}>Intermission</option>
<option value="magic"{% if pushover_data.attributes.sound == 'magic' %} selected{% endif %}>Magic</option>
<option value="mechanical"{% if pushover_data.attributes.sound == 'mechanical' %} selected{% endif %}>Mechanical</option>
<option value="pianobar"{% if pushover_data.attributes.sound == 'pianobar' %} selected{% endif %}>Piano Bar</option>
<option value="siren"{% if pushover_data.attributes.sound == 'siren' %} selected{% endif %}>Siren</option>
<option value="spacealarm"{% if pushover_data.attributes.sound == 'spacealarm' %} selected{% endif %}>Space Alarm</option>
<option value="tugboat"{% if pushover_data.attributes.sound == 'tugboat' %} selected{% endif %}>Tug Boat</option>
<option value="alien"{% if pushover_data.attributes.sound == 'alien' %} selected{% endif %}>Alien Alarm (long)</option>
<option value="climb"{% if pushover_data.attributes.sound == 'climb' %} selected{% endif %}>Climb (long)</option>
<option value="persistent"{% if pushover_data.attributes.sound == 'persistent' %} selected{% endif %}>Persistent (long)</option>
<option value="echo"{% if pushover_data.attributes.sound == 'echo' %} selected{% endif %}>Pushover Echo (long)</option>
<option value="updown"{% if pushover_data.attributes.sound == 'updown' %} selected{% endif %}>Up Down (long)</option>
<option value="vibrate"{% if pushover_data.attributes.sound == 'vibrate' %} selected{% endif %}>Vibrate Only</option>
<option value="none"{% if pushover_data.attributes.sound == 'none' %} selected{% endif %}> None (silent) </option>
</select>
</div>
</div>
<div class="col-sm-12">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
<div class="col-sm-12">
<legend style="cursor:pointer;margin-top:10px" data-bs-target="#po_advanced" unselectable="on" data-bs-toggle="collapse">
<i class="bi bi-plus"></i> {{ lang.edit.advanced_settings }}
</legend>
<hr />
</div>
<div class="col-sm-12 mb-4">
<div id="po_advanced" class="collapse">
<label for="text">{{ lang.edit.pushover_sender_regex }}</label>
<input type="text" class="form-control mt-2" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
<div class="form-check mt-4">
<label><input type="checkbox" class="form-check-input" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_evaluate_x_prio|raw }}</label>
</div>
<div class="form-check mt-2">
<label><input type="checkbox" class="form-check-input" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_only_x_prio|raw }}</label>
</div>
</div>
</div>
</div>
<div class="btn-group" data-acl="{{ acl.pushover }}">
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success" data-action="edit_selected" data-id="pushover" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{}' href="#">{{ lang.edit.save }}</a>
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="pushover-test" data-item="{{ mailbox }}" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.edit.pushover_verify }}</a>
<a id="pushover_delete" class="btn btn-sm d-block d-sm-inline btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> {{ lang.edit.remove }}</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</form>
</div>
<div id="mrl" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-rl">
<form data-id="mboxratelimit" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="text-muted">{{ lang.acl.ratelimit }}</p>
</div>
<div class="col-sm-10">
<input name="rl_value" type="number" autocomplete="off" value="{{ rl.value }}" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="mboxratelimit" data-item="{{ mailbox }}" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
<p class="text-muted mt-3">{{ lang.edit.mbox_rl_info }}</p>
<div id="macl" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-acl">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-macl" data-bs-toggle="collapse" aria-controls="collapse-tab-macl">
{{ lang.edit.acl }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-macl" class="card-body collapse" data-bs-parent="#mailbox-content">
<form data-id="useracl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="text-muted">ACL</p>
</div>
<div class="col-sm-10">
<select id="user_acl" name="user_acl" size="10" multiple>
{% for acl, val in user_acls %}
<option value="{{ acl }}"{% if val == 1 %} selected{% endif %}>{{ lang.acl[acl] }}</option>
{% endfor %}
</select>
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="useracl" data-item="{{ mailbox }}" data-api-url='edit/user-acl' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</form>
</div>
<div id="mrl" class="tab-pane fade" role="tabpanel" aria-labelledby="mailbox-rl">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-mrl" data-bs-toggle="collapse" aria-controls="collapse-tab-mrl">
{{ lang.edit.ratelimit }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-mrl" class="card-body collapse" data-bs-parent="#mailbox-content">
<form data-id="mboxratelimit" class="well" method="post">
<div class="row mb-2">
<div class="col-sm-2">
<p class="text-muted">{{ lang.acl.ratelimit }}</p>
</div>
<div class="col-sm-10">
<div class="input-group">
<input name="rl_value" type="number" autocomplete="off" value="{{ rl.value }}" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="mboxratelimit" data-item="{{ mailbox }}" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
<p class="text-muted mt-2">{{ lang.edit.mbox_rl_info }}</p>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% else %}
{{ parent() }}

View File

@ -22,8 +22,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -26,8 +26,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -38,8 +38,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.syncjob }}</h4>
<h4 class="mb-4">{{ lang.edit.syncjob }}</h4>
<form class="form-horizontal" data-id="editsyncjob" role="form" method="post">
<input type="hidden" value="0" name="delete2duplicates">
<input type="hidden" value="0" name="delete1">
@ -101,50 +101,50 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates"{% if result.delete2duplicates == '1' %} checked{% endif %}> {{ lang.edit.delete2duplicates }} (--delete2duplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2duplicates"{% if result.delete2duplicates == '1' %} checked{% endif %}> {{ lang.edit.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"{% if result.delete1 == '1' %} checked{% endif %}> {{ lang.edit.delete1 }} (--delete1)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete1"{% if result.delete1 == '1' %} checked{% endif %}> {{ lang.edit.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"{% if result.delete2 == '1' %} checked{% endif %}> {{ lang.edit.delete2 }} (--delete2)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2"{% if result.delete2 == '1' %} checked{% endif %}> {{ lang.edit.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap"{% if result.automap == '1' %} checked{% endif %}> {{ lang.edit.automap }} (--automap)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="automap"{% if result.automap == '1' %} checked{% endif %}> {{ lang.edit.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"{% if result.skipcrossduplicates == '1' %} checked{% endif %}> {{ lang.edit.skipcrossduplicates }} (--skipcrossduplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="skipcrossduplicates"{% if result.skipcrossduplicates == '1' %} checked{% endif %}> {{ lang.edit.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall"{% if result.subscribeall == '1' %} checked{% endif %}> {{ lang.add.subscribeall }} (--subscribeall)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="subscribeall"{% if result.subscribeall == '1' %} checked{% endif %}> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -32,8 +32,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -32,15 +32,15 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="is_mx_based"{% if result.is_mx_based == '1' %} checked{% endif %}> {{ lang.edit.lookup_mx|raw }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="is_mx_based"{% if result.is_mx_based == '1' %} checked{% endif %}> {{ lang.edit.lookup_mx|raw }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>

View File

@ -15,10 +15,10 @@
<form style="display:inline;" method="post">
<input type="hidden" name="unset_fido2_key" value="{{ key_info.cid }}">
<div class="btn-group">
<a href="#" class="btn btn-xs btn-secondary" data-cid="{{ key_info.cid }}" data-subject="{{ key_info.subject|base64_encode }}" data-bs-toggle="modal" data-bs-target="#fido2ChangeFn">
<a href="#" class="btn btn-sm btn-xs-lg btn-secondary" data-cid="{{ key_info.cid }}" data-subject="{{ key_info.subject|base64_encode }}" data-bs-toggle="modal" data-bs-target="#fido2ChangeFn">
<i class="bi bi-pencil-fill"></i> {{ lang.fido2.rename }}
</a>
<a href="#" onClick='return confirm("{{ lang.admin.ays }}")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger">
<a href="#" onClick='return confirm("{{ lang.admin.ays }}")?$(this).closest("form").submit():"";' class="btn btn-sm btn-xs-lg btn-danger">
<i class="bi bi-trash"></i> {{ lang.admin.remove }}
</a>
</div>

View File

@ -14,7 +14,10 @@
</div>
</div>
<div class="card-body">
<div class="text-center mailcow-logo mb-4"><img src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow"></div>
<div class="text-center mailcow-logo mb-4">
<img class="main-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow">
<img class="main-logo-dark" src="{{ logo_dark|default('/img/cow_mailcow.svg') }}" alt="mailcow-logo-dark">
</div>
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active %}
<div class="my-4 alert alert-{{ ui_texts.ui_announcement_type }} rot-enc ui-announcement-alert">{{ ui_texts.ui_announcement_text|rot13 }}</div>
{% endif %}
@ -37,11 +40,14 @@
<input name="pass_user" type="password" id="pass_user" class="form-control" placeholder="{{ lang.login.password }}" required="" autocomplete="current-password">
</div>
</div>
<div class="d-flex mt-4" style="position: relative">
<button type="submit" class="btn btn-xs-lg btn-success" value="Login">{{ lang.login.login }}</button>
<button type="button" class="btn btn-xs-lg btn-success ms-2" id="fido2-login"><i class="bi bi-shield-fill-check"></i> {{ lang.login.fido2_webauthn }}</button>
<div class="d-flex justify-content-between mt-4" style="position: relative">
<div class="d-grid gap-2 d-sm-block">
<button type="submit" class="btn btn-xs-lg btn-success" value="Login">{{ lang.login.login }}</button>
<button type="button" class="btn btn-xs-lg btn-success" id="fido2-login"><i class="bi bi-shield-fill-check"></i> {{ lang.login.fido2_webauthn }}</button>
</div>
{% if not oauth2_request %}
<button type="button" {% if available_languages|length == 1 %}disabled="true"{% endif %} class="btn btn-xs-lg btn-secondary ms-auto dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<div class="d-grid d-sm-block">
<button type="button" {% if available_languages|length == 1 %}disabled="true"{% endif %} class="btn btn-secondary ms-auto dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="flag-icon flag-icon-{{ mailcow_locale[-2:] }}"></span>
</button>
<ul class="dropdown-menu ms-auto login">
@ -53,6 +59,7 @@
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</form>
@ -62,19 +69,15 @@
<div class="my-4" id="fido2-alerts"></div>
{% if not oauth2_request and (mailcow_apps or app_links) %}
<legend><i class="bi bi-link-45deg"></i> {{ ui_texts.apps_name|raw }}</legend><hr />
<div class="my-2 d-flex flex-wrap apps">
<div class="my-2 d-grid gap-2 d-sm-block apps">
{% for app in mailcow_apps %}
{% if not skip_sogo or not is_uri('SOGo', app.link) %}
<div class="m-2">
<a href="{{ app.link }}" role="button" {% if app.description %}title="{{ app.description }}"{% endif %} class="btn btn-primary btn-block">{{ app.name }}</a>
</div>
{% endif %}
<a href="{{ app.link }}" role="button" {% if app.description %}title="{{ app.description }}"{% endif %} class="btn btn-primary">{{ app.name }}</a>
{% endif %}
{% endfor %}
{% for row in app_links %}
{% for key, val in row %}
<div class="m-2">
<a href="{{ val }}" role="button" class="btn btn-primary btn-block">{{ key }}</a>
</div>
<a href="{{ val }}" role="button" class="btn btn-primary">{{ key }}</a>
{% endfor %}
{% endfor %}
</div>

View File

@ -3,20 +3,28 @@
{% block content %}
<div id="mail-content" class="responsive-tabs">
<ul class="nav nav-tabs" role="tablist">
{% if mailcow_cc_role == 'admin' %}
<li class="nav-item dropdown" role="presentation">
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.domains }}</a>
<ul class="dropdown-menu">
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
<li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li>
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li>
</ul>
</li>
{% else %}
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
{% endif %}
{% if mailcow_cc_role == 'admin' %}
<li class="nav-item dropdown" role="presentation">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.mailboxes }}</a>
<ul class="dropdown-menu">
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-mailboxes" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mailboxes">{{ lang.mailbox.mailboxes }}</button></li>
<li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-mbox" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-mbox">{{ lang.mailbox.templates }}</button></li>
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-templates-mbox" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-mbox">{{ lang.mailbox.templates }}</button></li>
</ul>
</li>
{% else %}
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-mailboxes" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mailboxes">{{ lang.mailbox.mailboxes }}</button></li>
{% endif %}
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-resources" role="tab" data-bs-toggle="tab" data-bs-target="#tab-resources">{{ lang.mailbox.resources }}</button></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.aliases }}</a>
@ -35,9 +43,13 @@
<div class="col-md-12">
<div class="tab-content" style="padding-top:20px">
{% include 'mailbox/tab-domains.twig' %}
{% if mailcow_cc_role == 'admin' %}
{% include 'mailbox/tab-templates-domains.twig' %}
{% endif %}
{% include 'mailbox/tab-mailboxes.twig' %}
{% if mailcow_cc_role == 'admin' %}
{% include 'mailbox/tab-templates-mbox.twig' %}
{% endif %}
{% include 'mailbox/tab-resources.twig' %}
{% include 'mailbox/tab-domain-aliases.twig' %}
{% include 'mailbox/tab-mbox-aliases.twig' %}

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-bcc" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group" data-acl="{{ acl.bcc_maps }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -34,8 +34,8 @@
<table id="bcc_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group" data-acl="{{ acl.bcc_maps }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -48,7 +48,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="bcc_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="bcc_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</a>
</div>
</div>
</div>
@ -65,7 +65,7 @@
</div>
</div>
<div id="collapse-tab-bcc-filters" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -85,8 +85,8 @@
<table id="recipient_map_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -96,7 +96,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="recipient_map_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="recipient_map_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</a>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-domain-aliases" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -30,8 +30,8 @@
<table id="aliasdomain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -41,7 +41,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="aliasdomain_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="aliasdomain_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-bs-toggle="modal" data-bs-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-bs-toggle="modal" data-bs-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</a>
</div>
</div>
</div>

View File

@ -12,7 +12,7 @@
</div>
<div id="collapse-tab-domains" class="card-body collapse show" data-bs-parent="#mail-content">
{#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
@ -28,15 +28,15 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="domain_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</a>
<button class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</button>
{% endif %}
</div>
</div>
<table id="domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<ul class="dropdown-menu">
{% if mailcow_cc_role == 'admin' %}
<li><a class="dropdown-item" data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
@ -49,7 +49,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="domain_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
{% if mailcow_cc_role == 'admin' %}
<button class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</button>
<button class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</button>
{% endif %}
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-filters" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group" data-acl="{{ acl.filters }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -34,8 +34,8 @@
<table id="filter_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4 mb-4">
<div class="btn-group" data-acl="{{ acl.filters }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -48,7 +48,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="filter_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="filter_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</a>
</div>
</div>
<div class="{% if mailcow_cc_role != 'admin' %}hidden{% endif %}">
@ -64,8 +64,8 @@
<div class="row mt-2">
<div class="col-sm-10 add_filter_btns">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-half btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div>
</div>
</div>
@ -82,8 +82,8 @@
<div class="row mt-2">
<div class="col-sm-10 add_filter_btns">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-half btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-mailboxes" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group d-flex d-lg-none">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -128,8 +128,8 @@
<table id="mailbox_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group d-flex d-lg-none">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="mailbox_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="mailbox_table">{{ lang.datatables.collapse_all }}</a></li>
@ -173,7 +173,7 @@
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"sieve_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
</div>
<div class="btn-group d-none d-lg-flex">
<a class="btn btn-sm btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-mbox-aliases" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -37,8 +37,8 @@
<table id="alias_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu top33">
<li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -53,8 +53,8 @@
<li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"0"}' href="#">{{ lang.mailbox.sogo_visible_n }}</a></li>
{% endif %}
</ul>
<a class="btn btn-sm btn-secondary" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> {{ lang.mailbox.add_alias_expand }}</a>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</a>
<a class="btn btn-sm btn-xs-lg btn-secondary" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> {{ lang.mailbox.add_alias_expand }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</a>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-resources" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -34,8 +34,8 @@
<table id="resource_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -45,7 +45,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="resource_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="resource_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</a>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-syncjobs" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group" data-acl="{{ acl.syncjobs }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -32,8 +32,8 @@
<table id="sync_job_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group" data-acl="{{ acl.syncjobs }}">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":"","success":""}' href="#">{{ lang.mailbox.last_run_reset }}</a></li>
<li><hr class="dropdown-divider"></li>
@ -45,7 +45,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="sync_job_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="sync_job_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
<div class="tab-pane fade show" id="tab-templates-domains" role="tabpanel" aria-labelledby="tab-templates-domains">
<div class="tab-pane fade" id="tab-templates-domains" role="tabpanel" aria-labelledby="tab-templates-domains">
<div class="card mb-4">
<div class="card-header d-flex fs-5">
<button class="btn d-sm-block d-md-none flex-grow-1 text-start" data-bs-target="#collapse-tab-templates-domains" data-bs-toggle="collapse" aria-controls="collapse-tab-templates-domains">
@ -10,8 +10,8 @@
<button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_templates_domain_table" data-table="templates_domain_table">{{ lang.admin.refresh }}</button>
</div>
</div>
<div id="collapse-tab-templates-domains" class="card-body collapse show" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div id="collapse-tab-templates-domains" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
@ -24,15 +24,15 @@
{% endif %}
</ul>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</a>
<button class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#addDomainTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</button>
{% endif %}
</div>
</div>
<table id="templates_domain_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="domain_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<ul class="dropdown-menu">
{% if mailcow_cc_role == 'admin' %}
<li><a class="dropdown-item" data-action="delete_selected" data-id="domain_template" data-api-url='delete/domain/template' href="#">{{ lang.mailbox.remove }}</a></li>
@ -42,7 +42,7 @@
{% endif %}
</ul>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</a>
<button class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</button>
{% endif %}
</div>
</div>

View File

@ -1,4 +1,4 @@
<div class="tab-pane fade show" id="tab-templates-mbox" role="tabpanel" aria-labelledby="tab-templates-mbox">
<div class="tab-pane fade" id="tab-templates-mbox" role="tabpanel" aria-labelledby="tab-templates-mbox">
<div class="card mb-4">
<div class="card-header d-flex fs-5">
<button class="btn d-sm-block d-md-none flex-grow-1 text-start" data-bs-target="#collapse-tab-templates-mbox" data-bs-toggle="collapse" aria-controls="collapse-tab-templates-mbox">
@ -10,8 +10,8 @@
<button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_templates_mbox_table" data-table="templates_mbox_table">{{ lang.admin.refresh }}</button>
</div>
</div>
<div id="collapse-tab-templates-mbox" class="card-body collapse show" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div id="collapse-tab-templates-mbox" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
@ -24,15 +24,15 @@
{% endif %}
</ul>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</a>
<button class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#addMailboxTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</button>
{% endif %}
</div>
</div>
<table id="templates_mbox_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="mailbox_template" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</button>
<ul class="dropdown-menu">
{% if mailcow_cc_role == 'admin' %}
<li><a class="dropdown-item" data-action="delete_selected" data-id="mailbox_template" data-api-url='delete/mailbox/template' href="#">{{ lang.mailbox.remove }}</a></li>
@ -42,7 +42,7 @@
{% endif %}
</ul>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</a>
<button class="btn btn-sm btn-xs-lg btn-success" data-bs-toggle="modal" data-bs-target="#addMailboxTemplateModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_template }}</button>
{% endif %}
</div>
</div>

View File

@ -11,7 +11,7 @@
</div>
</div>
<div id="collapse-tab-tls-policy" class="card-body collapse" data-bs-parent="#mail-content">
<div class="mass-actions-mailbox mb-4">
<div class="mass-actions-mailbox mb-4 d-none d-sm-block">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
@ -31,8 +31,8 @@
<table id="tls_policy_table" class="table table-striped dt-responsive w-100"></table>
<div class="mass-actions-mailbox mt-4">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-lg btn-xs-half btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@ -42,7 +42,7 @@
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-expand="tls_policy_table">{{ lang.datatables.expand_all }}</a></li>
<li class="table_collapse_option"><a class="dropdown-item" data-datatables-collapse="tls_policy_table">{{ lang.datatables.collapse_all }}</a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</a>
<a class="btn btn-sm btn-xs-lg btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</a>
</div>
</div>
</div>

View File

@ -22,8 +22,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>
@ -81,8 +81,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>
@ -181,8 +181,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>

View File

@ -78,16 +78,16 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_never" autocomplete="off" value="never">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_never">{{ lang.user.never }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_never">{{ lang.user.never }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_hourly" autocomplete="off" value="hourly">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_daily" autocomplete="off" value="daily">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_daily">{{ lang.user.daily }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_daily">{{ lang.user.daily }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="quarantine_notification_weekly" autocomplete="off" value="weekly">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_notification_weekly">{{ lang.user.weekly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_notification_weekly">{{ lang.user.weekly }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
@ -97,13 +97,13 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_reject" autocomplete="off" value="reject">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_reject">{{ lang.user.q_reject }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_reject">{{ lang.user.q_reject }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_add_header" autocomplete="off" value="add_header">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="quarantine_category_all" autocomplete="off" value="all">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="quarantine_category_all">{{ lang.user.q_all }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="quarantine_category_all">{{ lang.user.q_all }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
@ -113,10 +113,10 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="checkbox" class="btn-check" name="tls_enforce_in" id="tls_enforce_in" autocomplete="off" value="1">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<input type="checkbox" class="btn-check" name="tls_enforce_out" id="tls_enforce_out" autocomplete="off" value="1">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
</div>
</div>
</div>
@ -155,14 +155,13 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-10">
<input name="rl_value" id="rl_value" type="number" autocomplete="off" value="" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" id="rl_frame" class="form-control">
<option value="s">{{ lang.ratelimit.second }}</option>
<option value="m">{{ lang.ratelimit.minute }}</option>
<option value="h">{{ lang.ratelimit.hour }}</option>
<option value="d">{{ lang.ratelimit.day }}</option>
</select>
<p class="text-muted mt-3">{{ lang.edit.mbox_rl_info }}</p>
<div class="input-group">
<input name="rl_value" id="rl_value" type="number" autocomplete="off" value="" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" id="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<p class="text-muted mt-1">{{ lang.edit.mbox_rl_info }}</p>
</div>
</div>
<div class="row mb-2">
@ -176,8 +175,8 @@
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update" id="force_pw_update"> {{ lang.edit.force_pw_update }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="force_pw_update" id="force_pw_update"> {{ lang.edit.force_pw_update }}</label>
<small class="text-muted">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
@ -185,8 +184,8 @@
{% if not skip_sogo %}
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_access" id="sogo_access"> {{ lang.edit.sogo_access }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access" id="sogo_access"> {{ lang.edit.sogo_access }}</label>
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>
@ -216,7 +215,7 @@
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access">
<input type="hidden" value="0" name="protocol_access">
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="template">{{ lang.mailbox.template }}</label>
@ -248,16 +247,16 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_notification" id="template_quarantine_notification_never" autocomplete="off" value="never">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_notification_never">{{ lang.user.never }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_notification_never">{{ lang.user.never }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="template_quarantine_notification_hourly" autocomplete="off" value="hourly">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_notification_hourly">{{ lang.user.hourly }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="template_quarantine_notification_daily" autocomplete="off" value="daily">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_notification_daily">{{ lang.user.daily }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_notification_daily">{{ lang.user.daily }}</label>
<input type="radio" class="btn-check" name="quarantine_notification" id="template_quarantine_notification_weekly" autocomplete="off" value="weekly">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_notification_weekly">{{ lang.user.weekly }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_notification_weekly">{{ lang.user.weekly }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
@ -267,13 +266,13 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="quarantine_category" id="template_quarantine_category_reject" autocomplete="off" value="reject" >
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_category_reject">{{ lang.user.q_reject }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_category_reject">{{ lang.user.q_reject }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="template_quarantine_category_add_header" autocomplete="off" value="add_header">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_category_add_header">{{ lang.user.q_add_header }}</label>
<input type="radio" class="btn-check" name="quarantine_category" id="template_quarantine_category_all" autocomplete="off" value="all">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_quarantine_category_all">{{ lang.user.q_all }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_quarantine_category_all">{{ lang.user.q_all }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
@ -283,10 +282,10 @@
<div class="col-sm-10">
<div class="btn-group">
<input type="checkbox" class="btn-check" name="tls_enforce_in" id="template_tls_enforce_in" autocomplete="off" value="1">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_tls_enforce_in">{{ lang.user.tls_enforce_in }}</label>
<input type="checkbox" class="btn-check" name="tls_enforce_out" id="template_tls_enforce_out" autocomplete="off" value="1">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-secondary" for="template_tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_tls_enforce_out">{{ lang.user.tls_enforce_out }}</label>
</div>
</div>
</div>
@ -304,7 +303,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end">ACL</label>
<div class="col-sm-10">
<select id="template_user_acl" name="acl" size="10" multiple class="form-control">
<select id="template_user_acl" name="acl" size="10" multiple class="form-control">
<option value="spam_alias" selected>{{ lang.acl["spam_alias"] }}</option>
<option value="tls_policy" selected>{{ lang.acl["tls_policy"] }}</option>
<option value="spam_score" selected>{{ lang.acl["spam_score"] }}</option>
@ -325,14 +324,13 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-10">
<input name="rl_value" type="number" autocomplete="off" value="" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
<option value="s">{{ lang.ratelimit.second }}</option>
<option value="m">{{ lang.ratelimit.minute }}</option>
<option value="h">{{ lang.ratelimit.hour }}</option>
<option value="d">{{ lang.ratelimit.day }}</option>
</select>
<p class="text-muted mt-3">{{ lang.edit.mbox_rl_info }}</p>
<div class="input-group">
<input name="rl_value" type="number" autocomplete="off" value="" class="form-control mb-2" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<p class="text-muted mt-1">{{ lang.edit.mbox_rl_info }}</p>
</div>
</div>
<hr>
@ -347,8 +345,8 @@
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update"> {{ lang.edit.force_pw_update }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="force_pw_update"> {{ lang.edit.force_pw_update }}</label>
<small class="text-muted">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
@ -356,8 +354,8 @@
{% if not skip_sogo %}
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_access"> {{ lang.edit.sogo_access }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_access"> {{ lang.edit.sogo_access }}</label>
<small class="text-muted">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>
@ -445,8 +443,8 @@
{% if not skip_sogo %}
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" id="addDomain_gal" value="1" name="gal" checked> {{ lang.edit.gal }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" id="addDomain_gal" value="1" name="gal" checked> {{ lang.edit.gal }}</label>
<small class="text-muted">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
@ -454,21 +452,21 @@
{% endif %}
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" id="addDomain_active" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" id="addDomain_active" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<hr>
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end" for="rl_frame">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-7">
<input name="rl_value" id="addDomain_rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="col-sm-3">
<select name="rl_frame" id="addDomain_rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
<div class="col-sm-10">
<div class="input-group">
<input name="rl_value" id="addDomain_rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" id="addDomain_rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
</div>
<hr>
@ -481,7 +479,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="key_size">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-secondary btn-sm" class="form-control" id="key_size" name="key_size">
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
<option data-subtext="bits" value="1024">1024</option>
<option data-subtext="bits" value="2048" selected>2048</option>
</select>
@ -491,12 +489,12 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.add.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" id="addDomain_relay_domain" value="1" name="backupmx"> {{ lang.add.relay_domain }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" id="addDomain_relay_domain" value="1" name="backupmx"> {{ lang.add.relay_domain }}</label>
<br>
<label><input type="checkbox" id="addDomain_relay_all" value="1" name="relay_all_recipients"> {{ lang.add.relay_all }}</label>
<label><input type="checkbox" class="form-check-input" id="addDomain_relay_all" value="1" name="relay_all_recipients"> {{ lang.add.relay_all }}</label>
<p>{{ lang.add.relay_all_info|raw }}</p>
<label><input type="checkbox" id="addDomain_relay_unknown_only" value="1" name="relay_unknown_only"> {{ lang.add.relay_unknown_only }}</label>
<label><input type="checkbox" class="form-check-input" id="addDomain_relay_unknown_only" value="1" name="relay_unknown_only"> {{ lang.add.relay_unknown_only }}</label>
<br>
<p>{{ lang.add.relay_transport_info|raw }}</p>
</div>
@ -508,7 +506,6 @@
{% if not skip_sogo %}
<button class="btn btn-xs-lg btn-xs-half d-block d-sm-inline btn-secondary" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"tags": []}' href="#">{{ lang.add.add_domain_only }}</button>
<button class="btn btn-xs-lg btn-xs-half d-block d-sm-inline btn-secondary" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1", "tags": []}' href="#">{{ lang.add.add_domain_restart }}</button>
<div class="clearfix visible-xs"></div>
{% else %}
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"tags": []}' href="#">{{ lang.add.add }}</button>
{% endif %}
@ -584,32 +581,29 @@
</div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="gal" checked> {{ lang.add.gal }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="gal" checked> {{ lang.add.gal }}</label>
<small class="text-muted">{{ lang.add.gal_info|raw }}</small>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<hr>
<div class="row">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.edit.ratelimit }}</label>
<div class="col-sm-7">
<input name="rl_value" type="number" value="" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="col-sm-3">
<select name="rl_frame" class="form-control">
<option value="s">{{ lang.ratelimit.second }}</option>
<option value="m">{{ lang.ratelimit.minute }}</option>
<option value="h">{{ lang.ratelimit.hour }}</option>
<option value="d">{{ lang.ratelimit.day }}</option>
</select>
<div class="col-sm-10">
<div class="input-group">
<input name="rl_value" type="number" value="" autocomplete="off" class="form-control mb-4" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
</div>
{% endif %}
@ -623,7 +617,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="key_size">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-secondary btn-sm" class="form-control" id="key_size" name="key_size">
<select data-style="btn btn-light" class="form-control" id="key_size" name="key_size">
<option data-subtext="bits">1024</option>
<option data-subtext="bits" selected>2048</option>
</select>
@ -633,12 +627,12 @@
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.edit.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"> {{ lang.edit.relay_domain }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="backupmx"> {{ lang.edit.relay_domain }}</label>
<br>
<label><input type="checkbox" value="1" name="relay_all_recipients"> {{ lang.edit.relay_all }}</label>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_all_recipients"> {{ lang.edit.relay_all }}</label>
<p>{{ lang.edit.relay_all_info|raw }}</p>
<label><input type="checkbox" value="1" name="relay_unknown_only"> {{ lang.edit.relay_unknown_only }}</label>
<label><input type="checkbox" class="form-check-input" value="1" name="relay_unknown_only"> {{ lang.edit.relay_unknown_only }}</label>
<br>
<p>{{ lang.edit.relay_transport_info|raw }}</p>
</div>
@ -708,8 +702,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -746,19 +740,19 @@
<div class="col-sm-10">
<textarea id="textarea_alias_goto" autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto" required></textarea>
<p>{{ lang.add.target_address_info|raw }}</p>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null"> {{ lang.add.goto_null }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_null"> {{ lang.add.goto_null }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam"> {{ lang.add.goto_spam|raw }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_spam"> {{ lang.add.goto_spam|raw }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham"> {{ lang.add.goto_ham|raw }}</label>
<div class="form-check">
<label><input class="form-check-input goto_checkbox" type="checkbox" value="1" name="goto_ham"> {{ lang.add.goto_ham|raw }}</label>
</div>
{% if not skip_sogo %}
<hr>
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_visible" checked> {{ lang.edit.sogo_visible }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible" checked> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="text-muted">{{ lang.edit.sogo_visible_info }}</p>
{% endif %}
@ -766,8 +760,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -811,21 +805,21 @@
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<hr>
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end" for="rl_frame">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-7">
<input name="rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="col-sm-3">
<select name="rl_frame" class="form-control">
<div class="col-sm-10">
<div class="input-group">
<input name="rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</select>
</div>
</div>
</div>
<hr>
@ -838,7 +832,7 @@
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end" for="key_size2">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-secondary btn-sm" class="form-control" id="key_size2" name="key_size">
<select data-style="btn btn-light" class="form-control" id="key_size2" name="key_size">
<option data-subtext="bits">1024</option>
<option data-subtext="bits" selected>2048</option>
</select>
@ -967,50 +961,50 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -1068,8 +1062,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -1121,8 +1115,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -1162,8 +1156,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -1218,8 +1212,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>

View File

@ -127,50 +127,50 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -228,8 +228,8 @@
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
@ -285,15 +285,13 @@
<label class="control-label col-sm-3" for="user_old_pass">{{ lang.user.password_now }}</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="user_old_pass" autocomplete="off" required>
{% if number_of_app_passwords > 0 %}
<div class="invalid-feedback d-block">
{{ lang.user.change_password_hint_app_passwords|format(number_of_app_passwords) }}
</div>
{% endif %}
</div>
</div>
{% if number_of_app_passwords > 0 %}
<div class="row mb-2">
<div class="offset-sm-3 col-sm-9">
<small>{{ lang.user.change_password_hint_app_passwords | replace({'{{number_of_app_passwords}}': number_of_app_passwords}) }}</small>
</div>
</div>
{% endif %}
<div class="row">
<div class="offset-sm-3 col-sm-9">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#">{{ lang.user.change_password }}</button>

View File

@ -80,8 +80,8 @@
</div>
</div>
<div class="col-sm-12">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.user.active }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.user.active }}</label>
</div>
</div>
<div class="col-sm-12">
@ -95,11 +95,11 @@
<div class="form-group">
<label for="text">{{ lang.user.pushover_sender_regex }}</label>
<input type="text" class="form-control mb-4" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
<div class="checkbox">
<label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_evaluate_x_prio|raw }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_evaluate_x_prio|raw }}</label>
</div>
<div class="checkbox">
<label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_only_x_prio|raw }}</label>
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_only_x_prio|raw }}</label>
</div>
</div>
</div>

View File

@ -45,9 +45,7 @@
<form class="form-inline mb-4" data-id="add_wl_policy_mailbox">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-secondary" data-action="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"wl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</span>
<button class="btn btn-secondary" data-action="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"wl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</div>
</form>
<table id="wl_policy_mailbox_table" class="table table-striped dt-responsive w-100"></table>
@ -69,9 +67,7 @@
<form class="form-inline mb-4" data-id="add_bl_policy_mailbox">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-secondary" data-action="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"bl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</span>
<button class="btn btn-secondary" data-action="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"bl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</div>
</form>
<table id="bl_policy_mailbox_table" class="table table-striped dt-responsive w-100"></table>

View File

@ -129,13 +129,13 @@
</div>
</div>
<div class="row">
<div class="col-md-3 col-12 text-sm-end text-start mb-4"><i class="bi bi-file-earmark-text"></i> {{ lang.user.apple_connection_profile }}<br />{{ lang.user.with_app_password }}:</div>
<div class="col-md-3 col-12 text-sm-end text-start mb-4"><i class="bi bi-file-earmark-text"></i> {{ lang.user.apple_connection_profile }}<br class="d-none d-lg-block" />{{ lang.user.with_app_password }}:</div>
<div class="col-md-9 col-12">
<p><i class="bi bi-file-earmark-post"></i> <a href="/mobileconfig.php?only_email&amp;app_password">{{ lang.user.email }}</a> <small>IMAP, SMTP</small></p>
<p class="text-muted">{{ lang.user.apple_connection_profile_mailonly }} {{ lang.user.apple_connection_profile_with_app_password }}</p>
<p class="text-muted">{{ lang.user.apple_connection_profile_mailonly }}<br /> {{ lang.user.apple_connection_profile_with_app_password }}</p>
{% if not skip_sogo %}
<p><i class="bi bi-file-earmark-post"></i> <a href="/mobileconfig.php?app_password">{{ lang.user.email_and_dav }}</a> <small>IMAP, SMTP, Cal/CardDAV</small></p>
<p class="text-muted">{{ lang.user.apple_connection_profile_complete }} {{ lang.user.apple_connection_profile_with_app_password }}</p>
<p class="text-muted">{{ lang.user.apple_connection_profile_complete }}<br /> {{ lang.user.apple_connection_profile_with_app_password }}</p>
{% endif %}
</div>
</div>

View File

@ -12,19 +12,19 @@
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tag_handling }}:</div>
<div class="col-sm-9 col-12">
<div class="btn-group" data-acl="{{ acl.delimiter_action }}">
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'subfolder' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'subfolder' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subfolder"}'>{{ lang.user.tag_in_subfolder }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'subject' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'subject' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subject"}'>{{ lang.user.tag_in_subject }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if get_tagging_options == 'none' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'none' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
@ -40,13 +40,13 @@
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.tls_policy }}:</div>
<div class="col-sm-9 col-12">
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark"{% endif %}"
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline{% if get_tls_policy.tls_enforce_in == '1' %} btn-dark"{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-light{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark"{% endif %}"
<button type="button" class="btn btn-sm btn-xs-half d-block d-sm-inline{% if get_tls_policy.tls_enforce_out == '1' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="tls_policy"
@ -61,25 +61,25 @@
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_notification }}:</div>
<div class="col-sm-9 col-12">
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'never' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'never' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'hourly' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'hourly' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'daily' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'daily' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light{% if quarantine_notification == 'weekly' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-quart d-block d-sm-inline{% if quarantine_notification == 'weekly' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
@ -93,19 +93,19 @@
<div class="col-sm-3 col-12 text-sm-end text-start text-xs-bold mb-4">{{ lang.user.quarantine_category }}:</div>
<div class="col-sm-9 col-12">
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'reject' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'reject' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'add_header' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'add_header' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline btn-light{% if quarantine_category == 'all' %} btn-dark{% endif %}"
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if quarantine_category == 'all' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"

View File

@ -62,16 +62,18 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
$user_domains = array_merge($user_domains, $user_alias_domains);
}
$template = 'user.twig';
// get number of app passwords
$number_of_app_passwords = 0;
foreach (app_passwd("get") as $app_password)
{
$app_password = app_passwd("details", $app_password['id']);
if ($app_password['active'])
{
++$number_of_app_passwords;
$number_of_app_passwords++;
}
}
$template = 'user.twig';
$template_data = [
'acl' => $_SESSION['acl'],
'acl_json' => json_encode($_SESSION['acl']),

View File

@ -189,7 +189,7 @@ if [[ ${SKIP_BRANCH} != y ]]; then
done
git fetch --all
git checkout -f $git_branch
git checkout -f $MAILCOW_BRANCH
elif [[ ${SKIP_BRANCH} == y ]]; then
echo -e "\033[33mEnabled Dev Mode.\033[0m"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?<version>.*)$
NEXTCLOUD_VERSION=27.0.1
NEXTCLOUD_VERSION=27.0.2
echo -ne "Checking prerequisites..."
sleep 1