Merge remote-tracking branch 'origin/feature/bootstrap5' into staging
This commit is contained in:
commit
41d56a867a
|
@ -8,11 +8,14 @@ RUN apk add --update --no-cache python3 \
|
|||
py3-pip \
|
||||
openssl \
|
||||
tzdata \
|
||||
py3-psutil \
|
||||
&& pip3 install --upgrade pip \
|
||||
docker \
|
||||
flask \
|
||||
flask-restful
|
||||
fastapi \
|
||||
uvicorn \
|
||||
aiodocker \
|
||||
redis
|
||||
|
||||
COPY docker-entrypoint.sh /app/
|
||||
COPY dockerapi.py /app/
|
||||
|
||||
CMD ["python3", "-u", "/app/dockerapi.py"]
|
||||
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
`openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
|
||||
-keyout /app/dockerapi_key.pem \
|
||||
-out /app/dockerapi_cert.pem \
|
||||
-subj /CN=dockerapi/O=mailcow \
|
||||
-addext subjectAltName=DNS:dockerapi`
|
||||
|
||||
`uvicorn --host 0.0.0.0 --port 443 --ssl-certfile=/app/dockerapi_cert.pem --ssl-keyfile=/app/dockerapi_key.pem dockerapi:app`
|
|
@ -1,419 +1,623 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from flask import Flask
|
||||
from flask_restful import Resource, Api
|
||||
from flask import jsonify
|
||||
from flask import Response
|
||||
from flask import request
|
||||
from threading import Thread
|
||||
import docker
|
||||
import uuid
|
||||
import signal
|
||||
from fastapi import FastAPI, Response, Request
|
||||
import aiodocker
|
||||
import psutil
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import ssl
|
||||
import socket
|
||||
import subprocess
|
||||
import traceback
|
||||
import json
|
||||
import asyncio
|
||||
import redis
|
||||
from datetime import datetime
|
||||
|
||||
docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
||||
app = Flask(__name__)
|
||||
api = Api(app)
|
||||
|
||||
class containers_get(Resource):
|
||||
def get(self):
|
||||
containers = {}
|
||||
containerIds_to_update = []
|
||||
host_stats_isUpdating = False
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/host/stats")
|
||||
async def get_host_update_stats():
|
||||
global host_stats_isUpdating
|
||||
|
||||
if host_stats_isUpdating == False:
|
||||
print("start host stats task")
|
||||
asyncio.create_task(get_host_stats())
|
||||
host_stats_isUpdating = True
|
||||
|
||||
while True:
|
||||
if redis_client.exists('host_stats'):
|
||||
break
|
||||
print("wait for host_stats results")
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
|
||||
print("host stats pulled")
|
||||
stats = json.loads(redis_client.get('host_stats'))
|
||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||
|
||||
@app.get("/containers/{container_id}/json")
|
||||
async def get_container(container_id : str):
|
||||
if container_id and container_id.isalnum():
|
||||
try:
|
||||
for container in docker_client.containers.list(all=True):
|
||||
containers.update({container.attrs['Id']: container.attrs})
|
||||
return containers
|
||||
for container in (await async_docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
container_info = await container.show()
|
||||
return Response(content=json.dumps(container_info, indent=4), media_type="application/json")
|
||||
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "no container found"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
except Exception as e:
|
||||
return jsonify(type='danger', msg=str(e))
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": str(e)
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "no or invalid id defined"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
class container_get(Resource):
|
||||
def get(self, container_id):
|
||||
if container_id and container_id.isalnum():
|
||||
try:
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
return container.attrs
|
||||
except Exception as e:
|
||||
return jsonify(type='danger', msg=str(e))
|
||||
else:
|
||||
return jsonify(type='danger', msg='no or invalid id defined')
|
||||
@app.get("/containers/json")
|
||||
async def get_containers():
|
||||
containers = {}
|
||||
try:
|
||||
for container in (await async_docker_client.containers.list()):
|
||||
container_info = await container.show()
|
||||
containers.update({container_info['Id']: container_info})
|
||||
return Response(content=json.dumps(containers, indent=4), media_type="application/json")
|
||||
except Exception as e:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": str(e)
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
class container_post(Resource):
|
||||
def post(self, container_id, post_action):
|
||||
if container_id and container_id.isalnum() and post_action:
|
||||
try:
|
||||
"""Dispatch container_post api call"""
|
||||
if post_action == 'exec':
|
||||
if not request.json or not 'cmd' in request.json:
|
||||
return jsonify(type='danger', msg='cmd is missing')
|
||||
if not request.json or not 'task' in request.json:
|
||||
return jsonify(type='danger', msg='task is missing')
|
||||
@app.post("/containers/{container_id}/{post_action}")
|
||||
async def post_containers(container_id : str, post_action : str, request: Request):
|
||||
try :
|
||||
request_json = await request.json()
|
||||
except Exception as err:
|
||||
request_json = {}
|
||||
|
||||
api_call_method_name = '__'.join(['container_post', str(post_action), str(request.json['cmd']), str(request.json['task']) ])
|
||||
else:
|
||||
api_call_method_name = '__'.join(['container_post', str(post_action) ])
|
||||
if container_id and container_id.isalnum() and post_action:
|
||||
try:
|
||||
"""Dispatch container_post api call"""
|
||||
if post_action == 'exec':
|
||||
if not request_json or not 'cmd' in request_json:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "cmd is missing"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
if not request_json or not 'task' in request_json:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "task is missing"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
api_call_method = getattr(self, api_call_method_name, lambda container_id: jsonify(type='danger', msg='container_post - unknown api call'))
|
||||
api_call_method_name = '__'.join(['container_post', str(post_action), str(request_json['cmd']), str(request_json['task']) ])
|
||||
else:
|
||||
api_call_method_name = '__'.join(['container_post', str(post_action) ])
|
||||
|
||||
docker_utils = DockerUtils(async_docker_client)
|
||||
api_call_method = getattr(docker_utils, api_call_method_name, lambda container_id: Response(content=json.dumps({'type': 'danger', 'msg':'container_post - unknown api call' }, indent=4), media_type="application/json"))
|
||||
|
||||
|
||||
print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
|
||||
return api_call_method(container_id)
|
||||
except Exception as e:
|
||||
print("error - container_post: %s" % str(e))
|
||||
return jsonify(type='danger', msg=str(e))
|
||||
print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
|
||||
return await api_call_method(container_id, request_json)
|
||||
except Exception as e:
|
||||
print("error - container_post: %s" % str(e))
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": str(e)
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
else:
|
||||
return jsonify(type='danger', msg='invalid container id or missing action')
|
||||
else:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "invalid container id or missing action"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
@app.post("/container/{container_id}/stats/update")
|
||||
async def post_container_update_stats(container_id : str):
|
||||
global containerIds_to_update
|
||||
|
||||
# start update task for container if no task is running
|
||||
if container_id not in containerIds_to_update:
|
||||
asyncio.create_task(get_container_stats(container_id))
|
||||
containerIds_to_update.append(container_id)
|
||||
|
||||
while True:
|
||||
if redis_client.exists(container_id + '_stats'):
|
||||
break
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
stats = json.loads(redis_client.get(container_id + '_stats'))
|
||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
|
||||
|
||||
class DockerUtils:
|
||||
def __init__(self, docker_client):
|
||||
self.docker_client = docker_client
|
||||
|
||||
# api call: container_post - post_action: stop
|
||||
def container_post__stop(self, container_id):
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
container.stop()
|
||||
return jsonify(type='success', msg='command completed successfully')
|
||||
|
||||
async def container_post__stop(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
await container.stop()
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'command completed successfully'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
# api call: container_post - post_action: start
|
||||
def container_post__start(self, container_id):
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
container.start()
|
||||
return jsonify(type='success', msg='command completed successfully')
|
||||
async def container_post__start(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
await container.start()
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'command completed successfully'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
# api call: container_post - post_action: restart
|
||||
def container_post__restart(self, container_id):
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
container.restart()
|
||||
return jsonify(type='success', msg='command completed successfully')
|
||||
async def container_post__restart(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
await container.restart()
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'command completed successfully'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
# api call: container_post - post_action: top
|
||||
def container_post__top(self, container_id):
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
return jsonify(type='success', msg=container.top())
|
||||
async def container_post__top(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
ps_exec = await container.exec("ps")
|
||||
async with ps_exec.start(detach=False) as stream:
|
||||
ps_return = await stream.read_out()
|
||||
|
||||
|
||||
# api call: container_post - post_action: stats
|
||||
def container_post__stats(self, container_id):
|
||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||
for stat in container.stats(decode=True, stream=True):
|
||||
return jsonify(type='success', msg=stat )
|
||||
exec_details = await ps_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': ps_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
'type': 'danger',
|
||||
'msg': ''
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: delete
|
||||
def container_post__exec__mailq__delete(self, container_id):
|
||||
if 'items' in request.json:
|
||||
async def container_post__exec__mailq__delete(self, container_id, request_json):
|
||||
if 'items' in request_json:
|
||||
r = re.compile("^[0-9a-fA-F]+$")
|
||||
filtered_qids = filter(r.match, request.json['items'])
|
||||
filtered_qids = filter(r.match, request_json['items'])
|
||||
if filtered_qids:
|
||||
flagged_qids = ['-d %s' % i for i in filtered_qids]
|
||||
sanitized_string = str(' '.join(flagged_qids));
|
||||
sanitized_string = str(' '.join(flagged_qids))
|
||||
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return exec_run_handler('generic', postsuper_r)
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return await exec_run_handler('generic', postsuper_r_exec)
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: hold
|
||||
def container_post__exec__mailq__hold(self, container_id):
|
||||
if 'items' in request.json:
|
||||
async def container_post__exec__mailq__hold(self, container_id, request_json):
|
||||
if 'items' in request_json:
|
||||
r = re.compile("^[0-9a-fA-F]+$")
|
||||
filtered_qids = filter(r.match, request.json['items'])
|
||||
filtered_qids = filter(r.match, request_json['items'])
|
||||
if filtered_qids:
|
||||
flagged_qids = ['-h %s' % i for i in filtered_qids]
|
||||
sanitized_string = str(' '.join(flagged_qids));
|
||||
sanitized_string = str(' '.join(flagged_qids))
|
||||
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return exec_run_handler('generic', postsuper_r)
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return await exec_run_handler('generic', postsuper_r_exec)
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: cat
|
||||
def container_post__exec__mailq__cat(self, container_id):
|
||||
if 'items' in request.json:
|
||||
async def container_post__exec__mailq__cat(self, container_id, request_json):
|
||||
if 'items' in request_json:
|
||||
r = re.compile("^[0-9a-fA-F]+$")
|
||||
filtered_qids = filter(r.match, request.json['items'])
|
||||
filtered_qids = filter(r.match, request_json['items'])
|
||||
if filtered_qids:
|
||||
sanitized_string = str(' '.join(filtered_qids));
|
||||
sanitized_string = str(' '.join(filtered_qids))
|
||||
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postcat_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
|
||||
if not postcat_return:
|
||||
postcat_return = 'err: invalid'
|
||||
return exec_run_handler('utf8_text_only', postcat_return)
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postcat_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
|
||||
return await exec_run_handler('utf8_text_only', postcat_exec)
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: unhold
|
||||
def container_post__exec__mailq__unhold(self, container_id):
|
||||
if 'items' in request.json:
|
||||
async def container_post__exec__mailq__unhold(self, container_id, request_json):
|
||||
if 'items' in request_json:
|
||||
r = re.compile("^[0-9a-fA-F]+$")
|
||||
filtered_qids = filter(r.match, request.json['items'])
|
||||
filtered_qids = filter(r.match, request_json['items'])
|
||||
if filtered_qids:
|
||||
flagged_qids = ['-H %s' % i for i in filtered_qids]
|
||||
sanitized_string = str(' '.join(flagged_qids));
|
||||
sanitized_string = str(' '.join(flagged_qids))
|
||||
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return exec_run_handler('generic', postsuper_r)
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||
return await exec_run_handler('generic', postsuper_r_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: deliver
|
||||
def container_post__exec__mailq__deliver(self, container_id):
|
||||
if 'items' in request.json:
|
||||
async def container_post__exec__mailq__deliver(self, container_id, request_json):
|
||||
if 'items' in request_json:
|
||||
r = re.compile("^[0-9a-fA-F]+$")
|
||||
filtered_qids = filter(r.match, request.json['items'])
|
||||
filtered_qids = filter(r.match, request_json['items'])
|
||||
if filtered_qids:
|
||||
flagged_qids = ['-i %s' % i for i in filtered_qids]
|
||||
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
for i in flagged_qids:
|
||||
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
|
||||
# todo: check each exit code
|
||||
return jsonify(type='success', msg=str("Scheduled immediate delivery"))
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
for i in flagged_qids:
|
||||
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
|
||||
async with postsuper_r_exec.start(detach=False) as stream:
|
||||
postsuper_r_return = await stream.read_out()
|
||||
# todo: check each exit code
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'Scheduled immediate delivery'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: list
|
||||
def container_post__exec__mailq__list(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix')
|
||||
return exec_run_handler('utf8_text_only', mailq_return)
|
||||
async def container_post__exec__mailq__list(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
mailq_exec = await container.exec(["/usr/sbin/postqueue", "-j"], user='postfix')
|
||||
return await exec_run_handler('utf8_text_only', mailq_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: flush
|
||||
def container_post__exec__mailq__flush(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix')
|
||||
return exec_run_handler('generic', postqueue_r)
|
||||
async def container_post__exec__mailq__flush(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postsuper_r_exec = await container.exec(["/usr/sbin/postqueue", "-f"], user='postfix')
|
||||
return await exec_run_handler('generic', postsuper_r_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: mailq - task: super_delete
|
||||
def container_post__exec__mailq__super_delete(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"])
|
||||
return exec_run_handler('generic', postsuper_r)
|
||||
async def container_post__exec__mailq__super_delete(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
postsuper_r_exec = await container.exec(["/usr/sbin/postsuper", "-d", "ALL"])
|
||||
return await exec_run_handler('generic', postsuper_r_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: system - task: fts_rescan
|
||||
def container_post__exec__system__fts_rescan(self, container_id):
|
||||
if 'username' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request.json['username'].replace("'", "'\\''") + "'"], user='vmail')
|
||||
if rescan_return.exit_code == 0:
|
||||
return jsonify(type='success', msg='fts_rescan: rescan triggered')
|
||||
else:
|
||||
return jsonify(type='warning', msg='fts_rescan error')
|
||||
async def container_post__exec__system__fts_rescan(self, container_id, request_json):
|
||||
if 'username' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
rescan_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request_json['username'].replace("'", "'\\''") + "'"], user='vmail')
|
||||
async with rescan_exec.start(detach=False) as stream:
|
||||
rescan_return = await stream.read_out()
|
||||
|
||||
if 'all' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
|
||||
if rescan_return.exit_code == 0:
|
||||
return jsonify(type='success', msg='fts_rescan: rescan triggered')
|
||||
else:
|
||||
return jsonify(type='warning', msg='fts_rescan error')
|
||||
exec_details = await rescan_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'fts_rescan: rescan triggered'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
'type': 'warning',
|
||||
'msg': 'fts_rescan error'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
if 'all' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
rescan_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
|
||||
async with rescan_exec.start(detach=False) as stream:
|
||||
rescan_return = await stream.read_out()
|
||||
|
||||
exec_details = await rescan_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'fts_rescan: rescan triggered'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
'type': 'warning',
|
||||
'msg': 'fts_rescan error'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: system - task: df
|
||||
def container_post__exec__system__df(self, container_id):
|
||||
if 'dir' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
df_return = container.exec_run(["/bin/bash", "-c", "/bin/df -H '" + request.json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
|
||||
if df_return.exit_code == 0:
|
||||
return df_return.output.decode('utf-8').rstrip()
|
||||
else:
|
||||
return "0,0,0,0,0,0"
|
||||
async def container_post__exec__system__df(self, container_id, request_json):
|
||||
if 'dir' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
df_exec = await container.exec(["/bin/bash", "-c", "/bin/df -H '" + request_json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
|
||||
async with df_exec.start(detach=False) as stream:
|
||||
df_return = await stream.read_out()
|
||||
|
||||
print(df_return)
|
||||
print(await df_exec.inspect())
|
||||
exec_details = await df_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
return df_return.data.decode('utf-8').rstrip()
|
||||
else:
|
||||
return "0,0,0,0,0,0"
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
|
||||
def container_post__exec__system__mysql_upgrade(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
|
||||
if sql_return.exit_code == 0:
|
||||
matched = False
|
||||
for line in sql_return.output.decode('utf-8').split("\n"):
|
||||
if 'is already upgraded to' in line:
|
||||
matched = True
|
||||
if matched:
|
||||
return jsonify(type='success', msg='mysql_upgrade: already upgraded', text=sql_return.output.decode('utf-8'))
|
||||
async def container_post__exec__system__mysql_upgrade(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
sql_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
|
||||
async with sql_exec.start(detach=False) as stream:
|
||||
sql_return = await stream.read_out()
|
||||
|
||||
exec_details = await sql_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
matched = False
|
||||
for line in sql_return.data.decode('utf-8').split("\n"):
|
||||
if 'is already upgraded to' in line:
|
||||
matched = True
|
||||
if matched:
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'mysql_upgrade: already upgraded',
|
||||
'text': sql_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
await container.restart()
|
||||
res = {
|
||||
'type': 'warning',
|
||||
'msg': 'mysql_upgrade: upgrade was applied',
|
||||
'text': sql_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
container.restart()
|
||||
return jsonify(type='warning', msg='mysql_upgrade: upgrade was applied', text=sql_return.output.decode('utf-8'))
|
||||
else:
|
||||
return jsonify(type='error', msg='mysql_upgrade: error running command', text=sql_return.output.decode('utf-8'))
|
||||
res = {
|
||||
'type': 'error',
|
||||
'msg': 'mysql_upgrade: error running command',
|
||||
'text': sql_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
|
||||
def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
|
||||
if sql_return.exit_code == 0:
|
||||
return jsonify(type='info', msg='mysql_tzinfo_to_sql: command completed successfully', text=sql_return.output.decode('utf-8'))
|
||||
else:
|
||||
return jsonify(type='error', msg='mysql_tzinfo_to_sql: error running command', text=sql_return.output.decode('utf-8'))
|
||||
async def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
sql_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
|
||||
async with sql_exec.start(detach=False) as stream:
|
||||
sql_return = await stream.read_out()
|
||||
|
||||
exec_details = await sql_exec.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
res = {
|
||||
'type': 'info',
|
||||
'msg': 'mysql_tzinfo_to_sql: command completed successfully',
|
||||
'text': sql_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
'type': 'error',
|
||||
'msg': 'mysql_tzinfo_to_sql: error running command',
|
||||
'text': sql_return.data.decode('utf-8')
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: reload - task: dovecot
|
||||
def container_post__exec__reload__dovecot(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
|
||||
return exec_run_handler('generic', reload_return)
|
||||
async def container_post__exec__reload__dovecot(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
reload_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
|
||||
return await exec_run_handler('generic', reload_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: reload - task: postfix
|
||||
def container_post__exec__reload__postfix(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
|
||||
return exec_run_handler('generic', reload_return)
|
||||
async def container_post__exec__reload__postfix(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
reload_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
|
||||
return await exec_run_handler('generic', reload_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: reload - task: nginx
|
||||
def container_post__exec__reload__nginx(self, container_id):
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
reload_return = container.exec_run(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
|
||||
return exec_run_handler('generic', reload_return)
|
||||
async def container_post__exec__reload__nginx(self, container_id, request_json):
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
reload_exec = await container.exec(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
|
||||
return await exec_run_handler('generic', reload_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: sieve - task: list
|
||||
def container_post__exec__sieve__list(self, container_id):
|
||||
if 'username' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"])
|
||||
return exec_run_handler('utf8_text_only', sieve_return)
|
||||
async def container_post__exec__sieve__list(self, container_id, request_json):
|
||||
if 'username' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
sieve_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request_json['username'].replace("'", "'\\''") + "'"])
|
||||
return await exec_run_handler('utf8_text_only', sieve_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: sieve - task: print
|
||||
def container_post__exec__sieve__print(self, container_id):
|
||||
if 'username' in request.json and 'script_name' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]
|
||||
sieve_return = container.exec_run(cmd)
|
||||
return exec_run_handler('utf8_text_only', sieve_return)
|
||||
async def container_post__exec__sieve__print(self, container_id, request_json):
|
||||
if 'username' in request_json and 'script_name' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
|
||||
sieve_exec = await container.exec(cmd)
|
||||
return await exec_run_handler('utf8_text_only', sieve_exec)
|
||||
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: maildir - task: cleanup
|
||||
def container_post__exec__maildir__cleanup(self, container_id):
|
||||
if 'maildir' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
sane_name = re.sub(r'\W+', '', request.json['maildir'])
|
||||
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
|
||||
maildir_cleanup = container.exec_run(cmd, user='vmail')
|
||||
return exec_run_handler('generic', maildir_cleanup)
|
||||
|
||||
|
||||
async def container_post__exec__maildir__cleanup(self, container_id, request_json):
|
||||
if 'maildir' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
sane_name = re.sub(r'\W+', '', request_json['maildir'])
|
||||
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
|
||||
maildir_cleanup_exec = await container.exec(cmd, user='vmail')
|
||||
return await exec_run_handler('generic', maildir_cleanup_exec)
|
||||
|
||||
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
|
||||
def container_post__exec__rspamd__worker_password(self, container_id):
|
||||
if 'raw' in request.json:
|
||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
||||
cmd = "/usr/bin/rspamadm pw -e -p '" + request.json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
|
||||
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
|
||||
matched = False
|
||||
for line in cmd_response.split("\n"):
|
||||
if '$2$' in line:
|
||||
hash = line.strip()
|
||||
hash_out = re.search('\$2\$.+$', hash).group(0)
|
||||
rspamd_passphrase_hash = re.sub('[^0-9a-zA-Z\$]+', '', hash_out.rstrip())
|
||||
async def container_post__exec__rspamd__worker_password(self, container_id, request_json):
|
||||
if 'raw' in request_json:
|
||||
for container in (await self.docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
|
||||
cmd = "./set_worker_password.sh '" + request_json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
|
||||
rspamd_password_exec = await container.exec(cmd, user='_rspamd')
|
||||
async with rspamd_password_exec.start(detach=False) as stream:
|
||||
rspamd_password_return = await stream.read_out()
|
||||
|
||||
rspamd_password_filename = "/etc/rspamd/override.d/worker-controller-password.inc"
|
||||
cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename)
|
||||
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
|
||||
matched = False
|
||||
if "OK" in rspamd_password_return.data.decode('utf-8'):
|
||||
matched = True
|
||||
await container.restart()
|
||||
|
||||
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
|
||||
container.restart()
|
||||
matched = True
|
||||
if matched:
|
||||
res = {
|
||||
'type': 'success',
|
||||
'msg': 'command completed successfully'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
res = {
|
||||
'type': 'danger',
|
||||
'msg': 'command did not complete'
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
|
||||
if matched:
|
||||
return jsonify(type='success', msg='command completed successfully')
|
||||
else:
|
||||
return jsonify(type='danger', msg='command did not complete')
|
||||
|
||||
def exec_cmd_container(container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
|
||||
|
||||
def recv_socket_data(c_socket, timeout):
|
||||
c_socket.setblocking(0)
|
||||
total_data=[];
|
||||
data='';
|
||||
begin=time.time()
|
||||
while True:
|
||||
if total_data and time.time()-begin > timeout:
|
||||
break
|
||||
elif time.time()-begin > timeout*2:
|
||||
break
|
||||
try:
|
||||
data = c_socket.recv(8192)
|
||||
if data:
|
||||
total_data.append(data.decode('utf-8'))
|
||||
#change the beginning time for measurement
|
||||
begin=time.time()
|
||||
else:
|
||||
#sleep for sometime to indicate a gap
|
||||
time.sleep(0.1)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
return ''.join(total_data)
|
||||
async def exec_run_handler(type, exec_obj):
|
||||
async with exec_obj.start(detach=False) as stream:
|
||||
exec_return = await stream.read_out()
|
||||
|
||||
try :
|
||||
socket = container.exec_run([shell_cmd], stdin=True, socket=True, user=user).output._sock
|
||||
if not cmd.endswith("\n"):
|
||||
cmd = cmd + "\n"
|
||||
socket.send(cmd.encode('utf-8'))
|
||||
data = recv_socket_data(socket, timeout)
|
||||
socket.close()
|
||||
return data
|
||||
if exec_return == None:
|
||||
exec_return = ""
|
||||
else:
|
||||
exec_return = exec_return.data.decode('utf-8')
|
||||
|
||||
except Exception as e:
|
||||
print("error - exec_cmd_container: %s" % str(e))
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
|
||||
def exec_run_handler(type, output):
|
||||
if type == 'generic':
|
||||
if output.exit_code == 0:
|
||||
return jsonify(type='success', msg='command completed successfully')
|
||||
if type == 'generic':
|
||||
exec_details = await exec_obj.inspect()
|
||||
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||
res = {
|
||||
"type": "success",
|
||||
"msg": "command completed successfully"
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
else:
|
||||
return jsonify(type='danger', msg='command failed: ' + output.output.decode('utf-8'))
|
||||
res = {
|
||||
"type": "success",
|
||||
"msg": "'command failed: " + exec_return
|
||||
}
|
||||
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||
if type == 'utf8_text_only':
|
||||
r = Response(response=output.output.decode('utf-8'), status=200, mimetype="text/plain")
|
||||
r.headers["Content-Type"] = "text/plain; charset=utf-8"
|
||||
return r
|
||||
return Response(content=exec_return, media_type="text/plain")
|
||||
|
||||
class GracefulKiller:
|
||||
kill_now = False
|
||||
def __init__(self):
|
||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||
signal.signal(signal.SIGTERM, self.exit_gracefully)
|
||||
async def get_host_stats(wait=5):
|
||||
global host_stats_isUpdating
|
||||
|
||||
def exit_gracefully(self, signum, frame):
|
||||
self.kill_now = True
|
||||
|
||||
def create_self_signed_cert():
|
||||
process = subprocess.Popen(
|
||||
"openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout /app/dockerapi_key.pem -out /app/dockerapi_cert.pem -subj /CN=dockerapi/O=mailcow -addext subjectAltName=DNS:dockerapi".split(),
|
||||
stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=False
|
||||
)
|
||||
process.wait()
|
||||
|
||||
def startFlaskAPI():
|
||||
create_self_signed_cert()
|
||||
try:
|
||||
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
ctx.check_hostname = False
|
||||
ctx.load_cert_chain(certfile='/app/dockerapi_cert.pem', keyfile='/app/dockerapi_key.pem')
|
||||
except:
|
||||
print ("Cannot initialize TLS, retrying in 5s...")
|
||||
time.sleep(5)
|
||||
app.run(debug=False, host='0.0.0.0', port=443, threaded=True, ssl_context=ctx)
|
||||
system_time = datetime.now()
|
||||
host_stats = {
|
||||
"cpu": {
|
||||
"cores": psutil.cpu_count(),
|
||||
"usage": psutil.cpu_percent()
|
||||
},
|
||||
"memory": {
|
||||
"total": psutil.virtual_memory().total,
|
||||
"usage": psutil.virtual_memory().percent,
|
||||
"swap": psutil.swap_memory()
|
||||
},
|
||||
"uptime": time.time() - psutil.boot_time(),
|
||||
"system_time": system_time.strftime("%d.%m.%Y %H:%M:%S")
|
||||
}
|
||||
|
||||
api.add_resource(containers_get, '/containers/json')
|
||||
api.add_resource(container_get, '/containers/<string:container_id>/json')
|
||||
api.add_resource(container_post, '/containers/<string:container_id>/<string:post_action>')
|
||||
redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||
except Exception as e:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": str(e)
|
||||
}
|
||||
print(json.dumps(res, indent=4))
|
||||
|
||||
if __name__ == '__main__':
|
||||
api_thread = Thread(target=startFlaskAPI)
|
||||
api_thread.daemon = True
|
||||
api_thread.start()
|
||||
killer = GracefulKiller()
|
||||
while True:
|
||||
time.sleep(1)
|
||||
if killer.kill_now:
|
||||
break
|
||||
print ("Stopping dockerapi-mailcow")
|
||||
await asyncio.sleep(wait)
|
||||
host_stats_isUpdating = False
|
||||
|
||||
|
||||
async def get_container_stats(container_id, wait=5, stop=False):
|
||||
global containerIds_to_update
|
||||
|
||||
if container_id and container_id.isalnum():
|
||||
try:
|
||||
for container in (await async_docker_client.containers.list()):
|
||||
if container._id == container_id:
|
||||
res = await container.stats(stream=False)
|
||||
|
||||
if redis_client.exists(container_id + '_stats'):
|
||||
stats = json.loads(redis_client.get(container_id + '_stats'))
|
||||
else:
|
||||
stats = []
|
||||
stats.append(res[0])
|
||||
if len(stats) > 3:
|
||||
del stats[0]
|
||||
redis_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
||||
except Exception as e:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": str(e)
|
||||
}
|
||||
print(json.dumps(res, indent=4))
|
||||
else:
|
||||
res = {
|
||||
"type": "danger",
|
||||
"msg": "no or invalid id defined"
|
||||
}
|
||||
print(json.dumps(res, indent=4))
|
||||
|
||||
await asyncio.sleep(wait)
|
||||
if stop == True:
|
||||
# update task was called second time, stop
|
||||
containerIds_to_update.remove(container_id)
|
||||
else:
|
||||
# call update task a second time
|
||||
await get_container_stats(container_id, wait=0, stop=True)
|
||||
|
||||
|
||||
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
||||
redis_client = redis.Redis(host=os.environ['REDIS_SLAVEOF_IP'], port=os.environ['REDIS_SLAVEOF_PORT'], db=0)
|
||||
else:
|
||||
redis_client = redis.Redis(host='redis-mailcow', port=6379, db=0)
|
||||
|
||||
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
||||
|
|
|
@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y \
|
|||
|
||||
COPY settings.conf /etc/rspamd/settings.conf
|
||||
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
|
||||
COPY set_worker_password.sh /set_worker_password.sh
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
password_file='/etc/rspamd/override.d/worker-controller-password.inc'
|
||||
password_hash=`/usr/bin/rspamadm pw -e -p $1`
|
||||
|
||||
echo 'enable_password = "'$password_hash'";' > $password_file
|
||||
|
||||
if grep -q "$password_hash" "$password_file"; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "ERROR"
|
||||
fi
|
|
@ -83,7 +83,6 @@ foreach ($RSPAMD_MAPS['regex'] as $rspamd_regex_desc => $rspamd_regex_map) {
|
|||
];
|
||||
}
|
||||
|
||||
|
||||
$template = 'admin.twig';
|
||||
$template_data = [
|
||||
'tfa_data' => $tfa_data,
|
||||
|
@ -91,7 +90,6 @@ $template_data = [
|
|||
'fido2_cid' => @$_SESSION['fido2_cid'],
|
||||
'fido2_data' => $fido2_data,
|
||||
'gal' => @$_SESSION['gal'],
|
||||
'license_guid' => license('guid'),
|
||||
'api' => [
|
||||
'ro' => admin_api('ro', 'get'),
|
||||
'rw' => admin_api('rw', 'get'),
|
||||
|
@ -112,6 +110,7 @@ $template_data = [
|
|||
'password_complexity' => password_complexity('get'),
|
||||
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
||||
'lang_admin' => json_encode($lang['admin']),
|
||||
'lang_datatables' => json_encode($lang['datatables'])
|
||||
];
|
||||
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-collapse.collapse{display:none!important}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
|
||||
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
|
|
@ -0,0 +1,487 @@
|
|||
/*!
|
||||
* Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
|
||||
*
|
||||
* Copyright 2012-2021 SnapAppointments, LLC
|
||||
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
@-webkit-keyframes bs-notify-fadeOut {
|
||||
0% {
|
||||
opacity: 0.9;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-o-keyframes bs-notify-fadeOut {
|
||||
0% {
|
||||
opacity: 0.9;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes bs-notify-fadeOut {
|
||||
0% {
|
||||
opacity: 0.9;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
select.bs-select-hidden,
|
||||
.bootstrap-select > select.bs-select-hidden,
|
||||
select.selectpicker {
|
||||
display: none !important;
|
||||
}
|
||||
.bootstrap-select {
|
||||
width: 220px \0;
|
||||
/*IE9 and below*/
|
||||
vertical-align: middle;
|
||||
}
|
||||
.bootstrap-select > .dropdown-toggle {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.bootstrap-select > .dropdown-toggle:after {
|
||||
margin-top: -1px;
|
||||
}
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder:active {
|
||||
color: #999;
|
||||
}
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:hover,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:focus,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:active,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:active,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:active,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:active,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:active,
|
||||
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:active {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.bootstrap-select > select {
|
||||
position: absolute !important;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
display: block !important;
|
||||
width: 0.5px !important;
|
||||
height: 100% !important;
|
||||
padding: 0 !important;
|
||||
opacity: 0 !important;
|
||||
border: none;
|
||||
z-index: 0 !important;
|
||||
}
|
||||
.bootstrap-select > select.mobile-device {
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
z-index: 2 !important;
|
||||
}
|
||||
.has-error .bootstrap-select .dropdown-toggle,
|
||||
.error .bootstrap-select .dropdown-toggle,
|
||||
.bootstrap-select.is-invalid .dropdown-toggle,
|
||||
.was-validated .bootstrap-select select:invalid + .dropdown-toggle {
|
||||
border-color: #b94a48;
|
||||
}
|
||||
.bootstrap-select.is-valid .dropdown-toggle,
|
||||
.was-validated .bootstrap-select select:valid + .dropdown-toggle {
|
||||
border-color: #28a745;
|
||||
}
|
||||
.bootstrap-select.fit-width {
|
||||
width: auto !important;
|
||||
}
|
||||
.bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) {
|
||||
width: 220px;
|
||||
}
|
||||
.bootstrap-select > select.mobile-device:focus + .dropdown-toggle,
|
||||
.bootstrap-select .dropdown-toggle:focus {
|
||||
outline: thin dotted #333333 !important;
|
||||
outline: 5px auto -webkit-focus-ring-color !important;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
.bootstrap-select.form-control {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
height: auto;
|
||||
}
|
||||
:not(.input-group) > .bootstrap-select.form-control:not([class*="col-"]) {
|
||||
width: 100%;
|
||||
}
|
||||
.bootstrap-select.form-control.input-group-btn {
|
||||
float: none;
|
||||
z-index: auto;
|
||||
}
|
||||
.form-inline .bootstrap-select,
|
||||
.form-inline .bootstrap-select.form-control:not([class*="col-"]) {
|
||||
width: auto;
|
||||
}
|
||||
.bootstrap-select:not(.input-group-btn),
|
||||
.bootstrap-select[class*="col-"] {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-left: 0;
|
||||
}
|
||||
.bootstrap-select.dropdown-menu-right,
|
||||
.bootstrap-select[class*="col-"].dropdown-menu-right,
|
||||
.row .bootstrap-select[class*="col-"].dropdown-menu-right {
|
||||
float: right;
|
||||
}
|
||||
.form-inline .bootstrap-select,
|
||||
.form-horizontal .bootstrap-select,
|
||||
.form-group .bootstrap-select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.form-group-lg .bootstrap-select.form-control,
|
||||
.form-group-sm .bootstrap-select.form-control {
|
||||
padding: 0;
|
||||
}
|
||||
.form-group-lg .bootstrap-select.form-control .dropdown-toggle,
|
||||
.form-group-sm .bootstrap-select.form-control .dropdown-toggle {
|
||||
height: 100%;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
border-radius: inherit;
|
||||
}
|
||||
.bootstrap-select.form-control-sm .dropdown-toggle,
|
||||
.bootstrap-select.form-control-lg .dropdown-toggle {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
border-radius: inherit;
|
||||
}
|
||||
.bootstrap-select.form-control-sm .dropdown-toggle {
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
.bootstrap-select.form-control-lg .dropdown-toggle {
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.form-inline .bootstrap-select .form-control {
|
||||
width: 100%;
|
||||
}
|
||||
.bootstrap-select.disabled,
|
||||
.bootstrap-select > .disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.bootstrap-select.disabled:focus,
|
||||
.bootstrap-select > .disabled:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.bootstrap-select.bs-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.bootstrap-select.bs-container .dropdown-menu {
|
||||
z-index: 1060;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .filter-option {
|
||||
position: static;
|
||||
top: 0;
|
||||
left: 0;
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
-webkit-box-flex: 0;
|
||||
-webkit-flex: 0 1 auto;
|
||||
-ms-flex: 0 1 auto;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
.bs3.bootstrap-select .dropdown-toggle .filter-option {
|
||||
padding-right: inherit;
|
||||
}
|
||||
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option {
|
||||
position: absolute;
|
||||
padding-top: inherit;
|
||||
padding-bottom: inherit;
|
||||
padding-left: inherit;
|
||||
float: none;
|
||||
}
|
||||
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner {
|
||||
padding-right: inherit;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .filter-option-inner-inner {
|
||||
overflow: hidden;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .filter-expand {
|
||||
width: 0 !important;
|
||||
float: left;
|
||||
opacity: 0 !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .caret {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 12px;
|
||||
margin-top: -2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-right: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
|
||||
padding-right: inherit;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
|
||||
position: relative;
|
||||
top: -webkit-calc(((-1em / 1.5) + 1ex) / 2);
|
||||
top: calc(((-1em / 1.5) + 1ex) / 2);
|
||||
pointer-events: none;
|
||||
}
|
||||
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
|
||||
top: auto;
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle.bs-placeholder .bs-select-clear-selected {
|
||||
display: none;
|
||||
}
|
||||
.input-group .bootstrap-select.form-control .dropdown-toggle {
|
||||
border-radius: inherit;
|
||||
}
|
||||
.bootstrap-select[class*="col-"] .dropdown-toggle {
|
||||
width: 100%;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu {
|
||||
min-width: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu > .inner:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu.inner {
|
||||
position: static;
|
||||
float: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li {
|
||||
position: relative;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li.active small {
|
||||
color: rgba(255, 255, 255, 0.5) !important;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li.disabled a {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li a {
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li a.opt {
|
||||
position: relative;
|
||||
padding-left: 2.25em;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li a span.check-mark {
|
||||
display: none;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li a span.text {
|
||||
display: inline-block;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu li small {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu .notify {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
width: 96%;
|
||||
margin: 0 2%;
|
||||
min-height: 26px;
|
||||
padding: 3px 5px;
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #e3e3e3;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
pointer-events: none;
|
||||
opacity: 0.9;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.bootstrap-select .dropdown-menu .notify.fadeOut {
|
||||
-webkit-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||
-o-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||
animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||
}
|
||||
.bootstrap-select .no-results {
|
||||
padding: 3px;
|
||||
background: #f5f5f5;
|
||||
margin: 0 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.bootstrap-select.fit-width .dropdown-toggle .filter-option {
|
||||
position: static;
|
||||
display: inline;
|
||||
padding: 0;
|
||||
}
|
||||
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner,
|
||||
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner {
|
||||
display: inline;
|
||||
}
|
||||
.bootstrap-select.fit-width .dropdown-toggle .bs-caret:before {
|
||||
content: '\00a0';
|
||||
}
|
||||
.bootstrap-select.fit-width .dropdown-toggle .caret {
|
||||
position: static;
|
||||
top: auto;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
right: 15px;
|
||||
top: 5px;
|
||||
}
|
||||
.bootstrap-select.show-tick .dropdown-menu li a span.text {
|
||||
margin-right: 34px;
|
||||
}
|
||||
.bootstrap-select .bs-ok-default:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 0.5em;
|
||||
height: 1em;
|
||||
border-style: solid;
|
||||
border-width: 0 0.26em 0.26em 0;
|
||||
-webkit-transform-style: preserve-3d;
|
||||
transform-style: preserve-3d;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle,
|
||||
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle {
|
||||
z-index: 1061;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before {
|
||||
content: '';
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid rgba(204, 204, 204, 0.2);
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 9px;
|
||||
display: none;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after {
|
||||
content: '';
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid white;
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 10px;
|
||||
display: none;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before {
|
||||
bottom: auto;
|
||||
top: -4px;
|
||||
border-top: 7px solid rgba(204, 204, 204, 0.2);
|
||||
border-bottom: 0;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after {
|
||||
bottom: auto;
|
||||
top: -4px;
|
||||
border-top: 6px solid white;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before {
|
||||
right: 12px;
|
||||
left: auto;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after {
|
||||
right: 13px;
|
||||
left: auto;
|
||||
}
|
||||
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:before,
|
||||
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:before,
|
||||
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:after,
|
||||
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:after {
|
||||
display: block;
|
||||
}
|
||||
.bs-searchbox,
|
||||
.bs-actionsbox,
|
||||
.bs-donebutton {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.bs-actionsbox {
|
||||
width: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.bs-actionsbox .btn-group {
|
||||
display: block;
|
||||
}
|
||||
.bs-actionsbox .btn-group button {
|
||||
width: 50%;
|
||||
}
|
||||
.bs-donebutton {
|
||||
float: left;
|
||||
width: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.bs-donebutton .btn-group {
|
||||
display: block;
|
||||
}
|
||||
.bs-donebutton .btn-group button {
|
||||
width: 100%;
|
||||
}
|
||||
.bs-searchbox + .bs-actionsbox {
|
||||
padding: 0 8px 4px;
|
||||
}
|
||||
.bs-searchbox .form-control {
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
float: none;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-select.css.map */
|
File diff suppressed because one or more lines are too long
|
@ -1,323 +0,0 @@
|
|||
table.footable-details,
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table.footable,
|
||||
table.footable-details {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.footable-hide-fouc {
|
||||
display: none;
|
||||
}
|
||||
table > tbody > tr > td > span.footable-toggle {
|
||||
margin-right: 8px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
table > tbody > tr > td > span.footable-toggle.last-column {
|
||||
margin-left: 8px;
|
||||
float: right;
|
||||
}
|
||||
table.table-condensed > tbody > tr > td > span.footable-toggle {
|
||||
margin-right: 5px;
|
||||
}
|
||||
table.footable-details > tbody > tr > th:nth-child(1) {
|
||||
min-width: 40px;
|
||||
width: 120px;
|
||||
}
|
||||
table.footable-details > tbody > tr > td:nth-child(2) {
|
||||
word-break: break-all;
|
||||
}
|
||||
table.footable-details > tbody > tr:first-child > td,
|
||||
table.footable-details > tbody > tr:first-child > th,
|
||||
table.footable-details > tfoot > tr:first-child > td,
|
||||
table.footable-details > tfoot > tr:first-child > th,
|
||||
table.footable-details > thead > tr:first-child > td,
|
||||
table.footable-details > thead > tr:first-child > th {
|
||||
border-top-width: 0;
|
||||
}
|
||||
table.footable-details.table-bordered > tbody > tr:first-child > td,
|
||||
table.footable-details.table-bordered > tbody > tr:first-child > th,
|
||||
table.footable-details.table-bordered > tfoot > tr:first-child > td,
|
||||
table.footable-details.table-bordered > tfoot > tr:first-child > th,
|
||||
table.footable-details.table-bordered > thead > tr:first-child > td,
|
||||
table.footable-details.table-bordered > thead > tr:first-child > th {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
div.footable-loader {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
div.footable-loader > span.fooicon {
|
||||
display: inline-block;
|
||||
opacity: 0.3;
|
||||
font-size: 30px;
|
||||
line-height: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-top: -16px;
|
||||
margin-left: -16px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-animation: fooicon-spin-r 2s infinite linear;
|
||||
animation: fooicon-spin-r 2s infinite linear;
|
||||
}
|
||||
table.footable > tbody > tr.footable-empty > td {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 30px;
|
||||
}
|
||||
table.footable > tbody > tr > td,
|
||||
table.footable > tbody > tr > th {
|
||||
display: none;
|
||||
}
|
||||
table.footable > tbody > tr.footable-detail-row > td,
|
||||
table.footable > tbody > tr.footable-detail-row > th,
|
||||
table.footable > tbody > tr.footable-empty > td,
|
||||
table.footable > tbody > tr.footable-empty > th {
|
||||
display: table-cell;
|
||||
}
|
||||
@-webkit-keyframes fooicon-spin-r {
|
||||
0% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes fooicon-spin-r {
|
||||
0% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
.fooicon {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
display: inline-block;
|
||||
font-family: "bootstrap-icons" !important;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@-moz-document url-prefix() {
|
||||
.fooicon {
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
.fooicon:after,
|
||||
.fooicon:before {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.fooicon-loader:before {
|
||||
content: "\f130";
|
||||
}
|
||||
.fooicon-plus:before {
|
||||
content: "\f4fd";
|
||||
}
|
||||
.fooicon-minus:before {
|
||||
content: "\f2e9";
|
||||
}
|
||||
.fooicon-search:before {
|
||||
content: "\f52a";
|
||||
}
|
||||
.fooicon-remove:before {
|
||||
content: "\f62a";
|
||||
}
|
||||
.fooicon-sort:before {
|
||||
content: "\f3c6";
|
||||
}
|
||||
.fooicon-sort-asc:before {
|
||||
content: "\f575";
|
||||
}
|
||||
.fooicon-sort-desc:before {
|
||||
content: "\f57b";
|
||||
}
|
||||
.fooicon-pencil:before {
|
||||
content: "\f4c9";
|
||||
}
|
||||
.fooicon-trash:before {
|
||||
content: "\f62a";
|
||||
}
|
||||
.fooicon-eye-close:before {
|
||||
content: "\f33f";
|
||||
}
|
||||
.fooicon-flash:before {
|
||||
content: "\f46e";
|
||||
}
|
||||
.fooicon-cog:before {
|
||||
content: "\f3e2";
|
||||
}
|
||||
.fooicon-stats:before {
|
||||
content: "\f359";
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th {
|
||||
border-bottom-width: 1px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-right,
|
||||
table.footable.footable-filtering-right > thead > tr.footable-filtering > th,
|
||||
table.footable > thead > tr.footable-filtering > th {
|
||||
text-align: right;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-left,
|
||||
table.footable.footable-filtering-left > thead > tr.footable-filtering > th {
|
||||
text-align: left;
|
||||
}
|
||||
.footable-filtering-external.footable-filtering-center,
|
||||
.footable-paging-external.footable-paging-center,
|
||||
table.footable-paging-center > tfoot > tr.footable-paging > td,
|
||||
table.footable.footable-filtering-center > thead > tr.footable-filtering > th,
|
||||
table.footable > tfoot > tr.footable-paging > td {
|
||||
text-align: center;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
|
||||
margin-top: 5px;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
||||
width: 100%;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox,
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox {
|
||||
margin: 0;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox > label,
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox > label {
|
||||
display: block;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox input[type="checkbox"],
|
||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox input[type="checkbox"] {
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
||||
width: auto;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
table.footable > tbody > tr > td.footable-sortable,
|
||||
table.footable > tbody > tr > th.footable-sortable,
|
||||
table.footable > tfoot > tr > td.footable-sortable,
|
||||
table.footable > tfoot > tr > th.footable-sortable,
|
||||
table.footable > thead > tr > td.footable-sortable,
|
||||
table.footable > thead > tr > th.footable-sortable {
|
||||
position: relative;
|
||||
padding-right: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
td.footable-sortable > span.fooicon,
|
||||
th.footable-sortable > span.fooicon {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in;
|
||||
}
|
||||
td.footable-sortable.footable-asc > span.fooicon,
|
||||
td.footable-sortable.footable-desc > span.fooicon,
|
||||
td.footable-sortable:hover > span.fooicon,
|
||||
th.footable-sortable.footable-asc > span.fooicon,
|
||||
th.footable-sortable.footable-desc > span.fooicon,
|
||||
th.footable-sortable:hover > span.fooicon {
|
||||
opacity: 1;
|
||||
}
|
||||
table.footable-sorting-disabled td.footable-sortable.footable-asc > span.fooicon,
|
||||
table.footable-sorting-disabled td.footable-sortable.footable-desc > span.fooicon,
|
||||
table.footable-sorting-disabled td.footable-sortable:hover > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable.footable-asc > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable.footable-desc > span.fooicon,
|
||||
table.footable-sorting-disabled th.footable-sortable:hover > span.fooicon {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.footable-paging-external ul.pagination,
|
||||
table.footable > tfoot > tr.footable-paging > td > ul.pagination {
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
.footable-paging-external span.label,
|
||||
table.footable > tfoot > tr.footable-paging > td > span.label {
|
||||
display: inline-block;
|
||||
margin: 0 0 10px;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
.footable-paging-external.footable-paging-left,
|
||||
table.footable-paging-left > tfoot > tr.footable-paging > td {
|
||||
text-align: left;
|
||||
}
|
||||
.footable-paging-external.footable-paging-right,
|
||||
table.footable-editing-right td.footable-editing,
|
||||
table.footable-editing-right tr.footable-editing,
|
||||
table.footable-paging-right > tfoot > tr.footable-paging > td {
|
||||
text-align: right;
|
||||
}
|
||||
ul.pagination > li.footable-page {
|
||||
display: none;
|
||||
}
|
||||
ul.pagination > li.footable-page.visible {
|
||||
display: inline;
|
||||
}
|
||||
td.footable-editing {
|
||||
width: 90px;
|
||||
max-width: 90px;
|
||||
}
|
||||
table.footable-editing-no-delete td.footable-editing,
|
||||
table.footable-editing-no-edit td.footable-editing,
|
||||
table.footable-editing-no-view td.footable-editing {
|
||||
width: 70px;
|
||||
max-width: 70px;
|
||||
}
|
||||
table.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
|
||||
table.footable-editing-no-edit.footable-editing-no-delete td.footable-editing,
|
||||
table.footable-editing-no-edit.footable-editing-no-view td.footable-editing {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
|
||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view th.footable-editing {
|
||||
width: 0;
|
||||
max-width: 0;
|
||||
display: none !important;
|
||||
}
|
||||
table.footable-editing-left td.footable-editing,
|
||||
table.footable-editing-left tr.footable-editing {
|
||||
text-align: left;
|
||||
}
|
||||
table.footable-editing button.footable-add,
|
||||
table.footable-editing button.footable-hide,
|
||||
table.footable-editing-show button.footable-show,
|
||||
table.footable-editing.footable-editing-always-show button.footable-hide,
|
||||
table.footable-editing.footable-editing-always-show button.footable-show,
|
||||
table.footable-editing.footable-editing-always-show.footable-editing-no-add tr.footable-editing {
|
||||
display: none;
|
||||
}
|
||||
table.footable-editing.footable-editing-always-show button.footable-add,
|
||||
table.footable-editing.footable-editing-show button.footable-add,
|
||||
table.footable-editing.footable-editing-show button.footable-hide {
|
||||
display: inline-block;
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
* This combined file was created by the DataTables downloader builder:
|
||||
* https://datatables.net/download
|
||||
*
|
||||
* To rebuild or modify this file with the latest versions of the included
|
||||
* software please visit:
|
||||
* https://datatables.net/download/#bs5/dt-1.12.0/r-2.3.0/sl-1.4.0
|
||||
*
|
||||
* Included libraries:
|
||||
* DataTables 1.12.0, Responsive 2.3.0, Select 1.4.0
|
||||
*/
|
||||
|
||||
@charset "UTF-8";
|
||||
table.dataTable td.dt-control {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
table.dataTable td.dt-control:before {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
margin-top: -9px;
|
||||
display: inline-block;
|
||||
color: white;
|
||||
border: 0.15em solid white;
|
||||
border-radius: 1em;
|
||||
box-shadow: 0 0 0.2em #444;
|
||||
box-sizing: content-box;
|
||||
text-align: center;
|
||||
text-indent: 0 !important;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
line-height: 1em;
|
||||
content: "+";
|
||||
background-color: #31b131;
|
||||
}
|
||||
table.dataTable tr.dt-hasChild td.dt-control:before {
|
||||
content: "-";
|
||||
background-color: #d33333;
|
||||
}
|
||||
|
||||
table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
|
||||
table.dataTable thead > tr > td.sorting,
|
||||
table.dataTable thead > tr > td.sorting_asc,
|
||||
table.dataTable thead > tr > td.sorting_desc,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-right: 26px;
|
||||
}
|
||||
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:after,
|
||||
table.dataTable thead > tr > td.sorting:before,
|
||||
table.dataTable thead > tr > td.sorting:after,
|
||||
table.dataTable thead > tr > td.sorting_asc:before,
|
||||
table.dataTable thead > tr > td.sorting_asc:after,
|
||||
table.dataTable thead > tr > td.sorting_desc:before,
|
||||
table.dataTable thead > tr > td.sorting_desc:after,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled:before,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled:after,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled:before,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
opacity: 0.125;
|
||||
right: 10px;
|
||||
line-height: 9px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
|
||||
table.dataTable thead > tr > td.sorting:before,
|
||||
table.dataTable thead > tr > td.sorting_asc:before,
|
||||
table.dataTable thead > tr > td.sorting_desc:before,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled:before,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled:before {
|
||||
bottom: 50%;
|
||||
content: "▴";
|
||||
}
|
||||
table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
|
||||
table.dataTable thead > tr > td.sorting:after,
|
||||
table.dataTable thead > tr > td.sorting_asc:after,
|
||||
table.dataTable thead > tr > td.sorting_desc:after,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled:after,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled:after {
|
||||
top: 50%;
|
||||
content: "▾";
|
||||
}
|
||||
table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
|
||||
table.dataTable thead > tr > td.sorting_asc:before,
|
||||
table.dataTable thead > tr > td.sorting_desc:after {
|
||||
opacity: 0.6;
|
||||
}
|
||||
table.dataTable thead > tr > th.sorting_desc_disabled:after, table.dataTable thead > tr > th.sorting_asc_disabled:before,
|
||||
table.dataTable thead > tr > td.sorting_desc_disabled:after,
|
||||
table.dataTable thead > tr > td.sorting_asc_disabled:before {
|
||||
display: none;
|
||||
}
|
||||
table.dataTable thead > tr > th:active,
|
||||
table.dataTable thead > tr > td:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.dataTables_scrollBody table.dataTable thead > tr > th:before, div.dataTables_scrollBody table.dataTable thead > tr > th:after,
|
||||
div.dataTables_scrollBody table.dataTable thead > tr > td:before,
|
||||
div.dataTables_scrollBody table.dataTable thead > tr > td:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
margin-left: -100px;
|
||||
margin-top: -26px;
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
}
|
||||
div.dataTables_processing > div:last-child {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 15px;
|
||||
margin: 1em auto;
|
||||
}
|
||||
div.dataTables_processing > div:last-child > div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border-radius: 50%;
|
||||
background: rgba(13, 110, 253, 0.9);
|
||||
animation-timing-function: cubic-bezier(0, 1, 1, 0);
|
||||
}
|
||||
div.dataTables_processing > div:last-child > div:nth-child(1) {
|
||||
left: 8px;
|
||||
animation: datatables-loader-1 0.6s infinite;
|
||||
}
|
||||
div.dataTables_processing > div:last-child > div:nth-child(2) {
|
||||
left: 8px;
|
||||
animation: datatables-loader-2 0.6s infinite;
|
||||
}
|
||||
div.dataTables_processing > div:last-child > div:nth-child(3) {
|
||||
left: 32px;
|
||||
animation: datatables-loader-2 0.6s infinite;
|
||||
}
|
||||
div.dataTables_processing > div:last-child > div:nth-child(4) {
|
||||
left: 56px;
|
||||
animation: datatables-loader-3 0.6s infinite;
|
||||
}
|
||||
|
||||
@keyframes datatables-loader-1 {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@keyframes datatables-loader-3 {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
@keyframes datatables-loader-2 {
|
||||
0% {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
100% {
|
||||
transform: translate(24px, 0);
|
||||
}
|
||||
}
|
||||
table.dataTable.nowrap th, table.dataTable.nowrap td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable th.dt-left,
|
||||
table.dataTable td.dt-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable th.dt-center,
|
||||
table.dataTable td.dt-center,
|
||||
table.dataTable td.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable th.dt-right,
|
||||
table.dataTable td.dt-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable th.dt-justify,
|
||||
table.dataTable td.dt-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable th.dt-nowrap,
|
||||
table.dataTable td.dt-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable thead th,
|
||||
table.dataTable thead td,
|
||||
table.dataTable tfoot th,
|
||||
table.dataTable tfoot td {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable thead th.dt-head-left,
|
||||
table.dataTable thead td.dt-head-left,
|
||||
table.dataTable tfoot th.dt-head-left,
|
||||
table.dataTable tfoot td.dt-head-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable thead th.dt-head-center,
|
||||
table.dataTable thead td.dt-head-center,
|
||||
table.dataTable tfoot th.dt-head-center,
|
||||
table.dataTable tfoot td.dt-head-center {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable thead th.dt-head-right,
|
||||
table.dataTable thead td.dt-head-right,
|
||||
table.dataTable tfoot th.dt-head-right,
|
||||
table.dataTable tfoot td.dt-head-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable thead th.dt-head-justify,
|
||||
table.dataTable thead td.dt-head-justify,
|
||||
table.dataTable tfoot th.dt-head-justify,
|
||||
table.dataTable tfoot td.dt-head-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable thead th.dt-head-nowrap,
|
||||
table.dataTable thead td.dt-head-nowrap,
|
||||
table.dataTable tfoot th.dt-head-nowrap,
|
||||
table.dataTable tfoot td.dt-head-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-left,
|
||||
table.dataTable tbody td.dt-body-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-center,
|
||||
table.dataTable tbody td.dt-body-center {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-right,
|
||||
table.dataTable tbody td.dt-body-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-justify,
|
||||
table.dataTable tbody td.dt-body-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-nowrap,
|
||||
table.dataTable tbody td.dt-body-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/*! Bootstrap 5 integration for DataTables
|
||||
*
|
||||
* ©2020 SpryMedia Ltd, all rights reserved.
|
||||
* License: MIT datatables.net/license/mit
|
||||
*/
|
||||
table.dataTable {
|
||||
clear: both;
|
||||
margin-top: 6px !important;
|
||||
margin-bottom: 6px !important;
|
||||
max-width: none !important;
|
||||
border-collapse: separate !important;
|
||||
border-spacing: 0;
|
||||
}
|
||||
table.dataTable td,
|
||||
table.dataTable th {
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
table.dataTable td.dataTables_empty,
|
||||
table.dataTable th.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable.nowrap th,
|
||||
table.dataTable.nowrap td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
|
||||
box-shadow: none;
|
||||
}
|
||||
table.dataTable > tbody > tr {
|
||||
background-color: transparent;
|
||||
}
|
||||
table.dataTable > tbody > tr.selected > * {
|
||||
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
|
||||
color: white;
|
||||
}
|
||||
table.dataTable.table-striped > tbody > tr.odd > * {
|
||||
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
table.dataTable.table-striped > tbody > tr.odd.selected > * {
|
||||
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
|
||||
}
|
||||
table.dataTable.table-hover > tbody > tr:hover > * {
|
||||
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
table.dataTable.table-hover > tbody > tr.selected:hover > * {
|
||||
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
|
||||
}
|
||||
|
||||
div.dataTables_wrapper div.dataTables_length label {
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_length select {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_filter {
|
||||
text-align: right;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_filter label {
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_filter input {
|
||||
margin-left: 0.5em;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_info {
|
||||
padding-top: 0.85em;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
||||
margin: 2px 0;
|
||||
white-space: nowrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
div.dataTables_scrollHead table.dataTable {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
div.dataTables_scrollBody > table {
|
||||
border-top: none;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
div.dataTables_scrollBody > table > thead .sorting:before,
|
||||
div.dataTables_scrollBody > table > thead .sorting_asc:before,
|
||||
div.dataTables_scrollBody > table > thead .sorting_desc:before,
|
||||
div.dataTables_scrollBody > table > thead .sorting:after,
|
||||
div.dataTables_scrollBody > table > thead .sorting_asc:after,
|
||||
div.dataTables_scrollBody > table > thead .sorting_desc:after {
|
||||
display: none;
|
||||
}
|
||||
div.dataTables_scrollBody > table > tbody tr:first-child th,
|
||||
div.dataTables_scrollBody > table > tbody tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
div.dataTables_scrollFoot > .dataTables_scrollFootInner {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
|
||||
margin-top: 0 !important;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dataTables_wrapper div.dataTables_length,
|
||||
div.dataTables_wrapper div.dataTables_filter,
|
||||
div.dataTables_wrapper div.dataTables_info,
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
text-align: center;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
|
||||
padding-right: 20px;
|
||||
}
|
||||
table.dataTable.table-sm .sorting:before,
|
||||
table.dataTable.table-sm .sorting_asc:before,
|
||||
table.dataTable.table-sm .sorting_desc:before {
|
||||
top: 5px;
|
||||
right: 0.85em;
|
||||
}
|
||||
table.dataTable.table-sm .sorting:after,
|
||||
table.dataTable.table-sm .sorting_asc:after,
|
||||
table.dataTable.table-sm .sorting_desc:after {
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
table.table-bordered.dataTable {
|
||||
border-right-width: 0;
|
||||
}
|
||||
table.table-bordered.dataTable thead tr:first-child th,
|
||||
table.table-bordered.dataTable thead tr:first-child td {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
table.table-bordered.dataTable th,
|
||||
table.table-bordered.dataTable td {
|
||||
border-left-width: 0;
|
||||
}
|
||||
table.table-bordered.dataTable th:first-child, table.table-bordered.dataTable th:first-child,
|
||||
table.table-bordered.dataTable td:first-child,
|
||||
table.table-bordered.dataTable td:first-child {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,
|
||||
table.table-bordered.dataTable td:last-child,
|
||||
table.table-bordered.dataTable td:last-child {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
table.table-bordered.dataTable th,
|
||||
table.table-bordered.dataTable td {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
div.dataTables_scrollHead table.table-bordered {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
div.table-responsive > div.dataTables_wrapper > div.row {
|
||||
margin: 0;
|
||||
}
|
||||
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
cursor: default !important;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
|
||||
display: none !important;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control {
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before {
|
||||
top: 50%;
|
||||
left: 5px;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
margin-top: -9px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
color: white;
|
||||
border: 0.15em solid white;
|
||||
border-radius: 1em;
|
||||
box-shadow: 0 0 0.2em #444;
|
||||
box-sizing: content-box;
|
||||
text-align: center;
|
||||
text-indent: 0 !important;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
line-height: 1em;
|
||||
content: "+";
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td.dtr-control:before,
|
||||
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th.dtr-control:before {
|
||||
content: "-";
|
||||
background-color: #d33333;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control,
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control {
|
||||
padding-left: 27px;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control:before,
|
||||
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control:before {
|
||||
left: 4px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 14px;
|
||||
line-height: 14px;
|
||||
text-indent: 3px;
|
||||
}
|
||||
table.dataTable.dtr-column > tbody > tr > td.dtr-control,
|
||||
table.dataTable.dtr-column > tbody > tr > th.dtr-control,
|
||||
table.dataTable.dtr-column > tbody > tr > td.control,
|
||||
table.dataTable.dtr-column > tbody > tr > th.control {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
table.dataTable.dtr-column > tbody > tr > td.dtr-control:before,
|
||||
table.dataTable.dtr-column > tbody > tr > th.dtr-control:before,
|
||||
table.dataTable.dtr-column > tbody > tr > td.control:before,
|
||||
table.dataTable.dtr-column > tbody > tr > th.control:before {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 0.8em;
|
||||
width: 0.8em;
|
||||
margin-top: -0.5em;
|
||||
margin-left: -0.5em;
|
||||
display: block;
|
||||
position: absolute;
|
||||
color: white;
|
||||
border: 0.15em solid white;
|
||||
border-radius: 1em;
|
||||
box-shadow: 0 0 0.2em #444;
|
||||
box-sizing: content-box;
|
||||
text-align: center;
|
||||
text-indent: 0 !important;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
line-height: 1em;
|
||||
content: "+";
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before,
|
||||
table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before,
|
||||
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
|
||||
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
|
||||
content: "-";
|
||||
background-color: #d33333;
|
||||
}
|
||||
table.dataTable > tbody > tr.child {
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
table.dataTable > tbody > tr.child:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul.dtr-details {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li {
|
||||
border-bottom: 1px solid #efefef;
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
table.dataTable > tbody > tr.child span.dtr-title {
|
||||
display: inline-block;
|
||||
min-width: 75px;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.dtr-modal {
|
||||
position: fixed;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
padding: 10em 1em;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-display {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
margin: auto;
|
||||
z-index: 102;
|
||||
overflow: auto;
|
||||
background-color: #f5f5f7;
|
||||
border: 1px solid black;
|
||||
border-radius: 0.5em;
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-content {
|
||||
position: relative;
|
||||
padding: 1em;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-close {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #eaeaea;
|
||||
background-color: #f9f9f9;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 12;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-close:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
div.dtr-modal div.dtr-modal-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 101;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dtr-modal div.dtr-modal-display {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
div.dtr-bs-modal table.table tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
table.dataTable.table-bordered th.dtr-control.dtr-hidden + *,
|
||||
table.dataTable.table-bordered td.dtr-control.dtr-hidden + * {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
|
||||
table.dataTable > tbody > tr > .selected {
|
||||
background-color: rgba(13, 110, 253, 0.9);
|
||||
color: white;
|
||||
}
|
||||
table.dataTable tbody td.select-checkbox,
|
||||
table.dataTable tbody th.select-checkbox {
|
||||
position: relative;
|
||||
}
|
||||
table.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,
|
||||
table.dataTable tbody th.select-checkbox:before,
|
||||
table.dataTable tbody th.select-checkbox:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 1.2em;
|
||||
left: 50%;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
table.dataTable tbody td.select-checkbox:before,
|
||||
table.dataTable tbody th.select-checkbox:before {
|
||||
content: " ";
|
||||
margin-top: -5px;
|
||||
margin-left: -6px;
|
||||
border: 1px solid black;
|
||||
border-radius: 3px;
|
||||
}
|
||||
table.dataTable tr.selected td.select-checkbox:before,
|
||||
table.dataTable tr.selected th.select-checkbox:before {
|
||||
border: 1px solid white;
|
||||
}
|
||||
table.dataTable tr.selected td.select-checkbox:after,
|
||||
table.dataTable tr.selected th.select-checkbox:after {
|
||||
content: "✓";
|
||||
font-size: 20px;
|
||||
margin-top: -19px;
|
||||
margin-left: -6px;
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
|
||||
}
|
||||
table.dataTable.compact tbody td.select-checkbox:before,
|
||||
table.dataTable.compact tbody th.select-checkbox:before {
|
||||
margin-top: -12px;
|
||||
}
|
||||
table.dataTable.compact tr.selected td.select-checkbox:after,
|
||||
table.dataTable.compact tr.selected th.select-checkbox:after {
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper span.select-info,
|
||||
div.dataTables_wrapper span.select-item {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
div.dataTables_wrapper span.select-info,
|
||||
div.dataTables_wrapper span.select-item {
|
||||
margin-left: 0;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
table.dataTable.table-sm tbody td.select-checkbox::before {
|
||||
margin-top: -9px;
|
||||
}
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
|
|
@ -1,7 +1,7 @@
|
|||
@font-face {
|
||||
font-family: "bootstrap-icons";
|
||||
src: url("/fonts/bootstrap-icons.woff2?45695e8b569b2b0178db2713ca47065c") format("woff2"),
|
||||
url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff");
|
||||
src: url("/fonts/bootstrap-icons.woff2?524846017b983fc8ded9325d94ed40f3") format("woff2"),
|
||||
url("/fonts/bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff");
|
||||
}
|
||||
|
||||
.bi::before,
|
||||
|
@ -19,6 +19,7 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.bi-123::before { content: "\f67f"; }
|
||||
.bi-alarm-fill::before { content: "\f101"; }
|
||||
.bi-alarm::before { content: "\f102"; }
|
||||
.bi-align-bottom::before { content: "\f103"; }
|
||||
|
@ -1425,3 +1426,279 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
|
|||
.bi-webcam-fill::before { content: "\f67c"; }
|
||||
.bi-webcam::before { content: "\f67d"; }
|
||||
.bi-yin-yang::before { content: "\f67e"; }
|
||||
.bi-bandaid-fill::before { content: "\f680"; }
|
||||
.bi-bandaid::before { content: "\f681"; }
|
||||
.bi-bluetooth::before { content: "\f682"; }
|
||||
.bi-body-text::before { content: "\f683"; }
|
||||
.bi-boombox::before { content: "\f684"; }
|
||||
.bi-boxes::before { content: "\f685"; }
|
||||
.bi-dpad-fill::before { content: "\f686"; }
|
||||
.bi-dpad::before { content: "\f687"; }
|
||||
.bi-ear-fill::before { content: "\f688"; }
|
||||
.bi-ear::before { content: "\f689"; }
|
||||
.bi-envelope-check-1::before { content: "\f68a"; }
|
||||
.bi-envelope-check-fill::before { content: "\f68b"; }
|
||||
.bi-envelope-check::before { content: "\f68c"; }
|
||||
.bi-envelope-dash-1::before { content: "\f68d"; }
|
||||
.bi-envelope-dash-fill::before { content: "\f68e"; }
|
||||
.bi-envelope-dash::before { content: "\f68f"; }
|
||||
.bi-envelope-exclamation-1::before { content: "\f690"; }
|
||||
.bi-envelope-exclamation-fill::before { content: "\f691"; }
|
||||
.bi-envelope-exclamation::before { content: "\f692"; }
|
||||
.bi-envelope-plus-fill::before { content: "\f693"; }
|
||||
.bi-envelope-plus::before { content: "\f694"; }
|
||||
.bi-envelope-slash-1::before { content: "\f695"; }
|
||||
.bi-envelope-slash-fill::before { content: "\f696"; }
|
||||
.bi-envelope-slash::before { content: "\f697"; }
|
||||
.bi-envelope-x-1::before { content: "\f698"; }
|
||||
.bi-envelope-x-fill::before { content: "\f699"; }
|
||||
.bi-envelope-x::before { content: "\f69a"; }
|
||||
.bi-explicit-fill::before { content: "\f69b"; }
|
||||
.bi-explicit::before { content: "\f69c"; }
|
||||
.bi-git::before { content: "\f69d"; }
|
||||
.bi-infinity::before { content: "\f69e"; }
|
||||
.bi-list-columns-reverse::before { content: "\f69f"; }
|
||||
.bi-list-columns::before { content: "\f6a0"; }
|
||||
.bi-meta::before { content: "\f6a1"; }
|
||||
.bi-mortorboard-fill::before { content: "\f6a2"; }
|
||||
.bi-mortorboard::before { content: "\f6a3"; }
|
||||
.bi-nintendo-switch::before { content: "\f6a4"; }
|
||||
.bi-pc-display-horizontal::before { content: "\f6a5"; }
|
||||
.bi-pc-display::before { content: "\f6a6"; }
|
||||
.bi-pc-horizontal::before { content: "\f6a7"; }
|
||||
.bi-pc::before { content: "\f6a8"; }
|
||||
.bi-playstation::before { content: "\f6a9"; }
|
||||
.bi-plus-slash-minus::before { content: "\f6aa"; }
|
||||
.bi-projector-fill::before { content: "\f6ab"; }
|
||||
.bi-projector::before { content: "\f6ac"; }
|
||||
.bi-qr-code-scan::before { content: "\f6ad"; }
|
||||
.bi-qr-code::before { content: "\f6ae"; }
|
||||
.bi-quora::before { content: "\f6af"; }
|
||||
.bi-quote::before { content: "\f6b0"; }
|
||||
.bi-robot::before { content: "\f6b1"; }
|
||||
.bi-send-check-fill::before { content: "\f6b2"; }
|
||||
.bi-send-check::before { content: "\f6b3"; }
|
||||
.bi-send-dash-fill::before { content: "\f6b4"; }
|
||||
.bi-send-dash::before { content: "\f6b5"; }
|
||||
.bi-send-exclamation-1::before { content: "\f6b6"; }
|
||||
.bi-send-exclamation-fill::before { content: "\f6b7"; }
|
||||
.bi-send-exclamation::before { content: "\f6b8"; }
|
||||
.bi-send-fill::before { content: "\f6b9"; }
|
||||
.bi-send-plus-fill::before { content: "\f6ba"; }
|
||||
.bi-send-plus::before { content: "\f6bb"; }
|
||||
.bi-send-slash-fill::before { content: "\f6bc"; }
|
||||
.bi-send-slash::before { content: "\f6bd"; }
|
||||
.bi-send-x-fill::before { content: "\f6be"; }
|
||||
.bi-send-x::before { content: "\f6bf"; }
|
||||
.bi-send::before { content: "\f6c0"; }
|
||||
.bi-steam::before { content: "\f6c1"; }
|
||||
.bi-terminal-dash-1::before { content: "\f6c2"; }
|
||||
.bi-terminal-dash::before { content: "\f6c3"; }
|
||||
.bi-terminal-plus::before { content: "\f6c4"; }
|
||||
.bi-terminal-split::before { content: "\f6c5"; }
|
||||
.bi-ticket-detailed-fill::before { content: "\f6c6"; }
|
||||
.bi-ticket-detailed::before { content: "\f6c7"; }
|
||||
.bi-ticket-fill::before { content: "\f6c8"; }
|
||||
.bi-ticket-perforated-fill::before { content: "\f6c9"; }
|
||||
.bi-ticket-perforated::before { content: "\f6ca"; }
|
||||
.bi-ticket::before { content: "\f6cb"; }
|
||||
.bi-tiktok::before { content: "\f6cc"; }
|
||||
.bi-window-dash::before { content: "\f6cd"; }
|
||||
.bi-window-desktop::before { content: "\f6ce"; }
|
||||
.bi-window-fullscreen::before { content: "\f6cf"; }
|
||||
.bi-window-plus::before { content: "\f6d0"; }
|
||||
.bi-window-split::before { content: "\f6d1"; }
|
||||
.bi-window-stack::before { content: "\f6d2"; }
|
||||
.bi-window-x::before { content: "\f6d3"; }
|
||||
.bi-xbox::before { content: "\f6d4"; }
|
||||
.bi-ethernet::before { content: "\f6d5"; }
|
||||
.bi-hdmi-fill::before { content: "\f6d6"; }
|
||||
.bi-hdmi::before { content: "\f6d7"; }
|
||||
.bi-usb-c-fill::before { content: "\f6d8"; }
|
||||
.bi-usb-c::before { content: "\f6d9"; }
|
||||
.bi-usb-fill::before { content: "\f6da"; }
|
||||
.bi-usb-plug-fill::before { content: "\f6db"; }
|
||||
.bi-usb-plug::before { content: "\f6dc"; }
|
||||
.bi-usb-symbol::before { content: "\f6dd"; }
|
||||
.bi-usb::before { content: "\f6de"; }
|
||||
.bi-boombox-fill::before { content: "\f6df"; }
|
||||
.bi-displayport-1::before { content: "\f6e0"; }
|
||||
.bi-displayport::before { content: "\f6e1"; }
|
||||
.bi-gpu-card::before { content: "\f6e2"; }
|
||||
.bi-memory::before { content: "\f6e3"; }
|
||||
.bi-modem-fill::before { content: "\f6e4"; }
|
||||
.bi-modem::before { content: "\f6e5"; }
|
||||
.bi-motherboard-fill::before { content: "\f6e6"; }
|
||||
.bi-motherboard::before { content: "\f6e7"; }
|
||||
.bi-optical-audio-fill::before { content: "\f6e8"; }
|
||||
.bi-optical-audio::before { content: "\f6e9"; }
|
||||
.bi-pci-card::before { content: "\f6ea"; }
|
||||
.bi-router-fill::before { content: "\f6eb"; }
|
||||
.bi-router::before { content: "\f6ec"; }
|
||||
.bi-ssd-fill::before { content: "\f6ed"; }
|
||||
.bi-ssd::before { content: "\f6ee"; }
|
||||
.bi-thunderbolt-fill::before { content: "\f6ef"; }
|
||||
.bi-thunderbolt::before { content: "\f6f0"; }
|
||||
.bi-usb-drive-fill::before { content: "\f6f1"; }
|
||||
.bi-usb-drive::before { content: "\f6f2"; }
|
||||
.bi-usb-micro-fill::before { content: "\f6f3"; }
|
||||
.bi-usb-micro::before { content: "\f6f4"; }
|
||||
.bi-usb-mini-fill::before { content: "\f6f5"; }
|
||||
.bi-usb-mini::before { content: "\f6f6"; }
|
||||
.bi-cloud-haze2::before { content: "\f6f7"; }
|
||||
.bi-device-hdd-fill::before { content: "\f6f8"; }
|
||||
.bi-device-hdd::before { content: "\f6f9"; }
|
||||
.bi-device-ssd-fill::before { content: "\f6fa"; }
|
||||
.bi-device-ssd::before { content: "\f6fb"; }
|
||||
.bi-displayport-fill::before { content: "\f6fc"; }
|
||||
.bi-mortarboard-fill::before { content: "\f6fd"; }
|
||||
.bi-mortarboard::before { content: "\f6fe"; }
|
||||
.bi-terminal-x::before { content: "\f6ff"; }
|
||||
.bi-arrow-through-heart-fill::before { content: "\f700"; }
|
||||
.bi-arrow-through-heart::before { content: "\f701"; }
|
||||
.bi-badge-sd-fill::before { content: "\f702"; }
|
||||
.bi-badge-sd::before { content: "\f703"; }
|
||||
.bi-bag-heart-fill::before { content: "\f704"; }
|
||||
.bi-bag-heart::before { content: "\f705"; }
|
||||
.bi-balloon-fill::before { content: "\f706"; }
|
||||
.bi-balloon-heart-fill::before { content: "\f707"; }
|
||||
.bi-balloon-heart::before { content: "\f708"; }
|
||||
.bi-balloon::before { content: "\f709"; }
|
||||
.bi-box2-fill::before { content: "\f70a"; }
|
||||
.bi-box2-heart-fill::before { content: "\f70b"; }
|
||||
.bi-box2-heart::before { content: "\f70c"; }
|
||||
.bi-box2::before { content: "\f70d"; }
|
||||
.bi-braces-asterisk::before { content: "\f70e"; }
|
||||
.bi-calendar-heart-fill::before { content: "\f70f"; }
|
||||
.bi-calendar-heart::before { content: "\f710"; }
|
||||
.bi-calendar2-heart-fill::before { content: "\f711"; }
|
||||
.bi-calendar2-heart::before { content: "\f712"; }
|
||||
.bi-chat-heart-fill::before { content: "\f713"; }
|
||||
.bi-chat-heart::before { content: "\f714"; }
|
||||
.bi-chat-left-heart-fill::before { content: "\f715"; }
|
||||
.bi-chat-left-heart::before { content: "\f716"; }
|
||||
.bi-chat-right-heart-fill::before { content: "\f717"; }
|
||||
.bi-chat-right-heart::before { content: "\f718"; }
|
||||
.bi-chat-square-heart-fill::before { content: "\f719"; }
|
||||
.bi-chat-square-heart::before { content: "\f71a"; }
|
||||
.bi-clipboard-check-fill::before { content: "\f71b"; }
|
||||
.bi-clipboard-data-fill::before { content: "\f71c"; }
|
||||
.bi-clipboard-fill::before { content: "\f71d"; }
|
||||
.bi-clipboard-heart-fill::before { content: "\f71e"; }
|
||||
.bi-clipboard-heart::before { content: "\f71f"; }
|
||||
.bi-clipboard-minus-fill::before { content: "\f720"; }
|
||||
.bi-clipboard-plus-fill::before { content: "\f721"; }
|
||||
.bi-clipboard-pulse::before { content: "\f722"; }
|
||||
.bi-clipboard-x-fill::before { content: "\f723"; }
|
||||
.bi-clipboard2-check-fill::before { content: "\f724"; }
|
||||
.bi-clipboard2-check::before { content: "\f725"; }
|
||||
.bi-clipboard2-data-fill::before { content: "\f726"; }
|
||||
.bi-clipboard2-data::before { content: "\f727"; }
|
||||
.bi-clipboard2-fill::before { content: "\f728"; }
|
||||
.bi-clipboard2-heart-fill::before { content: "\f729"; }
|
||||
.bi-clipboard2-heart::before { content: "\f72a"; }
|
||||
.bi-clipboard2-minus-fill::before { content: "\f72b"; }
|
||||
.bi-clipboard2-minus::before { content: "\f72c"; }
|
||||
.bi-clipboard2-plus-fill::before { content: "\f72d"; }
|
||||
.bi-clipboard2-plus::before { content: "\f72e"; }
|
||||
.bi-clipboard2-pulse-fill::before { content: "\f72f"; }
|
||||
.bi-clipboard2-pulse::before { content: "\f730"; }
|
||||
.bi-clipboard2-x-fill::before { content: "\f731"; }
|
||||
.bi-clipboard2-x::before { content: "\f732"; }
|
||||
.bi-clipboard2::before { content: "\f733"; }
|
||||
.bi-emoji-kiss-fill::before { content: "\f734"; }
|
||||
.bi-emoji-kiss::before { content: "\f735"; }
|
||||
.bi-envelope-heart-fill::before { content: "\f736"; }
|
||||
.bi-envelope-heart::before { content: "\f737"; }
|
||||
.bi-envelope-open-heart-fill::before { content: "\f738"; }
|
||||
.bi-envelope-open-heart::before { content: "\f739"; }
|
||||
.bi-envelope-paper-fill::before { content: "\f73a"; }
|
||||
.bi-envelope-paper-heart-fill::before { content: "\f73b"; }
|
||||
.bi-envelope-paper-heart::before { content: "\f73c"; }
|
||||
.bi-envelope-paper::before { content: "\f73d"; }
|
||||
.bi-filetype-aac::before { content: "\f73e"; }
|
||||
.bi-filetype-ai::before { content: "\f73f"; }
|
||||
.bi-filetype-bmp::before { content: "\f740"; }
|
||||
.bi-filetype-cs::before { content: "\f741"; }
|
||||
.bi-filetype-css::before { content: "\f742"; }
|
||||
.bi-filetype-csv::before { content: "\f743"; }
|
||||
.bi-filetype-doc::before { content: "\f744"; }
|
||||
.bi-filetype-docx::before { content: "\f745"; }
|
||||
.bi-filetype-exe::before { content: "\f746"; }
|
||||
.bi-filetype-gif::before { content: "\f747"; }
|
||||
.bi-filetype-heic::before { content: "\f748"; }
|
||||
.bi-filetype-html::before { content: "\f749"; }
|
||||
.bi-filetype-java::before { content: "\f74a"; }
|
||||
.bi-filetype-jpg::before { content: "\f74b"; }
|
||||
.bi-filetype-js::before { content: "\f74c"; }
|
||||
.bi-filetype-jsx::before { content: "\f74d"; }
|
||||
.bi-filetype-key::before { content: "\f74e"; }
|
||||
.bi-filetype-m4p::before { content: "\f74f"; }
|
||||
.bi-filetype-md::before { content: "\f750"; }
|
||||
.bi-filetype-mdx::before { content: "\f751"; }
|
||||
.bi-filetype-mov::before { content: "\f752"; }
|
||||
.bi-filetype-mp3::before { content: "\f753"; }
|
||||
.bi-filetype-mp4::before { content: "\f754"; }
|
||||
.bi-filetype-otf::before { content: "\f755"; }
|
||||
.bi-filetype-pdf::before { content: "\f756"; }
|
||||
.bi-filetype-php::before { content: "\f757"; }
|
||||
.bi-filetype-png::before { content: "\f758"; }
|
||||
.bi-filetype-ppt-1::before { content: "\f759"; }
|
||||
.bi-filetype-ppt::before { content: "\f75a"; }
|
||||
.bi-filetype-psd::before { content: "\f75b"; }
|
||||
.bi-filetype-py::before { content: "\f75c"; }
|
||||
.bi-filetype-raw::before { content: "\f75d"; }
|
||||
.bi-filetype-rb::before { content: "\f75e"; }
|
||||
.bi-filetype-sass::before { content: "\f75f"; }
|
||||
.bi-filetype-scss::before { content: "\f760"; }
|
||||
.bi-filetype-sh::before { content: "\f761"; }
|
||||
.bi-filetype-svg::before { content: "\f762"; }
|
||||
.bi-filetype-tiff::before { content: "\f763"; }
|
||||
.bi-filetype-tsx::before { content: "\f764"; }
|
||||
.bi-filetype-ttf::before { content: "\f765"; }
|
||||
.bi-filetype-txt::before { content: "\f766"; }
|
||||
.bi-filetype-wav::before { content: "\f767"; }
|
||||
.bi-filetype-woff::before { content: "\f768"; }
|
||||
.bi-filetype-xls-1::before { content: "\f769"; }
|
||||
.bi-filetype-xls::before { content: "\f76a"; }
|
||||
.bi-filetype-xml::before { content: "\f76b"; }
|
||||
.bi-filetype-yml::before { content: "\f76c"; }
|
||||
.bi-heart-arrow::before { content: "\f76d"; }
|
||||
.bi-heart-pulse-fill::before { content: "\f76e"; }
|
||||
.bi-heart-pulse::before { content: "\f76f"; }
|
||||
.bi-heartbreak-fill::before { content: "\f770"; }
|
||||
.bi-heartbreak::before { content: "\f771"; }
|
||||
.bi-hearts::before { content: "\f772"; }
|
||||
.bi-hospital-fill::before { content: "\f773"; }
|
||||
.bi-hospital::before { content: "\f774"; }
|
||||
.bi-house-heart-fill::before { content: "\f775"; }
|
||||
.bi-house-heart::before { content: "\f776"; }
|
||||
.bi-incognito::before { content: "\f777"; }
|
||||
.bi-magnet-fill::before { content: "\f778"; }
|
||||
.bi-magnet::before { content: "\f779"; }
|
||||
.bi-person-heart::before { content: "\f77a"; }
|
||||
.bi-person-hearts::before { content: "\f77b"; }
|
||||
.bi-phone-flip::before { content: "\f77c"; }
|
||||
.bi-plugin::before { content: "\f77d"; }
|
||||
.bi-postage-fill::before { content: "\f77e"; }
|
||||
.bi-postage-heart-fill::before { content: "\f77f"; }
|
||||
.bi-postage-heart::before { content: "\f780"; }
|
||||
.bi-postage::before { content: "\f781"; }
|
||||
.bi-postcard-fill::before { content: "\f782"; }
|
||||
.bi-postcard-heart-fill::before { content: "\f783"; }
|
||||
.bi-postcard-heart::before { content: "\f784"; }
|
||||
.bi-postcard::before { content: "\f785"; }
|
||||
.bi-search-heart-fill::before { content: "\f786"; }
|
||||
.bi-search-heart::before { content: "\f787"; }
|
||||
.bi-sliders2-vertical::before { content: "\f788"; }
|
||||
.bi-sliders2::before { content: "\f789"; }
|
||||
.bi-trash3-fill::before { content: "\f78a"; }
|
||||
.bi-trash3::before { content: "\f78b"; }
|
||||
.bi-valentine::before { content: "\f78c"; }
|
||||
.bi-valentine2::before { content: "\f78d"; }
|
||||
.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; }
|
||||
.bi-wrench-adjustable-circle::before { content: "\f78f"; }
|
||||
.bi-wrench-adjustable::before { content: "\f790"; }
|
||||
.bi-filetype-json::before { content: "\f791"; }
|
||||
.bi-filetype-pptx::before { content: "\f792"; }
|
||||
.bi-filetype-xlsx::before { content: "\f793"; }
|
|
@ -63,6 +63,17 @@
|
|||
.navbar-nav {
|
||||
margin: 0;
|
||||
}
|
||||
.navbar-nav .nav-item {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
.navbar-nav .nav-link {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
.navbar-fixed-bottom .navbar-collapse,
|
||||
.navbar-fixed-top .navbar-collapse {
|
||||
max-height: 1000px
|
||||
|
@ -75,6 +86,12 @@
|
|||
display: inline-block;
|
||||
font-size: inherit;
|
||||
}
|
||||
.btn-group-xs > .btn, .btn-xs {
|
||||
padding: .25rem .4rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1rem;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
.icon-spin {
|
||||
animation-name: spin;
|
||||
animation-duration: 2000ms;
|
||||
|
@ -105,13 +122,22 @@
|
|||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
||||
.footable-sortable {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
@keyframes blink {
|
||||
50% {
|
||||
color: transparent
|
||||
}
|
||||
}
|
||||
.loader-dot {
|
||||
animation: 1s blink infinite
|
||||
}
|
||||
.loader-dot:nth-child(2) {
|
||||
animation-delay: 250ms
|
||||
}
|
||||
.loader-dot:nth-child(3) {
|
||||
animation-delay: 500ms
|
||||
}
|
||||
|
||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
||||
/* Fix modal moving content left */
|
||||
body.modal-open {
|
||||
overflow: inherit;
|
||||
|
@ -166,19 +192,11 @@ legend {
|
|||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
opacity: 0.7;
|
||||
}
|
||||
#top {
|
||||
padding-top: 70px;
|
||||
}
|
||||
.bootstrap-select.btn-group .no-results {
|
||||
display: none;
|
||||
}
|
||||
.dropdown-desc {
|
||||
display: block;
|
||||
padding: 3px 10px;
|
||||
clear: both;
|
||||
font-weight: bold;
|
||||
color: #5a5a5a;
|
||||
white-space: nowrap;
|
||||
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||
color: rgb(197, 197, 197) !important;
|
||||
}
|
||||
.haveibeenpwned {
|
||||
cursor: pointer;
|
||||
|
@ -206,7 +224,7 @@ legend {
|
|||
flex-direction: column;
|
||||
}
|
||||
.footer .version {
|
||||
margin-left: auto;
|
||||
margin-left: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.slave-info {
|
||||
|
@ -225,15 +243,8 @@ legend {
|
|||
.btn-input-missing:active:hover,
|
||||
.btn-input-missing:active:focus {
|
||||
color: #000 !important;
|
||||
background-color: #ff4136;
|
||||
border-color: #ff291c;
|
||||
}
|
||||
table.footable>tbody>tr.footable-empty>td {
|
||||
font-style:italic;
|
||||
font-size: 1rem;
|
||||
}
|
||||
table>tbody>tr>td>span.footable-toggle {
|
||||
opacity: 0.75;
|
||||
background-color: #ff2f24 !important;
|
||||
border-color: #e21207 !important;
|
||||
}
|
||||
.navbar-nav > li {
|
||||
font-size: 1rem !important;
|
||||
|
@ -260,18 +271,11 @@ code {
|
|||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.list-group-item.webauthn-authenticator-selection,
|
||||
.list-group-item.totp-authenticator-selection,
|
||||
.list-group-item.yubi_otp-authenticator-selection {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
.pending-tfa-collapse {
|
||||
padding: 10px;
|
||||
background: #fbfbfb;
|
||||
border: 1px solid #ededed;
|
||||
min-height: 110px;
|
||||
.dropdown-header {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
.tag-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -295,7 +299,7 @@ code {
|
|||
}
|
||||
.tag-input {
|
||||
margin-left: 10px;
|
||||
border: 0;
|
||||
border: 0 !important;
|
||||
flex: 1;
|
||||
height: 24px;
|
||||
min-width: 150px;
|
||||
|
@ -308,3 +312,61 @@ code {
|
|||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
#dnstable {
|
||||
overflow-x: auto!important;
|
||||
}
|
||||
.well {
|
||||
border: 1px solid #dfdfdf;
|
||||
background-color: #f9f9f9;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
.btn-check-label {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.caret {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
a[aria-expanded='true'] > .caret,
|
||||
button[aria-expanded='true'] > .caret {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
|
||||
.list-group-details {
|
||||
background: #fff;
|
||||
}
|
||||
.list-group-header {
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
|
||||
.bg-primary, .alert-primary, .btn-primary {
|
||||
background-color: #0F688D !important;
|
||||
border-color: #0d526d !important;
|
||||
}
|
||||
.bg-info, .alert-info, .btn-info {
|
||||
background-color: #148DBC !important;
|
||||
border-color: #127ea8 !important;
|
||||
}
|
||||
|
||||
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||
color: rgb(137 137 137)!important;
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: #d5d5d5;
|
||||
}
|
||||
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.btn.btn-outline-secondary {
|
||||
border-color: #cfcfcf !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: #f0f0f0 !important;
|
||||
}
|
|
@ -1,7 +1,3 @@
|
|||
.space20 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn-xs-lg>.lang-sm:after {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
@ -10,110 +6,67 @@
|
|||
max-width: 350px;
|
||||
}
|
||||
|
||||
.panel-login .apps .btn {
|
||||
.card-login .apps .btn {
|
||||
width: auto;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
margin-top: auto;
|
||||
}
|
||||
.panel-login .apps .btn:hover {
|
||||
.card-login .apps .btn:hover {
|
||||
margin-top: 1px !important;
|
||||
border-bottom-width: 3px;
|
||||
}
|
||||
|
||||
.responsive-tabs .nav-tabs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dataTables_paginate.paging_simple_numbers .pagination {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.responsive-tabs .nav-tabs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.responsive-tabs .card .card-body.collapse {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.panel-login .apps .btn {
|
||||
.responsive-tabs .tab-pane {
|
||||
display: block !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.card-login .apps .btn {
|
||||
width: 100%;
|
||||
float: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.panel-login .apps .btn {
|
||||
.card-login .apps .btn {
|
||||
border-bottom-width: 4px;
|
||||
}
|
||||
|
||||
.media-clearfix::after {
|
||||
clear: both;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.media-clearfix::before {
|
||||
display: table;
|
||||
content: " ";
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.xs-show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-group .panel{
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-group .panel-body {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-group .js-tabcollapse-panel-body .panel-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-body .panel-heading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-body .well,
|
||||
.panel-body .form-inline.well {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.js-tabcollapse-panel-heading {
|
||||
display: block;
|
||||
height: 37px;
|
||||
line-height: 37px;
|
||||
text-indent: 15px;
|
||||
}
|
||||
.js-tabcollapse-panel-heading:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.js-tabcollapse-panel-heading {
|
||||
position: relative;
|
||||
}
|
||||
.js-tabcollapse-panel-heading:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
right: 17px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 2px;
|
||||
vertical-align: middle;
|
||||
border-bottom: 4px dashed;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.js-tabcollapse-panel-heading.collapsed:after {
|
||||
border-bottom: none;
|
||||
border-top: 4px dashed;
|
||||
}
|
||||
|
||||
.recent-login-success {
|
||||
font-size: 14px;
|
||||
margin-top: 10px !important;
|
||||
font-size: 14px;
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
.pull-xs-right {
|
||||
float: right !important;
|
||||
}
|
||||
.pull-xs-right .dropdown-menu {
|
||||
right: 0;
|
||||
left: auto;
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
.text-xs-left {
|
||||
text-align: left;
|
||||
|
@ -125,36 +78,29 @@
|
|||
font-weight: normal;
|
||||
text-align: justify;
|
||||
}
|
||||
.help-block {
|
||||
text-align: justify;
|
||||
}
|
||||
.btn.visible-xs-block {
|
||||
.btn.d-block {
|
||||
width: 100%;
|
||||
float: none;
|
||||
white-space: normal;
|
||||
}
|
||||
.btn-group.footable-actions .btn.btn-xs-half,
|
||||
.btn.visible-xs-block.btn-xs-half {
|
||||
.btn.btn-xs-half,
|
||||
.btn.d-block.btn-xs-half {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
.btn-group.footable-actions .btn.btn-xs-third,
|
||||
.btn.visible-xs-block.btn-xs-third {
|
||||
.btn.btn-xs-third,
|
||||
.btn.d-block.btn-xs-third {
|
||||
width: 33.33%;
|
||||
float: left;
|
||||
}
|
||||
.btn-group.footable-actions .btn.btn-xs-quart,
|
||||
.btn.visible-xs-block.btn-xs-quart {
|
||||
.btn.btn-xs-quart,
|
||||
.btn.d-block.btn-xs-quart {
|
||||
width: 25%;
|
||||
float: left;
|
||||
}
|
||||
.btn.visible-xs-block.btn-sm,
|
||||
.btn.d-block.btn-sm,
|
||||
.btn-xs-lg {
|
||||
padding: 15px 16px 13px;
|
||||
line-height: 15px;
|
||||
padding: .5rem 1rem;
|
||||
line-height: 20px;
|
||||
}
|
||||
.input-xs-lg {
|
||||
height: 47px;
|
||||
height: 47px;
|
||||
padding: 13px 16px;
|
||||
}
|
||||
.btn-group:not(.input-group-btn) {
|
||||
|
@ -167,27 +113,27 @@
|
|||
.btn-group.nowrap .dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
.panel-login .btn-group {
|
||||
.card-login .btn-group {
|
||||
display: block;
|
||||
}
|
||||
.mass-actions-user .btn-group {
|
||||
float: none;
|
||||
}
|
||||
div[class^='mass-actions'] .dropdown-menu,
|
||||
.panel-xs-lg .dropdown-menu,
|
||||
.card-xs-lg .dropdown-menu,
|
||||
.dropdown-menu.login {
|
||||
width: 100%;
|
||||
}
|
||||
div[class^='mass-actions'] .btn-group .dropdown-menu {
|
||||
top: 50%;
|
||||
top: 50%;
|
||||
}
|
||||
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
|
||||
div.mass-actions-quarantine .btn-group .dropdown-menu,
|
||||
.panel-xs-lg .dropdown-menu {
|
||||
.card-xs-lg .dropdown-menu {
|
||||
top: 100%;
|
||||
}
|
||||
div[class^='mass-actions'] .dropdown-menu>li>a,
|
||||
.panel-xs-lg .dropdown-menu>li>a,
|
||||
.card-xs-lg .dropdown-menu>li>a,
|
||||
.dropdown-menu.login>li>a {
|
||||
padding: 8px 20px;
|
||||
}
|
||||
|
@ -195,9 +141,6 @@
|
|||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.space20 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.top100 {
|
||||
top: 100% !important;
|
||||
}
|
||||
|
@ -210,34 +153,17 @@
|
|||
.btn-xs-lg>.lang-sm:after {
|
||||
top: 1px;
|
||||
}
|
||||
table.footable>tfoot>tr.footable-paging>td {
|
||||
text-align: left;
|
||||
}
|
||||
.footable-first-visible {
|
||||
min-width: 55px;
|
||||
}
|
||||
table>tbody>tr>td>span.footable-toggle {
|
||||
font-size: 24px;
|
||||
margin-right: 14px !important;
|
||||
}
|
||||
table>tbody>tr>td>span.footable-toggle + input {
|
||||
position: absolute;
|
||||
left: 38px;
|
||||
}
|
||||
.pagination {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
tr.footable-filtering>th>form {
|
||||
width: 270px;
|
||||
}
|
||||
.mass-actions-mailbox {
|
||||
padding: 0;
|
||||
}
|
||||
.panel-xs-lg .panel-heading {
|
||||
.card-xs-lg .card-header {
|
||||
height: 66px;
|
||||
line-height: 47px;
|
||||
}
|
||||
.panel-xs-lg .btn-group .btn {
|
||||
.card-xs-lg .btn-group .btn {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
@ -250,55 +176,29 @@
|
|||
.bootstrap-select {
|
||||
max-width: 100%;
|
||||
}
|
||||
.img-responsive {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.btn-group.footable-actions {
|
||||
position: absolute;
|
||||
width: 90vw !important;
|
||||
left: 0;
|
||||
height: 36px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
.btn-group.footable-actions .btn {
|
||||
padding: 10px 16px 7px;
|
||||
line-height: 15px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
.btn-group.footable-actions:after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
|
||||
margin-right: 14px;
|
||||
white-space: normal;
|
||||
}
|
||||
.clearfix {
|
||||
flex-basis: 100%;
|
||||
height: 0;
|
||||
}
|
||||
.btn-group > .btn-group {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.btn-group .btn {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.btn-group .btn i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.btn-group .btn .caret {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.panel-login .btn-group .btn {
|
||||
.card-login .btn-group .btn {
|
||||
display: block !important;
|
||||
}
|
||||
.panel-login .clearfix {
|
||||
height: auto;
|
||||
|
||||
.dt-sm-head-hidden .dtr-title {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
|
@ -306,3 +206,9 @@
|
|||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
|
||||
max-width: 1600px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
.dataTables_info {
|
||||
margin: 15px 0 !important;
|
||||
padding: 0px !important;
|
||||
}
|
||||
.dataTables_paginate, .dataTables_length, .dataTables_filter {
|
||||
margin: 15px 0 !important;
|
||||
}
|
||||
.dtr-details {
|
||||
width: 100%;
|
||||
}
|
||||
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
td.child>ul>li {
|
||||
display: flex;
|
||||
}
|
||||
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.129);
|
||||
padding: 0.5em 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: #5e5e5e;
|
||||
}
|
||||
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 {
|
||||
background-color: #979797 !important;
|
||||
border: 1.5px solid #616161 !important;
|
||||
border-radius: 2px !important;
|
||||
color: #fff;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
line-height: 1.25em;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
font-size: 14px;
|
||||
transition: 0.5s all;
|
||||
}
|
||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||
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;
|
||||
}
|
||||
table.dataTable.table-striped>tbody>tr>td>input[type="checkbox"] {
|
||||
margin-top: 7px;
|
||||
}
|
||||
td.dtr-col-lg {
|
||||
min-width: 350px;
|
||||
word-break: break-word;
|
||||
}
|
||||
td.dtr-col-md {
|
||||
min-width: 250px;
|
||||
word-break: break-word;
|
||||
}
|
||||
td.dtr-col-sm {
|
||||
min-width: 125px;
|
||||
word-break: break-word;
|
||||
}
|
||||
.dt-data-w100 .dtr-data {
|
||||
width: 100%;
|
||||
}
|
||||
li .dtr-data {
|
||||
word-break: break-all;
|
||||
flex: 1;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
table.dataTable>tbody>tr.child span.dtr-title {
|
||||
width: 30%;
|
||||
max-width: 250px;
|
||||
}
|
|
@ -25,7 +25,6 @@ body.modal-open {
|
|||
}
|
||||
.mass-actions-admin {
|
||||
user-select: none;
|
||||
padding:10px 0 10px 0;
|
||||
}
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
}
|
||||
.mass-actions-debug {
|
||||
user-select: none;
|
||||
padding:10px 0 10px 10px;
|
||||
}
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
}
|
||||
.mass-actions-user {
|
||||
user-select: none;
|
||||
padding:10px 0 10px 0;
|
||||
}
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136;
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
}
|
||||
.mass-actions-mailbox {
|
||||
user-select: none;
|
||||
padding:10px 0 10px 10px;
|
||||
}
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
.mass-actions-quarantine {
|
||||
user-select: none;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.inputMissingAttr {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
}
|
||||
.mass-actions-user {
|
||||
user-select: none;
|
||||
padding:10px 0;
|
||||
}
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,360 @@
|
|||
body {
|
||||
background-color: #414141;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid #1c1c1c;
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
legend {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
.card-header {
|
||||
color: #bbb;
|
||||
background-color: #2c2c2c;
|
||||
border-color: transparent;
|
||||
}
|
||||
.btn-secondary, .paginate_button, .page-link, .btn-light {
|
||||
color: #fff !important;
|
||||
background-color: #7a7a7a !important;
|
||||
border-color: #5c5c5c !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;
|
||||
}
|
||||
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
|
||||
background-color: #7a7a7a;
|
||||
border-color: #5c5c5c !important;
|
||||
color: #fff;
|
||||
}
|
||||
.btn-secondary:disabled, .btn-secondary.disabled {
|
||||
border-color: #7a7a7a !important;
|
||||
}
|
||||
.modal-content {
|
||||
background-color: #414141;
|
||||
}
|
||||
.modal-header {
|
||||
border-bottom: 1px solid #161616;
|
||||
}
|
||||
.modal-title {
|
||||
color: white;
|
||||
}
|
||||
.modal .btn-close {
|
||||
filter: invert(1) grayscale(100%) brightness(200%);
|
||||
}
|
||||
.navbar.bg-light {
|
||||
background-color: #222222 !important;
|
||||
border-color: #181818;
|
||||
}
|
||||
.nav-link {
|
||||
color: #ccc !important;
|
||||
}
|
||||
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
||||
background: none;
|
||||
}
|
||||
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
|
||||
border-bottom-color: #414141;
|
||||
}
|
||||
|
||||
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background-color: #585858;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
|
||||
color: #fafafa;
|
||||
}
|
||||
|
||||
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder:active, .bootstrap-select>.dropdown-toggle.bs-placeholder:focus, .bootstrap-select>.dropdown-toggle.bs-placeholder:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||
color: #d4d4d4 !important;
|
||||
}
|
||||
tbody tr {
|
||||
color: #555;
|
||||
}
|
||||
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
.list-group-item {
|
||||
background-color: #333;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||
background-color: #333;
|
||||
}
|
||||
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;
|
||||
}
|
||||
.progress {
|
||||
background-color: #555;
|
||||
}
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
color: #ccc;
|
||||
}
|
||||
div.numberedtextarea-number {
|
||||
color: #999;
|
||||
}
|
||||
.well {
|
||||
border: 1px solid #555;
|
||||
background-color: #333;
|
||||
}
|
||||
pre {
|
||||
color: #ccc;
|
||||
background-color: #333;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
input.form-control, textarea.form-control {
|
||||
color: #e2e2e2 !important;
|
||||
background-color: #555 !important;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
input.form-control:focus, textarea.form-control {
|
||||
background-color: #555 !important;
|
||||
}
|
||||
input.form-control:disabled, textarea.form-disabled {
|
||||
color: #a8a8a8 !important;
|
||||
background-color: #6e6e6e !important;
|
||||
}
|
||||
.input-group-addon {
|
||||
color: #ccc;
|
||||
background-color: #555 !important;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
.input-group-text {
|
||||
color: #ccc;
|
||||
background-color: #242424;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.list-group-item {
|
||||
color: #ccc;
|
||||
}
|
||||
.dropdown-item {
|
||||
color: #ccc;
|
||||
}
|
||||
.dropdown-item:hover {
|
||||
color: #616161 !important;
|
||||
}
|
||||
.dropdown-item.active:hover {
|
||||
color: #fff !important;
|
||||
background-color: #31b1e4;
|
||||
}
|
||||
.form-select {
|
||||
color: #e2e2e2!important;
|
||||
background-color: #555!important;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.responsive-tabs .card-header button[data-bs-toggle="collapse"] {
|
||||
color: #c7c7c7;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
.breadcrumb {
|
||||
color: #fff !important;
|
||||
background-color: #7a7a7a !important;
|
||||
border-color: #5c5c5c !important;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
color: #6fc7e9;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #3daedb;
|
||||
}
|
||||
|
||||
.breadcrumb-item.active {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
|
||||
.list-group-item.disabled, .list-group-item:disabled {
|
||||
color: #fff;
|
||||
background-color: #a8a8a8 !important;
|
||||
border-color: #a8a8a8;
|
||||
}
|
||||
|
||||
.card.bg-light .card-title {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.card.bg-light .card-text {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.accordion-item {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
.accordion-button {
|
||||
color: #bbb;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
.accordion-button:not(.collapsed) {
|
||||
color: #6fc7e9;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
.accordion-button::after {
|
||||
background-image: none;
|
||||
}
|
||||
.accordion-button:not(.collapsed)::after {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
|
||||
.toast-header {
|
||||
background-color: #4c4c4c;
|
||||
}
|
||||
.toast-body {
|
||||
background-color: #626262;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.tag-box {
|
||||
background-color: #555;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
.tag-input {
|
||||
color: #fff;
|
||||
background-color: #555;
|
||||
}
|
||||
.tag-add {
|
||||
color: #ccc;
|
||||
}
|
||||
.tag-add: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;
|
||||
}
|
||||
.btn.btn-outline-secondary {
|
||||
color: #fff !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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.btn-input-missing,
|
||||
.btn-input-missing:hover,
|
||||
.btn-input-missing:active,
|
||||
.btn-input-missing:focus,
|
||||
.btn-input-missing:active:hover,
|
||||
.btn-input-missing:active:focus {
|
||||
color: #fff !important;
|
||||
background-color: #ff2f24 !important;
|
||||
border-color: #e21207 !important;
|
||||
}
|
||||
|
||||
.inputMissingAttr {
|
||||
border-color: #FF4136 !important;
|
||||
}
|
||||
|
||||
|
||||
.list-group-details {
|
||||
background: #444444;
|
||||
}
|
||||
.list-group-header {
|
||||
background: #333;
|
||||
}
|
||||
|
|
@ -44,15 +44,24 @@ foreach ($containers as $container => $container_info) {
|
|||
$containers[$container]['State']['StartedAtHR'] = $started;
|
||||
}
|
||||
|
||||
// get mailcow data
|
||||
$hostname = getenv('MAILCOW_HOSTNAME');
|
||||
$timezone = getenv('TZ');
|
||||
|
||||
$template = 'debug.twig';
|
||||
$template_data = [
|
||||
'log_lines' => getenv('LOG_LINES'),
|
||||
'vmail_df' => $vmail_df,
|
||||
'hostname' => $hostname,
|
||||
'timezone' => $timezone,
|
||||
'license_guid' => license('guid'),
|
||||
'solr_status' => $solr_status,
|
||||
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
|
||||
'clamd_status' => $clamd_status,
|
||||
'containers' => $containers,
|
||||
'lang_admin' => json_encode($lang['admin']),
|
||||
'lang_debug' => json_encode($lang['debug']),
|
||||
'lang_datatables' => json_encode($lang['datatables']),
|
||||
];
|
||||
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||
|
|
|
@ -38,24 +38,46 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
$template = 'edit/admin.twig';
|
||||
$template_data = ['admin' => $admin];
|
||||
}
|
||||
elseif (isset($_GET['domain']) &&
|
||||
is_valid_domain_name($_GET["domain"]) &&
|
||||
!empty($_GET["domain"])) {
|
||||
$domain = $_GET["domain"];
|
||||
$result = mailbox('get', 'domain_details', $domain);
|
||||
$quota_notification_bcc = quota_notification_bcc('get', $domain);
|
||||
$rl = ratelimit('get', 'domain', $domain);
|
||||
$rlyhosts = relayhost('get');
|
||||
$template = 'edit/domain.twig';
|
||||
elseif (isset($_GET['domain'])) {
|
||||
if (is_valid_domain_name($_GET["domain"]) &&
|
||||
!empty($_GET["domain"])) {
|
||||
// edit domain
|
||||
$domain = $_GET["domain"];
|
||||
$result = mailbox('get', 'domain_details', $domain);
|
||||
$quota_notification_bcc = quota_notification_bcc('get', $domain);
|
||||
$rl = ratelimit('get', 'domain', $domain);
|
||||
$rlyhosts = relayhost('get');
|
||||
$template = 'edit/domain.twig';
|
||||
$template_data = [
|
||||
'acl' => $_SESSION['acl'],
|
||||
'domain' => $domain,
|
||||
'quota_notification_bcc' => $quota_notification_bcc,
|
||||
'rl' => $rl,
|
||||
'rlyhosts' => $rlyhosts,
|
||||
'dkim' => dkim('details', $domain),
|
||||
'domain_details' => $result,
|
||||
];
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET["template"])){
|
||||
$domain_template = mailbox('get', 'domain_templates', $_GET["template"]);
|
||||
if ($domain_template){
|
||||
$template_data = [
|
||||
'acl' => $_SESSION['acl'],
|
||||
'domain' => $domain,
|
||||
'quota_notification_bcc' => $quota_notification_bcc,
|
||||
'rl' => $rl,
|
||||
'rlyhosts' => $rlyhosts,
|
||||
'dkim' => dkim('details', $domain),
|
||||
'domain_details' => $result,
|
||||
'template' => $domain_template
|
||||
];
|
||||
$template = 'edit/domain-templates.twig';
|
||||
$result = true;
|
||||
}
|
||||
else {
|
||||
$mailbox_template = mailbox('get', 'mailbox_templates', $_GET["template"]);
|
||||
if ($mailbox_template){
|
||||
$template_data = [
|
||||
'template' => $mailbox_template
|
||||
];
|
||||
$template = 'edit/mailbox-templates.twig';
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['oauth2client']) &&
|
||||
is_numeric($_GET["oauth2client"]) &&
|
||||
|
@ -79,29 +101,32 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
'dkim' => dkim('details', $alias_domain),
|
||||
];
|
||||
}
|
||||
elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
||||
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
|
||||
$result = mailbox('get', 'mailbox_details', $mailbox);
|
||||
$rl = ratelimit('get', 'mailbox', $mailbox);
|
||||
$pushover_data = pushover('get', $mailbox);
|
||||
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
|
||||
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
|
||||
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
|
||||
$rlyhosts = relayhost('get');
|
||||
$template = 'edit/mailbox.twig';
|
||||
$template_data = [
|
||||
'acl' => $_SESSION['acl'],
|
||||
'mailbox' => $mailbox,
|
||||
'rl' => $rl,
|
||||
'pushover_data' => $pushover_data,
|
||||
'quarantine_notification' => $quarantine_notification,
|
||||
'quarantine_category' => $quarantine_category,
|
||||
'get_tls_policy' => $get_tls_policy,
|
||||
'rlyhosts' => $rlyhosts,
|
||||
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
||||
'user_acls' => acl('get', 'user', $mailbox),
|
||||
'mailbox_details' => $result
|
||||
];
|
||||
elseif (isset($_GET['mailbox'])){
|
||||
if(filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
||||
// edit mailbox
|
||||
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
|
||||
$result = mailbox('get', 'mailbox_details', $mailbox);
|
||||
$rl = ratelimit('get', 'mailbox', $mailbox);
|
||||
$pushover_data = pushover('get', $mailbox);
|
||||
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
|
||||
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
|
||||
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
|
||||
$rlyhosts = relayhost('get');
|
||||
$template = 'edit/mailbox.twig';
|
||||
$template_data = [
|
||||
'acl' => $_SESSION['acl'],
|
||||
'mailbox' => $mailbox,
|
||||
'rl' => $rl,
|
||||
'pushover_data' => $pushover_data,
|
||||
'quarantine_notification' => $quarantine_notification,
|
||||
'quarantine_category' => $quarantine_category,
|
||||
'get_tls_policy' => $get_tls_policy,
|
||||
'rlyhosts' => $rlyhosts,
|
||||
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
||||
'user_acls' => acl('get', 'user', $mailbox),
|
||||
'mailbox_details' => $result
|
||||
];
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
|
||||
$relayhost = intval($_GET["relayhost"]);
|
||||
|
@ -189,5 +214,6 @@ $js_minifier->add('/web/js/site/pwgen.js');
|
|||
$template_data['result'] = $result;
|
||||
$template_data['return_to'] = $_SESSION['return_to'];
|
||||
$template_data['lang_user'] = json_encode($lang['user']);
|
||||
$template_data['lang_datatables'] = json_encode($lang['datatables']);
|
||||
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
|
@ -436,7 +436,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
|||
}
|
||||
?>
|
||||
</table>
|
||||
<a id='download-zonefile' class="btn btn-sm btn-default visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline" style="margin-top:10px" data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
|
||||
<a id='download-zonefile' class="btn btn-sm btn-secondary visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline mb-4" style="margin-top:10px" data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
|
||||
<script>
|
||||
var zonefile_dl_link = document.getElementById('download-zonefile');
|
||||
var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile'));
|
||||
|
|
|
@ -2,8 +2,18 @@
|
|||
function customize($_action, $_item, $_data = null) {
|
||||
global $redis;
|
||||
global $lang;
|
||||
|
||||
switch ($_action) {
|
||||
case 'add':
|
||||
// disable functionality when demo mode is enabled
|
||||
if ($GLOBALS["DEMO_MODE"]) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => 'demo_mode_enabled'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
|
@ -72,6 +82,15 @@ function customize($_action, $_item, $_data = null) {
|
|||
}
|
||||
break;
|
||||
case 'edit':
|
||||
// disable functionality when demo mode is enabled
|
||||
if ($GLOBALS["DEMO_MODE"]) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => 'demo_mode_enabled'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
|
@ -116,6 +135,7 @@ function customize($_action, $_item, $_data = null) {
|
|||
$ui_announcement_text = $_data['ui_announcement_text'];
|
||||
$ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false;
|
||||
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
||||
|
||||
try {
|
||||
$redis->set('TITLE_NAME', htmlspecialchars($title_name));
|
||||
$redis->set('MAIN_NAME', htmlspecialchars($main_name));
|
||||
|
@ -143,6 +163,15 @@ function customize($_action, $_item, $_data = null) {
|
|||
}
|
||||
break;
|
||||
case 'delete':
|
||||
// disable functionality when demo mode is enabled
|
||||
if ($GLOBALS["DEMO_MODE"]) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => 'demo_mode_enabled'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
||||
global $DOCKER_TIMEOUT;
|
||||
global $redis;
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
||||
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
||||
|
@ -32,6 +33,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||
}
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case 'containers':
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
@ -51,6 +53,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||
if (strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +97,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||
unset($container['Config']['Env']);
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +107,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||
unset($container['Config']['Env']);
|
||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
|
||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config'];
|
||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($decoded_response['Id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,5 +151,46 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'container_stats':
|
||||
if (empty($service_name)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$container_id = $service_name;
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/container/' . $container_id . '/stats/update');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
$response = curl_exec($curl);
|
||||
if ($response === false) {
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
return $err;
|
||||
}
|
||||
else {
|
||||
curl_close($curl);
|
||||
$stats = json_decode($response, true);
|
||||
if (!empty($stats)) return $stats;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case 'host_stats':
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/host/stats');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
$response = curl_exec($curl);
|
||||
if ($response === false) {
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
return $err;
|
||||
}
|
||||
else {
|
||||
curl_close($curl);
|
||||
$stats = json_decode($response, true);
|
||||
if (!empty($stats)) return $stats;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ function password_check($password1, $password2) {
|
|||
|
||||
return true;
|
||||
}
|
||||
function last_login($action, $username, $sasl_limit_days = 7) {
|
||||
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||
global $pdo;
|
||||
global $redis;
|
||||
$sasl_limit_days = intval($sasl_limit_days);
|
||||
|
@ -319,8 +319,11 @@ function last_login($action, $username, $sasl_limit_days = 7) {
|
|||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
||||
AND JSON_EXTRACT(`call`, "$[1]") = :username
|
||||
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET 1');
|
||||
$stmt->execute(array(':username' => $username));
|
||||
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET :offset');
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':offset' => $ui_offset
|
||||
));
|
||||
$ui = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1020,6 +1020,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
if (empty($name)) {
|
||||
$name = $local_part;
|
||||
}
|
||||
if (isset($_data['protocol_access'])) {
|
||||
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
$active = intval($_data['active']);
|
||||
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||
|
@ -1200,10 +1207,63 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
':domain' => $domain,
|
||||
':active' => $active
|
||||
));
|
||||
$stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
|
||||
|
||||
if (isset($_data['acl'])) {
|
||||
$_data['acl'] = (array)$_data['acl'];
|
||||
$_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||
$_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||
$_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||
$_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||
$_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||
$_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||
$_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||
$_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO `user_acl`
|
||||
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
|
||||
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
|
||||
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
|
||||
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':spam_alias' => $_data['spam_alias'],
|
||||
':tls_policy' => $_data['tls_policy'],
|
||||
':spam_score' => $_data['spam_score'],
|
||||
':spam_policy' => $_data['spam_policy'],
|
||||
':delimiter_action' => $_data['delimiter_action'],
|
||||
':syncjobs' => $_data['syncjobs'],
|
||||
':eas_reset' => $_data['eas_reset'],
|
||||
':sogo_profile_reset' => $_data['sogo_profile_reset'],
|
||||
':pushover' => $_data['pushover'],
|
||||
':quarantine' => $_data['quarantine'],
|
||||
':quarantine_attachments' => $_data['quarantine_attachments'],
|
||||
':quarantine_notification' => $_data['quarantine_notification'],
|
||||
':quarantine_category' => $_data['quarantine_category'],
|
||||
':app_passwds' => $_data['app_passwds']
|
||||
));
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
}
|
||||
|
||||
if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
|
||||
ratelimit('edit', 'mailbox', array(
|
||||
'object' => $username,
|
||||
'rl_frame' => $_data['rl_frame'],
|
||||
'rl_value' => $_data['rl_value']
|
||||
));
|
||||
}
|
||||
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
|
@ -1322,6 +1382,190 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
'msg' => array('resource_added', htmlspecialchars($name))
|
||||
);
|
||||
break;
|
||||
case 'domain_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (empty($_data["template"])){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'template_name_invalid'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if template name exists, return false
|
||||
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||
$stmt->execute(array(
|
||||
":type" => "domain",
|
||||
":template" => $_data["template"]
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!empty($row)){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => array('template_exists', $_data["template"])
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check attributes
|
||||
$attr = array();
|
||||
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||
$attr['max_num_aliases_for_domain'] = (!empty($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 400;
|
||||
$attr['max_num_mboxes_for_domain'] = (!empty($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 10;
|
||||
$attr['def_quota_for_mbox'] = (!empty($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 3072 * 1048576;
|
||||
$attr['max_quota_for_mbox'] = (!empty($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 10240 * 1048576;
|
||||
$attr['max_quota_for_domain'] = (!empty($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 10240 * 1048576;
|
||||
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
|
||||
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
|
||||
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
|
||||
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
|
||||
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
|
||||
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
|
||||
|
||||
// save template
|
||||
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||
VALUES (:type, :template, :attributes)");
|
||||
$stmt->execute(array(
|
||||
":type" => "domain",
|
||||
":template" => $_data["template"],
|
||||
":attributes" => json_encode($attr)
|
||||
));
|
||||
|
||||
// success
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('template_added', $_data["template"])
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
case 'mailbox_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (empty($_data["template"])){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'template_name_invalid'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if template name exists, return false
|
||||
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||
$stmt->execute(array(
|
||||
":type" => "mailbox",
|
||||
":template" => $_data["template"]
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($row)){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => array('template_exists', $_data["template"])
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// check attributes
|
||||
$attr = array();
|
||||
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
|
||||
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
||||
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
|
||||
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||
if (isset($_data['protocol_access'])) {
|
||||
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||
}
|
||||
else {
|
||||
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||
$attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||
$attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||
$attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||
}
|
||||
if (isset($_data['acl'])) {
|
||||
$_data['acl'] = (array)$_data['acl'];
|
||||
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||
} else {
|
||||
$_data['acl'] = (array)$_data['acl'];
|
||||
$attr['acl_spam_alias'] = 1;
|
||||
$attr['acl_tls_policy'] = 1;
|
||||
$attr['acl_spam_score'] = 1;
|
||||
$attr['acl_spam_policy'] = 1;
|
||||
$attr['acl_delimiter_action'] = 1;
|
||||
$attr['acl_syncjobs'] = 0;
|
||||
$attr['acl_eas_reset'] = 1;
|
||||
$attr['acl_sogo_profile_reset'] = 0;
|
||||
$attr['acl_pushover'] = 1;
|
||||
$attr['acl_quarantine'] = 1;
|
||||
$attr['acl_quarantine_attachments'] = 1;
|
||||
$attr['acl_quarantine_notification'] = 1;
|
||||
$attr['acl_quarantine_category'] = 1;
|
||||
$attr['acl_app_passwds'] = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// save template
|
||||
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||
VALUES (:type, :template, :attributes)");
|
||||
$stmt->execute(array(
|
||||
":type" => "mailbox",
|
||||
":template" => $_data["template"],
|
||||
":attributes" => json_encode($attr)
|
||||
));
|
||||
|
||||
// success
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('template_added', $_data["template"])
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'edit':
|
||||
|
@ -2472,6 +2716,79 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'domain_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!is_array($_data['ids'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['ids'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['ids'];
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$is_now = mailbox("get", "domain_templates", $id);
|
||||
if (empty($is_now) ||
|
||||
$is_now["type"] != "domain"){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'template_id_invalid'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check name
|
||||
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
|
||||
// keep template name of Default template
|
||||
$_data["template"] = $is_now["template"];
|
||||
}
|
||||
else {
|
||||
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
|
||||
}
|
||||
// check attributes
|
||||
$attr = array();
|
||||
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||
$attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
|
||||
$attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
|
||||
$attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
|
||||
$attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
|
||||
$attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
|
||||
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
|
||||
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
|
||||
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
|
||||
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
|
||||
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
|
||||
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
|
||||
|
||||
// update template
|
||||
$stmt = $pdo->prepare("UPDATE `templates`
|
||||
SET `template` = :template, `attributes` = :attributes
|
||||
WHERE id = :id");
|
||||
$stmt->execute(array(
|
||||
":id" => $id ,
|
||||
":template" => $_data["template"] ,
|
||||
":attributes" => json_encode($attr)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('template_modified', $_data["template"])
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
case 'mailbox':
|
||||
if (!is_array($_data['username'])) {
|
||||
$usernames = array();
|
||||
|
@ -2814,6 +3131,110 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
);
|
||||
}
|
||||
break;
|
||||
case 'mailbox_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!is_array($_data['ids'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['ids'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['ids'];
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$is_now = mailbox("get", "mailbox_templates", $id);
|
||||
if (empty($is_now) ||
|
||||
$is_now["type"] != "mailbox"){
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||
'msg' => 'template_id_invalid'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// check name
|
||||
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
|
||||
// keep template name of Default template
|
||||
$_data["template"] = $is_now["template"];
|
||||
}
|
||||
else {
|
||||
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
|
||||
}
|
||||
// check attributes
|
||||
$attr = array();
|
||||
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
|
||||
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
|
||||
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
|
||||
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
|
||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
|
||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
|
||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
|
||||
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
|
||||
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
|
||||
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
|
||||
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
|
||||
if (isset($_data['protocol_access'])) {
|
||||
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
foreach ($is_now as $key => $value){
|
||||
$attr[$key] = $is_now[$key];
|
||||
}
|
||||
}
|
||||
if (isset($_data['acl'])) {
|
||||
$_data['acl'] = (array)$_data['acl'];
|
||||
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||
} else {
|
||||
foreach ($is_now as $key => $value){
|
||||
$attr[$key] = $is_now[$key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update template
|
||||
$stmt = $pdo->prepare("UPDATE `templates`
|
||||
SET `template` = :template, `attributes` = :attributes
|
||||
WHERE id = :id");
|
||||
$stmt->execute(array(
|
||||
":id" => $id ,
|
||||
":template" => $_data["template"] ,
|
||||
":attributes" => json_encode($attr)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('template_modified', $_data["template"])
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
case 'resource':
|
||||
if (!is_array($_data['name'])) {
|
||||
$names = array();
|
||||
|
@ -3606,6 +4027,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
`mailboxes`,
|
||||
`defquota`,
|
||||
`maxquota`,
|
||||
`created`,
|
||||
`modified`,
|
||||
`quota`,
|
||||
`relayhost`,
|
||||
`relay_all_recipients`,
|
||||
|
@ -3678,6 +4101,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
$domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
|
||||
$domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
|
||||
$domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
|
||||
$domaindata['created'] = $row['created'];
|
||||
$domaindata['modified'] = $row['modified'];
|
||||
$stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
|
||||
WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
|
||||
AND `address` NOT IN (
|
||||
|
@ -3711,6 +4136,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
|
||||
return $domaindata;
|
||||
break;
|
||||
case 'domain_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||
return false;
|
||||
}
|
||||
$_data = (isset($_data)) ? intval($_data) : null;
|
||||
|
||||
if (isset($_data)){
|
||||
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||
WHERE `id` = :id AND type = :type");
|
||||
$stmt->execute(array(
|
||||
":id" => $_data,
|
||||
":type" => "domain"
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($row)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$row["attributes"] = json_decode($row["attributes"], true);
|
||||
return $row;
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'");
|
||||
$stmt->execute();
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($rows)){
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($rows as $key => $row){
|
||||
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
break;
|
||||
case 'mailbox_details':
|
||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||
return false;
|
||||
|
@ -3725,6 +4187,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
`mailbox`.`domain`,
|
||||
`mailbox`.`local_part`,
|
||||
`mailbox`.`quota`,
|
||||
`mailbox`.`created`,
|
||||
`mailbox`.`modified`,
|
||||
`quota2`.`bytes`,
|
||||
`attributes`,
|
||||
`quota2`.`messages`
|
||||
|
@ -3743,6 +4207,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
`mailbox`.`domain`,
|
||||
`mailbox`.`local_part`,
|
||||
`mailbox`.`quota`,
|
||||
`mailbox`.`created`,
|
||||
`mailbox`.`modified`,
|
||||
`quota2replica`.`bytes`,
|
||||
`attributes`,
|
||||
`quota2replica`.`messages`
|
||||
|
@ -3769,6 +4235,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
|
||||
$mailboxdata['quota_used'] = intval($row['bytes']);
|
||||
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||
$mailboxdata['created'] = $row['created'];
|
||||
$mailboxdata['modified'] = $row['modified'];
|
||||
|
||||
if ($mailboxdata['percent_in_use'] === '- ') {
|
||||
$mailboxdata['percent_class'] = "info";
|
||||
|
@ -3856,6 +4324,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
|
||||
return $mailboxdata;
|
||||
break;
|
||||
case 'mailbox_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||
return false;
|
||||
}
|
||||
$_data = (isset($_data)) ? intval($_data) : null;
|
||||
|
||||
if (isset($_data)){
|
||||
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||
WHERE `id` = :id AND type = :type");
|
||||
$stmt->execute(array(
|
||||
":id" => $_data,
|
||||
":type" => "mailbox"
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($row)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$row["attributes"] = json_decode($row["attributes"], true);
|
||||
return $row;
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'");
|
||||
$stmt->execute();
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($rows)){
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($rows as $key => $row){
|
||||
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
break;
|
||||
case 'resource_details':
|
||||
$resourcedata = array();
|
||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||
|
@ -4224,6 +4729,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
);
|
||||
}
|
||||
break;
|
||||
case 'domain_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!is_array($_data['ids'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['ids'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['ids'];
|
||||
}
|
||||
|
||||
|
||||
foreach ($ids as $id) {
|
||||
// delete template
|
||||
$stmt = $pdo->prepare("DELETE FROM `templates`
|
||||
WHERE id = :id AND type = :type AND NOT template = :template");
|
||||
$stmt->execute(array(
|
||||
":id" => $id,
|
||||
":type" => "domain",
|
||||
":template" => "Default"
|
||||
));
|
||||
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('template_removed', htmlspecialchars($id))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'alias':
|
||||
if (!is_array($_data['id'])) {
|
||||
$ids = array();
|
||||
|
@ -4518,6 +5059,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||
);
|
||||
}
|
||||
break;
|
||||
case 'mailbox_templates':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!is_array($_data['ids'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['ids'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['ids'];
|
||||
}
|
||||
|
||||
|
||||
foreach ($ids as $id) {
|
||||
// delete template
|
||||
$stmt = $pdo->prepare("DELETE FROM `templates`
|
||||
WHERE id = :id AND type = :type AND NOT template = :template");
|
||||
$stmt->execute(array(
|
||||
":id" => $id,
|
||||
":type" => "mailbox",
|
||||
":template" => "Default"
|
||||
));
|
||||
}
|
||||
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'template_removed'
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
case 'resource':
|
||||
if (!is_array($_data['name'])) {
|
||||
$names = array();
|
||||
|
|
|
@ -39,7 +39,6 @@ $globalVariables = [
|
|||
'dual_login' => @$_SESSION['dual-login'],
|
||||
'ui_texts' => $UI_TEXTS,
|
||||
'css_path' => '/cache/'.basename($CSSPath),
|
||||
'theme' => strtolower(trim($DEFAULT_THEME)),
|
||||
'logo' => customize('get', 'main_logo'),
|
||||
'available_languages' => $AVAILABLE_LANGUAGES,
|
||||
'lang' => $lang,
|
||||
|
@ -49,6 +48,7 @@ $globalVariables = [
|
|||
'app_links' => customize('get', 'app_links'),
|
||||
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
|
||||
'uri' => $_SERVER['REQUEST_URI'],
|
||||
'last_login' => last_login('get', $_SESSION['mailcow_cc_username'], 7, 0)['ui']['time']
|
||||
];
|
||||
|
||||
foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
|
||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
|||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "17112022_2115";
|
||||
$db_version = "23122022_1445";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
@ -225,6 +225,22 @@ function init_db_schema() {
|
|||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"templates" => array(
|
||||
"cols" => array(
|
||||
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||
"template" => "VARCHAR(255) NOT NULL",
|
||||
"type" => "VARCHAR(255) NOT NULL",
|
||||
"attributes" => "JSON",
|
||||
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP"
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
"" => array("id")
|
||||
)
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"domain" => array(
|
||||
// Todo: Move some attributes to json
|
||||
"cols" => array(
|
||||
|
@ -1293,6 +1309,95 @@ function init_db_schema() {
|
|||
// Fix domain_admins
|
||||
$pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';");
|
||||
|
||||
// add default templates
|
||||
$default_domain_template = array(
|
||||
"template" => "Default",
|
||||
"type" => "domain",
|
||||
"attributes" => array(
|
||||
"tags" => array(),
|
||||
"max_num_aliases_for_domain" => 400,
|
||||
"max_num_mboxes_for_domain" => 10,
|
||||
"def_quota_for_mbox" => 3072 * 1048576,
|
||||
"max_quota_for_mbox" => 10240 * 1048576,
|
||||
"max_quota_for_domain" => 10240 * 1048576,
|
||||
"rl_frame" => "s",
|
||||
"rl_value" => "",
|
||||
"active" => 1,
|
||||
"gal" => 1,
|
||||
"backupmx" => 0,
|
||||
"relay_all_recipients" => 0,
|
||||
"relay_unknown_only" => 0,
|
||||
"dkim_selector" => "dkim",
|
||||
"key_size" => 2048,
|
||||
"max_quota_for_domain" => 10240 * 1048576,
|
||||
)
|
||||
);
|
||||
$default_mailbox_template = array(
|
||||
"template" => "Default",
|
||||
"type" => "mailbox",
|
||||
"attributes" => array(
|
||||
"tags" => array(),
|
||||
"quota" => 0,
|
||||
"quarantine_notification" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_notification']),
|
||||
"quarantine_category" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_category']),
|
||||
"rl_frame" => "s",
|
||||
"rl_value" => "",
|
||||
"force_pw_update" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_pw_update']),
|
||||
"sogo_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_access']),
|
||||
"active" => 1,
|
||||
"tls_enforce_in" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_in']),
|
||||
"tls_enforce_out" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_out']),
|
||||
"imap_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['imap_access']),
|
||||
"pop3_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['pop3_access']),
|
||||
"smtp_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['smtp_access']),
|
||||
"sieve_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sieve_access']),
|
||||
"acl_spam_alias" => 1,
|
||||
"acl_tls_policy" => 1,
|
||||
"acl_spam_score" => 1,
|
||||
"acl_spam_policy" => 1,
|
||||
"acl_delimiter_action" => 1,
|
||||
"acl_syncjobs" => 0,
|
||||
"acl_eas_reset" => 1,
|
||||
"acl_sogo_profile_reset" => 0,
|
||||
"acl_pushover" => 1,
|
||||
"acl_quarantine" => 1,
|
||||
"acl_quarantine_attachments" => 1,
|
||||
"acl_quarantine_notification" => 1,
|
||||
"acl_quarantine_category" => 1,
|
||||
"acl_app_passwds" => 1,
|
||||
)
|
||||
);
|
||||
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||
$stmt->execute(array(
|
||||
":type" => "domain",
|
||||
":template" => $default_domain_template["template"]
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (empty($row)){
|
||||
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||
VALUES (:type, :template, :attributes)");
|
||||
$stmt->execute(array(
|
||||
":type" => "domain",
|
||||
":template" => $default_domain_template["template"],
|
||||
":attributes" => json_encode($default_domain_template["attributes"])
|
||||
));
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||
$stmt->execute(array(
|
||||
":type" => "mailbox",
|
||||
":template" => $default_mailbox_template["template"]
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (empty($row)){
|
||||
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||
VALUES (:type, :template, :attributes)");
|
||||
$stmt->execute(array(
|
||||
":type" => "mailbox",
|
||||
":template" => $default_mailbox_template["template"],
|
||||
":attributes" => json_encode($default_mailbox_template["attributes"])
|
||||
));
|
||||
}
|
||||
|
||||
if (php_sapi_name() == "cli") {
|
||||
echo "DB initialization completed" . PHP_EOL;
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
// check for development mode
|
||||
$DEV_MODE = (getenv('DEV_MODE') == 'y');
|
||||
// check for demo mode
|
||||
$DEMO_MODE = (getenv('DEMO_MODE') == 'y');
|
||||
|
||||
// Slave does not serve UI
|
||||
/* if (!preg_match('/y|yes/i', getenv('MASTER'))) {
|
||||
|
@ -44,21 +46,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/CSSminifierExtended.php';
|
|||
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/array_merge_real.php';
|
||||
|
||||
// Minify JS
|
||||
use MatthiasMullie\Minify;
|
||||
$js_minifier = new JSminifierExtended();
|
||||
$js_dir = array_diff(scandir('/web/js/build'), array('..', '.'));
|
||||
foreach ($js_dir as $js_file) {
|
||||
$js_minifier->add('/web/js/build/' . $js_file);
|
||||
}
|
||||
|
||||
// Minify CSS
|
||||
$css_minifier = new CSSminifierExtended();
|
||||
$css_dir = array_diff(scandir('/web/css/build'), array('..', '.'));
|
||||
foreach ($css_dir as $css_file) {
|
||||
$css_minifier->add('/web/css/build/' . $css_file);
|
||||
}
|
||||
|
||||
// U2F API + T/HOTP API
|
||||
// u2f - deprecated, should be removed
|
||||
$u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']);
|
||||
|
@ -278,6 +265,7 @@ if(file_exists($langFile)) {
|
|||
$lang = array_merge_real($lang, json_decode(file_get_contents($langFile), true));
|
||||
}
|
||||
|
||||
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php';
|
||||
|
@ -312,4 +300,29 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
// }
|
||||
acl('to_session');
|
||||
}
|
||||
|
||||
// init frontend
|
||||
// Minify JS
|
||||
use MatthiasMullie\Minify;
|
||||
$js_minifier = new JSminifierExtended();
|
||||
$js_dir = array_diff(scandir('/web/js/build'), array('..', '.'));
|
||||
// Minify CSS
|
||||
$css_minifier = new CSSminifierExtended();
|
||||
$css_dir = array_diff(scandir('/web/css/build'), array('..', '.'));
|
||||
// get customized ui data
|
||||
$UI_TEXTS = customize('get', 'ui_texts');
|
||||
|
||||
|
||||
// minify bootstrap theme
|
||||
if (file_exists('/web/css/themes/'.$UI_THEME.'-bootstrap.css'))
|
||||
$css_minifier->add('/web/css/themes/'.$UI_THEME.'-bootstrap.css');
|
||||
else
|
||||
$css_minifier->add('/web/css/themes/lumen-bootstrap.css');
|
||||
// minify css build files
|
||||
foreach ($css_dir as $css_file) {
|
||||
$css_minifier->add('/web/css/build/' . $css_file);
|
||||
}
|
||||
// minify js build files
|
||||
foreach ($js_dir as $js_file) {
|
||||
$js_minifier->add('/web/js/build/' . $js_file);
|
||||
}
|
||||
|
|
|
@ -107,12 +107,10 @@ $AVAILABLE_LANGUAGES = array(
|
|||
'zh-tw' => '繁體中文 (Traditional Chinese)',
|
||||
);
|
||||
|
||||
// Change theme (default: lumen)
|
||||
// Needs to be one of those: cerulean, cosmo, cyborg, darkly, flatly, journal, lumen, paper, readable, sandstone,
|
||||
// simplex, slate, spacelab, superhero, united, yeti
|
||||
// See https://bootswatch.com/
|
||||
// WARNING: Only lumen is loaded locally. Enabling any other theme, will download external sources.
|
||||
$DEFAULT_THEME = 'lumen';
|
||||
// default theme is lumen
|
||||
// additional themes can be found here: https://bootswatch.com/
|
||||
// copy them to data/web/css/themes/{THEME-NAME}-bootstrap.css
|
||||
$UI_THEME = "lumen";
|
||||
|
||||
// Show DKIM private keys - false by default
|
||||
$SHOW_DKIM_PRIV_KEYS = false;
|
||||
|
|
|
@ -8,7 +8,7 @@ if (isset($_SESSION['mailcow_cc_role']) && isset($_SESSION['oauth2_request'])) {
|
|||
exit();
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin') {
|
||||
header('Location: /admin');
|
||||
header('Location: /debug');
|
||||
exit();
|
||||
}
|
||||
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* This plug-in for DataTables represents the ultimate option in extensibility
|
||||
* for sorting date / time strings correctly. It uses
|
||||
* [Moment.js](http://momentjs.com) to create automatic type detection and
|
||||
* sorting plug-ins for DataTables based on a given format. This way, DataTables
|
||||
* will automatically detect your temporal information and sort it correctly.
|
||||
*
|
||||
* For usage instructions, please see the DataTables blog
|
||||
* post that [introduces it](//datatables.net/blog/2014-12-18).
|
||||
*
|
||||
* @name Ultimate Date / Time sorting
|
||||
* @summary Sort date and time in any format using Moment.js
|
||||
* @author [Allan Jardine](//datatables.net)
|
||||
* @depends DataTables 1.10+, Moment.js 1.7+
|
||||
*
|
||||
* @example
|
||||
* $.fn.dataTable.moment( 'HH:mm MMM D, YY' );
|
||||
* $.fn.dataTable.moment( 'dddd, MMMM Do, YYYY' );
|
||||
*
|
||||
* $('#example').DataTable();
|
||||
*/
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["jquery", "moment", "datatables.net"], factory);
|
||||
} else {
|
||||
factory(jQuery, moment);
|
||||
}
|
||||
}(function ($, moment) {
|
||||
|
||||
function strip (d) {
|
||||
if ( typeof d === 'string' ) {
|
||||
// Strip HTML tags and newline characters if possible
|
||||
d = d.replace(/(<.*?>)|(\r?\n|\r)/g, '');
|
||||
|
||||
// Strip out surrounding white space
|
||||
d = d.trim();
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
$.fn.dataTable.moment = function ( format, locale, reverseEmpties ) {
|
||||
var types = $.fn.dataTable.ext.type;
|
||||
|
||||
// Add type detection
|
||||
types.detect.unshift( function ( d ) {
|
||||
d = strip(d);
|
||||
|
||||
// Null and empty values are acceptable
|
||||
if ( d === '' || d === null ) {
|
||||
return 'moment-'+format;
|
||||
}
|
||||
|
||||
return moment( d, format, locale, true ).isValid() ?
|
||||
'moment-'+format :
|
||||
null;
|
||||
} );
|
||||
|
||||
// Add sorting method - use an integer for the sorting
|
||||
types.order[ 'moment-'+format+'-pre' ] = function ( d ) {
|
||||
d = strip(d);
|
||||
|
||||
return !moment(d, format, locale, true).isValid() ?
|
||||
(reverseEmpties ? -Infinity : Infinity) :
|
||||
parseInt( moment( d, format, locale, true ).format( 'x' ), 10 );
|
||||
};
|
||||
};
|
||||
|
||||
}));
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,778 +0,0 @@
|
|||
//Copyright 2014-2015 Google Inc. All rights reserved.
|
||||
|
||||
//Use of this source code is governed by a BSD-style
|
||||
//license that can be found in the LICENSE file or at
|
||||
//https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// ref: https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js
|
||||
|
||||
/**
|
||||
* @fileoverview The U2F api.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Modification:
|
||||
* Wrap implementation so that we can exit if window.u2f is already supplied by the browser (see below).
|
||||
*/
|
||||
(function (root) {
|
||||
/**
|
||||
* Modification:
|
||||
* Only continue load this library if window.u2f is not already supplied by the browser.
|
||||
*/
|
||||
var browserImplementsU2f = !!((typeof root.u2f !== 'undefined') && root.u2f.register);
|
||||
|
||||
if (browserImplementsU2f) {
|
||||
root.u2f.isSupported = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Namespace for the U2F api.
|
||||
* @type {Object}
|
||||
*/
|
||||
var u2f = root.u2f || {};
|
||||
|
||||
/**
|
||||
* Modification:
|
||||
* Check if browser supports U2F API before this wrapper was added.
|
||||
*/
|
||||
u2f.isSupported = !!(((typeof u2f !== 'undefined') && u2f.register) || ((typeof chrome !== 'undefined') && chrome.runtime));
|
||||
|
||||
/**
|
||||
* FIDO U2F Javascript API Version
|
||||
* @number
|
||||
*/
|
||||
var js_api_version;
|
||||
|
||||
/**
|
||||
* The U2F extension id
|
||||
* @const {string}
|
||||
*/
|
||||
// The Chrome packaged app extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the package Chrome app and does not require installing the U2F Chrome extension.
|
||||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||||
// The U2F Chrome extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the U2F Chrome extension to authenticate.
|
||||
// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
|
||||
|
||||
|
||||
/**
|
||||
* Message types for messsages to/from the extension
|
||||
* @const
|
||||
* @enum {string}
|
||||
*/
|
||||
u2f.MessageTypes = {
|
||||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||||
'U2F_SIGN_RESPONSE': 'u2f_sign_response',
|
||||
'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
|
||||
'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response status codes
|
||||
* @const
|
||||
* @enum {number}
|
||||
*/
|
||||
u2f.ErrorCodes = {
|
||||
'OK': 0,
|
||||
'OTHER_ERROR': 1,
|
||||
'BAD_REQUEST': 2,
|
||||
'CONFIGURATION_UNSUPPORTED': 3,
|
||||
'DEVICE_INELIGIBLE': 4,
|
||||
'TIMEOUT': 5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration requests
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* appId: ?string,
|
||||
* timeoutSeconds: ?number,
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fRequest;
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration responses
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fResponse;
|
||||
|
||||
|
||||
/**
|
||||
* An error object for responses
|
||||
* @typedef {{
|
||||
* errorCode: u2f.ErrorCodes,
|
||||
* errorMessage: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.Error;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
|
||||
*/
|
||||
u2f.Transport;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {Array<u2f.Transport>}
|
||||
*/
|
||||
u2f.Transports;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* keyHandle: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a sign response.
|
||||
* @typedef {{
|
||||
* keyHandle: string,
|
||||
* signatureData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration response.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: Transports,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registered key.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: ?Transports,
|
||||
* appId: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisteredKey;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a get API register response.
|
||||
* @typedef {{
|
||||
* js_api_version: number
|
||||
* }}
|
||||
*/
|
||||
u2f.GetJsApiVersionResponse;
|
||||
|
||||
|
||||
//Low level MessagePort API support
|
||||
|
||||
/**
|
||||
* Sets up a MessagePort to the U2F extension using the
|
||||
* available mechanisms.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
*/
|
||||
u2f.getMessagePort = function (callback) {
|
||||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||||
// The actual message here does not matter, but we need to get a reply
|
||||
// for the callback to run. Thus, send an empty signature request
|
||||
// in order to get a failure response.
|
||||
var msg = {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: []
|
||||
};
|
||||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function () {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// We are on a whitelisted origin and can talk directly
|
||||
// with the extension.
|
||||
u2f.getChromeRuntimePort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was available, but we couldn't message
|
||||
// the extension directly, use iframe
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
});
|
||||
} else if (u2f.isAndroidChrome_()) {
|
||||
u2f.getAuthenticatorPort_(callback);
|
||||
} else if (u2f.isIosChrome_()) {
|
||||
u2f.getIosPort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was not available at all, which is normal
|
||||
// when this origin doesn't have access to any extensions.
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on android based on the browser's useragent.
|
||||
* @private
|
||||
*/
|
||||
u2f.isAndroidChrome_ = function () {
|
||||
var userAgent = navigator.userAgent;
|
||||
return userAgent.indexOf('Chrome') != -1 &&
|
||||
userAgent.indexOf('Android') != -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on iOS based on the browser's platform.
|
||||
* @private
|
||||
*/
|
||||
u2f.isIosChrome_ = function () {
|
||||
return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects directly to the extension via chrome.runtime.connect.
|
||||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getChromeRuntimePort_ = function (callback) {
|
||||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||||
{ 'includeTlsChannelId': true });
|
||||
setTimeout(function () {
|
||||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the Authenticator app.
|
||||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getAuthenticatorPort_ = function (callback) {
|
||||
setTimeout(function () {
|
||||
callback(new u2f.WrappedAuthenticatorPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the iOS client app.
|
||||
* @param {function(u2f.WrappedIosPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIosPort_ = function (callback) {
|
||||
setTimeout(function () {
|
||||
callback(new u2f.WrappedIosPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||||
* @param {Port} port
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_ = function (port) {
|
||||
this.port_ = port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a sign request compliant with the JS API version supported by the extension.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatSignRequest_ =
|
||||
function (appId, challenge, registeredKeys, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: challenge,
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: signRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
appId: appId,
|
||||
challenge: challenge,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a register request compliant with the JS API version supported by the extension..
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatRegisterRequest_ =
|
||||
function (appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
for (var i = 0; i < registerRequests.length; i++) {
|
||||
registerRequests[i].appId = appId;
|
||||
}
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: registerRequests[0],
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
signRequests: signRequests,
|
||||
registerRequests: registerRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
appId: appId,
|
||||
registerRequests: registerRequests,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Posts a message on the underlying channel.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function (message) {
|
||||
this.port_.postMessage(message);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||||
function (eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message' || name == 'onmessage') {
|
||||
this.port_.onMessage.addListener(function (message) {
|
||||
// Emulate a minimal MessageEvent object
|
||||
handler({ 'data': message });
|
||||
});
|
||||
} else {
|
||||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the Authenticator app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_ = function () {
|
||||
this.requestId_ = -1;
|
||||
this.requestObject_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the Authenticator intent.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function (message) {
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.request=' + encodeURIComponent(JSON.stringify(message)) +
|
||||
';end';
|
||||
document.location = intentUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.getPortType = function () {
|
||||
return "WrappedAuthenticatorPort_";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function (eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message') {
|
||||
var self = this;
|
||||
/* Register a callback to that executes when
|
||||
* chrome injects the response. */
|
||||
window.addEventListener(
|
||||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||||
} else {
|
||||
console.error('WrappedAuthenticatorPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when a response is received from the Authenticator.
|
||||
* @param function({data: Object}) callback
|
||||
* @param {Object} message message Object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||||
function (callback, message) {
|
||||
var messageObject = JSON.parse(message.data);
|
||||
var intentUrl = messageObject['intentURL'];
|
||||
|
||||
var errorCode = messageObject['errorCode'];
|
||||
var responseObject = null;
|
||||
if (messageObject.hasOwnProperty('data')) {
|
||||
responseObject = /** @type {Object} */ (
|
||||
JSON.parse(messageObject['data']));
|
||||
}
|
||||
|
||||
callback({ 'data': responseObject });
|
||||
};
|
||||
|
||||
/**
|
||||
* Base URL for intents to Authenticator.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||||
|
||||
/**
|
||||
* Wrap the iOS client app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedIosPort_ = function () { };
|
||||
|
||||
/**
|
||||
* Launch the iOS client app request
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.postMessage = function (message) {
|
||||
var str = JSON.stringify(message);
|
||||
var url = "u2f://auth?" + encodeURI(str);
|
||||
location.replace(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.getPortType = function () {
|
||||
return "WrappedIosPort_";
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.addEventListener = function (eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name !== 'message') {
|
||||
console.error('WrappedIosPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||||
* @param {function(MessagePort)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIframePort_ = function (callback) {
|
||||
// Create the iframe
|
||||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||||
iframe.setAttribute('style', 'display:none');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
var ready = function (message) {
|
||||
if (message.data == 'ready') {
|
||||
channel.port1.removeEventListener('message', ready);
|
||||
callback(channel.port1);
|
||||
} else {
|
||||
console.error('First event on iframe port was not "ready"');
|
||||
}
|
||||
};
|
||||
channel.port1.addEventListener('message', ready);
|
||||
channel.port1.start();
|
||||
|
||||
iframe.addEventListener('load', function () {
|
||||
// Deliver the port to the iframe and initialize
|
||||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//High-level JS API
|
||||
|
||||
/**
|
||||
* Default extension response timeout in seconds.
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||||
|
||||
/**
|
||||
* A singleton instance for a MessagePort to the extension.
|
||||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||||
* @private
|
||||
*/
|
||||
u2f.port_ = null;
|
||||
|
||||
/**
|
||||
* Callbacks waiting for a port
|
||||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.waitingForPort_ = [];
|
||||
|
||||
/**
|
||||
* A counter for requestIds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
u2f.reqCounter_ = 0;
|
||||
|
||||
/**
|
||||
* A map from requestIds to client callbacks
|
||||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.callbackMap_ = {};
|
||||
|
||||
/**
|
||||
* Creates or retrieves the MessagePort singleton to use.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getPortSingleton_ = function (callback) {
|
||||
if (u2f.port_) {
|
||||
callback(u2f.port_);
|
||||
} else {
|
||||
if (u2f.waitingForPort_.length == 0) {
|
||||
u2f.getMessagePort(function (port) {
|
||||
u2f.port_ = port;
|
||||
u2f.port_.addEventListener('message',
|
||||
/** @type {function(Event)} */(u2f.responseHandler_));
|
||||
|
||||
// Careful, here be async callbacks. Maybe.
|
||||
while (u2f.waitingForPort_.length)
|
||||
u2f.waitingForPort_.shift()(u2f.port_);
|
||||
});
|
||||
}
|
||||
u2f.waitingForPort_.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles response messages from the extension.
|
||||
* @param {MessageEvent.<u2f.Response>} message
|
||||
* @private
|
||||
*/
|
||||
u2f.responseHandler_ = function (message) {
|
||||
var response = message.data;
|
||||
var reqId = response['requestId'];
|
||||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||||
console.error('Unknown or missing requestId in response.');
|
||||
return;
|
||||
}
|
||||
var cb = u2f.callbackMap_[reqId];
|
||||
delete u2f.callbackMap_[reqId];
|
||||
cb(response['responseData']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the sign request.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sign = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual sign request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual sign request in the supported API version.
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendSignRequest = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function (port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the register request.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.register = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual register request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual register request in the supported API version.
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendRegisterRequest = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function (port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatRegisterRequest_(
|
||||
appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a message to the extension to find out the supported
|
||||
* JS API version.
|
||||
* If the user is on a mobile phone and is thus using Google Authenticator instead
|
||||
* of the Chrome extension, don't send the request and simply return 0.
|
||||
* @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.getApiVersion = function (callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function (port) {
|
||||
// If we are using Android Google Authenticator or iOS client app,
|
||||
// do not fire an intent to ask which JS API version to use.
|
||||
if (port.getPortType) {
|
||||
var apiVersion;
|
||||
switch (port.getPortType()) {
|
||||
case 'WrappedIosPort_':
|
||||
case 'WrappedAuthenticatorPort_':
|
||||
apiVersion = 1.1;
|
||||
break;
|
||||
|
||||
default:
|
||||
apiVersion = 0;
|
||||
break;
|
||||
}
|
||||
callback({ 'js_api_version': apiVersion });
|
||||
return;
|
||||
}
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var req = {
|
||||
type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
|
||||
timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
|
||||
requestId: reqId
|
||||
};
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Modification:
|
||||
* Assign u2f back to window (root) scope.
|
||||
*/
|
||||
root.u2f = u2f;
|
||||
}(this));
|
|
@ -11,7 +11,7 @@ $(document).ready(function() {
|
|||
} else {
|
||||
var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent();
|
||||
if (parent_btn_grp.hasClass('btn-group')) {
|
||||
parent_btn_grp.replaceWith('<button class="btn btn-default btn-sm" disabled>' + lang_footer.loading + '</a>');
|
||||
parent_btn_grp.replaceWith('<button class="btn btn-secondary btn-sm" disabled>' + lang_footer.loading + '</a>');
|
||||
}
|
||||
$(elem).text(lang_footer.loading);
|
||||
$(elem).attr('data-submitted', '1');
|
||||
|
@ -355,11 +355,8 @@ $(document).ready(function() {
|
|||
data_array[i] = decodeURIComponent(data_array[i]);
|
||||
$("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
|
||||
}
|
||||
});
|
||||
$('#ConfirmDeleteModal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: false
|
||||
})
|
||||
})
|
||||
$('#ConfirmDeleteModal').modal('show')
|
||||
.one('click', '#IsConfirmed', function(e) {
|
||||
if (is_active($('#IsConfirmed'))) { return false; }
|
||||
$.ajax({
|
||||
|
@ -383,4 +380,18 @@ $(document).ready(function() {
|
|||
$('#ConfirmDeleteModal').modal('hide');
|
||||
});
|
||||
});
|
||||
|
||||
// toggle jquery datatables child rows
|
||||
$('button[data-datatables-expand], a[data-datatables-expand]').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var tableId = e.target.getAttribute("data-datatables-expand");
|
||||
var table = $("#" + tableId).DataTable();
|
||||
table.rows(':not(.parent)').nodes().to$().find('td:first-child').trigger('click');
|
||||
});
|
||||
$('button[data-datatables-collapse], a[data-datatables-collapse]').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
var tableId = e.target.getAttribute("data-datatables-collapse");
|
||||
var table = $("#" + tableId).DataTable();
|
||||
table.rows('.parent').nodes().to$().find('td:first-child').trigger('click');
|
||||
});
|
||||
});
|
|
@ -1,239 +0,0 @@
|
|||
!function ($) {
|
||||
|
||||
"use strict";
|
||||
|
||||
// TABCOLLAPSE CLASS DEFINITION
|
||||
// ======================
|
||||
|
||||
var TabCollapse = function (el, options) {
|
||||
this.options = options;
|
||||
this.$tabs = $(el);
|
||||
|
||||
this._accordionVisible = false; //content is attached to tabs at first
|
||||
this._initAccordion();
|
||||
this._checkStateOnResize();
|
||||
|
||||
|
||||
// checkState() has gone to setTimeout for making it possible to attach listeners to
|
||||
// shown-accordion.bs.tabcollapse event on page load.
|
||||
// See https://github.com/flatlogic/bootstrap-tabcollapse/issues/23
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
that.checkState();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
TabCollapse.DEFAULTS = {
|
||||
accordionClass: 'visible-xs',
|
||||
tabsClass: 'hidden-xs',
|
||||
accordionTemplate: function(heading, groupId, parentId, active) {
|
||||
return '<div class="panel panel-default">' +
|
||||
' <div class="panel-heading">' +
|
||||
' <h4 class="panel-title">' +
|
||||
' </h4>' +
|
||||
' </div>' +
|
||||
' <div id="' + groupId + '" class="panel-collapse collapse ' + (active ? 'in' : '') + '">' +
|
||||
' <div class="panel-body js-tabcollapse-panel-body">' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
'</div>'
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TabCollapse.prototype.checkState = function(){
|
||||
if (this.$tabs.is(':visible') && this._accordionVisible){
|
||||
this.showTabs();
|
||||
this._accordionVisible = false;
|
||||
} else if (this.$accordion.is(':visible') && !this._accordionVisible){
|
||||
this.showAccordion();
|
||||
this._accordionVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
TabCollapse.prototype.showTabs = function(){
|
||||
var view = this;
|
||||
this.$tabs.trigger($.Event('show-tabs.bs.tabcollapse'));
|
||||
|
||||
var $panelHeadings = this.$accordion.find('.js-tabcollapse-panel-heading').detach();
|
||||
|
||||
$panelHeadings.each(function() {
|
||||
var $panelHeading = $(this),
|
||||
$parentLi = $panelHeading.data('bs.tabcollapse.parentLi');
|
||||
|
||||
var $oldHeading = view._panelHeadingToTabHeading($panelHeading);
|
||||
|
||||
$parentLi.removeClass('active');
|
||||
if ($parentLi.parent().hasClass('dropdown-menu') && !$parentLi.siblings('li').hasClass('active')) {
|
||||
$parentLi.parent().parent().removeClass('active');
|
||||
}
|
||||
|
||||
if (!$oldHeading.hasClass('collapsed')) {
|
||||
$parentLi.addClass('active');
|
||||
$('.tab-pane').removeClass('active');
|
||||
$($panelHeading.attr('href')).addClass('active');
|
||||
if ($parentLi.parent().hasClass('dropdown-menu')) {
|
||||
$parentLi.parent().parent().addClass('active');
|
||||
}
|
||||
} else {
|
||||
$oldHeading.removeClass('collapsed');
|
||||
}
|
||||
|
||||
$parentLi.append($panelHeading);
|
||||
});
|
||||
|
||||
if (!$('li').hasClass('active')) {
|
||||
$('li').first().addClass('active')
|
||||
}
|
||||
|
||||
var $panelBodies = this.$accordion.find('.js-tabcollapse-panel-body');
|
||||
$panelBodies.each(function(){
|
||||
var $panelBody = $(this),
|
||||
$tabPane = $panelBody.data('bs.tabcollapse.tabpane');
|
||||
$tabPane.append($panelBody.contents().detach());
|
||||
});
|
||||
this.$accordion.html('');
|
||||
|
||||
if(this.options.updateLinks) {
|
||||
var $tabContents = this.getTabContentElement();
|
||||
$tabContents.find('[data-toggle-was="tab"], [data-toggle-was="pill"]').each(function() {
|
||||
var $el = $(this);
|
||||
var href = $el.attr('href').replace(/-collapse$/g, '');
|
||||
$el.attr({
|
||||
'data-toggle': $el.attr('data-toggle-was'),
|
||||
'data-toggle-was': '',
|
||||
'data-parent': '',
|
||||
href: href
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.$tabs.trigger($.Event('shown-tabs.bs.tabcollapse'));
|
||||
};
|
||||
|
||||
TabCollapse.prototype.getTabContentElement = function(){
|
||||
var $tabContents = $(this.options.tabContentSelector);
|
||||
if($tabContents.length === 0) {
|
||||
$tabContents = this.$tabs.siblings('.tab-content');
|
||||
}
|
||||
return $tabContents;
|
||||
};
|
||||
|
||||
TabCollapse.prototype.showAccordion = function(){
|
||||
this.$tabs.trigger($.Event('show-accordion.bs.tabcollapse'));
|
||||
|
||||
var $headings = this.$tabs.find('li:not(.dropdown) [data-toggle="tab"], li:not(.dropdown) [data-toggle="pill"]'),
|
||||
view = this;
|
||||
$headings.each(function(){
|
||||
var $heading = $(this),
|
||||
$parentLi = $heading.parent();
|
||||
$heading.data('bs.tabcollapse.parentLi', $parentLi);
|
||||
view.$accordion.append(view._createAccordionGroup(view.$accordion.attr('id'), $heading.detach()));
|
||||
});
|
||||
|
||||
if(this.options.updateLinks) {
|
||||
var parentId = this.$accordion.attr('id');
|
||||
var $selector = this.$accordion.find('.js-tabcollapse-panel-body');
|
||||
$selector.find('[data-toggle="tab"], [data-toggle="pill"]').each(function() {
|
||||
var $el = $(this);
|
||||
var href = $el.attr('href') + '-collapse';
|
||||
$el.attr({
|
||||
'data-toggle-was': $el.attr('data-toggle'),
|
||||
'data-toggle': 'collapse',
|
||||
'data-parent': '#' + parentId,
|
||||
href: href
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.$tabs.trigger($.Event('shown-accordion.bs.tabcollapse'));
|
||||
};
|
||||
|
||||
TabCollapse.prototype._panelHeadingToTabHeading = function($heading) {
|
||||
var href = $heading.attr('href').replace(/-collapse$/g, '');
|
||||
$heading.attr({
|
||||
'data-toggle': 'tab',
|
||||
'href': href,
|
||||
'data-parent': ''
|
||||
});
|
||||
return $heading;
|
||||
};
|
||||
|
||||
TabCollapse.prototype._tabHeadingToPanelHeading = function($heading, groupId, parentId, active) {
|
||||
$heading.addClass('js-tabcollapse-panel-heading ' + (active ? '' : 'collapsed'));
|
||||
$heading.attr({
|
||||
'data-toggle': 'collapse',
|
||||
'data-parent': '#' + parentId,
|
||||
'href': '#' + groupId
|
||||
});
|
||||
return $heading;
|
||||
};
|
||||
|
||||
TabCollapse.prototype._checkStateOnResize = function(){
|
||||
var view = this;
|
||||
$(window).resize(function(){
|
||||
clearTimeout(view._resizeTimeout);
|
||||
view._resizeTimeout = setTimeout(function(){
|
||||
view.checkState();
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
TabCollapse.prototype._initAccordion = function(){
|
||||
var randomString = function() {
|
||||
var result = "",
|
||||
possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for( var i=0; i < 5; i++ ) {
|
||||
result += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var srcId = this.$tabs.attr('id'),
|
||||
accordionId = (srcId ? srcId : randomString()) + '-accordion';
|
||||
|
||||
this.$accordion = $('<div class="panel-group ' + this.options.accordionClass + '" id="' + accordionId +'"></div>');
|
||||
this.$tabs.after(this.$accordion);
|
||||
this.$tabs.addClass(this.options.tabsClass);
|
||||
this.getTabContentElement().addClass(this.options.tabsClass);
|
||||
};
|
||||
|
||||
TabCollapse.prototype._createAccordionGroup = function(parentId, $heading){
|
||||
var tabSelector = $heading.attr('data-target'),
|
||||
active = $heading.data('bs.tabcollapse.parentLi').is('.active');
|
||||
|
||||
if (!tabSelector) {
|
||||
tabSelector = $heading.attr('href');
|
||||
tabSelector = tabSelector && tabSelector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
|
||||
}
|
||||
|
||||
var $tabPane = $(tabSelector),
|
||||
groupId = $tabPane.attr('id') + '-collapse',
|
||||
$panel = $(this.options.accordionTemplate($heading, groupId, parentId, active));
|
||||
$panel.find('.panel-heading > .panel-title').append(this._tabHeadingToPanelHeading($heading, groupId, parentId, active));
|
||||
$panel.find('.panel-body').append($tabPane.contents().detach())
|
||||
.data('bs.tabcollapse.tabpane', $tabPane);
|
||||
|
||||
return $panel;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// TABCOLLAPSE PLUGIN DEFINITION
|
||||
// =======================
|
||||
|
||||
$.fn.tabCollapse = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.tabcollapse');
|
||||
var options = $.extend({}, TabCollapse.DEFAULTS, $this.data(), typeof option === 'object' && option);
|
||||
|
||||
if (!data) $this.data('bs.tabcollapse', new TabCollapse(this, options));
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.tabCollapse.Constructor = TabCollapse;
|
||||
|
||||
|
||||
}(window.jQuery);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -55,14 +55,14 @@ $(document).ready(function() {
|
|||
|
||||
// tooltips
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
});
|
||||
|
||||
// remember last navigation pill
|
||||
(function () {
|
||||
'use strict';
|
||||
if ($('a[data-toggle="tab"]').length) {
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
// remember desktop tabs
|
||||
$('button[data-bs-toggle="tab"]').on('click', function (e) {
|
||||
if ($(this).data('dont-remember') == 1) {
|
||||
return true;
|
||||
}
|
||||
|
@ -71,8 +71,28 @@ $(document).ready(function() {
|
|||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
localStorage.setItem(key, $(e.target).attr('href'));
|
||||
|
||||
var tab_id = $(e.target).attr('data-bs-target').substring(1);
|
||||
localStorage.setItem(key, tab_id);
|
||||
});
|
||||
// remember mobile tabs
|
||||
$('button[data-bs-target^="#collapse-tab-"]').on('click', function (e) {
|
||||
// only remember tab if its being opened
|
||||
if ($(this).hasClass('collapsed')) return false;
|
||||
var tab_id = $(this).closest('div[role="tabpanel"]').attr('id');
|
||||
|
||||
if ($(this).data('dont-remember') == 1) {
|
||||
return true;
|
||||
}
|
||||
var id = $(this).parents('[role="tablist"]').attr('id');;
|
||||
var key = 'lastTag';
|
||||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
|
||||
localStorage.setItem(key, tab_id);
|
||||
});
|
||||
// open last tab
|
||||
$('[role="tablist"]').each(function (idx, elem) {
|
||||
var id = $(elem).attr('id');
|
||||
var key = 'lastTag';
|
||||
|
@ -81,10 +101,11 @@ $(document).ready(function() {
|
|||
}
|
||||
var lastTab = localStorage.getItem(key);
|
||||
if (lastTab) {
|
||||
$('[href="' + lastTab + '"]').tab('show');
|
||||
$('[data-bs-target="#' + lastTab + '"]').click();
|
||||
var tab = $('[id^="' + lastTab + '"]');
|
||||
$(tab).find('.card-body.collapse').collapse('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
// IE fix to hide scrollbars when table body is empty
|
||||
|
@ -119,7 +140,7 @@ $(document).ready(function() {
|
|||
shake(password_field);
|
||||
}
|
||||
else {
|
||||
$(hibp_result).attr('class', 'hibp-out label label-info');
|
||||
$(hibp_result).attr('class', 'hibp-out badge fs-5 bg-info');
|
||||
$(hibp_result).text(lang_footer.loading);
|
||||
var password_digest = $.sha1($(password_field).val())
|
||||
var digest_five = password_digest.substring(0, 5).toUpperCase();
|
||||
|
@ -130,16 +151,16 @@ $(document).ready(function() {
|
|||
type: 'GET',
|
||||
success: function(res) {
|
||||
if (res.search(compl_digest) > -1){
|
||||
$(hibp_result).removeClass('label label-info').addClass('label label-danger');
|
||||
$(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-danger');
|
||||
$(hibp_result).text(lang_footer.hibp_nok)
|
||||
} else {
|
||||
$(hibp_result).removeClass('label label-info').addClass('label label-success');
|
||||
$(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-success');
|
||||
$(hibp_result).text(lang_footer.hibp_ok)
|
||||
}
|
||||
$(hibp_field).removeClass('task-running');
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
$(hibp_result).removeClass('label label-info').addClass('label label-warning');
|
||||
$(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-warning');
|
||||
$(hibp_result).text('API error: ' + xhr.responseText)
|
||||
$(hibp_field).removeClass('task-running');
|
||||
}
|
||||
|
@ -150,8 +171,8 @@ $(document).ready(function() {
|
|||
// Disable disallowed inputs
|
||||
$('[data-acl="0"]').each(function(event){
|
||||
if ($(this).is("a")) {
|
||||
$(this).removeAttr("data-toggle");
|
||||
$(this).removeAttr("data-target");
|
||||
$(this).removeAttr("data-bs-toggle");
|
||||
$(this).removeAttr("data-bs-target");
|
||||
$(this).removeAttr("data-action");
|
||||
$(this).click(function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -166,8 +187,8 @@ $(document).ready(function() {
|
|||
if ($(this).hasClass('btn-group')) {
|
||||
$(this).find('a').each(function(){
|
||||
$(this).removeClass('dropdown-toggle')
|
||||
.removeAttr('data-toggle')
|
||||
.removeAttr('data-target')
|
||||
.removeAttr('data-bs-toggle')
|
||||
.removeAttr('data-bs-target')
|
||||
.removeAttr('data-action')
|
||||
.removeAttr('id')
|
||||
.attr("disabled", true);
|
||||
|
@ -182,7 +203,7 @@ $(document).ready(function() {
|
|||
} else if ($(this).hasClass('input-group')) {
|
||||
$(this).find('input').each(function() {
|
||||
$(this).removeClass('dropdown-toggle')
|
||||
.removeAttr('data-toggle')
|
||||
.removeAttr('data-bs-toggle')
|
||||
.attr("disabled", true);
|
||||
$(this).click(function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -226,7 +247,7 @@ $(document).ready(function() {
|
|||
$('#containerName').text(container);
|
||||
$('#triggerRestartContainer').click(function(){
|
||||
$(this).prop("disabled",true);
|
||||
$(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> ');
|
||||
$(this).html('<div class="spinner-border text-white" role="status"><span class="visually-hidden">Loading...</span></div>');
|
||||
$('#statusTriggerRestartContainer').html(lang_footer.restarting_container);
|
||||
$.ajax({
|
||||
method: 'get',
|
||||
|
@ -253,26 +274,11 @@ $(document).ready(function() {
|
|||
});
|
||||
})
|
||||
|
||||
// responsive tabs
|
||||
$('.responsive-tabs').tabCollapse({
|
||||
tabsClass: 'hidden-xs',
|
||||
accordionClass: 'js-tabcollapse-panel-group visible-xs'
|
||||
});
|
||||
$(document).on("shown.bs.collapse shown.bs.tab", function (e) {
|
||||
var target = $(e.target);
|
||||
if($(window).width() <= 767) {
|
||||
var offset = target.offset().top - 112;
|
||||
$("html, body").stop().animate({
|
||||
scrollTop: offset
|
||||
}, 100);
|
||||
}
|
||||
if(target.hasClass('panel-collapse')){
|
||||
var id = e.target.id.replace(/-collapse$/g, '');
|
||||
if(id){
|
||||
localStorage.setItem('lastTag', '#'+id);
|
||||
}
|
||||
}
|
||||
// Jquery Datatables, enable responsive plugin and date sort plugin
|
||||
$.extend($.fn.dataTable.defaults, {
|
||||
responsive: true
|
||||
});
|
||||
$.fn.dataTable.moment('dd:mm:YYYY');
|
||||
|
||||
// tag boxes
|
||||
$('.tag-box .tag-add').click(function(){
|
||||
|
@ -284,40 +290,65 @@ $(document).ready(function() {
|
|||
addTag(this);
|
||||
}
|
||||
});
|
||||
function addTag(tagAddElem){
|
||||
var tagboxElem = $(tagAddElem).parent();
|
||||
var tagInputElem = $(tagboxElem).find(".tag-input")[0];
|
||||
var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
|
||||
|
||||
var tag = escapeHtml($(tagInputElem).val());
|
||||
if (!tag) return;
|
||||
var value_tags = [];
|
||||
try {
|
||||
value_tags = JSON.parse($(tagValuesElem).val());
|
||||
} catch {}
|
||||
if (!Array.isArray(value_tags)) value_tags = [];
|
||||
if (value_tags.includes(tag)) return;
|
||||
|
||||
$('<span class="badge badge-primary tag-badge btn-badge"><i class="bi bi-tag-fill"></i> ' + tag + '</span>').insertBefore('.tag-input').click(function(){
|
||||
var del_tag = unescapeHtml($(this).text());
|
||||
var del_tags = [];
|
||||
try {
|
||||
del_tags = JSON.parse($(tagValuesElem).val());
|
||||
} catch {}
|
||||
if (Array.isArray(del_tags)){
|
||||
del_tags.splice(del_tags.indexOf(del_tag), 1);
|
||||
$(tagValuesElem).val(JSON.stringify(del_tags));
|
||||
}
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
value_tags.push($(tagInputElem).val());
|
||||
$(tagValuesElem).val(JSON.stringify(value_tags));
|
||||
$(tagInputElem).val('');
|
||||
// Dark Mode Loader
|
||||
$('#dark-mode-toggle').click(toggleDarkMode);
|
||||
if ($('#dark-mode-theme').length) {
|
||||
$('#dark-mode-toggle').prop('checked', true);
|
||||
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');
|
||||
}
|
||||
function toggleDarkMode(){
|
||||
if($('#dark-mode-theme').length){
|
||||
$('#dark-mode-theme').remove();
|
||||
$('#dark-mode-toggle').prop('checked', false);
|
||||
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);
|
||||
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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
||||
// https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
||||
function escapeHtml(n){var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
|
||||
function unescapeHtml(t){var n={"&":"&","<":"<",">":">",""":'"',"'":"'","/":"/","`":"`","=":"="};return String(t).replace(/&|<|>|"|'|/|`|=/g,function(t){return n[t]})}
|
||||
|
||||
function addTag(tagAddElem, tag = null){
|
||||
var tagboxElem = $(tagAddElem).parent();
|
||||
var tagInputElem = $(tagboxElem).find(".tag-input")[0];
|
||||
var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
|
||||
|
||||
if (!tag)
|
||||
tag = $(tagInputElem).val();
|
||||
if (!tag) return;
|
||||
var value_tags = [];
|
||||
try {
|
||||
value_tags = JSON.parse($(tagValuesElem).val());
|
||||
} catch {}
|
||||
if (!Array.isArray(value_tags)) value_tags = [];
|
||||
if (value_tags.includes(tag)) return;
|
||||
|
||||
$('<span class="badge bg-primary tag-badge btn-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(tag) + '</span>').insertBefore('.tag-input').click(function(){
|
||||
var del_tag = unescapeHtml($(this).text());
|
||||
var del_tags = [];
|
||||
try {
|
||||
del_tags = JSON.parse($(tagValuesElem).val());
|
||||
} catch {}
|
||||
if (Array.isArray(del_tags)){
|
||||
del_tags.splice(del_tags.indexOf(del_tag), 1);
|
||||
$(tagValuesElem).val(JSON.stringify(del_tags));
|
||||
}
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
value_tags.push(tag);
|
||||
$(tagValuesElem).val(JSON.stringify(value_tags));
|
||||
$(tagInputElem).val('');
|
||||
}
|
|
@ -53,237 +53,426 @@ jQuery(function($){
|
|||
$("#show_rspamd_global_filters").click(function() {
|
||||
$.get("inc/ajax/show_rspamd_global_filters.php");
|
||||
$("#confirm_show_rspamd_global_filters").hide();
|
||||
$("#rspamd_global_filters").removeClass("hidden");
|
||||
$("#rspamd_global_filters").removeClass("d-none");
|
||||
});
|
||||
$("#super_delete").click(function() { return confirm(lang.queue_ays); });
|
||||
|
||||
$(".refresh_table").on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table_name = $(this).data('table');
|
||||
$('#' + table_name).find("tr.footable-empty").remove();
|
||||
draw_table = $(this).data('draw');
|
||||
eval(draw_table + '()');
|
||||
$('#' + table_name).DataTable().ajax.reload();
|
||||
});
|
||||
function table_admin_ready(ft, name) {
|
||||
heading = ft.$el.parents('.panel').find('.panel-heading')
|
||||
var ft_paging = ft.use(FooTable.Paging)
|
||||
$(heading).children('.table-lines').text(function(){
|
||||
return ft_paging.totalRows;
|
||||
})
|
||||
}
|
||||
function draw_domain_admins() {
|
||||
ft_domainadmins = FooTable.init('#domainadminstable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
|
||||
{"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
|
||||
{"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/domain-admin/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw domain admin table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#domainadminstable') ) {
|
||||
$('#domainadminstable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#domainadminstable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/domain-admin/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'domainadminstable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"state": {"enabled": true},
|
||||
"filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.username,
|
||||
data: 'username',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.admin_domains,
|
||||
data: 'selected_domains',
|
||||
defaultContent: '',
|
||||
},
|
||||
{
|
||||
title: "TFA",
|
||||
data: 'tfa_active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
],
|
||||
initComplete: function(settings, json){
|
||||
}
|
||||
});
|
||||
}
|
||||
function draw_oauth2_clients() {
|
||||
ft_oauth2clientstable = FooTable.init('#oauth2clientstable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
|
||||
{"name":"client_id","type":"text","title":lang.oauth2_client_id,"style":{"width":"200px"}},
|
||||
{"name":"client_secret","title":lang.oauth2_client_secret,"breakpoints":"xs sm md","style":{"width":"200px"}},
|
||||
{"name":"redirect_uri","title":lang.oauth2_redirect_uri, "type": "text"},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/oauth2-client/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw oauth2 clients table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) {
|
||||
$('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#oauth2clientstable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/oauth2-client/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'oauth2clientstable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.oauth2_client_id,
|
||||
data: 'client_id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.oauth2_client_secret,
|
||||
data: 'client_secret',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.oauth2_redirect_uri,
|
||||
data: 'redirect_uri',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_admins() {
|
||||
ft_admins = FooTable.init('#adminstable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"sorted": true,"name":"usr","title":lang.username,"style":{"width":"250px"}},
|
||||
{"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/admin/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw admin table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#adminstable') ) {
|
||||
$('#adminstable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#adminstable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/admin/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'adminstable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"filtering": {"enabled": false},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.username,
|
||||
data: 'username',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: "TFA",
|
||||
data: 'tfa_active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
defaultContent: '',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right'
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_fwd_hosts() {
|
||||
ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
|
||||
{"name":"source","title":lang.source,"breakpoints":"xs sm"},
|
||||
{"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 'yes'==value?'<i class="bi bi-x-lg"></i>':'no'==value&&'<i class="bi bi-check-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/fwdhost/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw forwarding hosts table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) {
|
||||
$('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#forwardinghoststable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/fwdhost/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'forwardinghoststable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.host,
|
||||
data: 'host',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.source,
|
||||
data: 'source',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.spamfilter,
|
||||
data: 'keep_spam',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_relayhosts() {
|
||||
ft_relayhoststable = FooTable.init('#relayhoststable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
|
||||
{"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
|
||||
{"name":"username","title":lang.username,"breakpoints":"xs sm"},
|
||||
{"name":"in_use_by","title":lang.in_use_by,"style":{"min-width":"200px","width":"200px"}, "type": "text","breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/relayhost/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw forwarding hosts table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#relayhoststable') ) {
|
||||
$('#relayhoststable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#relayhoststable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/relayhost/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'relayhoststable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.host,
|
||||
data: 'hostname',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.username,
|
||||
data: 'username',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.in_use_by,
|
||||
data: 'in_use_by',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_transport_maps() {
|
||||
ft_transportstable = FooTable.init('#transportstable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
|
||||
{"name":"destination","type":"text","title":lang.destination,"style":{"min-width":"300px","width":"300px"}},
|
||||
{"name":"nexthop","type":"text","title":lang.nexthop,"style":{"min-width":"200px","width":"200px"}},
|
||||
{"name":"username","title":lang.username,"breakpoints":"xs sm"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/transport/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw transports table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#transportstable') ) {
|
||||
$('#transportstable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#transportstable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/transport/all",
|
||||
dataSrc: function(data){
|
||||
return process_table_data(data, 'transportstable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle",
|
||||
"on": {
|
||||
"ready.ft.table": function(e, ft){
|
||||
$('.mx-info').tooltip();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function draw_queue() {
|
||||
ft_queuetable = FooTable.init('#queuetable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"queue_id","type":"text","title":"QID","style":{"width":"50px"}},
|
||||
{"name":"queue_name","type":"text","title":"Queue","style":{"width":"120px"}},
|
||||
{"name":"arrival_time","sorted": true,"direction": "DESC","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.arrival_time,"style":{"width":"170px"}},
|
||||
{"name":"message_size","style":{"whiteSpace":"nowrap"},"title":lang.message_size,"formatter": function(value){
|
||||
return humanFileSize(value);
|
||||
}},
|
||||
{"name":"sender","title":lang.sender, "type": "text","breakpoints":"xs sm"},
|
||||
{"name":"recipients","title":lang.recipients, "type": "text","style":{"word-break":"break-all","min-width":"300px"},"breakpoints":"xs sm md"},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/mailq/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw forwarding hosts table');
|
||||
},
|
||||
success: function (data) {
|
||||
return process_table_data(data, 'queuetable');
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
|
||||
"sorting": {"enabled": true},
|
||||
"toggleSelector": "table tbody span.footable-toggle",
|
||||
"on": {
|
||||
"ready.ft.table": function(e, ft){
|
||||
table_admin_ready(ft, 'queuetable');
|
||||
}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.destination,
|
||||
data: 'destination',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.nexthop,
|
||||
data: 'nexthop',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.username,
|
||||
data: 'username',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
if(data == 1) return '<i class="bi bi-check-lg"></i>';
|
||||
else return '<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function process_table_data(data, table) {
|
||||
if (table == 'relayhoststable') {
|
||||
$.each(data, function (i, item) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-default"><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-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
|
||||
|
@ -294,14 +483,14 @@ jQuery(function($){
|
|||
} else if (table == 'transportstable') {
|
||||
$.each(data, function (i, item) {
|
||||
if (item.is_mx_based) {
|
||||
item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>';
|
||||
item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-bs-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>';
|
||||
}
|
||||
if (item.username) {
|
||||
item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username;
|
||||
}
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-default"><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-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
|
||||
|
@ -313,21 +502,21 @@ jQuery(function($){
|
|||
return escapeHtml(i);
|
||||
});
|
||||
item.recipients = rcpts.join('<hr style="margin:1px!important">');
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="#" data-toggle="modal" data-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-default">' + lang.queue_show_message + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
});
|
||||
} else if (table == 'forwardinghoststable') {
|
||||
$.each(data, function (i, item) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
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>' +
|
||||
'</div>';
|
||||
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
|
||||
});
|
||||
} else if (table == 'oauth2clientstable') {
|
||||
$.each(data, function (i, item) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
item.scope = "profile";
|
||||
|
@ -339,8 +528,8 @@ jQuery(function($){
|
|||
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.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
|
@ -353,22 +542,38 @@ jQuery(function($){
|
|||
item.usr = item.username;
|
||||
}
|
||||
item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
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>' +
|
||||
'</div>';
|
||||
});
|
||||
}
|
||||
return data
|
||||
};
|
||||
// Initial table drawings
|
||||
draw_domain_admins();
|
||||
draw_admins();
|
||||
draw_fwd_hosts();
|
||||
draw_relayhosts();
|
||||
draw_oauth2_clients();
|
||||
draw_transport_maps();
|
||||
draw_queue();
|
||||
|
||||
// detect element visibility changes
|
||||
function onVisible(element, callback) {
|
||||
$(document).ready(function() {
|
||||
element_object = document.querySelector(element);
|
||||
if (element_object === null) return;
|
||||
|
||||
new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if(entry.intersectionRatio > 0) {
|
||||
callback(element_object);
|
||||
}
|
||||
});
|
||||
}).observe(element_object);
|
||||
});
|
||||
}
|
||||
// Draw Table if tab is active
|
||||
onVisible("[id^=adminstable]", () => draw_admins());
|
||||
onVisible("[id^=domainadminstable]", () => draw_domain_admins());
|
||||
onVisible("[id^=oauth2clientstable]", () => draw_oauth2_clients());
|
||||
onVisible("[id^=forwardinghoststable]", () => draw_fwd_hosts());
|
||||
onVisible("[id^=relayhoststable]", () => draw_relayhosts());
|
||||
onVisible("[id^=transportstable]", () => draw_transport_maps());
|
||||
|
||||
|
||||
$('body').on('click', 'span.footable-toggle', function () {
|
||||
event.stopPropagation();
|
||||
|
@ -427,27 +632,11 @@ jQuery(function($){
|
|||
$('#transport_type').val(button.data('transport-type'));
|
||||
}
|
||||
})
|
||||
// Queue item
|
||||
$('#showQueuedMsg').on('show.bs.modal', function (e) {
|
||||
$('#queue_msg_content').text(lang.loading);
|
||||
button = $(e.relatedTarget)
|
||||
if (button != null) {
|
||||
$('#queue_id').text(button.data('queue-id'));
|
||||
}
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/api/v1/get/postcat/' + button.data('queue-id'),
|
||||
dataType: 'text',
|
||||
complete: function (data) {
|
||||
$('#queue_msg_content').text(data.responseText);
|
||||
}
|
||||
});
|
||||
})
|
||||
$('#test_transport').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
prev = $('#test_transport').text();
|
||||
$(this).prop("disabled",true);
|
||||
$(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> ');
|
||||
$(this).html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div> ');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: 'inc/ajax/transport_check.php',
|
||||
|
@ -481,13 +670,13 @@ jQuery(function($){
|
|||
function add_table_row(table_id, type) {
|
||||
var row = $('<tr />');
|
||||
if (type == "app_link") {
|
||||
cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
|
||||
cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
|
||||
cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
|
||||
cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
|
||||
} else if (type == "f2b_regex") {
|
||||
cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
|
||||
cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
|
||||
cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
|
||||
cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
|
||||
}
|
||||
row.append(cols);
|
||||
table_id.append(row);
|
||||
|
@ -507,4 +696,3 @@ jQuery(function($){
|
|||
add_table_row($('#f2b_regex_table'), "f2b_regex");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,6 +57,17 @@ $(document).ready(function() {
|
|||
$("#multiple_bookings_custom").bind("change keypress keyup blur", function() {
|
||||
$('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val());
|
||||
});
|
||||
|
||||
// load tags
|
||||
if ($('#tags').length){
|
||||
var tagsEl = $('#tags').parent().find('.tag-values')[0];
|
||||
console.log($(tagsEl).val())
|
||||
var tags = JSON.parse($(tagsEl).val());
|
||||
$(tagsEl).val("");
|
||||
|
||||
for (var i = 0; i < tags.length; i++)
|
||||
addTag($('#tags'), tags[i]);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(function($){
|
||||
|
@ -66,22 +77,14 @@ jQuery(function($){
|
|||
return re.test(email);
|
||||
}
|
||||
function draw_wl_policy_domain_table() {
|
||||
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_domain_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
|
||||
{"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule},
|
||||
{"name":"object","title":"Scope"}
|
||||
],
|
||||
"empty": lang_user.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
$('#wl_policy_domain_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/policy_wl_domain/' + table_for_domain,
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw mailbox policy wl table');
|
||||
},
|
||||
success: function (data) {
|
||||
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 + '" />';
|
||||
|
@ -90,35 +93,53 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'prefid',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang_user.spamfilter_table_rule,
|
||||
data: 'value',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'Scope',
|
||||
data: 'object',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_bl_policy_domain_table() {
|
||||
ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_domain_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
|
||||
{"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule},
|
||||
{"name":"object","title":"Scope"}
|
||||
],
|
||||
"empty": lang_user.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
$('#bl_policy_domain_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/policy_bl_domain/' + table_for_domain,
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw mailbox policy bl table');
|
||||
},
|
||||
success: function (data) {
|
||||
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 + '" />';
|
||||
|
@ -127,18 +148,63 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'prefid',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang_user.spamfilter_table_rule,
|
||||
data: 'value',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'Scope',
|
||||
data: 'object',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
draw_wl_policy_domain_table();
|
||||
draw_bl_policy_domain_table();
|
||||
|
||||
|
||||
// detect element visibility changes
|
||||
function onVisible(element, callback) {
|
||||
$(document).ready(function() {
|
||||
element_object = document.querySelector(element);
|
||||
if (element_object === null) return;
|
||||
|
||||
new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if(entry.intersectionRatio > 0) {
|
||||
callback(element_object);
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
}).observe(element_object);
|
||||
});
|
||||
}
|
||||
// Draw Table if tab is active
|
||||
onVisible("[id^=wl_policy_domain_table]", () => draw_wl_policy_domain_table());
|
||||
onVisible("[id^=bl_policy_domain_table]", () => draw_bl_policy_domain_table());
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
$(document).ready(function() {
|
||||
var theme = localStorage.getItem("theme");
|
||||
localStorage.clear();
|
||||
localStorage.setItem("theme", theme);
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -40,17 +40,17 @@ jQuery(function($){
|
|||
if (value.score > 0) highlightClass = 'negative'
|
||||
else if (value.score < 0) highlightClass = 'positive'
|
||||
else highlightClass = 'neutral'
|
||||
$('#qid_detail_symbols').append('<span data-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
|
||||
$('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
}
|
||||
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
|
||||
if (data.action === "add header") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
|
||||
} else if (data.action === "reject") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
|
||||
} else if (data.action === "rewrite subject") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
|
||||
}
|
||||
}
|
||||
if (typeof data.recipients !== 'undefined') {
|
||||
|
|
|
@ -7,67 +7,20 @@ jQuery(function($){
|
|||
var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
|
||||
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
|
||||
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
|
||||
// Set paging
|
||||
$('[data-page-size]').on('click', function(e){
|
||||
e.preventDefault();
|
||||
var new_size = $(this).data('page-size');
|
||||
var parent_ul = $(this).closest('ul');
|
||||
var table_id = $(parent_ul).data('table-id');
|
||||
FooTable.get('#' + table_id).pageSize(new_size);
|
||||
//$(this).parent().addClass('active').siblings().removeClass('active')
|
||||
heading = $(this).parents('.panel').find('.panel-heading')
|
||||
var n_results = $(heading).children('.table-lines').text().split(' / ')[1];
|
||||
$(heading).children('.table-lines').text(function(){
|
||||
if (new_size > n_results) {
|
||||
new_size = n_results;
|
||||
}
|
||||
return new_size + ' / ' + n_results;
|
||||
})
|
||||
});
|
||||
$(".refresh_table").on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table_name = $(this).data('table');
|
||||
$('#' + table_name).find("tr.footable-empty").remove();
|
||||
draw_table = $(this).data('draw');
|
||||
eval(draw_table + '()');
|
||||
$('#' + table_name).DataTable().ajax.reload();
|
||||
});
|
||||
function table_quarantine_ready(ft, name) {
|
||||
$('.refresh_table').prop("disabled", false);
|
||||
heading = ft.$el.parents('.panel').find('.panel-heading')
|
||||
var ft_paging = ft.use(FooTable.Paging)
|
||||
$(heading).children('.table-lines').text(function(){
|
||||
var total_rows = ft_paging.totalRows;
|
||||
var size = ft_paging.size;
|
||||
if (size > total_rows) {
|
||||
size = total_rows;
|
||||
}
|
||||
return size + ' / ' + total_rows;
|
||||
})
|
||||
}
|
||||
function draw_quarantine_table() {
|
||||
ft_quarantinetable = FooTable.init('#quarantinetable', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"id","type":"ID","filterable": false,"sorted": true,"direction":"DESC","title":"ID","style":{"width":"50px"}},
|
||||
{"name":"qid","breakpoints":"all","type":"text","title":lang.qid,"style":{"width":"125px"}},
|
||||
{"name":"sender","title":lang.sender},
|
||||
{"name":"subject","title":lang.subj, "type": "text"},
|
||||
{"name":"rspamdaction","title":lang.rspamd_result, "type": "html"},
|
||||
{"name":"rcpt","title":lang.rcpt, "type": "text"},
|
||||
{"name":"virus","title":lang.danger, "type": "text"},
|
||||
{"name":"score","title": lang.spam_score, "type": "text"},
|
||||
{"name":"notified","title":lang.notified, "type": "text"},
|
||||
{"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.received,"style":{"width":"170px"}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"min-width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||
],
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/quarantine/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw quarantine table');
|
||||
},
|
||||
success: function (data) {
|
||||
$('#quarantinetable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/quarantine/all",
|
||||
dataSrc: function(data){
|
||||
$.each(data, function (i, item) {
|
||||
if (item.subject === null) {
|
||||
item.subject = '';
|
||||
|
@ -78,16 +31,16 @@ jQuery(function($){
|
|||
item.score = '-';
|
||||
}
|
||||
if (item.virus_flag > 0) {
|
||||
item.virus = '<span class="label label-danger">' + lang.high_danger + '</span>';
|
||||
item.virus = '<span class="badge fs-6 bg-danger">' + lang.high_danger + '</span>';
|
||||
} else {
|
||||
item.virus = '<span class="label label-default">' + lang.neutral_danger + '</span>';
|
||||
item.virus = '<span class="badge fs-6 bg-secondary">' + lang.neutral_danger + '</span>';
|
||||
}
|
||||
if (item.action === "reject") {
|
||||
item.rspamdaction = '<span class="label label-danger">' + lang.rejected + '</span>';
|
||||
item.rspamdaction = '<span class="badge fs-6 bg-danger">' + lang.rejected + '</span>';
|
||||
} else if (item.action === "add header") {
|
||||
item.rspamdaction = '<span class="label label-warning">' + lang.junk_folder + '</span>';
|
||||
item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.junk_folder + '</span>';
|
||||
} else if (item.action === "rewrite subject") {
|
||||
item.rspamdaction = '<span class="label label-warning">' + lang.rewrite_subject + '</span>';
|
||||
item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.rewrite_subject + '</span>';
|
||||
}
|
||||
if(item.notified > 0) {
|
||||
item.notified = '✔';
|
||||
|
@ -95,7 +48,7 @@ jQuery(function($){
|
|||
item.notified = '✖';
|
||||
}
|
||||
if (acl_data.login_as === 1) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' +
|
||||
'<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
|
||||
'</div>';
|
||||
|
@ -107,25 +60,87 @@ jQuery(function($){
|
|||
}
|
||||
item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />';
|
||||
});
|
||||
}
|
||||
}),
|
||||
"empty": lang.empty,
|
||||
"paging": {"enabled": true,"limit": 5,"size": pagination_size},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {"enabled": true},
|
||||
"filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
|
||||
"toggleSelector": "table tbody span.footable-toggle",
|
||||
"on": {
|
||||
"destroy.ft.table": function(e, ft){
|
||||
$('.refresh_table').attr('disabled', 'true');
|
||||
},
|
||||
"ready.ft.table": function(e, ft){
|
||||
table_quarantine_ready(ft, 'quarantinetable');
|
||||
},
|
||||
"after.ft.filtering": function(e, ft){
|
||||
table_quarantine_ready(ft, 'quarantinetable');
|
||||
|
||||
return data;
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.qid,
|
||||
data: 'qid',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.sender,
|
||||
data: 'sender',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.subj,
|
||||
data: 'sender',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.rspamd_result,
|
||||
data: 'rspamdaction',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.rcpt,
|
||||
data: 'rcpt',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.danger,
|
||||
data: 'virus',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.spam_score,
|
||||
data: 'score',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.notified,
|
||||
data: 'notified',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.received,
|
||||
data: 'created',
|
||||
defaultContent: '',
|
||||
render: function (data,type) {
|
||||
var date = new Date(data ? data * 1000 : 0);
|
||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -175,9 +190,9 @@ jQuery(function($){
|
|||
if (value.score > 0) highlightClass = 'negative'
|
||||
else if (value.score < 0) highlightClass = 'positive'
|
||||
else highlightClass = 'neutral'
|
||||
$('#qid_detail_symbols').append('<span data-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
|
||||
$('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
}
|
||||
if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) {
|
||||
$.each(data.fuzzy_hashes, function (index, value) {
|
||||
|
@ -188,11 +203,11 @@ jQuery(function($){
|
|||
}
|
||||
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
|
||||
if (data.action == "add header") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
|
||||
} else if (data.action == "reject") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
|
||||
} else if (data.action == "rewrite subject") {
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
|
||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
|
||||
}
|
||||
}
|
||||
if (typeof data.recipients !== 'undefined') {
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
jQuery(function($){
|
||||
|
||||
$(".refresh_table").on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var table_name = $(this).data('table');
|
||||
$('#' + table_name).DataTable().ajax.reload();
|
||||
});
|
||||
|
||||
|
||||
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
|
||||
|
||||
// Queue item
|
||||
$('#showQueuedMsg').on('show.bs.modal', function (e) {
|
||||
$('#queue_msg_content').text(lang.loading);
|
||||
button = $(e.relatedTarget)
|
||||
if (button != null) {
|
||||
$('#queue_id').text(button.data('queue-id'));
|
||||
}
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/api/v1/get/postcat/' + button.data('queue-id'),
|
||||
dataType: 'text',
|
||||
complete: function (data) {
|
||||
console.log(data);
|
||||
$('#queue_msg_content').text(data.responseText);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
function draw_queue() {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#queuetable') ) {
|
||||
$('#queuetable').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#queuetable').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
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 + '" />';
|
||||
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>' +
|
||||
'</div>';
|
||||
});
|
||||
return data;
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'QID',
|
||||
data: 'queue_id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'Queue',
|
||||
data: 'queue_name',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang_admin.arrival_time,
|
||||
data: 'arrival_time',
|
||||
defaultContent: '',
|
||||
render: function (data, type){
|
||||
var date = new Date(data ? data * 1000 : 0);
|
||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang_admin.message_size,
|
||||
data: 'message_size',
|
||||
defaultContent: '',
|
||||
render: function (data, type){
|
||||
return humanFileSize(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang_admin.sender,
|
||||
data: 'sender',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang_admin.recipients,
|
||||
data: 'recipients',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang_admin.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
},
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
draw_queue();
|
||||
|
||||
})
|
|
@ -101,7 +101,7 @@ jQuery(function($){
|
|||
$.each(data.sasl, function (i, item) {
|
||||
var datetime = new Date(item.datetime.replace(/-/g, "/"));
|
||||
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
var service = '<div class="label label-default">' + item.service.toUpperCase() + '</div>';
|
||||
var service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>';
|
||||
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : '';
|
||||
var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.he.net/ip/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>";
|
||||
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
|
||||
|
@ -128,26 +128,24 @@ jQuery(function($){
|
|||
}
|
||||
|
||||
function draw_tla_table() {
|
||||
ft_tla_table = FooTable.init('#tla_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"address","title":lang.alias},
|
||||
{"name":"validity","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.alias_valid_until,"style":{"width":"170px"}},
|
||||
{"sorted": true,"sortValue": function(value){res = new Date(value);return res.getTime();},"direction":"DESC","name":"created","formatter":function date_format(datetime) { var date = new Date(datetime.replace(/-/g, "/")); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.created_on,"style":{"width":"170px"}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
url: '/api/v1/get/time_limited_aliases',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw tla table');
|
||||
},
|
||||
success: function (data) {
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#tla_table') ) {
|
||||
$('#tla_table').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#tla_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: "/api/v1/get/time_limited_aliases",
|
||||
dataSrc: function(data){
|
||||
console.log(data);
|
||||
$.each(data, function (i, item) {
|
||||
if (acl_data.spam_alias === 1) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
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) + '" />';
|
||||
|
@ -158,49 +156,77 @@ jQuery(function($){
|
|||
item.action = '<span>-</span>';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.alias,
|
||||
data: 'address',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.alias_valid_until,
|
||||
data: 'validity',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
var date = new Date(data ? data * 1000 : 0);
|
||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.created_on,
|
||||
data: 'created',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
var date = new Date(data.replace(/-/g, "/"));
|
||||
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_sync_job_table() {
|
||||
ft_syncjob_table = FooTable.init('#sync_job_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
|
||||
{"name":"server_w_port","title":"Server","breakpoints":"xs sm md","style":{"word-break":"break-all"}},
|
||||
{"name":"enc1","title":lang.encryption,"breakpoints":"all"},
|
||||
{"name":"user1","title":lang.username},
|
||||
{"name":"exclude","title":lang.excludes,"breakpoints":"all"},
|
||||
{"name":"mins_interval","title":lang.interval + " (min)","breakpoints":"all"},
|
||||
{"name":"last_run","title":lang.last_run,"breakpoints":"xs sm md"},
|
||||
{"name":"exit_status","filterable": false,"title":lang.syncjob_last_run_result},
|
||||
{"name":"log","title":"Log"},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"260px","width":"260px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#sync_job_table') ) {
|
||||
$('#sync_job_table').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#sync_job_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw sync job table');
|
||||
},
|
||||
success: function (data) {
|
||||
dataSrc: function(data){
|
||||
console.log(data);
|
||||
$.each(data, function (i, item) {
|
||||
item.user1 = escapeHtml(item.user1);
|
||||
item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
|
||||
item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
|
||||
if (!item.exclude > 0) {
|
||||
item.exclude = '-';
|
||||
} else {
|
||||
|
@ -208,8 +234,8 @@ jQuery(function($){
|
|||
}
|
||||
item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
|
||||
if (acl_data.syncjobs === 1) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<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 + '" />';
|
||||
|
@ -219,9 +245,9 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled />';
|
||||
}
|
||||
if (item.is_running == 1) {
|
||||
item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
|
||||
item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
|
||||
} else {
|
||||
item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
|
||||
item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>';
|
||||
}
|
||||
if (!item.last_run > 0) {
|
||||
item.last_run = lang.waiting;
|
||||
|
@ -239,39 +265,115 @@ jQuery(function($){
|
|||
}
|
||||
item.exit_status = item.success + ' ' + item.exit_status;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: '',
|
||||
responsivePriority: 1
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: '',
|
||||
responsivePriority: 2
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: '',
|
||||
responsivePriority: 3
|
||||
},
|
||||
{
|
||||
title: 'Server',
|
||||
data: 'server_w_port',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.username,
|
||||
data: 'user1',
|
||||
defaultContent: '',
|
||||
responsivePriority: 3
|
||||
},
|
||||
{
|
||||
title: lang.last_run,
|
||||
data: 'last_run',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.syncjob_last_run_result,
|
||||
data: 'exit_status',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'Log',
|
||||
data: 'log',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.status,
|
||||
data: 'is_running',
|
||||
defaultContent: '',
|
||||
responsivePriority: 5
|
||||
},
|
||||
{
|
||||
title: lang.encryption,
|
||||
data: 'enc1',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.excludes,
|
||||
data: 'exclude',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.interval + " (min)",
|
||||
data: 'mins_interval',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: '',
|
||||
responsivePriority: 5
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_app_passwd_table() {
|
||||
ft_apppasswd_table = FooTable.init('#app_passwd_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
|
||||
{"name":"name","title":lang.app_name},
|
||||
{"name":"protocols","title":lang.allowed_protocols},
|
||||
{"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#app_passwd_table') ) {
|
||||
$('#app_passwd_table').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#app_passwd_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/app-passwd/all',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw app passwd table');
|
||||
},
|
||||
success: function (data) {
|
||||
dataSrc: function(data){
|
||||
console.log(data);
|
||||
$.each(data, function (i, item) {
|
||||
item.name = escapeHtml(item.name)
|
||||
item.protocols = []
|
||||
|
@ -283,8 +385,8 @@ jQuery(function($){
|
|||
if (item.sieve_access == 1) { item.protocols.push("<code>Sieve</code>"); }
|
||||
item.protocols = item.protocols.join(" ")
|
||||
if (acl_data.app_passwds === 1) {
|
||||
item.action = '<div class="btn-group footable-actions">' +
|
||||
'<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
|
||||
item.action = '<div class="btn-group">' +
|
||||
'<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 + '" />';
|
||||
|
@ -294,37 +396,74 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled />';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
},
|
||||
"toggleSelector": "table tbody span.footable-toggle"
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'id',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.app_name,
|
||||
data: 'name',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.allowed_protocols,
|
||||
data: 'protocols',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.active,
|
||||
data: 'active',
|
||||
defaultContent: '',
|
||||
render: function (data, type) {
|
||||
return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lang.action,
|
||||
data: 'action',
|
||||
className: 'text-md-end dt-sm-head-hidden dt-body-right',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_wl_policy_mailbox_table() {
|
||||
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
|
||||
{"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
|
||||
{"name":"object","title":"Scope"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#wl_policy_mailbox_table') ) {
|
||||
$('#wl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#wl_policy_mailbox_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/policy_wl_mailbox',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw mailbox policy wl table');
|
||||
},
|
||||
success: function (data) {
|
||||
dataSrc: function(data){
|
||||
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 + '" />';
|
||||
|
@ -336,36 +475,60 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled />';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"state": {"enabled": true},
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'prefid',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.spamfilter_table_rule,
|
||||
data: 'value',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title:'Scope',
|
||||
data: 'object',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
function draw_bl_policy_mailbox_table() {
|
||||
ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_mailbox_table', {
|
||||
"columns": [
|
||||
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
|
||||
{"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
|
||||
{"name":"object","title":"Scope"}
|
||||
],
|
||||
"empty": lang.empty,
|
||||
"rows": $.ajax({
|
||||
dataType: 'json',
|
||||
// just recalc width if instance already exists
|
||||
if ($.fn.DataTable.isDataTable('#bl_policy_mailbox_table') ) {
|
||||
$('#bl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#bl_policy_mailbox_table').DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
language: lang_datatables,
|
||||
ajax: {
|
||||
type: "GET",
|
||||
url: '/api/v1/get/policy_bl_mailbox',
|
||||
jsonp: false,
|
||||
error: function () {
|
||||
console.log('Cannot draw mailbox policy bl table');
|
||||
},
|
||||
success: function (data) {
|
||||
dataSrc: function(data){
|
||||
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 + '" />';
|
||||
|
@ -377,31 +540,45 @@ jQuery(function($){
|
|||
item.chkbox = '<input type="checkbox" disabled />';
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}),
|
||||
"paging": {
|
||||
"enabled": true,
|
||||
"limit": 5,
|
||||
"size": pagination_size
|
||||
},
|
||||
"state": {"enabled": true},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
columns: [
|
||||
{
|
||||
// placeholder, so checkbox will not block child row toggle
|
||||
title: '',
|
||||
data: null,
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
data: 'chkbox',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
data: 'prefid',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title: lang.spamfilter_table_rule,
|
||||
data: 'value',
|
||||
defaultContent: ''
|
||||
},
|
||||
{
|
||||
title:'Scope',
|
||||
data: 'object',
|
||||
defaultContent: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
$('body').on('click', 'span.footable-toggle', function () {
|
||||
event.stopPropagation();
|
||||
})
|
||||
|
||||
draw_sync_job_table();
|
||||
draw_app_passwd_table();
|
||||
draw_tla_table();
|
||||
draw_wl_policy_mailbox_table();
|
||||
draw_bl_policy_mailbox_table();
|
||||
last_logins('get');
|
||||
|
||||
// FIDO2 friendly name modal
|
||||
$('#fido2ChangeFn').on('show.bs.modal', function (e) {
|
||||
rename_link = $(e.relatedTarget)
|
||||
|
@ -433,4 +610,28 @@ jQuery(function($){
|
|||
$('#userFilterModal').on('hidden.bs.modal', function () {
|
||||
$('#user_sieve_filter').text(lang.loading);
|
||||
});
|
||||
|
||||
// detect element visibility changes
|
||||
function onVisible(element, callback) {
|
||||
$(document).ready(function() {
|
||||
element_object = document.querySelector(element);
|
||||
if (element_object === null) return;
|
||||
|
||||
new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if(entry.intersectionRatio > 0) {
|
||||
callback(element_object);
|
||||
}
|
||||
});
|
||||
}).observe(element_object);
|
||||
});
|
||||
}
|
||||
|
||||
// Load only if the tab is visible
|
||||
onVisible("[id^=tla_table]", () => draw_tla_table());
|
||||
onVisible("[id^=bl_policy_mailbox_table]", () => draw_bl_policy_mailbox_table());
|
||||
onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table());
|
||||
onVisible("[id^=sync_job_table]", () => draw_sync_job_table());
|
||||
onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table());
|
||||
last_logins('get');
|
||||
});
|
||||
|
|
|
@ -230,13 +230,27 @@ if (isset($_GET['query'])) {
|
|||
process_add_return(rsettings('add', $attr));
|
||||
break;
|
||||
case "mailbox":
|
||||
process_add_return(mailbox('add', 'mailbox', $attr));
|
||||
switch ($object) {
|
||||
case "template":
|
||||
process_add_return(mailbox('add', 'mailbox_templates', $attr));
|
||||
break;
|
||||
default:
|
||||
process_add_return(mailbox('add', 'mailbox', $attr));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "oauth2-client":
|
||||
process_add_return(oauth2('add', 'client', $attr));
|
||||
break;
|
||||
case "domain":
|
||||
process_add_return(mailbox('add', 'domain', $attr));
|
||||
switch ($object) {
|
||||
case "template":
|
||||
process_add_return(mailbox('add', 'domain_templates', $attr));
|
||||
break;
|
||||
default:
|
||||
process_add_return(mailbox('add', 'domain', $attr));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "resource":
|
||||
process_add_return(mailbox('add', 'resource', $attr));
|
||||
|
@ -519,7 +533,16 @@ if (isset($_GET['query'])) {
|
|||
echo '{}';
|
||||
}
|
||||
break;
|
||||
|
||||
case "template":
|
||||
switch ($extra){
|
||||
case "all":
|
||||
process_get_return(mailbox('get', 'domain_templates'));
|
||||
break;
|
||||
default:
|
||||
process_get_return(mailbox('get', 'domain_templates', $extra));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$data = mailbox('get', 'domain_details', $object);
|
||||
process_get_return($data);
|
||||
|
@ -992,7 +1015,16 @@ if (isset($_GET['query'])) {
|
|||
echo '{}';
|
||||
}
|
||||
break;
|
||||
|
||||
case "template":
|
||||
switch ($extra){
|
||||
case "all":
|
||||
process_get_return(mailbox('get', 'mailbox_templates'));
|
||||
break;
|
||||
default:
|
||||
process_get_return(mailbox('get', 'mailbox_templates', $extra));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$tags = null;
|
||||
if (isset($_GET['tags']) && $_GET['tags'] != '')
|
||||
|
@ -1472,6 +1504,10 @@ if (isset($_GET['query'])) {
|
|||
}
|
||||
echo json_encode($temp, JSON_UNESCAPED_SLASHES);
|
||||
break;
|
||||
case "container":
|
||||
$container_stats = docker('container_stats', $extra);
|
||||
echo json_encode($container_stats);
|
||||
break;
|
||||
case "vmail":
|
||||
$exec_fields_vmail = array('cmd' => 'system', 'task' => 'df', 'dir' => '/var/vmail');
|
||||
$vmail_df = explode(',', json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields_vmail), true));
|
||||
|
@ -1483,29 +1519,53 @@ if (isset($_GET['query'])) {
|
|||
'used_percent' => $vmail_df[4]
|
||||
);
|
||||
echo json_encode($temp, JSON_UNESCAPED_SLASHES);
|
||||
break;
|
||||
case "solr":
|
||||
$solr_status = solr_status();
|
||||
$solr_size = ($solr_status['status']['dovecot-fts']['index']['size']);
|
||||
$solr_documents = ($solr_status['status']['dovecot-fts']['index']['numDocs']);
|
||||
if (strtolower(getenv('SKIP_SOLR')) != 'n') {
|
||||
$solr_enabled = false;
|
||||
}
|
||||
else {
|
||||
$solr_enabled = true;
|
||||
}
|
||||
echo json_encode(array(
|
||||
'type' => 'info',
|
||||
'solr_enabled' => $solr_enabled,
|
||||
'solr_size' => $solr_size,
|
||||
'solr_documents' => $solr_documents
|
||||
));
|
||||
break;
|
||||
case "version":
|
||||
echo json_encode(array(
|
||||
'version' => $GLOBALS['MAILCOW_GIT_VERSION']
|
||||
));
|
||||
break;
|
||||
break;
|
||||
case "solr":
|
||||
$solr_status = solr_status();
|
||||
$solr_size = ($solr_status['status']['dovecot-fts']['index']['size']);
|
||||
$solr_documents = ($solr_status['status']['dovecot-fts']['index']['numDocs']);
|
||||
if (strtolower(getenv('SKIP_SOLR')) != 'n') {
|
||||
$solr_enabled = false;
|
||||
}
|
||||
else {
|
||||
$solr_enabled = true;
|
||||
}
|
||||
echo json_encode(array(
|
||||
'type' => 'info',
|
||||
'solr_enabled' => $solr_enabled,
|
||||
'solr_size' => $solr_size,
|
||||
'solr_documents' => $solr_documents
|
||||
));
|
||||
break;
|
||||
case "host":
|
||||
if (!$extra){
|
||||
$stats = docker("host_stats");
|
||||
echo json_encode($stats);
|
||||
}
|
||||
else if ($extra == "ip") {
|
||||
// get public ips
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
$ipv4 = curl_exec($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
$ipv6 = curl_exec($curl);
|
||||
$ips = array(
|
||||
"ipv4" => $ipv4,
|
||||
"ipv6" => $ipv6
|
||||
);
|
||||
curl_close($curl);
|
||||
echo json_encode($ips);
|
||||
}
|
||||
break;
|
||||
case "version":
|
||||
echo json_encode(array(
|
||||
'version' => $GLOBALS['MAILCOW_GIT_VERSION']
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1613,6 +1673,9 @@ if (isset($_GET['query'])) {
|
|||
case "tag":
|
||||
process_delete_return(mailbox('delete', 'tags_domain', array('tags' => $items, 'domain' => $extra)));
|
||||
break;
|
||||
case "template":
|
||||
process_delete_return(mailbox('delete', 'domain_templates', array('ids' => $items)));
|
||||
break;
|
||||
default:
|
||||
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
|
||||
}
|
||||
|
@ -1625,6 +1688,9 @@ if (isset($_GET['query'])) {
|
|||
case "tag":
|
||||
process_delete_return(mailbox('delete', 'tags_mailbox', array('tags' => $items, 'username' => $extra)));
|
||||
break;
|
||||
case "template":
|
||||
process_delete_return(mailbox('delete', 'mailbox_templates', array('ids' => $items)));
|
||||
break;
|
||||
default:
|
||||
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
|
||||
}
|
||||
|
@ -1786,7 +1852,14 @@ if (isset($_GET['query'])) {
|
|||
process_edit_return(mailbox('edit', 'time_limited_alias', array_merge(array('address' => $items), $attr)));
|
||||
break;
|
||||
case "mailbox":
|
||||
process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
|
||||
switch ($object) {
|
||||
case "template":
|
||||
process_edit_return(mailbox('edit', 'mailbox_templates', array_merge(array('ids' => $items), $attr)));
|
||||
break;
|
||||
default:
|
||||
process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "syncjob":
|
||||
process_edit_return(mailbox('edit', 'syncjob', array_merge(array('id' => $items), $attr)));
|
||||
|
@ -1798,7 +1871,14 @@ if (isset($_GET['query'])) {
|
|||
process_edit_return(mailbox('edit', 'resource', array_merge(array('name' => $items), $attr)));
|
||||
break;
|
||||
case "domain":
|
||||
process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
|
||||
switch ($object) {
|
||||
case "template":
|
||||
process_edit_return(mailbox('edit', 'domain_templates', array_merge(array('ids' => $items), $attr)));
|
||||
break;
|
||||
default:
|
||||
process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "rl-domain":
|
||||
process_edit_return(ratelimit('edit', 'domain', array_merge(array('object' => $items), $attr)));
|
||||
|
|
|
@ -269,8 +269,8 @@
|
|||
"header": {
|
||||
"administration": "Administració",
|
||||
"debug": "Debug",
|
||||
"mailboxes": "Bústies",
|
||||
"mailcow_settings": "Configuració",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuració",
|
||||
"quarantine": "Quarantena",
|
||||
"restart_sogo": "Reiniciar SOGo",
|
||||
"user_settings": "Preferències d'usuari"
|
||||
|
@ -316,6 +316,7 @@
|
|||
"bcc_type": "BCC type",
|
||||
"deactivate": "Desactivar",
|
||||
"description": "Descripció",
|
||||
"dkim_key_length": "Mida de la clau DKIM (bits)",
|
||||
"domain": "Domini",
|
||||
"domain_admins": "Administradores de dominio",
|
||||
"domain_aliases": "Àlies de domini",
|
||||
|
@ -327,6 +328,7 @@
|
|||
"filter_table": "Filtrar taula",
|
||||
"filters": "Filtres",
|
||||
"fname": "Nom complert",
|
||||
"force_pw_update": "Forçar l'actualització de la contrassenya al proper login",
|
||||
"in_use": "En ús (%)",
|
||||
"inactive": "Inactiu",
|
||||
"kind": "Tipus",
|
||||
|
@ -334,6 +336,9 @@
|
|||
"last_run_reset": "Executar a continuació",
|
||||
"mailbox_quota": "Mida màx. de quota",
|
||||
"mailboxes": "Bústies",
|
||||
"max_aliases": "Màx. àlies possibles",
|
||||
"max_mailboxes": "Màx. bústies possibles",
|
||||
"max_quota": "Màx. quota per bústia",
|
||||
"mins_interval": "Intèrval (min)",
|
||||
"msg_num": "Missatge #",
|
||||
"multiple_bookings": "Múltiples reserves",
|
||||
|
@ -346,6 +351,7 @@
|
|||
"recipient_map_new": "Nou destinatari",
|
||||
"recipient_map_old": "Destinatari original",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "Retransmetre tods els recipients",
|
||||
"remove": "Esborrar",
|
||||
"resources": "Recursos",
|
||||
"running": "Executant-se",
|
||||
|
@ -386,6 +392,18 @@
|
|||
"text_plain_content": "Contingut (text/plain)",
|
||||
"toggle_all": "Marcar tots"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Delete all",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_command_success": "Queue command completed successfully",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold"
|
||||
},
|
||||
"start": {
|
||||
"help": "Mostrar/Ocultar panell d'ajuda",
|
||||
"mailcow_apps_detail": "Tria una aplicació (de moment només SOGo) per a accedir als teus correus, calendari, contactes i més.",
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
"relay_all": "Předávání všech příjemců",
|
||||
"relay_all_info": "<small>Pokud se rozhodnete <b>nepředávat</b> všechny příjemce, musíte přidat prázdnou mailovou schránku pro každého příjemce, který se má předávat.</small>",
|
||||
"relay_domain": "Předávání domény",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> U této domény lze pro konkrétní cíl nastavit transportní mapu. Není-li nastavena, použije se MX záznam.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> U této domény lze pro konkrétní cíl nastavit transportní mapu. Není-li nastavena, použije se MX záznam.",
|
||||
"relay_unknown_only": "Předávat jen neexistující schránky. Doručení do existujících proběhne lokálně.",
|
||||
"relayhost_wrapped_tls_info": "<b>Nepoužívejte</b> prosím porty s aktivním protokolem TLS (většinou port 465).<br>\r\nPoužívejte porty bez TLS a pak pošlete příkaz STARTTLS. Pravidlo k vynucení užití TLS lze vytvořit pomocí mapy TLS pravidel.",
|
||||
"select": "Prosím vyberte...",
|
||||
|
@ -150,7 +150,6 @@
|
|||
"credentials_transport_warning": "<b>Upozornění</b>: Přidání položky do transportní mapy aktualizuje také přihlašovací údaje všech záznamů s odpovídajícím skokem.",
|
||||
"customer_id": "ID zákazníka",
|
||||
"customize": "Přizpůsobení",
|
||||
"delete_queue": "Smazat vše",
|
||||
"destination": "Cíl",
|
||||
"dkim_add_key": "Přidat ARC/DKIM klíč",
|
||||
"dkim_domains_selector": "Selektor",
|
||||
|
@ -187,7 +186,6 @@
|
|||
"f2b_retry_window": "Časový horizont pro maximum pokusů (s)",
|
||||
"f2b_whitelist": "Sítě/hostitelé na whitelistu",
|
||||
"filter_table": "Tabulka filtrů",
|
||||
"flush_queue": "Vyprázdnit frontu (opětovně doručit)",
|
||||
"forwarding_hosts": "Předávající servery",
|
||||
"forwarding_hosts_add_hint": "Lze zadat IPv4/IPv6 adresy, sítě ve formátu CIDR, názvy serverů (budou převedeny na IP adresy) nebo názvy domén (budou převedeny na IP pomocí SPF záznamů, příp. MX záznamů).",
|
||||
"forwarding_hosts_hint": "Příchozí zprávy od zde uvedených serverů jsou bezpodmínečně přijaty. U těchto serverů se nekontroluje DNSBL a nepoužije greylisting. Spam od těchto serverů se nikdy neodmítá, ale občas může skončit ve složce se spamem. Nejčastěji se zde uvádějí mailové servery, jež předávají příchozí e-maily na tento mailový server.",
|
||||
|
@ -257,13 +255,6 @@
|
|||
"quarantine_release_format_att": "Jako příloha",
|
||||
"quarantine_release_format_raw": "Nezměněný originál",
|
||||
"quarantine_retention_size": "Počet zadržených zpráv na mailovou schránku<br />0 znamená <b>neaktivní</b>.",
|
||||
"queue_ays": "Potvrďte prosím, že chcete odstranit všechny položky z aktuální fronty.",
|
||||
"queue_deliver_mail": "Doručit",
|
||||
"queue_hold_mail": "Zadržet",
|
||||
"queue_manager": "Správce fronty",
|
||||
"queue_show_message": "Zobrazit zprávu",
|
||||
"queue_unban": "odblokovat",
|
||||
"queue_unhold_mail": "Propustit",
|
||||
"quota_notification_html": "Šablona upozornění:<br><small>Ponechte prázdné, aby se obnovila výchozí šablona.</small>",
|
||||
"quota_notification_sender": "Odesílatel upozornění",
|
||||
"quota_notification_subject": "Předmět upozornění",
|
||||
|
@ -516,6 +507,7 @@
|
|||
"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.",
|
||||
"client_id": "ID klienta",
|
||||
"client_secret": "Tajný klíč klienta",
|
||||
"created_on": "Vytvoreno",
|
||||
"comment_info": "Soukromý komentář se nezobrazí uživateli; veřejný komentář se zobrazí jako nápověda při zastavení se kurzorem v přehledu uživatelů",
|
||||
"delete1": "Odstranit ze zdrojové schránky, po dokončení přenosu",
|
||||
"delete2": "Odstranit zprávy v cílové schránce, pokud nejsou ve zdrojové",
|
||||
|
@ -543,6 +535,7 @@
|
|||
"hostname": "Jméno hostitele",
|
||||
"inactive": "Neaktivní",
|
||||
"kind": "Druh",
|
||||
"last_modified": "Naposledy změněn",
|
||||
"lookup_mx": "Cíl je regulární výraz který se shoduje s MX záznamem (<code>.*google\\.com</code> směřuje veškerou poštu na MX které jsou cílem pro google.com přes tento skok)",
|
||||
"mailbox": "Úprava mailové schránky",
|
||||
"mailbox_quota_def": "Výchozí kvóta schránky",
|
||||
|
@ -579,7 +572,7 @@
|
|||
"relay_all": "Předávání všech příjemců",
|
||||
"relay_all_info": "<small>Pokud se rozhodnete <b>nepředávat</b> všechny příjemce, musíte přidat prázdnou mailovou schránku pro každého příjemce, který se má předávat.</small>",
|
||||
"relay_domain": "Předávání domény",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> U této domény lze pro konkrétní cíl nastavit transportní mapu. Není-li nastavena, použije se MX záznam.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> U této domény lze pro konkrétní cíl nastavit transportní mapu. Není-li nastavena, použije se MX záznam.",
|
||||
"relay_unknown_only": "Předávat jen neexistující schránky. Doručení do existujících proběhne lokálně.",
|
||||
"relayhost": "Předávání podle odesílatele",
|
||||
"remove": "Smazat",
|
||||
|
@ -587,7 +580,7 @@
|
|||
"save": "Uložit změny",
|
||||
"scope": "Rozsah",
|
||||
"sender_acl": "Povolit odesílání jako",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odesílatele vypnuta</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Kontrola odesílatele vypnuta</span>",
|
||||
"sender_acl_info": "Má-li uživatel schránky A dovoleno odesílat jako uživatel schránky B, nezobrazuje se adresa odesílatele B v seznamu \"Od\" v SOGo automaticky.<br>\r\n Uživatel schránky A musí nejdříve v SOGo vytvořit pověření, jež umožní uživateli B vybrat svou adresu jako odesílatele. Tento mechanismus neplatí pro aliasy.",
|
||||
"sieve_desc": "Krátký popis",
|
||||
"sieve_type": "Typ filtru",
|
||||
|
@ -643,8 +636,8 @@
|
|||
"administration": "Hlavní nastavení",
|
||||
"apps": "Aplikace",
|
||||
"debug": "Systémové informace",
|
||||
"mailboxes": "Nastavení mailů",
|
||||
"mailcow_settings": "Nastavení",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Nastavení",
|
||||
"quarantine": "Karanténa",
|
||||
"restart_netfilter": "Restartovat netfilter",
|
||||
"restart_sogo": "Restartovat SOGo",
|
||||
|
@ -710,15 +703,19 @@
|
|||
"booking_ltnull": "Neomezeno, ale po rezervaci se ukazuje jako obsazené",
|
||||
"booking_lt0_short": "Volný limit",
|
||||
"catch_all": "Doménový koš",
|
||||
"created_on": "Vytvoreno",
|
||||
"daily": "Každý den",
|
||||
"deactivate": "Vypnout",
|
||||
"description": "Popis",
|
||||
"disable_login": "Zakázat přihlášení (ale stále přijímat poštu)",
|
||||
"disable_x": "Vypnout",
|
||||
"dkim_domains_selector": "Selektor",
|
||||
"dkim_key_length": "Délka DKIM klíče (v bitech)",
|
||||
"domain": "Doména",
|
||||
"domain_admins": "Správci domén",
|
||||
"domain_aliases": "Doménové aliasy",
|
||||
"domain_quota": "Kvóta",
|
||||
"domain_quota_total": "Celková kvóta domény",
|
||||
"domains": "Domény",
|
||||
"edit": "Upravit",
|
||||
"empty": "Žádné výsledky",
|
||||
|
@ -727,6 +724,8 @@
|
|||
"filter_table": "Filtrovat tabulku",
|
||||
"filters": "Filtry",
|
||||
"fname": "Celé jméno",
|
||||
"force_pw_update": "Vynutit změnu hesla při příštím přihlášení",
|
||||
"gal": "Globální seznam adres",
|
||||
"goto_ham": "Učit se jako <b>ham</b>",
|
||||
"goto_spam": "Učit se jako <b>spam</b>",
|
||||
"hourly": "Každou hodinu",
|
||||
|
@ -735,6 +734,7 @@
|
|||
"insert_preset": "Vložit ukázkovou položku \"%s\"",
|
||||
"kind": "Druh",
|
||||
"last_mail_login": "Poslední přihlášení",
|
||||
"last_modified": "Naposledy změněn",
|
||||
"last_pw_change": "Naposledy změněno heslo",
|
||||
"last_run": "Naposledy spuštěno",
|
||||
"last_run_reset": "Znovu naplánovat",
|
||||
|
@ -744,6 +744,9 @@
|
|||
"mailbox_defquota": "Výchozí velikost schránky",
|
||||
"mailbox_quota": "Max. velikost schránky",
|
||||
"mailboxes": "Mailové schránky",
|
||||
"max_aliases": "Max. počet aliasů",
|
||||
"max_mailboxes": "Max. počet mailových schránek",
|
||||
"max_quota": "Max. kvóta mailové schránky",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Počet zpráv",
|
||||
"multiple_bookings": "Vícenásobné rezervace",
|
||||
|
@ -769,6 +772,7 @@
|
|||
"recipient_map_old": "Původní příjemce",
|
||||
"recipient_map_old_info": "Původní příjemce musí být platná emailová adresa nebo název domény.",
|
||||
"recipient_maps": "Mapy příjemců",
|
||||
"relay_all": "Předávání všech příjemců",
|
||||
"remove": "Smazat",
|
||||
"resources": "Zdroje",
|
||||
"running": "Běží",
|
||||
|
@ -884,6 +888,17 @@
|
|||
"toggle_all": "Označit vše",
|
||||
"type": "Typ"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Smazat vše",
|
||||
"flush_queue": "Vyprázdnit frontu (opětovně doručit)",
|
||||
"queue_ays": "Potvrďte prosím, že chcete odstranit všechny položky z aktuální fronty.",
|
||||
"queue_deliver_mail": "Doručit",
|
||||
"queue_hold_mail": "Zadržet",
|
||||
"queue_manager": "Správce fronty",
|
||||
"queue_show_message": "Zobrazit zprávu",
|
||||
"queue_unban": "odblokovat",
|
||||
"queue_unhold_mail": "Propustit"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Vypnuto",
|
||||
"second": "zpráv za sekundu",
|
||||
|
@ -1097,7 +1112,7 @@
|
|||
"running": "Běží",
|
||||
"save": "Uložit změny",
|
||||
"save_changes": "Uložit změny",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odesílatele vypnuta</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Kontrola odesílatele vypnuta</span>",
|
||||
"shared_aliases": "Sdílené aliasy",
|
||||
"shared_aliases_desc": "Na sdílené aliasy se neuplatňuje uživatelské nastavení jako filtr spamu nebo pravidla šifrování. Nastavení filtrování spamu může provádět jen správce pro celou doménu.",
|
||||
"show_sieve_filters": "Zobrazit aktivní sieve filtr uživatele",
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
"relay_all": "Send alle modtagere videre",
|
||||
"relay_all_info": "↪ Hvis du vælger <b> ikke </b> at videresende alle modtagere, skal du tilføje et (\"blind\") postkasse til hver enkelt modtager, der skal videresendes.",
|
||||
"relay_domain": "Send dette domæne videre",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis ikke indstillet, foretages der et MX-opslag.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis ikke indstillet, foretages der et MX-opslag.",
|
||||
"relay_unknown_only": "Videresend kun ikke-eksisterende postkasser. Eksisterende postkasser leveres lokalt.",
|
||||
"relayhost_wrapped_tls_info": "Vær sød <b>ikke</b> at bruge TLS-indpakkede porte (bruges mest på port 465) .<br>\r\nBrug en ikke-pakket port, og udgiv STARTTLS. En TLS-politik til at håndhæve TLS kan oprettes i \"TLS policy maps\".",
|
||||
"select": "Vælg venligst...",
|
||||
|
@ -141,7 +141,6 @@
|
|||
"credentials_transport_warning": "<b>Advarsel</b>: Tilføjelse af en ny transportkortpost opdaterer legitimationsoplysningerne for alle poster med en matchende nexthop-kolonne.",
|
||||
"customer_id": "Kunde ID",
|
||||
"customize": "Tilpas",
|
||||
"delete_queue": "Slet alt",
|
||||
"destination": "Bestemmelsessted",
|
||||
"dkim_add_key": "Tilføj ARC/DKIM nøgle",
|
||||
"dkim_domains_selector": "Vælger",
|
||||
|
@ -178,7 +177,6 @@
|
|||
"f2b_retry_window": "Genindlæs vindue om (s) for max. forsøg",
|
||||
"f2b_whitelist": "Hvidlisted netværk/vært",
|
||||
"filter_table": "Filtertabel",
|
||||
"flush_queue": "Tøm kø",
|
||||
"forwarding_hosts": "Videresendelse af værter",
|
||||
"forwarding_hosts_add_hint": "Du kan enten angive IPv4 / IPv6-adresser, netværk i CIDR-notation, værtsnavne (som løses til IP-adresser) eller domænenavne (som løses til IP-adresser ved at spørge SPF-poster eller i mangel af MX-poster).",
|
||||
"forwarding_hosts_hint": "Indgående beskeder accepteres ubetinget fra værter, der er anført her. Disse værter kontrolleres derefter ikke mod DNSBL'er eller udsættes for gråt notering. Spam modtaget fra dem afvises aldrig, men det kan eventuelt arkiveres i Junk-mappen. Den mest almindelige anvendelse til dette er at specificere mailservere, hvor du har oprettet en regel, der videresender indgående e-mails til din mailcow-server. ",
|
||||
|
@ -237,13 +235,6 @@
|
|||
"quarantine_release_format_att": "Som vedhæftet fil",
|
||||
"quarantine_release_format_raw": "Umodificeret original",
|
||||
"quarantine_retention_size": "Tilbageholdelse pr. Postkasse:<br><small>0 angiver <b>inaktiv</b>.</small>",
|
||||
"queue_ays": "Bekræft venligst, at du vil slette alle emner fra den aktuelle kø.",
|
||||
"queue_deliver_mail": "Aflevere",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Køadministrator",
|
||||
"queue_unban": "kø ikke udeluk",
|
||||
"queue_unhold_mail": "Unhold",
|
||||
"queue_show_message": "Vis besked",
|
||||
"quota_notification_html": "Notifikations-e-mail-skabelon:<br><small>Lad det være tomt for at gendanne standardskabelonen.</small>",
|
||||
"quota_notification_sender": "Afsender af underretnings-e-mail",
|
||||
"quota_notification_subject": "Underretningens e-mail-emne",
|
||||
|
@ -535,7 +526,7 @@
|
|||
"relay_all": "Send alle modtagere videre",
|
||||
"relay_all_info": "↪ Hvis du vælger <b>ikke</b> for at videresende alle modtagere skal du tilføje en (\"blind\") postkasse til hver enkelt modtager, der skal videresendes.",
|
||||
"relay_domain": "Send dette domæne videre",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis den ikke er indstillet, foretages der et MX-opslag.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis den ikke er indstillet, foretages der et MX-opslag.",
|
||||
"relay_unknown_only": "Videresend kun ikke-eksisterende postkasser. Eksisterende postkasser leveres lokalt.",
|
||||
"relayhost": "Afsenderafhængige transporter",
|
||||
"remove": "Fjerne",
|
||||
|
@ -543,7 +534,7 @@
|
|||
"save": "Gem ændringer",
|
||||
"scope": "Anvendelsesområde",
|
||||
"sender_acl": "Tillad at sende som",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Afsenderkontrol er deaktiveret</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Afsenderkontrol er deaktiveret</span>",
|
||||
"sender_acl_info": "Hvis postkassebruger A har tilladelse til at sende som postkassebruger B, vises afsenderadressen ikke automatisk som valgbar \"from\" felt i SOGo.<br>\r\n Postkassebruger B skal oprette en delegation i SOGo for at tillade postkassebruger A at vælge deres adresse som afsender. For at delegere en postkasse i SOGo skal du bruge menuen (tre prikker) til højre for dit postkassens navn øverst til venstre, mens du er i postvisningen. Denne adfærd gælder ikke for aliasadresser.",
|
||||
"sieve_desc": "Kort beskrivelse",
|
||||
"sieve_type": "Filtertype",
|
||||
|
@ -581,8 +572,8 @@
|
|||
"administration": "Konfiguration og detailer",
|
||||
"apps": "Apps",
|
||||
"debug": "Systemoplysninger",
|
||||
"mailboxes": "Mailopsætning",
|
||||
"mailcow_settings": "Konfiguration",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Konfiguration",
|
||||
"quarantine": "Karantæne",
|
||||
"restart_netfilter": "Genstart netfilter",
|
||||
"restart_sogo": "Genstart SOGo",
|
||||
|
@ -649,11 +640,14 @@
|
|||
"deactivate": "Deaktiver",
|
||||
"description": "Beskrivelse",
|
||||
"disable_login": "Tillad ikke login (indgående mail accepteres stadig)",
|
||||
"disable_x": "Deaktiver",
|
||||
"disable_x": "Deaktiver",
|
||||
"dkim_domains_selector": "Vælger",
|
||||
"dkim_key_length": "DKIM nøgle længde (bits)",
|
||||
"domain": "Domæne",
|
||||
"domain_admins": "Domæneadministratorer",
|
||||
"domain_aliases": "Domænealiaser",
|
||||
"domain_quota": "Kvote",
|
||||
"domain_quota_total": "Samlet domænekvote",
|
||||
"domains": "Domains",
|
||||
"edit": "Edit",
|
||||
"empty": "Ingen resultater",
|
||||
|
@ -662,6 +656,8 @@
|
|||
"filter_table": "Filtertabel",
|
||||
"filters": "Filtre",
|
||||
"fname": "Fulde navn",
|
||||
"force_pw_update": "Tving adgangskodeopdatering til næste login",
|
||||
"gal": "Global adresseliste",
|
||||
"hourly": "Hver time",
|
||||
"in_use": "I brug (%)",
|
||||
"inactive": "Inaktiv",
|
||||
|
@ -676,6 +672,9 @@
|
|||
"mailboxes": "Postkasser",
|
||||
"mailbox_defaults": "Standardindstillinger",
|
||||
"mailbox_defaults_info": "Definer standardindstillinger for nye postkasser.",
|
||||
"max_aliases": "Maks. mulige aliasser",
|
||||
"max_mailboxes": "Maks. mulige postkasser",
|
||||
"max_quota": "Maks. kvote pr. postkasse",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Besked #",
|
||||
"multiple_bookings": "Flere bookinger",
|
||||
|
@ -803,6 +802,17 @@
|
|||
"text_plain_content": "Indhold (text/plain)",
|
||||
"toggle_all": "Skift alt"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Slet alt",
|
||||
"flush_queue": "Tøm kø",
|
||||
"queue_ays": "Bekræft venligst, at du vil slette alle emner fra den aktuelle kø.",
|
||||
"queue_deliver_mail": "Aflevere",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Køadministrator",
|
||||
"queue_unban": "kø ikke udeluk",
|
||||
"queue_unhold_mail": "Unhold",
|
||||
"queue_show_message": "Vis besked"
|
||||
},
|
||||
"start": {
|
||||
"help": "Vis / skjul hjælpepanel",
|
||||
"imap_smtp_server_auth_info": "Brug din fulde e-mail-adresse og PLAIN-godkendelsesmekanismen.<br>\r\nDine login-data bliver krypteret af den obligatoriske kryptering på serversiden.",
|
||||
|
@ -1005,7 +1015,7 @@
|
|||
"running": "Kører",
|
||||
"save": "Gem ændring",
|
||||
"save_changes": "Gem ændringer",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Afsender tjek er slået fra</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Afsender tjek er slået fra</span>",
|
||||
"shared_aliases": "Delte aliasadresser",
|
||||
"shared_aliases_desc": "Delt alias påvirkes ikke af brugerspecifikke indstillinger såsom spamfilter eller krypteringspolitik. Tilselementnde spamfiltre kan kun foretages af en administrator som en politik, der dækker hele domænet.",
|
||||
"show_sieve_filters": "Vis det aktive brugerfilter",
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
"relay_all": "Alle Empfänger-Adressen relayen",
|
||||
"relay_all_info": "↪ Wenn <b>nicht</b> alle Empfänger-Adressen relayt werden sollen, müssen \"blinde\" Mailboxen für jede Adresse, die relayt werden soll, erstellt werden.",
|
||||
"relay_domain": "Diese Domain relayen",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Transport-Maps können erstellt werden, um individuelle Ziele für eine Relay-Domain zu definieren.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Transport-Maps können erstellt werden, um individuelle Ziele für eine Relay-Domain zu definieren.",
|
||||
"relay_unknown_only": "Nur nicht-lokale Mailboxen relayen. Existente Mailboxen werden weiterhin lokal zugestellt.",
|
||||
"relayhost_wrapped_tls_info": "Bitte <b>keine</b> \"TLS-wrapped Ports\" verwenden (etwa SMTPS via Port 465/tcp).<br>\r\nDer Transport wird stattdessen STARTTLS anfordern, um TLS zu verwenden. TLS kann unter \"TLS Policy Maps\" erzwungen werden.",
|
||||
"select": "Bitte auswählen",
|
||||
|
@ -150,7 +150,6 @@
|
|||
"credentials_transport_warning": "<b>Warnung</b>: Das Hinzufügen einer neuen Regel bewirkt die Aktualisierung der Authentifizierungsdaten aller vorhandenen Einträge mit identischem Next Hop.",
|
||||
"customer_id": "Kunde",
|
||||
"customize": "UI-Anpassung",
|
||||
"delete_queue": "Alle löschen",
|
||||
"destination": "Ziel",
|
||||
"dkim_add_key": "ARC/DKIM-Key hinzufügen",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -187,7 +186,6 @@
|
|||
"f2b_retry_window": "Wiederholungen im Zeitraum von (s)",
|
||||
"f2b_whitelist": "Whitelist für Netzwerke und Hosts",
|
||||
"filter_table": "Tabelle filtern",
|
||||
"flush_queue": "Flush Queue",
|
||||
"forwarding_hosts": "Weiterleitungs-Hosts",
|
||||
"forwarding_hosts_add_hint": "Sie können entweder IPv4-/IPv6-Adressen, Netzwerke in CIDR-Notation, Hostnamen (die zu IP-Adressen aufgelöst werden), oder Domainnamen (die zu IP-Adressen aufgelöst werden, indem ihr SPF-Record abgefragt wird oder, in dessen Abwesenheit, ihre MX-Records) angeben.",
|
||||
"forwarding_hosts_hint": "Eingehende Nachrichten werden von den hier gelisteten Hosts bedingungslos akzeptiert. Diese Hosts werden dann nicht mit DNSBLs abgeglichen oder Greylisting unterworfen. Von ihnen empfangener Spam wird nie abgelehnt, optional kann er aber in den Spam-Ordner einsortiert werden. Die übliche Verwendung für diese Funktion ist, um Mailserver anzugeben, auf denen eine Weiterleitung zu Ihrem mailcow-Server eingerichtet wurde.",
|
||||
|
@ -230,6 +228,7 @@
|
|||
"oauth2_renew_secret": "Neues Client Secret generieren",
|
||||
"oauth2_revoke_tokens": "Alle Client Tokens entfernen",
|
||||
"optional": "Optional",
|
||||
"options": "Einstellungen",
|
||||
"password": "Passwort",
|
||||
"password_length": "Passwortlänge",
|
||||
"password_policy": "Passwortrichtlinie",
|
||||
|
@ -255,13 +254,6 @@
|
|||
"quarantine_release_format_att": "Als Anhang",
|
||||
"quarantine_release_format_raw": "Unverändertes Original",
|
||||
"quarantine_retention_size": "Rückhaltungen pro Mailbox:<br><small>0 bedeutet <b>inaktiv</b>.</small>",
|
||||
"queue_ays": "Soll die derzeitige Queue wirklich komplett bereinigt werden?",
|
||||
"queue_deliver_mail": "Ausliefern",
|
||||
"queue_hold_mail": "Zurückhalten",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Nachricht anzeigen",
|
||||
"queue_unban": "Entsperren einreihen",
|
||||
"queue_unhold_mail": "Freigeben",
|
||||
"quota_notification_html": "Benachrichtigungs-E-Mail Inhalt:<br><small>Leer lassen, um Standard-Template wiederherzustellen.</small>",
|
||||
"quota_notification_sender": "Benachrichtigungs-E-Mail Absender",
|
||||
"quota_notification_subject": "Benachrichtigungs-E-Mail Betreff",
|
||||
|
@ -361,6 +353,7 @@
|
|||
"bcc_must_be_email": "BCC-Ziel %s ist keine gültige E-Mail-Adresse",
|
||||
"comment_too_long": "Kommentarfeld darf maximal 160 Zeichen enthalten",
|
||||
"defquota_empty": "Standard-Quota darf nicht 0 sein",
|
||||
"demo_mode_enabled": "Demo Mode ist aktiviert",
|
||||
"description_invalid": "Ressourcenbeschreibung für %s ist ungültig",
|
||||
"dkim_domain_or_sel_exists": "Ein DKIM-Key für die Domain \"%s\" existiert und wird nicht überschrieben",
|
||||
"dkim_domain_or_sel_invalid": "DKIM-Domain oder Selector nicht korrekt: %s",
|
||||
|
@ -465,9 +458,39 @@
|
|||
"value_missing": "Bitte alle Felder ausfüllen",
|
||||
"yotp_verification_failed": "Yubico OTP-Verifizierung fehlgeschlagen: %s"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "Alle Einklappen",
|
||||
"decimal": "",
|
||||
"emptyTable": "Keine Daten in der Tabelle vorhanden",
|
||||
"expand_all": "Alle Ausklappen",
|
||||
"info": "_START_ bis _END_ von _TOTAL_ Einträgen",
|
||||
"infoEmpty": "0 bis 0 von 0 Einträgen",
|
||||
"infoFiltered": "(gefiltert von _MAX_ Einträgen)",
|
||||
"infoPostFix": "",
|
||||
"thousands": ".",
|
||||
"lengthMenu": "_MENU_ Einträge anzeigen",
|
||||
"loadingRecords": "Wird geladen...",
|
||||
"processing": "Bitte warten...",
|
||||
"search": "Suchen",
|
||||
"zeroRecords": "Keine Einträge vorhanden.",
|
||||
"paginate": {
|
||||
"first": "Erste",
|
||||
"previous": "Zurück",
|
||||
"next": "Nächste",
|
||||
"last": "Letzte"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": aktivieren, um Spalte aufsteigend zu sortieren",
|
||||
"sortDescending": ": aktivieren, um Spalte absteigend zu sortieren"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"chart_this_server": "Chart (dieser Server)",
|
||||
"containers_info": "Container-Information",
|
||||
"container_running": "Läuft",
|
||||
"container_stopped": "Angehalten",
|
||||
"cores": "Kerne",
|
||||
"current_time": "Systemzeit",
|
||||
"disk_usage": "Festplattennutzung",
|
||||
"docs": "Dokumente",
|
||||
"external_logs": "Externe Logs",
|
||||
|
@ -478,6 +501,7 @@
|
|||
"log_info": "<p>mailcow <b>in-memory Logs</b> werden in Redis Listen gespeichert, die maximale Anzahl der Einträge pro Anwendung richtet sich nach LOG_LINES (%d).\r\n <br>In-memory Logs sind vergänglich und nicht zur ständigen Aufbewahrung bestimmt. Alle Anwendungen, die in-memory protokollieren, schreiben ebenso in den Docker Daemon.\r\n <br>Das in-memory Protokoll versteht sich als schnelle Übersicht zum Debugging eines Containers, für komplexere Protokolle sollte der Docker Daemon konsultiert werden.</p>\r\n <p><b>Externe Logs</b> werden via API externer Applikationen bezogen.</p>\r\n <p><b>Statische Logs</b> sind weitestgehend Aktivitätsprotokolle, die nicht in den Docker Daemon geschrieben werden, jedoch permanent verfügbar sein müssen (ausgeschlossen API Logs).</p>",
|
||||
"login_time": "Zeit",
|
||||
"logs": "Protokolle",
|
||||
"memory": "Arbeitsspeicher",
|
||||
"online_users": "Benutzer online",
|
||||
"restart_container": "Neustart",
|
||||
"service": "Dienst",
|
||||
|
@ -489,7 +513,11 @@
|
|||
"static_logs": "Statische Logs",
|
||||
"success": "Erfolg",
|
||||
"system_containers": "System & Container",
|
||||
"uptime": "Uptime",
|
||||
"timezone": "Zeitzone",
|
||||
"uptime": "Betriebszeit",
|
||||
"update_available": "Es ist ein Update verfügbar",
|
||||
"no_update_available": "Das System ist auf aktuellem Stand",
|
||||
"update_failed": "Es konnte nicht nach einem Update gesucht werden",
|
||||
"username": "Benutzername"
|
||||
},
|
||||
"diagnostics": {
|
||||
|
@ -521,6 +549,7 @@
|
|||
"client_id": "Client-ID",
|
||||
"client_secret": "Client-Secret",
|
||||
"comment_info": "Ein privater Kommentar ist für den Benutzer nicht einsehbar. Ein öffentlicher Kommentar wird als Tooltip im Interface des Benutzers angezeigt.",
|
||||
"created_on": "Erstellt am",
|
||||
"delete1": "Lösche Nachricht nach Übertragung vom Quell-Server",
|
||||
"delete2": "Lösche Nachrichten von Ziel-Server, die nicht auf Quell-Server vorhanden sind",
|
||||
"delete2duplicates": "Lösche Duplikate im Ziel",
|
||||
|
@ -547,6 +576,7 @@
|
|||
"hostname": "Servername",
|
||||
"inactive": "Inaktiv",
|
||||
"kind": "Art",
|
||||
"last_modified": "Zuletzt geändert",
|
||||
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
|
||||
"mailbox": "Mailbox bearbeiten",
|
||||
"mailbox_quota_def": "Standard-Quota einer Mailbox",
|
||||
|
@ -584,7 +614,7 @@
|
|||
"relay_all": "Alle Empfänger-Adressen relayen",
|
||||
"relay_all_info": "↪ Wenn <b>nicht</b> alle Empfänger-Adressen relayt werden sollen, müssen \"blinde\" Mailboxen für jede Adresse, die relayt werden soll, erstellen werden.",
|
||||
"relay_domain": "Diese Domain relayen",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Transport Maps können erstellt werden, um individuelle Ziele für eine Relay Domain zu definieren.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Transport Maps können erstellt werden, um individuelle Ziele für eine Relay Domain zu definieren.",
|
||||
"relay_unknown_only": "Nur nicht-lokale Mailboxen relayen. Existente Mailboxen werden weiterhin lokal zugestellt.",
|
||||
"relayhost": "Senderabhängige Transport Maps",
|
||||
"remove": "Entfernen",
|
||||
|
@ -592,7 +622,7 @@
|
|||
"save": "Änderungen speichern",
|
||||
"scope": "Scope",
|
||||
"sender_acl": "Darf Nachrichten versenden als",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Absenderprüfung deaktiviert</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Absenderprüfung deaktiviert</span>",
|
||||
"sender_acl_info": "Wird einem Mailbox-Benutzer A der Versand als Mailbox-Benutzer B gestattet, so erscheint der Absender <b>nicht</b> automatisch in SOGo zur Auswahl.<br>\r\n In SOGo muss zusätzlich eine Delegation eingerichtet werden. Dieses Verhalten trifft nicht auf Alias-Adressen zu.",
|
||||
"sieve_desc": "Kurze Beschreibung",
|
||||
"sieve_type": "Filtertyp",
|
||||
|
@ -649,9 +679,9 @@
|
|||
"header": {
|
||||
"administration": "Server-Konfiguration",
|
||||
"apps": "Apps",
|
||||
"debug": "Systeminformation",
|
||||
"mailboxes": "E-Mail-Setup",
|
||||
"mailcow_settings": "Konfiguration",
|
||||
"debug": "Information",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Konfiguration",
|
||||
"quarantine": "Quarantäne",
|
||||
"restart_netfilter": "Netfilter neustarten",
|
||||
"restart_sogo": "SOGo neustarten",
|
||||
|
@ -685,6 +715,7 @@
|
|||
"add_filter": "Filter erstellen",
|
||||
"add_mailbox": "Mailbox hinzufügen",
|
||||
"add_recipient_map_entry": "Empfängerumschreibung hinzufügen",
|
||||
"add_template": "Vorlage hinzufügen",
|
||||
"add_resource": "Ressource hinzufügen",
|
||||
"add_tls_policy_map": "TLS-Richtlinieneintrag hinzufügen",
|
||||
"address_rewriting": "Adressumschreibung",
|
||||
|
@ -715,15 +746,20 @@
|
|||
"booking_custom_short": "Hartes Limit",
|
||||
"booking_ltnull": "Unbegrenzt, jedoch anzeigen, wenn gebucht",
|
||||
"booking_lt0_short": "Weiches Limit",
|
||||
"created_on": "Erstellt am",
|
||||
"daily": "Täglich",
|
||||
"deactivate": "Deaktivieren",
|
||||
"description": "Beschreibung",
|
||||
"disable_login": "Login verbieten (Mails werden weiterhin angenommen)",
|
||||
"disable_x": "Deaktivieren",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "DKIM-Schlüssellänge (bits)",
|
||||
"domain": "Domain",
|
||||
"domain_admins": "Domain-Administratoren",
|
||||
"domain_aliases": "Domain-Aliasse",
|
||||
"domain_templates": "Domainweite Vorlagen",
|
||||
"domain_quota": "Gesamtspeicher",
|
||||
"domain_quota_total": "Domain-Speicherplatz gesamt",
|
||||
"domains": "Domains",
|
||||
"edit": "Bearbeiten",
|
||||
"empty": "Keine Einträge vorhanden",
|
||||
|
@ -732,12 +768,15 @@
|
|||
"filter_table": "Filtern",
|
||||
"filters": "Filter",
|
||||
"fname": "Name",
|
||||
"force_pw_update": "Erzwinge Passwortänderung bei nächstem Login",
|
||||
"gal": "Globales Adressbuch",
|
||||
"hourly": "Stündlich",
|
||||
"in_use": "Prozentualer Gebrauch",
|
||||
"inactive": "Inaktiv",
|
||||
"insert_preset": "Beispiel \"%s\" laden",
|
||||
"kind": "Art",
|
||||
"last_mail_login": "Letzter Mail-Login",
|
||||
"last_modified": "Zuletzt geändert",
|
||||
"last_pw_change": "Letzte Passwortänderung",
|
||||
"last_run": "Letzte Ausführung",
|
||||
"last_run_reset": "Als nächstes ausführen",
|
||||
|
@ -745,8 +784,12 @@
|
|||
"mailbox_defaults": "Standardeinstellungen",
|
||||
"mailbox_defaults_info": "Steuert die Standardeinstellungen für neue Mailboxen.",
|
||||
"mailbox_defquota": "Standard-Quota",
|
||||
"mailbox_templates": "Mailboxweite Vorlagen",
|
||||
"mailbox_quota": "Max. Größe einer Mailbox",
|
||||
"mailboxes": "Mailboxen",
|
||||
"max_aliases": "Max. mögliche Aliasse",
|
||||
"max_mailboxes": "Max. mögliche Mailboxen",
|
||||
"max_quota": "Max. Größe per Mailbox",
|
||||
"mins_interval": "Intervall (min)",
|
||||
"msg_num": "Anzahl Nachrichten",
|
||||
"multiple_bookings": "Mehrfachbuchen",
|
||||
|
@ -770,6 +813,8 @@
|
|||
"recipient_map_old": "Original-Empfänger",
|
||||
"recipient_map_old_info": "Der originale Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
|
||||
"recipient_maps": "Empfängerumschreibungen",
|
||||
"relay_all": "Alle Empfänger-Adressen relayen",
|
||||
"relay_unknown": "Unbekannte Mailboxen relayen",
|
||||
"remove": "Entfernen",
|
||||
"resources": "Ressourcen",
|
||||
"running": "In Ausführung",
|
||||
|
@ -796,6 +841,8 @@
|
|||
"table_size_show_n": "Zeige %s Einträge",
|
||||
"target_address": "Ziel-Adresse",
|
||||
"target_domain": "Ziel-Domain",
|
||||
"templates": "Vorlagen",
|
||||
"template": "Vorlage",
|
||||
"tls_enforce_in": "TLS eingehend erzwingen",
|
||||
"tls_enforce_out": "TLS ausgehend erzwingen",
|
||||
"tls_map_dest": "Ziel",
|
||||
|
@ -891,6 +938,22 @@
|
|||
"toggle_all": "Alle auswählen",
|
||||
"type": "Typ"
|
||||
},
|
||||
"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",
|
||||
"legend": "Funktionen der Mailqueue Aktionen:",
|
||||
"ays": "Soll die derzeitige Queue wirklich komplett bereinigt werden?",
|
||||
"deliver_mail": "Ausliefern",
|
||||
"deliver_mail_legend": "Versucht eine erneute Zustellung der ausgwählten Mails.",
|
||||
"hold_mail": "Zurückhalten",
|
||||
"hold_mail_legend": "Hält die ausgewählten Mails zurück. (Verhindert weitere Zustellversuche)",
|
||||
"queue_manager": "Queue Manager",
|
||||
"show_message": "Nachricht anzeigen",
|
||||
"unban": "queue unban",
|
||||
"unhold_mail": "Freigeben",
|
||||
"unhold_mail_legend": "Gibt ausgewählte Mails zur Auslieferung frei. (Erfordert vorheriges Zurückhalten)"
|
||||
},
|
||||
"start": {
|
||||
"help": "Hilfe ein-/ausblenden",
|
||||
"imap_smtp_server_auth_info": "Bitte verwenden Sie Ihre vollständige E-Mail-Adresse sowie das PLAIN-Authentifizierungsverfahren.<br>\r\nIhre Anmeldedaten werden durch die obligatorische Verschlüsselung entgegen des Begriffes \"PLAIN\" nicht unverschlüsselt übertragen.",
|
||||
|
@ -966,6 +1029,9 @@
|
|||
"saved_settings": "Regel wurde gespeichert",
|
||||
"settings_map_added": "Regel wurde gespeichert",
|
||||
"settings_map_removed": "Regeln wurden entfernt: %s",
|
||||
"template_added": "Template %s hinzugefügt",
|
||||
"template_modified": "Änderungen am Template %s wurden gespeichert",
|
||||
"template_removed": "Template ID %s wurde gelöscht",
|
||||
"sogo_profile_reset": "ActiveSync-Gerät des Benutzers %s wurde zurückgesetzt",
|
||||
"tls_policy_map_entry_deleted": "TLS-Richtlinie mit der ID %s wurde gelöscht",
|
||||
"tls_policy_map_entry_saved": "TLS-Richtlinieneintrag \"%s\" wurde gespeichert",
|
||||
|
@ -1103,7 +1169,7 @@
|
|||
"running": "Wird ausgeführt",
|
||||
"save": "Änderungen speichern",
|
||||
"save_changes": "Änderungen speichern",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Absenderprüfung deaktiviert</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Absenderprüfung deaktiviert</span>",
|
||||
"shared_aliases": "Geteilte Alias-Adressen",
|
||||
"shared_aliases_desc": "Geteilte Alias-Adressen werden nicht bei benutzerdefinierten Einstellungen, wie die des Spam-Filters oder der Verschlüsselungsrichtlinie, berücksichtigt. Entsprechende Spam-Filter können lediglich von einem Administrator vorgenommen werden.",
|
||||
"show_sieve_filters": "Zeige aktiven Filter des Benutzers",
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
"relay_all": "Relay all recipients",
|
||||
"relay_all_info": "↪ If you choose <b>not</b> to relay all recipients, you will need to add a (\"blind\") mailbox for every single recipient that should be relayed.",
|
||||
"relay_domain": "Relay this domain",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_unknown_only": "Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.",
|
||||
"relayhost_wrapped_tls_info": "Please do <b>not</b> use TLS-wrapped ports (mostly used on port 465).<br>\r\nUse any non-wrapped port and issue STARTTLS. A TLS policy to enforce TLS can be created in \"TLS policy maps\".",
|
||||
"select": "Please select...",
|
||||
|
@ -152,7 +152,6 @@
|
|||
"credentials_transport_warning": "<b>Warning</b>: Adding a new transport map entry will update the credentials for all entries with a matching next hop column.",
|
||||
"customer_id": "Customer ID",
|
||||
"customize": "Customize",
|
||||
"delete_queue": "Delete all",
|
||||
"destination": "Destination",
|
||||
"dkim_add_key": "Add ARC/DKIM key",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -189,7 +188,6 @@
|
|||
"f2b_retry_window": "Retry window (s) for max. attempts",
|
||||
"f2b_whitelist": "Whitelisted networks/hosts",
|
||||
"filter_table": "Filter table",
|
||||
"flush_queue": "Flush queue",
|
||||
"forwarding_hosts": "Forwarding Hosts",
|
||||
"forwarding_hosts_add_hint": "You can either specify IPv4/IPv6 addresses, networks in CIDR notation, host names (which will be resolved to IP addresses), or domain names (which will be resolved to IP addresses by querying SPF records or, in their absence, MX records).",
|
||||
"forwarding_hosts_hint": "Incoming messages are unconditionally accepted from any hosts listed here. These hosts are then not checked against DNSBLs or subjected to greylisting. Spam received from them is never rejected, but optionally it can be filed into the Junk folder. The most common use for this is to specify mail servers on which you have set up a rule that forwards incoming emails to your mailcow server.",
|
||||
|
@ -234,6 +232,7 @@
|
|||
"oauth2_renew_secret": "Generate new client secret",
|
||||
"oauth2_revoke_tokens": "Revoke all client tokens",
|
||||
"optional": "optional",
|
||||
"options": "Options",
|
||||
"password": "Password",
|
||||
"password_length": "Password length",
|
||||
"password_policy": "Password policy",
|
||||
|
@ -259,13 +258,6 @@
|
|||
"quarantine_release_format_att": "As attachment",
|
||||
"quarantine_release_format_raw": "Unmodified original",
|
||||
"quarantine_retention_size": "Retentions per mailbox:<br><small>0 indicates <b>inactive</b>.</small>",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold",
|
||||
"quota_notification_html": "Notification email template:<br><small>Leave empty to restore default template.</small>",
|
||||
"quota_notification_sender": "Notification email sender",
|
||||
"quota_notification_subject": "Notification email subject",
|
||||
|
@ -361,6 +353,7 @@
|
|||
"bcc_must_be_email": "BCC destination %s is not a valid email address",
|
||||
"comment_too_long": "Comment too long, max 160 chars allowed",
|
||||
"defquota_empty": "Default quota per mailbox must not be 0.",
|
||||
"demo_mode_enabled": "Demo Mode is enabled",
|
||||
"description_invalid": "Resource description for %s is invalid",
|
||||
"dkim_domain_or_sel_exists": "A DKIM key for \"%s\" exists and will not be overwritten",
|
||||
"dkim_domain_or_sel_invalid": "DKIM domain or selector invalid: %s",
|
||||
|
@ -448,6 +441,9 @@
|
|||
"target_domain_invalid": "Target domain %s is invalid",
|
||||
"targetd_not_found": "Target domain %s not found",
|
||||
"targetd_relay_domain": "Target domain %s is a relay domain",
|
||||
"template_exists": "Template %s already exists",
|
||||
"template_id_invalid": "Template ID %s invalid",
|
||||
"template_name_invalid": "Template name invalid",
|
||||
"temp_error": "Temporary error",
|
||||
"text_empty": "Text must not be empty",
|
||||
"tfa_token_invalid": "TFA token invalid",
|
||||
|
@ -465,9 +461,39 @@
|
|||
"value_missing": "Please provide all values",
|
||||
"yotp_verification_failed": "Yubico OTP verification failed: %s"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "Collapse All",
|
||||
"decimal": "",
|
||||
"emptyTable": "No data available in table",
|
||||
"expand_all": "Expand All",
|
||||
"info": "Showing _START_ to _END_ of _TOTAL_ entries",
|
||||
"infoEmpty": "Showing 0 to 0 of 0 entries",
|
||||
"infoFiltered": "(filtered from _MAX_ total entries)",
|
||||
"infoPostFix": "",
|
||||
"thousands": ",",
|
||||
"lengthMenu": "Show _MENU_ entries",
|
||||
"loadingRecords": "Loading...",
|
||||
"processing": "Please wait...",
|
||||
"search": "Search:",
|
||||
"zeroRecords": "No matching records found",
|
||||
"paginate": {
|
||||
"first": "First",
|
||||
"last": "Last",
|
||||
"next": "Next",
|
||||
"previous": "Previous"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": activate to sort column ascending",
|
||||
"sortDescending": ": activate to sort column descending"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"chart_this_server": "Chart (this server)",
|
||||
"containers_info": "Container information",
|
||||
"container_running": "Running",
|
||||
"container_stopped": "Stopped",
|
||||
"cores": "Cores",
|
||||
"current_time": "System Time",
|
||||
"disk_usage": "Disk usage",
|
||||
"docs": "Docs",
|
||||
"external_logs": "External logs",
|
||||
|
@ -478,6 +504,7 @@
|
|||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"login_time": "Time",
|
||||
"logs": "Logs",
|
||||
"memory": "Memory",
|
||||
"online_users": "Users online",
|
||||
"restart_container": "Restart",
|
||||
"service": "Service",
|
||||
|
@ -489,7 +516,11 @@
|
|||
"static_logs": "Static logs",
|
||||
"success": "Success",
|
||||
"system_containers": "System & Containers",
|
||||
"timezone": "Timezone",
|
||||
"uptime": "Uptime",
|
||||
"update_available": "There is an update available",
|
||||
"no_update_available": "The System is on the latest version",
|
||||
"update_failed": "Could not check for an Update",
|
||||
"username": "Username"
|
||||
},
|
||||
"diagnostics": {
|
||||
|
@ -521,6 +552,7 @@
|
|||
"client_id": "Client ID",
|
||||
"client_secret": "Client secret",
|
||||
"comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",
|
||||
"created_on": "Created on",
|
||||
"delete1": "Delete from source when completed",
|
||||
"delete2": "Delete messages on destination that are not on source",
|
||||
"delete2duplicates": "Delete duplicates on destination",
|
||||
|
@ -547,6 +579,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Inactive",
|
||||
"kind": "Kind",
|
||||
"last_modified": "Last modified",
|
||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||
"mailbox": "Edit mailbox",
|
||||
"mailbox_quota_def": "Default mailbox quota",
|
||||
|
@ -585,7 +618,7 @@
|
|||
"relay_all": "Relay all recipients",
|
||||
"relay_all_info": "↪ If you choose <b>not</b> to relay all recipients, you will need to add a (\"blind\") mailbox for every single recipient that should be relayed.",
|
||||
"relay_domain": "Relay this domain",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_unknown_only": "Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.",
|
||||
"relayhost": "Sender-dependent transports",
|
||||
"remove": "Remove",
|
||||
|
@ -593,7 +626,7 @@
|
|||
"save": "Save changes",
|
||||
"scope": "Scope",
|
||||
"sender_acl": "Allow to send as",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.",
|
||||
"sieve_desc": "Short description",
|
||||
"sieve_type": "Filter type",
|
||||
|
@ -650,9 +683,10 @@
|
|||
"header": {
|
||||
"administration": "Configuration & Details",
|
||||
"apps": "Apps",
|
||||
"debug": "System Information",
|
||||
"mailboxes": "Mail Setup",
|
||||
"mailcow_settings": "Configuration",
|
||||
"debug": "Information",
|
||||
"email": "E-Mail",
|
||||
"mailcow_system": "System",
|
||||
"mailcow_config": "Configuration",
|
||||
"quarantine": "Quarantine",
|
||||
"restart_netfilter": "Restart netfilter",
|
||||
"restart_sogo": "Restart SOGo",
|
||||
|
@ -687,6 +721,7 @@
|
|||
"add_mailbox": "Add mailbox",
|
||||
"add_recipient_map_entry": "Add recipient map",
|
||||
"add_resource": "Add resource",
|
||||
"add_template": "Add Template",
|
||||
"add_tls_policy_map": "Add TLS policy map",
|
||||
"address_rewriting": "Address rewriting",
|
||||
"alias": "Alias",
|
||||
|
@ -718,15 +753,20 @@
|
|||
"booking_ltnull": "Unlimited, but show as busy when booked",
|
||||
"booking_lt0_short": "Soft limit",
|
||||
"catch_all": "Catch-All",
|
||||
"created_on": "Created on",
|
||||
"daily": "Daily",
|
||||
"deactivate": "Deactivate",
|
||||
"description": "Description",
|
||||
"disable_login": "Disallow login (incoming mail is still accepted)",
|
||||
"disable_x": "Disable",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "DKIM key length (bits)",
|
||||
"domain": "Domain",
|
||||
"domain_admins": "Domain administrators",
|
||||
"domain_aliases": "Domain aliases",
|
||||
"domain_templates": "Domain Templates",
|
||||
"domain_quota": "Quota",
|
||||
"domain_quota_total": "Total domain quota",
|
||||
"domains": "Domains",
|
||||
"edit": "Edit",
|
||||
"empty": "No results",
|
||||
|
@ -735,6 +775,8 @@
|
|||
"filter_table": "Filter table",
|
||||
"filters": "Filters",
|
||||
"fname": "Full name",
|
||||
"force_pw_update": "Force password update at next login",
|
||||
"gal": "Global Address List",
|
||||
"goto_ham": "Learn as <b>ham</b>",
|
||||
"goto_spam": "Learn as <b>spam</b>",
|
||||
"hourly": "Hourly",
|
||||
|
@ -743,6 +785,7 @@
|
|||
"insert_preset": "Insert example preset \"%s\"",
|
||||
"kind": "Kind",
|
||||
"last_mail_login": "Last mail login",
|
||||
"last_modified": "Last modified",
|
||||
"last_pw_change": "Last password change",
|
||||
"last_run": "Last run",
|
||||
"last_run_reset": "Schedule next",
|
||||
|
@ -750,8 +793,12 @@
|
|||
"mailbox_defaults": "Default settings",
|
||||
"mailbox_defaults_info": "Define default settings for new mailboxes.",
|
||||
"mailbox_defquota": "Default mailbox size",
|
||||
"mailbox_templates": "Mailbox Templates",
|
||||
"mailbox_quota": "Max. size of a mailbox",
|
||||
"mailboxes": "Mailboxes",
|
||||
"max_aliases": "Max. aliases",
|
||||
"max_mailboxes": "Max. possible mailboxes",
|
||||
"max_quota": "Max. quota per mailbox",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Message #",
|
||||
"multiple_bookings": "Multiple bookings",
|
||||
|
@ -777,6 +824,8 @@
|
|||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "Relay all recipients",
|
||||
"relay_unknown": "Relay unknown mailboxes",
|
||||
"remove": "Remove",
|
||||
"resources": "Resources",
|
||||
"running": "Running",
|
||||
|
@ -813,6 +862,8 @@
|
|||
"table_size_show_n": "Show %s items",
|
||||
"target_address": "Goto address",
|
||||
"target_domain": "Target domain",
|
||||
"templates": "Templates",
|
||||
"template": "Template",
|
||||
"tls_enforce_in": "Enforce TLS incoming",
|
||||
"tls_enforce_out": "Enforce TLS outgoing",
|
||||
"tls_map_dest": "Destination",
|
||||
|
@ -892,6 +943,22 @@
|
|||
"toggle_all": "Toggle all",
|
||||
"type": "Type"
|
||||
},
|
||||
"queue": {
|
||||
"delete": "Delete all",
|
||||
"flush": "Flush queue",
|
||||
"info" : "The mail queue contains all e-mails that are waiting for delivery. If an email is stuck in the mail queue for a long time, it is automatically deleted by the system.<br>The error message of the respective mail gives information about why the mail could not be delivered.",
|
||||
"legend": "Mail queue actions functions:",
|
||||
"ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"deliver_mail": "Deliver",
|
||||
"deliver_mail_legend": "Attempts to redeliver selected mails.",
|
||||
"hold_mail": "Hold",
|
||||
"hold_mail_legend": "Holds the selected mails. (Prevents further delivery attempts)",
|
||||
"queue_manager": "Queue Manager",
|
||||
"show_message": "Show message",
|
||||
"unban": "queue unban",
|
||||
"unhold_mail": "Unhold",
|
||||
"unhold_mail_legend": "Releases selected mails for delivery. (Requires prior hold)"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Disabled",
|
||||
"second": "msgs / second",
|
||||
|
@ -975,6 +1042,9 @@
|
|||
"settings_map_added": "Added settings map entry",
|
||||
"settings_map_removed": "Removed settings map ID %s",
|
||||
"sogo_profile_reset": "SOGo profile for user %s was reset",
|
||||
"template_added": "Added template %s",
|
||||
"template_modified": "Changes to template %s have been saved",
|
||||
"template_removed": "Template ID %s has been deleted",
|
||||
"tls_policy_map_entry_deleted": "TLS policy map ID %s has been deleted",
|
||||
"tls_policy_map_entry_saved": "TLS policy map entry \"%s\" has been saved",
|
||||
"ui_texts": "Saved changes to UI texts",
|
||||
|
@ -1113,7 +1183,7 @@
|
|||
"running": "Running",
|
||||
"save": "Save changes",
|
||||
"save_changes": "Save changes",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"shared_aliases": "Shared alias addresses",
|
||||
"shared_aliases_desc": "Shared aliases are not affected by user specific settings such as the spam filter or encryption policy. Corresponding spam filters can only be made by an administrator as a domain-wide policy.",
|
||||
"show_sieve_filters": "Show active user sieve filter",
|
||||
|
|
|
@ -119,7 +119,6 @@
|
|||
"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.",
|
||||
"customize": "Personalizar",
|
||||
"delete_queue": "Eliminar todos",
|
||||
"destination": "Destino",
|
||||
"dkim_add_key": "Agregar registro ARC/DKIM",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -151,7 +150,6 @@
|
|||
"f2b_retry_window": "Ventana de tiempo entre reintentos",
|
||||
"f2b_whitelist": "Redes y hosts en lista blanca",
|
||||
"filter_table": "Filtrar tabla",
|
||||
"flush_queue": "Vaciar la cola",
|
||||
"forwarding_hosts": "Hosts de reenvío",
|
||||
"forwarding_hosts_add_hint": "Se puede especificar direcciones IPv4 / IPv6, redes en notación CIDR, nombres de host (que se resolverán en direcciones IP) o dominios (que se resolverán en direcciones IP consultando registros SPF o, en su defecto, registros MX)",
|
||||
"forwarding_hosts_hint": "Los mensajes entrantes son aceptados incondicionalmente de cualquiera de los hosts enumerados aquí. Estos hosts no se comprueban con listas DNSBL o se someten a greylisting. El spam recibido de ellos nunca se rechaza, pero opcionalmente se puede archivar en la carpeta de correo no deseado. El uso más común para esto es especificar los servidores de correo en los que ha configurado una regla que reenvía los correos electrónicos entrantes al servidor mailcow.",
|
||||
|
@ -192,12 +190,6 @@
|
|||
"quarantine_release_format_att": "Como adjunto",
|
||||
"quarantine_release_format_raw": "Original sin modificar",
|
||||
"quarantine_retention_size": "Retenciones por buzón:<br><small>0 indica <b>inactivo</b>.</small>",
|
||||
"queue_ays": "Confirme que desea eliminar todos los elementos de la cola actual.",
|
||||
"queue_deliver_mail": "Entregar",
|
||||
"queue_hold_mail": "Retener",
|
||||
"queue_manager": "Administrador de cola",
|
||||
"queue_unban": "Encolar desbloqueo",
|
||||
"queue_unhold_mail": "Liberar retención",
|
||||
"quota_notification_html": "Plantilla del email de notificación:<br><small>Dejar en blanco para usar la planilla predeterminada.</small>",
|
||||
"quota_notification_sender": "Remitente del email de notificación",
|
||||
"quota_notification_subject": "Asunto del email de notificación",
|
||||
|
@ -391,6 +383,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Inactivo",
|
||||
"kind": "Tipo",
|
||||
"last_modified": "Última modificación",
|
||||
"mailbox": "Editar buzón",
|
||||
"mailbox_quota_def": "Cuota de buzón predeterminada",
|
||||
"max_aliases": "Máx. alias:",
|
||||
|
@ -438,8 +431,8 @@
|
|||
"header": {
|
||||
"administration": "Administración",
|
||||
"debug": "Información del sistema",
|
||||
"mailboxes": "Buzones",
|
||||
"mailcow_settings": "Configuración",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuración",
|
||||
"quarantine": "Cuarentena",
|
||||
"restart_sogo": "Reiniciar SOGo",
|
||||
"user_settings": "Configuraciones de usuario"
|
||||
|
@ -496,10 +489,13 @@
|
|||
"deactivate": "Desactivar",
|
||||
"description": "Descripción",
|
||||
"disable_x": "Desactivar",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "Longitud de la llave DKIM (bits)",
|
||||
"domain": "Dominio",
|
||||
"domain_admins": "Administradores por dominio",
|
||||
"domain_aliases": "Alias de dominio",
|
||||
"domain_quota": "Cuota",
|
||||
"domain_quota_total": "Cuota total del dominio",
|
||||
"domains": "Dominios",
|
||||
"edit": "Editar",
|
||||
"empty": "Sin resultados",
|
||||
|
@ -508,14 +504,20 @@
|
|||
"filter_table": "Filtrar tabla",
|
||||
"filters": "Filtros",
|
||||
"fname": "Nombre completo",
|
||||
"force_pw_update": "Forzar cambio de contraseña en el próximo inicio de sesión",
|
||||
"gal": "Lista global de direcciones (GAL)",
|
||||
"hourly": "Cada hora",
|
||||
"in_use": "En uso (%)",
|
||||
"inactive": "Inactivo",
|
||||
"kind": "Tipo",
|
||||
"last_modified": "Última modificación",
|
||||
"last_run": "Última ejecución",
|
||||
"mailbox_defquota": "Tamaño de buzón predeterminado",
|
||||
"mailbox_quota": "Tamaño máx. de cuota",
|
||||
"mailboxes": "Buzones",
|
||||
"max_aliases": "Máx. alias posibles",
|
||||
"max_mailboxes": "Máx. buzones posibles",
|
||||
"max_quota": "Máx. cuota por buzón",
|
||||
"mins_interval": "Intervalo (min)",
|
||||
"msg_num": "Mensaje #",
|
||||
"multiple_bookings": "Reservas multiples",
|
||||
|
@ -531,6 +533,7 @@
|
|||
"recipient_map_old": "Destinatario original",
|
||||
"recipient_map_old_info": "El destino original de una regla de destinatario debe ser una dirección de correo electrónico válida o un nombre de dominio.",
|
||||
"recipient_maps": "Reglas de destinatario",
|
||||
"relay_all": "Retransmitir todos los destinatarios",
|
||||
"remove": "Eliminar",
|
||||
"resources": "Recursos",
|
||||
"running": "En marcha",
|
||||
|
@ -598,6 +601,16 @@
|
|||
"text_plain_content": "Contenido (text/plain)",
|
||||
"toggle_all": "Seleccionar todos"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Eliminar todos",
|
||||
"flush_queue": "Vaciar la cola",
|
||||
"queue_ays": "Confirme que desea eliminar todos los elementos de la cola actual.",
|
||||
"queue_deliver_mail": "Entregar",
|
||||
"queue_hold_mail": "Retener",
|
||||
"queue_manager": "Administrador de cola",
|
||||
"queue_unban": "Encolar desbloqueo",
|
||||
"queue_unhold_mail": "Liberar retención"
|
||||
},
|
||||
"start": {
|
||||
"help": "Mostrar/Ocultar panel de ayuda",
|
||||
"imap_smtp_server_auth_info": "Por favor utiliza tu dirección de correo completa y el mecanismo de autenticación PLAIN.<br>\r\nTus datos para iniciar sesión serán cifrados por el cifrado obligatorio del servidor",
|
||||
|
|
|
@ -127,7 +127,6 @@
|
|||
"credentials_transport_warning": "<b>Varoitus</b>: Uuden kuljetuskarttatietueen lisääminen päivittää kaikkien merkintöjen käyttöoikeustiedot vastaavalla nexthop-sarakkeella.",
|
||||
"customer_id": "Asiakkaan tunnus ID",
|
||||
"customize": "Muokkaa",
|
||||
"delete_queue": "Poista kaikki",
|
||||
"destination": "Määränpää",
|
||||
"dkim_add_key": "Lisää ARC/DKIM-avain",
|
||||
"dkim_domains_selector": "Valitsin",
|
||||
|
@ -160,7 +159,6 @@
|
|||
"f2b_retry_window": "Yritä uudelleen-ikkuna (s) Max. Yrittää",
|
||||
"f2b_whitelist": "Sallitut verkot/isännät",
|
||||
"filter_table": "Suodata taulukko",
|
||||
"flush_queue": "Tyhjennä jono",
|
||||
"forwarding_hosts": "Palveluntarjoajien välittäminen",
|
||||
"forwarding_hosts_add_hint": "Voit joko määrittää IPv4 / IPv6-osoitteet, verkot CIDR-merkinnässä, isäntänimet (jotka määritetään IP-osoitteiksi) tai verkkotunnusten nimet (jotka määritetään IP-osoitteiksi kyselyllä SPF-tietueista tai niiden puuttuessa MX-tietueista). .",
|
||||
"forwarding_hosts_hint": "Saapuvat viestit hyväksytään ehdoitta kaikilta täällä luetelluilta isännöimiltä. Näitä isäntiä ei sitten tarkisteta DNSBL: ien suhteen, eikä heille suoriteta tyyliluettelointia. Heiltä vastaanotettua roskapostia ei koskaan hylätä, mutta valinnaisesti se voidaan tallentaa Roskakori-kansioon. Yleisin käyttö tähän tarkoitukseen on määrittää postipalvelimet, joille olet asettanut säännön, joka välittää tulevat sähköpostit mailcow-palvelimellesi.",
|
||||
|
@ -214,12 +212,6 @@
|
|||
"quarantine_release_format_att": "Liitteenä",
|
||||
"quarantine_release_format_raw": "Muuttamaton alkuperäinen",
|
||||
"quarantine_retention_size": " Pidätykset per postilaatikko:<br><small>0 ilmaisee <b>inactive</b>.</small>",
|
||||
"queue_ays": "Vahvista, että haluat poistaa kaikki nykyisen jonon kohteet.",
|
||||
"queue_deliver_mail": "Toimittaa",
|
||||
"queue_hold_mail": "Pidossa",
|
||||
"queue_manager": "Jonon hallinta",
|
||||
"queue_unban": "jono unban",
|
||||
"queue_unhold_mail": "Poista pidosta",
|
||||
"quota_notification_html": "Ilmoitusviestin malli:<br><small>Jätä tyhjä palauttaaksesi oletusmallin.</small>",
|
||||
"quota_notification_sender": "Ilmoitusviestin lähettäjä",
|
||||
"quota_notification_subject": "Ilmoitusviestin aihe",
|
||||
|
@ -441,6 +433,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Passiivinen",
|
||||
"kind": "Kiltti",
|
||||
"last_modified": "Viimeksi muokattu",
|
||||
"mailbox": "Muokkaa sähköposti tiliä",
|
||||
"mailbox_quota_def": "Sähköpostin oletus kiintiö",
|
||||
"max_aliases": "Maks. Aliaksia",
|
||||
|
@ -468,7 +461,7 @@
|
|||
"save": "Tallenna muutokset",
|
||||
"scope": "Laajuus",
|
||||
"sender_acl": "Salli lähettää nimellä",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>",
|
||||
"sender_acl_info": "Jos postilaatikon käyttäjän A sallitaan lähettävän postilaatikon käyttäjäksi B, lähettäjän osoitetta ei näytetä automaattisesti valittavana \"alkaen\" -kentässä SOGossa.<br>\r\nSähkö postilaatikon käyttäjän A on luotava valtuutus SOGoon, jotta sähkö postilaatikon käyttäjä b voi valita osoitteen lähettäjäksi. Tämä käyttäytyminen ei koske alias-osoitteita",
|
||||
"sieve_desc": "Lyhyt kuvaus",
|
||||
"sieve_type": "Suodattimen tyyppi",
|
||||
|
@ -506,8 +499,8 @@
|
|||
"administration": "Kokoonpanon & tiedot",
|
||||
"apps": "Sovellukset",
|
||||
"debug": "Järjestelmä tiedot",
|
||||
"mailboxes": "Verkkotunnuksien asetukset",
|
||||
"mailcow_settings": "Kokoonpano",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Kokoonpano",
|
||||
"quarantine": "Karanteeni",
|
||||
"restart_netfilter": "Uudelleen käynnistä netfilter",
|
||||
"restart_sogo": "Uudelleen käynnistä SOGo",
|
||||
|
@ -566,11 +559,14 @@
|
|||
"daily": "Päivittäin",
|
||||
"deactivate": "Deaktivoi",
|
||||
"description": "Kuvaus",
|
||||
"disable_x": "Poista käytöstä",
|
||||
"disable_x": "Poista käytöstä",
|
||||
"dkim_domains_selector": "Valitsin",
|
||||
"dkim_key_length": "DKIM avaimen pituus (bits)",
|
||||
"domain": "Verkkotunnukset",
|
||||
"domain_admins": "Verkkotunnuksien järjestelmänvalvojat",
|
||||
"domain_aliases": "Domain alueiden aliakset",
|
||||
"domain_quota": "Kiintiö",
|
||||
"domain_quota_total": "Verkkotunnuksen kokonaiskiintiö",
|
||||
"domains": "Verkkotunnukset",
|
||||
"edit": "Muokkaa",
|
||||
"empty": "Ei tuloksia",
|
||||
|
@ -579,16 +575,22 @@
|
|||
"filter_table": "Suodata taulu",
|
||||
"filters": "Suodattimet",
|
||||
"fname": "Koko nimi",
|
||||
"force_pw_update": "Pakota salasanan vaihto seuraavan sisään kirjautumisen jälkeen",
|
||||
"gal": "Yleinen osoite luettelo",
|
||||
"hourly": "Tunnin välein",
|
||||
"in_use": "Käytössä (%)",
|
||||
"inactive": "Epäaktiivinen",
|
||||
"kind": "Sellainen",
|
||||
"last_modified": "Viimeksi muokattu",
|
||||
"last_run": "Viimeisin suoritus",
|
||||
"last_run_reset": "Ajoita seuraava",
|
||||
"mailbox": "Postilaatikko",
|
||||
"mailbox_defquota": "Tilin koko",
|
||||
"mailbox_quota": "Kiintiön koko",
|
||||
"mailboxes": "Sähköposti tilit",
|
||||
"max_aliases": "Max. mahdolliset aliakset",
|
||||
"max_mailboxes": "Max. mahdolliset sähkö postilaatikot",
|
||||
"max_quota": "Maks. Kiintiö sähköposti laatikkoa kohden",
|
||||
"mins_interval": "Aikaväli (min)",
|
||||
"msg_num": "Viestejä #",
|
||||
"multiple_bookings": "Useita varauksia",
|
||||
|
@ -608,6 +610,7 @@
|
|||
"recipient_map_old": "Alkuperäinen vastaanottaja",
|
||||
"recipient_map_old_info": "Vastaanottajan yhdistämis määritysten alkuperäisen kohteen on oltava kelvollinen sähköposti osoite tai verkkotunnus alueen nimi.",
|
||||
"recipient_maps": "Vastaanottajien yhdistämis määritykset",
|
||||
"relay_all": "Välitä kaikki vastaanottajat",
|
||||
"remove": "Poista",
|
||||
"resources": "Resursseja",
|
||||
"running": "Running",
|
||||
|
@ -682,6 +685,16 @@
|
|||
"text_plain_content": "Sisältö (teksti / tavallinen)",
|
||||
"toggle_all": "Valitse kaikki"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Poista kaikki",
|
||||
"flush_queue": "Tyhjennä jono",
|
||||
"queue_ays": "Vahvista, että haluat poistaa kaikki nykyisen jonon kohteet.",
|
||||
"queue_deliver_mail": "Toimittaa",
|
||||
"queue_hold_mail": "Pidossa",
|
||||
"queue_manager": "Jonon hallinta",
|
||||
"queue_unban": "jono unban",
|
||||
"queue_unhold_mail": "Poista pidosta"
|
||||
},
|
||||
"start": {
|
||||
"help": "Näytä/Piilota help paneeli",
|
||||
"imap_smtp_server_auth_info": "Käytä täydellistä sähkö posti osoitetta ja tavallista todennus mekanismia.<br>\r\nPalvelin puolen pakollinen salaus salaa kirjautumistietosi.",
|
||||
|
@ -831,7 +844,7 @@
|
|||
"remove": "Poistaa",
|
||||
"running": "Käynnissä",
|
||||
"save_changes": "Tallenna muutokset",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>",
|
||||
"shared_aliases": "Jaetut aliaksen osoitteet",
|
||||
"shared_aliases_desc": "Käyttäjäkohtaiset asetukset, kuten roska posti suodatin tai salaus käytäntö, eivät vaikuta jaettuihin alias-sähköposti tunnuksiin. Vastaavat roska posti suodattimet voi tehdä vain järjestelmänvalvoja verkkoaluelaajuisiksi käytännöiksi.",
|
||||
"show_sieve_filters": "Näytä aktiivisen käyttäjän sieve suodatin",
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
"relay_all": "Relayer tous les destinataires",
|
||||
"relay_all_info": "↪ Si vous choissisez <b>de ne pas</b> relayer tous les destinataires, vous devez ajouter une boîte (\"aveugle\") pour chaque destinataire simple qui doit être relayé.",
|
||||
"relay_domain": "Relayer ce domaine",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. sinon, une recherche MX sera effectuée.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. sinon, une recherche MX sera effectuée.",
|
||||
"relay_unknown_only": "Relayer uniquement les boîtes inexistantes. Les boîtes existantes seront livrées localement.",
|
||||
"relayhost_wrapped_tls_info": "Veuillez <b>ne pas</b> utiliser des ports TLS wrappés (généralement utilisés sur le port 465).<br>\r\nUtilisez n'importe quel port non encapsulé et lancez STARTTLS. Une politique TLS pour appliquer TLS peut être créée dans \"Cartes de politique TLS\".",
|
||||
"select": "Veuillez sélectionner...",
|
||||
|
@ -144,7 +144,6 @@
|
|||
"credentials_transport_warning": "<b>Attention</b> : L’ajout d’une nouvelle entrée de carte de transport mettra à jour les informations d’identification pour toutes les entrées avec une colonne nexthop.",
|
||||
"customer_id": "ID client",
|
||||
"customize": "Personnaliser",
|
||||
"delete_queue": "Tout supprimer",
|
||||
"destination": "Destination",
|
||||
"dkim_add_key": "Ajouter clé ARC/DKIM",
|
||||
"dkim_domains_selector": "Sélecteur",
|
||||
|
@ -181,7 +180,6 @@
|
|||
"f2b_retry_window": "Fenêtre de nouvel essai pour le nb max. de tentatives",
|
||||
"f2b_whitelist": "Réseaux/hôtes en liste blanche",
|
||||
"filter_table": "Table de filtrage",
|
||||
"flush_queue": "Vider la file d'attente",
|
||||
"forwarding_hosts": "Hôtes de réexpédition",
|
||||
"forwarding_hosts_add_hint": "Vous pouvez aussi bien indiquer des adresses IPv4/IPv6, des réseaux en notation CIDR, des noms d'hôtes (qui seront convertis en adresses IP), ou des noms de domaine (qui seront convertis en adresses IP par une requête SPF ou, en son absence, l'enregistrement MX).",
|
||||
"forwarding_hosts_hint": "Tous les messages entrants sont acceptés sans condition depuis les hôtes listés ici. Ces hôtes ne sont pas validés par DNSBLs ou sujets à un greylisting. Les pourriels reçus de ces hôtes ne sont jamais rejetés, mais occasionnellement, ils peuvent se retrouver dans le dossier Pourriel. L'usage le plus courant est pour les serveurs de courriels qui ont été configurés pour réexpédier leurs courriels entrants vers votre serveur Mailcow.",
|
||||
|
@ -240,13 +238,6 @@
|
|||
"quarantine_release_format_att": "En pièce jointe",
|
||||
"quarantine_release_format_raw": "Original non modifié",
|
||||
"quarantine_retention_size": "Rétentions par boîte:<br><small>0 indique <b>inactive</b>.</small>",
|
||||
"queue_ays": "Veuillez confirmer que vous voulez supprimer tous les éléments de la file d’attente actuelle.",
|
||||
"queue_deliver_mail": "Délivrer",
|
||||
"queue_hold_mail": "Garder",
|
||||
"queue_manager": "Gestion de la file d'attente",
|
||||
"queue_unban": "file d’attente unban",
|
||||
"queue_unhold_mail": "Ne pas garder",
|
||||
"queue_show_message": "Montrer message",
|
||||
"quota_notification_html": "Modèle de courriel de notification:<br><small>Laisser vide pour restaurer le modèle par défaut.</small>",
|
||||
"quota_notification_sender": "Notification par e-mail de l’expéditeur",
|
||||
"quota_notification_subject": "Objet du courriel de notification",
|
||||
|
@ -521,6 +512,7 @@
|
|||
"hostname": "Nom d'hôte",
|
||||
"inactive": "Inactif",
|
||||
"kind": "Type",
|
||||
"last_modified": "Dernière modification",
|
||||
"mailbox": "Edition de la boîte mail",
|
||||
"mailbox_quota_def": "Quota par défaut de la boîte",
|
||||
"max_aliases": "Nombre max. d'alias",
|
||||
|
@ -552,7 +544,7 @@
|
|||
"relay_all": "Relayer tous les destinataires",
|
||||
"relay_all_info": "↪ Si vous <b>ne choissisez pas</b> de relayer tous les destinataires, vous devrez ajouter une boîte (\"aveugle\") pour chaque destinataire qui devrait être relayé.",
|
||||
"relay_domain": "Relayer ce domaine",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. Si elle n’est pas configurée, une recherche MX sera effectuée.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Vous pouvez définir des cartes de transport vers une destination personnalisée pour ce domaine. Si elle n’est pas configurée, une recherche MX sera effectuée.",
|
||||
"relay_unknown_only": "Relais des boîtes non existantes seulement. Les boîtes existantes seront livrées localement..",
|
||||
"relayhost": "Transports dépendant de l’expéditeur",
|
||||
"remove": "Enlever",
|
||||
|
@ -560,7 +552,7 @@
|
|||
"save": "Enregistrer les modifications",
|
||||
"scope": "Portée",
|
||||
"sender_acl": "Permettre d’envoyer comme",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Le contrôle de l’expéditeur est désactivé</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Le contrôle de l’expéditeur est désactivé</span>",
|
||||
"sender_acl_info": "Si l’utilisateur de la boîte A est autorisé à envoyer en tant qu’utilisateur de la boîte B, l’adresse de l’expéditeur n’est pas automatiquement affichée comme sélectionnable du champ \"from\" dans SOGo.<br>\r\n L’utilisateur B de la boîte doit créer une délégation dans Sogo pour permettre à l’utilisateur A de la boîte de sélectionner son adresse comme expéditeur. Pour déléguer une boîte dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne s’applique pas aux adresses alias.",
|
||||
"sieve_desc": "Description courte",
|
||||
"sieve_type": "Type de filtre",
|
||||
|
@ -601,8 +593,8 @@
|
|||
"administration": "Configuration & détails",
|
||||
"apps": "Applications",
|
||||
"debug": "Information Système",
|
||||
"mailboxes": "Configuration du courrier",
|
||||
"mailcow_settings": "Configuration",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuration",
|
||||
"quarantine": "Quarantaine",
|
||||
"restart_netfilter": "Redémarrer Netfilter",
|
||||
"restart_sogo": "Redémarrer SOGo",
|
||||
|
@ -670,24 +662,30 @@
|
|||
"description": "Description",
|
||||
"disable_login": "Refuser l’ouverture de session (le courrier entrant est toujours accepté)",
|
||||
"disable_x": "Désactiver",
|
||||
"dkim_domains_selector": "Sélecteur",
|
||||
"dkim_key_length": "Longueur de la clé DKIM (bits)",
|
||||
"domain": "Domaine",
|
||||
"domain_admins": "Administrateurs de domaine",
|
||||
"domain_aliases": "Alias de domaine",
|
||||
"domain_quota": "Quota",
|
||||
"domain_quota_total": "Quota total du domaine",
|
||||
"domains": "Domaines",
|
||||
"edit": "Editer",
|
||||
"empty": "Pas de résulats",
|
||||
"enable_x": "Activer",
|
||||
"excludes": "Exclut",
|
||||
"filter_table": "Table de filtre",
|
||||
"filters": "Filtres",
|
||||
"filters": "Filtres",
|
||||
"fname": "Nom complet",
|
||||
"force_pw_update": "Forcer la mise à jour du mot de passe à la prochaine ouverture de session",
|
||||
"gal": "Carnet d'Adresses Global (GAL)",
|
||||
"hourly": "Horaire",
|
||||
"in_use": "Utilisé (%)",
|
||||
"inactive": "Inactif",
|
||||
"insert_preset": "Insérer un exemple de préréglage \"%s\"",
|
||||
"kind": "Type",
|
||||
"last_mail_login": "Dernière connexion mail",
|
||||
"last_modified": "Dernière modification",
|
||||
"last_run": "Dernière éxécution",
|
||||
"last_run_reset": "Calendrier suivant",
|
||||
"mailbox": "Mailbox",
|
||||
|
@ -696,6 +694,9 @@
|
|||
"mailboxes": "Boîtes mail",
|
||||
"mailbox_defaults": "Paramètres par défaut",
|
||||
"mailbox_defaults_info": "Définir les paramètres par défaut pour les nouvelles boîtes aux lettres.",
|
||||
"max_aliases": "Nombre maximal d'alias",
|
||||
"max_mailboxes": "Nombre maximal de boîtes",
|
||||
"max_quota": "Quota max. par boîte mail",
|
||||
"mins_interval": "Intervalle (min)",
|
||||
"msg_num": "Message #",
|
||||
"multiple_bookings": "Réservations multiples",
|
||||
|
@ -719,6 +720,7 @@
|
|||
"recipient_map_old": "Destinataire original",
|
||||
"recipient_map_old_info": "Une carte de destination originale doit être une adresse e-mail valide ou un nom de domaine.",
|
||||
"recipient_maps": "Cartes des bénéficiaires",
|
||||
"relay_all": "Relayer tous les destinataires",
|
||||
"remove": "Supprimer",
|
||||
"resources": "Ressources",
|
||||
"running": "En fonctionnement",
|
||||
|
@ -824,6 +826,17 @@
|
|||
"text_plain_content": "Contenu (text/plain)",
|
||||
"toggle_all": "Tout basculer"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Tout supprimer",
|
||||
"flush_queue": "Vider la file d'attente",
|
||||
"queue_ays": "Veuillez confirmer que vous voulez supprimer tous les éléments de la file d’attente actuelle.",
|
||||
"queue_deliver_mail": "Délivrer",
|
||||
"queue_hold_mail": "Garder",
|
||||
"queue_manager": "Gestion de la file d'attente",
|
||||
"queue_unban": "file d’attente unban",
|
||||
"queue_unhold_mail": "Ne pas garder",
|
||||
"queue_show_message": "Montrer message"
|
||||
},
|
||||
"start": {
|
||||
"help": "Afficher/masquer le panneau d’aide",
|
||||
"imap_smtp_server_auth_info": "Veuillez utiliser votre adresse e-mail complète et le mécanisme d’authentification PLAIN.<br>\r\nVos données de connexion seront cryptées par le cryptage obligatoire côté serveur.",
|
||||
|
@ -1027,7 +1040,7 @@
|
|||
"running": "En fonction",
|
||||
"save": "Sauvegarder les changements",
|
||||
"save_changes": "Sauvegarder les changements",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Le contrôle de l’expéditeur est désactivé</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Le contrôle de l’expéditeur est désactivé</span>",
|
||||
"shared_aliases": "Adresses alias partagées",
|
||||
"shared_aliases_desc": "Les alias partagés ne sont pas affectés par les paramètres spécifiques à l’utilisateur tels que le filtre anti-spam ou la politique de chiffrement. Les filtres anti-spam correspondants ne peuvent être effectués que par un administrateur en tant que politique de domaine.",
|
||||
"show_sieve_filters": "Afficher le filtre de tamis actif de l’utilisateur",
|
||||
|
|
|
@ -54,8 +54,8 @@
|
|||
"administration": "Beállítások és részletek",
|
||||
"apps": "Appok",
|
||||
"debug": "Rendszer információ",
|
||||
"mailboxes": "Email beállítások",
|
||||
"mailcow_settings": "Beállítások",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Beállítások",
|
||||
"quarantine": "Karantén",
|
||||
"restart_netfilter": "Netfilter újraindítása",
|
||||
"restart_sogo": "SOGo újraindítása",
|
||||
|
@ -118,6 +118,7 @@
|
|||
"filter_table": "Szűrő-táblázat",
|
||||
"filters": "Szűrők",
|
||||
"fname": "Teljes név",
|
||||
"force_pw_update": "Új jelszót kell beállítania a csoportos szolgáltatások eléréséhez.",
|
||||
"hourly": "Óránként",
|
||||
"in_use": "Foglalt (%)",
|
||||
"inactive": "Inaktív",
|
||||
|
@ -214,6 +215,18 @@
|
|||
"text_plain_content": "Tartalom (sima szöveg)",
|
||||
"toggle_all": "Összes átkapcsolása"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Delete all",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_command_success": "Queue command completed successfully",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold"
|
||||
},
|
||||
"start": {
|
||||
"help": "Súgó panel megjelenítése/elrejtése",
|
||||
"imap_smtp_server_auth_info": "Kérjük használja a teljes email címét és a PLAIN hitelesítési mechanizmust.<br>\r\nAdatai el lesznek kódolva szerver-oldali kötelező titkosítással.",
|
||||
|
@ -328,7 +341,7 @@
|
|||
"running": "Fut",
|
||||
"save": "Módosítások mentése",
|
||||
"save_changes": "Módosítások mentése",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Küldő ellenőrzése letiltva</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Küldő ellenőrzése letiltva</span>",
|
||||
"shared_aliases": "Megosztott alias címek",
|
||||
"show_sieve_filters": "Aktív felhasználói szűrők megjelenítése",
|
||||
"spam_aliases": "Ideiglenes email alias-ok",
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
"relay_all": "Trasmettere a tutti i destinatari",
|
||||
"relay_all_info": "↪ Se si sceglie di <b>non</b> inviare a tutti i destinatari, è necessario aggiungere una casella di posta (\"blind\") per ogni singolo destinatario a cui deve essere inoltrato.",
|
||||
"relay_domain": "Trasmetti questo dominio",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Puoi definire mappe di trasporto verso una destinazione a tua scelta per questo dominio. Se non viene impostata, si guarderà il record MX.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Puoi definire mappe di trasporto verso una destinazione a tua scelta per questo dominio. Se non viene impostata, si guarderà il record MX.",
|
||||
"relay_unknown_only": "Inoltra solo caselle di posta inesistenti. I messaggi per gli indirizzi esistenti verranno consegnati localmente.",
|
||||
"relayhost_wrapped_tls_info": "Please do <b>not</b> use TLS-wrapped ports (mostly used on port 465).<br>\r\nUse any non-wrapped port and issue STARTTLS. A TLS policy to enforce TLS can be created in \"TLS policy maps\".",
|
||||
"select": "Si prega di selezionare...",
|
||||
|
@ -150,7 +150,6 @@
|
|||
"credentials_transport_warning": "<b>Warning</b>: Adding a new transport map entry will update the credentials for all entries with a matching next hop column.",
|
||||
"customer_id": "ID cliente",
|
||||
"customize": "Personalizzare",
|
||||
"delete_queue": "Elimina tutto",
|
||||
"destination": "Destinazione",
|
||||
"dkim_add_key": "Aggiungi chiave ARC/DKIM",
|
||||
"dkim_domains_selector": "Selettore",
|
||||
|
@ -187,7 +186,6 @@
|
|||
"f2b_retry_window": "Retry window (s) for max. attempts",
|
||||
"f2b_whitelist": "Host/reti in whitelist",
|
||||
"filter_table": "Tabella filtro",
|
||||
"flush_queue": "Svuota la coda",
|
||||
"forwarding_hosts": "Inoltro degli host",
|
||||
"forwarding_hosts_add_hint": "È possibile specificare indirizzi IPv4 / IPv6, reti nella notazione CIDR, nomi host (che verranno risolti in indirizzi IP) o nomi di dominio (che verranno risolti agli indirizzi IP richiamando i record SPF o, in assenza, i record MX) .",
|
||||
"forwarding_hosts_hint": "I messaggi in entrata sono accettati in maniera incondizionata da tutti gli host qui elencati. Questi host sono quindi non controllati tramite DNSBL o sottoposti a greylisting. Lo spam ricevuto da questi host non viene mai rifiutato, ma potrebbe essere archiviato nella cartella Posta indesiderata. L'utilizzo più comune è quello di specificare i server di posta elettronica su cui è stata impostata una regola che inoltra le email in arrivo al server mailcow.",
|
||||
|
@ -255,13 +253,6 @@
|
|||
"quarantine_release_format_att": "Come allegato",
|
||||
"quarantine_release_format_raw": "Originale non modificato",
|
||||
"quarantine_retention_size": "Retention per casella di posta:<br><small>0 indica <b>inattivo</b>.</small>",
|
||||
"queue_ays": "Conferma di voler eliminare tutti gli elementi dalla coda corrente.",
|
||||
"queue_deliver_mail": "Consegna",
|
||||
"queue_hold_mail": "Trattieni",
|
||||
"queue_manager": "Gestore code",
|
||||
"queue_show_message": "Visualizza messaggio",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Rilascia",
|
||||
"quota_notification_html": "Modello e-mail di notifica:<br><small>Lascia vuoto per utilizzare il modello predefinito.</small>",
|
||||
"quota_notification_sender": "Mittente e-mail di notifica",
|
||||
"quota_notification_subject": "Oggetto e-mail di notifica",
|
||||
|
@ -518,6 +509,7 @@
|
|||
"bcc_dest_format": "BCC destination must be a single valid email address.",
|
||||
"client_id": "Client ID",
|
||||
"client_secret": "Client secret",
|
||||
"created_on": "Creato il",
|
||||
"comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",
|
||||
"delete1": "Elimina dalla sorgente al termine",
|
||||
"delete2": "Delete messages on destination that are not on source",
|
||||
|
@ -545,6 +537,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Inattivo",
|
||||
"kind": "Genere",
|
||||
"last_mail_login": "Last mail login",
|
||||
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
|
||||
"mailbox": "Modifica casella di posta",
|
||||
"mailbox_quota_def": "Default mailbox quota",
|
||||
|
@ -580,7 +573,7 @@
|
|||
"relay_all": "Relay tutti i destinatari",
|
||||
"relay_all_info": "↪ Se si sceglie di <b>non</b> inviare a tutti i destinatari, è necessario aggiungere una casella di posta (\"blind\") per ogni singolo destinatario a cui deve essere inoltrato.",
|
||||
"relay_domain": "Relay dominio",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_unknown_only": "Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.",
|
||||
"relayhost": "Sender-dependent transports",
|
||||
"remove": "Rimuovi",
|
||||
|
@ -588,7 +581,7 @@
|
|||
"save": "Salva modifiche",
|
||||
"scope": "Scope",
|
||||
"sender_acl": "Consenti di inviare come",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.",
|
||||
"sieve_desc": "Short description",
|
||||
"sieve_type": "Filter type",
|
||||
|
@ -650,8 +643,8 @@
|
|||
"administration": "Amministrazione",
|
||||
"apps": "App",
|
||||
"debug": "Informazioni di sistema",
|
||||
"mailboxes": "Caselle",
|
||||
"mailcow_settings": "Configurazione",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configurazione",
|
||||
"quarantine": "Quarantena",
|
||||
"restart_netfilter": "Riavvia netfilter",
|
||||
"restart_sogo": "Riavvia SOGo",
|
||||
|
@ -715,15 +708,19 @@
|
|||
"booking_custom_short": "Hard limit",
|
||||
"booking_ltnull": "Unlimited, but show as busy when booked",
|
||||
"booking_lt0_short": "Soft limit",
|
||||
"created_on": "Creato il",
|
||||
"daily": "Giornaliero",
|
||||
"deactivate": "Disattiva",
|
||||
"description": "Descrizione",
|
||||
"disable_login": "Disabilita l'accesso (la posta in arrivo viene correttamente recapitata)",
|
||||
"disable_x": "Disabilita",
|
||||
"dkim_domains_selector": "Selettore",
|
||||
"dkim_key_length": "Lunghezza chiave DKIM (bits)",
|
||||
"domain": "Dominio",
|
||||
"domain_admins": "Amministratori di dominio",
|
||||
"domain_aliases": "Alias di domini",
|
||||
"domain_quota": "Spazio",
|
||||
"domain_quota_total": "Spazio totale dominio",
|
||||
"domains": "Domini",
|
||||
"edit": "Modifica",
|
||||
"empty": "Nessun risultato",
|
||||
|
@ -738,6 +735,7 @@
|
|||
"insert_preset": "Insert example preset \"%s\"",
|
||||
"kind": "Tipo",
|
||||
"last_mail_login": "Last mail login",
|
||||
"last_modified": "Ultima modifica",
|
||||
"last_pw_change": "Ultima modifica della password",
|
||||
"last_run": "Ultima esecuzione",
|
||||
"last_run_reset": "Schedule next",
|
||||
|
@ -747,6 +745,9 @@
|
|||
"mailbox_defquota": "Dimensione predefinita della casella di posta",
|
||||
"mailbox_quota": "Massima dimensione della casella",
|
||||
"mailboxes": "Caselle",
|
||||
"max_aliases": "Numero massimo alias",
|
||||
"max_mailboxes": "Numero massimo caselle di posta",
|
||||
"max_quota": "Massimo spazio per casella",
|
||||
"mins_interval": "Intervallo (min)",
|
||||
"msg_num": "Messaggio #",
|
||||
"multiple_bookings": "Prenotazioni multiple",
|
||||
|
@ -770,6 +771,7 @@
|
|||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "Trasmettere a tutti i destinatari",
|
||||
"remove": "Rimuovi",
|
||||
"resources": "Risorse",
|
||||
"running": "In esecuzione",
|
||||
|
@ -891,6 +893,17 @@
|
|||
"toggle_all": "Inverti tutti",
|
||||
"type": "Tipologia"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Elimina tutto",
|
||||
"flush_queue": "Svuota la coda",
|
||||
"queue_ays": "Conferma di voler eliminare tutti gli elementi dalla coda corrente.",
|
||||
"queue_deliver_mail": "Consegna",
|
||||
"queue_hold_mail": "Trattieni",
|
||||
"queue_manager": "Gestore code",
|
||||
"queue_show_message": "Visualizza messaggio",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Rilascia"
|
||||
},
|
||||
"start": {
|
||||
"help": "Mostra/Nascondi pannello di aiuto",
|
||||
"imap_smtp_server_auth_info": "Please use your full email address and the PLAIN authentication mechanism.<br />\r\nYour login data will be encrypted by the server-side mandatory encryption.",
|
||||
|
@ -1099,7 +1112,7 @@
|
|||
"running": "In esecuzione",
|
||||
"save": "Salva modifiche",
|
||||
"save_changes": "Salva modifiche",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"shared_aliases": "Indirizzi alias condivisi",
|
||||
"shared_aliases_desc": "Shared aliases are not affected by user specific settings such as the spam filter or encryption policy. Corresponding spam filters can only be made by an administrator as a domain-wide policy.",
|
||||
"show_sieve_filters": "Show active user sieve filter",
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
"relay_all": "모든 수신자에게 릴레이",
|
||||
"relay_all_info": "↪ 모든 수신자에게 릴레이를 하지 않으면, 릴레이 받아야 하는 모든 수신자에게 블라인드 메일함을 만들어야 합니다.",
|
||||
"relay_domain": "Relay this domain",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_unknown_only": "Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.",
|
||||
"relayhost_wrapped_tls_info": "Please do <b>not</b> use TLS-wrapped ports (mostly used on port 465).<br>\r\nUse any non-wrapped port and issue STARTTLS. A TLS policy to enforce TLS can be created in \"TLS policy maps\".",
|
||||
"select": "선택하세요...",
|
||||
|
@ -141,7 +141,6 @@
|
|||
"credentials_transport_warning": "<b>Warning</b>: Adding a new transport map entry will update the credentials for all entries with a matching nexthop column.",
|
||||
"customer_id": "고객 ID",
|
||||
"customize": "사용자 정의",
|
||||
"delete_queue": "전부 삭제",
|
||||
"destination": "목적지",
|
||||
"dkim_add_key": "ARC/DKIM key 추가",
|
||||
"dkim_domains_selector": "선택기",
|
||||
|
@ -174,7 +173,6 @@
|
|||
"f2b_retry_window": "최대 시도 횟수",
|
||||
"f2b_whitelist": "화이트리스트에 저장된 네트워크/호스트",
|
||||
"filter_table": "필터 테이블",
|
||||
"flush_queue": "큐 비우기",
|
||||
"forwarding_hosts": "포워딩 호스트",
|
||||
"forwarding_hosts_add_hint": "IPv4/IPv6 주소, CIDR 방식의 네트워크, 호스트 이름 (IP 주소로 확인된 호스트 이름), 또는 도메인 이름 (SPF 레코드를 쿼리하거나 MX레코드가 없는 경우 IP 주소로 확인된 도메인 이름)을 지정할 수 있습니다.",
|
||||
"forwarding_hosts_hint": "수신된 메시지는 여기에 나열된 모든 호스트에 무조건 허용됩니다. 받은 다음에 이 호스트들은 DNSML에 대해 검사되지 않거나 그레이리스트에 포함되지 않습니다. 이들에게서 받은 스팸은 절대 거부되지 않지만, 선택적으로 정크 폴더에 저장될 수 있습니다. 일반적으로 수신받은 메일을 mailcow 서버로 전달하는 메일 서버를 지정하는 용도로 사용됩니다.",
|
||||
|
@ -230,13 +228,6 @@
|
|||
"quarantine_release_format_att": "첨부 파일",
|
||||
"quarantine_release_format_raw": "수정되지 않은 원본",
|
||||
"quarantine_retention_size": "메일함당 보관:<br><small>0은 <b>비활성</b>을 나타냅니다.</small>",
|
||||
"queue_ays": "현재 대기열에서 모든 항목을 삭제할지 확인하십시오.",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "대기열 관리자",
|
||||
"queue_unban": "대기열 밴 해제",
|
||||
"queue_unhold_mail": "Unhold",
|
||||
"queue_show_message": "메시지 표시",
|
||||
"quota_notification_html": "알림 이메일 탬플릿:<br><small>없으면 기본 템플릿이 복구됩니다.</small>",
|
||||
"quota_notification_sender": "이메일 발신자 알림",
|
||||
"quota_notification_subject": "이메일 주제 알림",
|
||||
|
@ -496,6 +487,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Inactive",
|
||||
"kind": "Kind",
|
||||
"last_modified": "Last modified",
|
||||
"mailbox": "Edit mailbox",
|
||||
"mailbox_quota_def": "Default mailbox quota",
|
||||
"max_aliases": "Max. aliases",
|
||||
|
@ -526,7 +518,7 @@
|
|||
"relay_all": "Relay all recipients",
|
||||
"relay_all_info": "↪ If you choose <b>not</b> to relay all recipients, you will need to add a (\"blind\") mailbox for every single recipient that should be relayed.",
|
||||
"relay_domain": "Relay this domain",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> You can define transport maps for a custom destination for this domain. If not set, a MX lookup will be made.",
|
||||
"relay_unknown_only": "Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.",
|
||||
"relayhost": "Sender-dependent transports",
|
||||
"remove": "Remove",
|
||||
|
@ -534,7 +526,7 @@
|
|||
"save": "Save changes",
|
||||
"scope": "Scope",
|
||||
"sender_acl": "Allow to send as",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.",
|
||||
"sieve_desc": "Short description",
|
||||
"sieve_type": "Filter type",
|
||||
|
@ -572,8 +564,8 @@
|
|||
"administration": "Configuration & Details",
|
||||
"apps": "Apps",
|
||||
"debug": "System Information",
|
||||
"mailboxes": "Mail Setup",
|
||||
"mailcow_settings": "Configuration",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuration",
|
||||
"quarantine": "Quarantine",
|
||||
"restart_netfilter": "Restart netfilter",
|
||||
"restart_sogo": "Restart SOGo",
|
||||
|
@ -636,10 +628,13 @@
|
|||
"description": "설명",
|
||||
"disable_login": "로그인 비활성화 (오는 메일은 계속 받습니다.)",
|
||||
"disable_x": "비활성화",
|
||||
"dkim_domains_selector": "선택기",
|
||||
"dkim_key_length": "DKIM key 길이 (bits)",
|
||||
"domain": "도메인",
|
||||
"domain_admins": "도메인 관리자",
|
||||
"domain_aliases": "도메인 별칭",
|
||||
"domain_quota": "한도",
|
||||
"domain_quota_total": "도메인에 할당할 디스크 크기",
|
||||
"domains": "도메인",
|
||||
"edit": "수정",
|
||||
"empty": "결과 없음",
|
||||
|
@ -648,18 +643,24 @@
|
|||
"filter_table": "Filter table",
|
||||
"filters": "Filters",
|
||||
"fname": "Full name",
|
||||
"force_pw_update": "그룹웨어 관련 서비스에 접근하기 위해서는 새 비밀번호를 <b>꼭</b> 설정해야 합니다.",
|
||||
"gal": "글로벌 주소 리스트",
|
||||
"hourly": "Hourly",
|
||||
"in_use": "In use (%)",
|
||||
"inactive": "Inactive",
|
||||
"insert_preset": "Insert example preset \"%s\"",
|
||||
"kind": "Kind",
|
||||
"last_mail_login": "Last mail login",
|
||||
"last_modified": "Last modified",
|
||||
"last_run": "Last run",
|
||||
"last_run_reset": "Schedule next",
|
||||
"mailbox": "Mailbox",
|
||||
"mailbox_defquota": "Default mailbox size",
|
||||
"mailbox_quota": "Max. size of a mailbox",
|
||||
"mailboxes": "Mailboxes",
|
||||
"max_aliases": "최대 별칭 주소",
|
||||
"max_mailboxes": "최대 메일함 수",
|
||||
"max_quota": "Max. quota per mailbox",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Message #",
|
||||
"multiple_bookings": "Multiple bookings",
|
||||
|
@ -679,6 +680,7 @@
|
|||
"recipient_map_old": "Original recipient",
|
||||
"recipient_map_old_info": "A recipient maps original destination must be valid email addresses or a domain name.",
|
||||
"recipient_maps": "Recipient maps",
|
||||
"relay_all": "모든 수신자에게 릴레이",
|
||||
"remove": "Remove",
|
||||
"resources": "Resources",
|
||||
"running": "Running",
|
||||
|
@ -774,6 +776,17 @@
|
|||
"text_plain_content": "내용 (text/plain)",
|
||||
"toggle_all": "선택 반전"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "전부 삭제",
|
||||
"flush_queue": "큐 비우기",
|
||||
"queue_ays": "현재 대기열에서 모든 항목을 삭제할지 확인하십시오.",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "대기열 관리자",
|
||||
"queue_unban": "대기열 밴 해제",
|
||||
"queue_unhold_mail": "Unhold",
|
||||
"queue_show_message": "메시지 표시"
|
||||
},
|
||||
"start": {
|
||||
"help": "Show/Hide help panel",
|
||||
"imap_smtp_server_auth_info": "Please use your full email address and the PLAIN authentication mechanism.<br>\r\nYour login data will be encrypted by the server-side mandatory encryption.",
|
||||
|
@ -955,7 +968,7 @@
|
|||
"running": "실행중",
|
||||
"save": "변경사항 저장",
|
||||
"save_changes": "변경사항 저장",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sender check is disabled</span>",
|
||||
"shared_aliases": "공동 사용 메일 주소 별칭",
|
||||
"shared_aliases_desc": "공동 사용 메일 별칭은 스팸 필터, 암호화 등 사용자의 설정의 영향을 받지 않습니다. 해당 주소의 스팸 필터는 관리자가 도메인 정책 형식으로 만들어야만 적용됩니다.",
|
||||
"show_sieve_filters": "활성화된 사용자 필터 표시",
|
||||
|
|
|
@ -277,8 +277,8 @@
|
|||
"header": {
|
||||
"administration": "Administrēšana",
|
||||
"debug": "Atkļūdošana",
|
||||
"mailboxes": "Pastkastes",
|
||||
"mailcow_settings": "Configurācija",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configurācija",
|
||||
"quarantine": "Karantīna",
|
||||
"restart_sogo": "Restartēt SOGo",
|
||||
"user_settings": "Lietotāja uzstādījumi"
|
||||
|
@ -323,10 +323,12 @@
|
|||
"bcc_type": "BCC tips",
|
||||
"deactivate": "Deaktivizēt",
|
||||
"description": "Apraksts",
|
||||
"dkim_key_length": "DKIM atslēgas garums (bits)",
|
||||
"domain": "Domēns",
|
||||
"domain_admins": "Domēna administratori",
|
||||
"domain_aliases": "Domēna aliases",
|
||||
"domain_quota": "Kvota",
|
||||
"domain_quota_total": "Kopējā domēna kvota",
|
||||
"domains": "Domēns",
|
||||
"edit": "Labot",
|
||||
"empty": "Nav rezultātu",
|
||||
|
@ -334,6 +336,7 @@
|
|||
"filter_table": "Filtra tabula",
|
||||
"filters": "Filtri",
|
||||
"fname": "Pilns vārds",
|
||||
"force_pw_update": "Piespiedu paroles atjaunošana pie nākošās pieslēgšanās",
|
||||
"in_use": "Lietošanā (%)",
|
||||
"inactive": "Neaktīvs",
|
||||
"kind": "Veids",
|
||||
|
@ -341,6 +344,9 @@
|
|||
"last_run_reset": "Nākamais grafiks",
|
||||
"mailbox_quota": "Maks. pastkastes izmērs",
|
||||
"mailboxes": "Pastkaste",
|
||||
"max_aliases": "Maks. iespejamās aliases",
|
||||
"max_mailboxes": "Maks. iespējamās pastkastes",
|
||||
"max_quota": "Maks. kvota uz pastkasti",
|
||||
"mins_interval": "Intervāls (min)",
|
||||
"msg_num": "Vēstule #",
|
||||
"multiple_bookings": "Vairāki rezervējumi",
|
||||
|
@ -352,6 +358,7 @@
|
|||
"recipient_map_new": "Jauns saņēmējs",
|
||||
"recipient_map_old": "Oriģinālais saņēmējs",
|
||||
"recipient_maps": "Saņēmēja kartes",
|
||||
"relay_all": "Pārsūtīt visus saņēmējus",
|
||||
"remove": "Noņemt",
|
||||
"resources": "Resursi",
|
||||
"running": "Darbojas",
|
||||
|
@ -392,6 +399,18 @@
|
|||
"text_plain_content": "Saturs (teksts/vienkāršs)",
|
||||
"toggle_all": "Pārslēgt visu"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Delete all",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_command_success": "Queue command completed successfully",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold"
|
||||
},
|
||||
"start": {
|
||||
"help": "Rādīt/Paslēp palīdzības paneli",
|
||||
"imap_smtp_server_auth_info": "Lūdzu, izmantojiet pilnu e-pasta adresi un PLAIN autentifikācijas mehānismu.<br>\r\nJūsu pieteikšanās dati tiks šifrēti, izmantojot servera puses obligātu šifrēšanu",
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
"relay_all": "Forward alle ontvangers",
|
||||
"relay_all_info": "↪ Wanneer er wordt gekozen om <b>niet</b> alle ontvangers te forwarden, dient er per ontvanger een lege mailbox aangemaakt te worden.",
|
||||
"relay_domain": "Forward dit domein",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Je kunt transport-maps aanmaken om een aangepaste bestemming in te stellen voor dit domein. Zo niet, zal er een MX-lookup plaatsvinden.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Je kunt transport-maps aanmaken om een aangepaste bestemming in te stellen voor dit domein. Zo niet, zal er een MX-lookup plaatsvinden.",
|
||||
"relay_unknown_only": "Forward uitsluitend niet-bestaande mailboxen. Bestaande mailboxen zullen lokaal afgeleverd worden.",
|
||||
"relayhost_wrapped_tls_info": "Gebruik <b>geen</b> in TLS verpakte poorten (meestal poort 465).<br>Gebruik een reguliere poort en initieer STARTTLS. Beleid om verleuteling te forceren kan worden ingesteld bij \"Globaal versleutelingsbeleid\".",
|
||||
"select": "Selecteer...",
|
||||
|
@ -143,7 +143,6 @@
|
|||
"credentials_transport_warning": "<b>Waarschuwing</b>: Bij het toevoegen van een nieuwe transport-map zullen de aanmeldingsgegevens voor alle items met een overeenkomende nexthop-kolom worden overgeschreven.",
|
||||
"customer_id": "Klantnummer",
|
||||
"customize": "Personalisatie",
|
||||
"delete_queue": "Verwijder alles",
|
||||
"destination": "Bestemming",
|
||||
"dkim_add_key": "Voeg key toe",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -180,7 +179,6 @@
|
|||
"f2b_retry_window": "Tijdsbestek voor maximale pogingen (s)",
|
||||
"f2b_whitelist": "Netwerken/hosts op de whitelist",
|
||||
"filter_table": "Filtertabel",
|
||||
"flush_queue": "Leeg queue",
|
||||
"forwarding_hosts": "Forwarding hosts",
|
||||
"forwarding_hosts_add_hint": "Het is mogelijk om IPv4- of IPv6-adressen, netwerken in CIDR-notatie, hostnames (worden omgezet naar IP-adressen) of domeinnamen (worden tevens omgezet naar IP-adressen of, bij gebrek daaraan, MX-records) op te geven.",
|
||||
"forwarding_hosts_hint": "Inkomende berichten worden onvoorwaardelijk geaccepteerd vanaf iedere host hieronder vermeld. Deze hosts worden hierdoor niet gecontroleerd op DNSBLs, en zullen de greylisting omzeilen. Spam wordt daarentegen zoals gebruikelijk in de spamfolder geplaatst. Dit wordt vaak gebruikt om mailservers te specificeren die forwarden naar deze Mailcow-server.",
|
||||
|
@ -238,13 +236,6 @@
|
|||
"quarantine_release_format_att": "Bijlage",
|
||||
"quarantine_release_format_raw": "Origineel",
|
||||
"quarantine_retention_size": "Maximale retenties per mailbox:<br><small>Gebruik 0 om deze functionaliteit <b>uit te schakelen</b>.</small>",
|
||||
"queue_ays": "Bevestig het verwijderen van alle items uit de queue.",
|
||||
"queue_deliver_mail": "Lever af",
|
||||
"queue_hold_mail": "Houd vast",
|
||||
"queue_manager": "Queue manager",
|
||||
"queue_unban": "hef verbanning op",
|
||||
"queue_unhold_mail": "Geef vrij",
|
||||
"queue_show_message": "Toon item",
|
||||
"quota_notification_html": "Meldingssjabloon:<br><small>Laat leeg om de standaardsjabloon te herstellen.</small>",
|
||||
"quota_notification_sender": "Afzender van meldingen",
|
||||
"quota_notification_subject": "Onderwerp van meldingen",
|
||||
|
@ -513,6 +504,7 @@
|
|||
"hostname": "Hostname",
|
||||
"inactive": "Inactief",
|
||||
"kind": "Soort",
|
||||
"last_modified": "Voor het laatst bijgewerkt op",
|
||||
"mailbox": "Wijzig mailbox",
|
||||
"mailbox_quota_def": "Standaard mailboxquota",
|
||||
"max_aliases": "Maximaal aantal aliassen",
|
||||
|
@ -545,7 +537,7 @@
|
|||
"relay_all": "Forward alle ontvangers",
|
||||
"relay_all_info": "↪ Wanneer er wordt gekozen om <b>niet</b> alle ontvangers te forwarden, dient er per ontvanger een lege mailbox aangemaakt te worden.",
|
||||
"relay_domain": "Forward dit domein",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Je kunt transport-maps aanmaken om een aangepaste bestemming in te stellen voor dit domein. Zo niet, zal er een MX-lookup plaatsvinden.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Je kunt transport-maps aanmaken om een aangepaste bestemming in te stellen voor dit domein. Zo niet, zal er een MX-lookup plaatsvinden.",
|
||||
"relay_unknown_only": "Forward uitsluitend niet-bestaande mailboxen. Bestaande mailboxen zullen lokaal afgeleverd worden.",
|
||||
"relayhost": "Afzendergebonden transport-maps",
|
||||
"remove": "Verwijder",
|
||||
|
@ -553,7 +545,7 @@
|
|||
"save": "Wijzigingen opslaan",
|
||||
"scope": "Scope",
|
||||
"sender_acl": "Sta toe om te verzenden als",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Verzendcontrole is uitgeschakeld</span>",
|
||||
"sender_acl_info": "Wanneer mailboxgebruiker A toegestaan is te verzenden namens mailboxgebruiker B, zal het verzendadres niet automatisch worden weergegeven in het \"van\"-veld in SOGo. Mailboxgebruiker A dient hiervoor een aparte vermelding te maken in SOGo. Om een mailbox te delegeren in SOGo kan het menu (drie punten) aan de rechterkant van de naam van het mailbox linksboven worden gebruikt in de mailweergave. Dit is niet van toepassing op aliasadressen.",
|
||||
"sieve_desc": "Korte beschrijving",
|
||||
"sieve_type": "Filtertype",
|
||||
|
@ -592,8 +584,8 @@
|
|||
"administration": "Configuratie & details",
|
||||
"apps": "Apps",
|
||||
"debug": "Systeeminformatie",
|
||||
"mailboxes": "Mailconfiguratie",
|
||||
"mailcow_settings": "Beheer",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Beheer",
|
||||
"quarantine": "Quarantaine",
|
||||
"restart_netfilter": "Herstart netfilter",
|
||||
"restart_sogo": "Herstart SOGo",
|
||||
|
@ -661,10 +653,13 @@
|
|||
"description": "Beschrijving",
|
||||
"disable_login": "Weiger aanmelden (inkomende mail blijft binnenkomen)",
|
||||
"disable_x": "Schakel uit",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "Grootte van key (bits)",
|
||||
"domain": "Domein",
|
||||
"domain_admins": "Domeinadministrators",
|
||||
"domain_aliases": "Domeinaliassen",
|
||||
"domain_quota": "Quota",
|
||||
"domain_quota_m": "Totale domeinquota",
|
||||
"domains": "Domeinen",
|
||||
"edit": "Wijzig",
|
||||
"empty": "Geen resultaten",
|
||||
|
@ -673,12 +668,15 @@
|
|||
"filter_table": "Filtertabel",
|
||||
"filters": "Filters",
|
||||
"fname": "Volledige naam",
|
||||
"force_pw_update": "Vereis nieuw wachtwoord bij eerstvolgende login",
|
||||
"gal": "Globale adreslijst",
|
||||
"hourly": "Ieder uur",
|
||||
"in_use": "In gebruik (%)",
|
||||
"inactive": "Inactief",
|
||||
"insert_preset": "Voeg voorbeelden in \"%s\"",
|
||||
"kind": "Soort",
|
||||
"last_mail_login": "Laatste mail login",
|
||||
"last_modified": "Voor het laatst bijgewerkt op",
|
||||
"last_run": "Laatst uitgevoerd",
|
||||
"last_run_reset": "Plan volgende",
|
||||
"mailbox": "Mailbox",
|
||||
|
@ -687,6 +685,9 @@
|
|||
"mailboxes": "Mailboxen",
|
||||
"mailbox_defaults": "Standaardinstellingen",
|
||||
"mailbox_defaults_info": "Stel standaardinstellingen in voor nieuwe mailboxen.",
|
||||
"max_aliases": "Maximaal aantal aliassen",
|
||||
"max_mailboxes": "Maximaal aantal mailboxen",
|
||||
"max_quota": "Mailboxquota",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Bericht #",
|
||||
"multiple_bookings": "Meerdere boekingen",
|
||||
|
@ -709,6 +710,7 @@
|
|||
"recipient_map_old": "Oorspronkelijke ontvanger",
|
||||
"recipient_map_old_info": "De oorspronkelijke bestemming van een ontvanger-map dient een geldig mailadres of domeinnaam te zijn.",
|
||||
"recipient_maps": "Ontvanger-maps",
|
||||
"relay_all": "Forward alle ontvangers",
|
||||
"remove": "Verwijder",
|
||||
"resources": "Resources",
|
||||
"running": "Wordt uitgevoerd",
|
||||
|
@ -813,6 +815,17 @@
|
|||
"text_plain_content": "Inhoud (tekst)",
|
||||
"toggle_all": "Selecteer alles"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Verwijder alles",
|
||||
"flush_queue": "Leeg queue",
|
||||
"queue_ays": "Bevestig het verwijderen van alle items uit de queue.",
|
||||
"queue_deliver_mail": "Lever af",
|
||||
"queue_hold_mail": "Houd vast",
|
||||
"queue_manager": "Queue manager",
|
||||
"queue_unban": "hef verbanning op",
|
||||
"queue_unhold_mail": "Geef vrij",
|
||||
"queue_show_message": "Toon item"
|
||||
},
|
||||
"start": {
|
||||
"help": "Toon/verberg hulppaneel",
|
||||
"imap_smtp_server_auth_info": "Gebruik je volledige mailadres en het bijbehorende (onversleutelde) verificatiemechanisme.<br>De aanmeldgegevens worden versleuteld verzonden.",
|
||||
|
@ -1017,7 +1030,7 @@
|
|||
"running": "Wordt uitgevoerd",
|
||||
"save": "Sla wijzigingen op",
|
||||
"save_changes": "Wijzigingen opslaan",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Verzendcontrole is uitgeschakeld</span>",
|
||||
"shared_aliases": "Gedeelde aliasadressen",
|
||||
"shared_aliases_desc": "Een gedeeld aliasadres wordt niet beïnvloed door gebruikersspecifieke instellingen. Een aangepast spamfilter kan eventueel worden ingesteld door een administrator.",
|
||||
"show_sieve_filters": "Toon actieve filters",
|
||||
|
|
|
@ -201,8 +201,8 @@
|
|||
},
|
||||
"header": {
|
||||
"administration": "Administrowanie",
|
||||
"mailboxes": "Skrzynki",
|
||||
"mailcow_settings": "Konfiguracja",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Konfiguracja",
|
||||
"quarantine": "Kwarantanna",
|
||||
"restart_sogo": "Uruchom ponownie SOGo",
|
||||
"user_settings": "Ustawienia użytkownika"
|
||||
|
@ -233,10 +233,12 @@
|
|||
"daily": "Co dzień",
|
||||
"deactivate": "Wyłącz",
|
||||
"description": "Opis",
|
||||
"dkim_key_length": "Długość klucza DKIM (bity)",
|
||||
"domain": "Domena",
|
||||
"domain_admins": "Administratorzy domeny",
|
||||
"domain_aliases": "Aliasy domeny",
|
||||
"domain_quota": "Limit wielkości",
|
||||
"domain_quota_total": "Łączny limit domeny",
|
||||
"domains": "Domeny",
|
||||
"edit": "Edytuj",
|
||||
"empty": "Brak wyników",
|
||||
|
@ -250,6 +252,9 @@
|
|||
"last_run": "Ostatnie uruchomienie",
|
||||
"mailbox_quota": "Maks. wielkość skrzynki",
|
||||
"mailboxes": "Skrzynki",
|
||||
"max_aliases": "Maks. liczba aliasów",
|
||||
"max_mailboxes": "Maks. liczba skrzynek",
|
||||
"max_quota": "Maks. wielkość skrzynki",
|
||||
"mins_interval": "Zakres (min)",
|
||||
"msg_num": "Wiadomość #",
|
||||
"multiple_bookings": "Wielokrotne rejestracje",
|
||||
|
@ -258,6 +263,7 @@
|
|||
"no_record_single": "Brak rekordu",
|
||||
"quarantine_notification": "Powiadomienia o kwarantannie",
|
||||
"quick_actions": "Szybkie działania",
|
||||
"relay_all": "Przekaż wszystkim odbiorcom",
|
||||
"remove": "Usuń",
|
||||
"resources": "Zasoby",
|
||||
"spam_aliases": "Alias tymczasowy",
|
||||
|
@ -278,6 +284,18 @@
|
|||
"remove": "Usuń",
|
||||
"toggle_all": "Zaznacz wszystkie"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Delete all",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_command_success": "Queue command completed successfully",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold"
|
||||
},
|
||||
"start": {
|
||||
"help": "Pokaż/Ukryj panel pomocy",
|
||||
"imap_smtp_server_auth_info": "Proszę korzystać z pełnego adresu email i mechanizmu uwierzytelniania PLAIN.<br>\r\nTwoje dane logowania zostaną zaszyfrowane przez obowiązkowe szyfrowanie po stronie serwera.",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"backup_mx_options": "Opções Backup MX:",
|
||||
"description": "Descrição:",
|
||||
"domain": "Domínio",
|
||||
"domain_quota_m": "Total de espaço por domínio(MiB):",
|
||||
"domain_quota_m": "Total de espaço por domínio (MiB):",
|
||||
"full_name": "Nome:",
|
||||
"mailbox_quota_m": "Máximo espaço por conta (MiB):",
|
||||
"mailbox_username": "Usuário (primeira parte do endereço de email):",
|
||||
|
@ -136,8 +136,8 @@
|
|||
},
|
||||
"header": {
|
||||
"administration": "Administração",
|
||||
"mailboxes": "Contas",
|
||||
"mailcow_settings": "Configuração",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configuração",
|
||||
"user_settings": "Configurações do usuário"
|
||||
},
|
||||
"info": {
|
||||
|
@ -161,10 +161,12 @@
|
|||
"aliases": "Apelidos",
|
||||
"backup_mx": "Backup MX",
|
||||
"description": "Descrição:",
|
||||
"dkim_key_length": "Tamanho do registro DKIM (bits)",
|
||||
"domain": "Domínio",
|
||||
"domain_admins": "Administradores de domínio",
|
||||
"domain_aliases": "Encaminhamento de Domínio",
|
||||
"domain_quota": "Espaço",
|
||||
"domain_quota_total": "Total de espaço por domínio",
|
||||
"domains": "Domínios",
|
||||
"edit": "Alterar",
|
||||
"filter_table": "Procurar",
|
||||
|
@ -172,9 +174,13 @@
|
|||
"in_use": "Em uso (%)",
|
||||
"mailbox_quota": "Espaço máximo da Conta",
|
||||
"mailboxes": "Contas",
|
||||
"max_aliases": "Máximo de apelidos",
|
||||
"max_mailboxes": "Máximo de contas",
|
||||
"max_quota": "Máximo espaço por conta",
|
||||
"msg_num": "Mensagens",
|
||||
"no_record": "Nenhum registro",
|
||||
"no_record_single": "Nenhum registro",
|
||||
"relay_all": "Relay para todas as contas",
|
||||
"remove": "Remover",
|
||||
"target_address": "Encaminhar para",
|
||||
"target_domain": "Domínio Destino",
|
||||
|
@ -186,6 +192,18 @@
|
|||
"action": "Ação",
|
||||
"remove": "Remover"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Delete all",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_ays": "Please confirm you want to delete all items from the current queue.",
|
||||
"queue_command_success": "Queue command completed successfully",
|
||||
"queue_deliver_mail": "Deliver",
|
||||
"queue_hold_mail": "Hold",
|
||||
"queue_manager": "Queue Manager",
|
||||
"queue_show_message": "Show message",
|
||||
"queue_unban": "queue unban",
|
||||
"queue_unhold_mail": "Unhold"
|
||||
},
|
||||
"start": {
|
||||
"help": "Mostrar/Ocultar painel de ajuda",
|
||||
"imap_smtp_server_auth_info": "Utilize o endereço de email completo com o método de autentucação PLAIN.<br>\r\nOs dados de login serão encryptados pelo servidor.",
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
"relay_all": "Retransmite toți destinatarii",
|
||||
"relay_all_info": "↪ Dacă alegi să <b>nu</b> retransmiți toți destinatarii, va trebui să adaugi o cutie poștală (\"oarbă\") pentru fiecare destinatar care trebuie retransmis.",
|
||||
"relay_domain": "Retransmite acest domeniu",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Puteți defini hărți de transport pentru o destinație personalizată pentru acest domeniu. Dacă nu este setat, se va face o căutare MX.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Puteți defini hărți de transport pentru o destinație personalizată pentru acest domeniu. Dacă nu este setat, se va face o căutare MX.",
|
||||
"relay_unknown_only": "Releu doar pentru cutiile poștale inexistente. Cutiile poștale existente vor fi livrate local.",
|
||||
"relayhost_wrapped_tls_info": "Vă rugăm să <b>nu</b> utilizați porturi înfășurate TLS (utilizate mai ales pe portul 465).<br>\r\nUtilizați orice port neînfășurat și emiteți STARTTLS. O politică TLS pentru impunerea TLS poate fi creată în \"Hărți ale politicii TLS\".",
|
||||
"select": "Te rog selectează...",
|
||||
|
@ -151,7 +151,6 @@
|
|||
"credentials_transport_warning": "<b>Avertisment</b>: Adăugarea unei noi intrări hartă de transport va actualiza datele de acreditare pentru toate intrările cu o coloană nexthop corespunzătoare.",
|
||||
"customer_id": "ID client",
|
||||
"customize": "Personalizează",
|
||||
"delete_queue": "Șterge tot",
|
||||
"destination": "Destinaţie",
|
||||
"dkim_add_key": "Adaugă cheia ARC/DKIM",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -188,7 +187,6 @@
|
|||
"f2b_retry_window": "Reîncercați fereastra (ele) pentru max. încercări",
|
||||
"f2b_whitelist": "Rețele/gazde pe lista albă",
|
||||
"filter_table": "Tabel filtre",
|
||||
"flush_queue": "Elimină coadă",
|
||||
"forwarding_hosts": "Gazde de redirecționare",
|
||||
"forwarding_hosts_add_hint": "Poți specifica fie adrese IPv4 / IPv6, rețele în notație CIDR, nume gazdă (care vor fi rezolvate la adrese IP), fie nume de domenii (care vor fi rezolvate la adrese IP prin interogarea înregistrărilor SPF sau, în absența acestora, a înregistrărilor MX).",
|
||||
"forwarding_hosts_hint": "Mesajele primite sunt acceptate necondiționat de la orice gazde listate aici. Aceste gazde nu sunt verificate împotriva DNSBL sau supuse la greylisting. Spamul primit de la ele nu este niciodată respins, dar opțional poate fi depus în folderul Junk. Cea mai obișnuită utilizare pentru acest lucru este de a specifica serverele de email pe care ai configurat o regulă care transmite mesajele primite către serverul mailcow.",
|
||||
|
@ -258,13 +256,6 @@
|
|||
"quarantine_release_format_att": "Ca atașament",
|
||||
"quarantine_release_format_raw": "Original nemodificat",
|
||||
"quarantine_retention_size": "Retențiile per căsuță poștală:<br><small>0 indică <b>inactiv</b>.</small>",
|
||||
"queue_ays": "Te rog confirmă că dorești să ștergi toate articolele din coada curentă.",
|
||||
"queue_deliver_mail": "Livrează",
|
||||
"queue_hold_mail": "Blochează",
|
||||
"queue_manager": "Manager de coadă",
|
||||
"queue_unban": "coadă pentru dezactivare interdicție",
|
||||
"queue_unhold_mail": "Deblochează",
|
||||
"queue_show_message": "Arată mesajul",
|
||||
"quota_notification_html": "Șablon email de notificare:<br><small>Se lasă gol pentru a restabili șablonul implicit.</small>",
|
||||
"quota_notification_sender": "Expeditor email de notificare",
|
||||
"quota_notification_subject": "Subiect email de notificare",
|
||||
|
@ -520,6 +511,7 @@
|
|||
"client_id": "ID Client",
|
||||
"client_secret": "Secret client",
|
||||
"comment_info": "Un comentariu privat nu este vizibil pentru utilizator, în timp ce un comentariu public este afișat ca un tooltip când se trece peste el într-o privire de ansamblu asupra utilizatorilor",
|
||||
"created_on": "Creat în",
|
||||
"delete1": "Șterge de la sursă când ai terminat",
|
||||
"delete2": "Șterge mesajele la destinație care nu sunt la sursă",
|
||||
"delete2duplicates": "Șterge duplicate la destinație",
|
||||
|
@ -546,6 +538,7 @@
|
|||
"hostname": "Nume gazdă",
|
||||
"inactive": "Inactiv",
|
||||
"kind": "Fel",
|
||||
"last_modified": "Ultima modificare",
|
||||
"lookup_mx": "Destinația este o expresie regulată care potrivită cu numele MX (<code>.*google\\.com</code> pentru a direcționa toate e-mailurile vizate către un MX care se termină în google.com peste acest hop)",
|
||||
"mailbox": "Editează căsuța poștală",
|
||||
"mailbox_quota_def": "Cota implicită a căsuței poștale",
|
||||
|
@ -583,7 +576,7 @@
|
|||
"relay_all": "Retransmite toți destinatarii",
|
||||
"relay_all_info": "↪ Dacă alegi să <b>nu</b> retransmiți toți destinatarii, va trebui să adaugi o cutie poștală (\"oarbă\") pentru fiecare destinatar care trebuie retransmis.",
|
||||
"relay_domain": "Acest domeniu este releu",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Puteți defini hărți de transport pentru o destinație personalizată pentru acest domeniu. Dacă nu este setat, se va face o căutare MX.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Puteți defini hărți de transport pentru o destinație personalizată pentru acest domeniu. Dacă nu este setat, se va face o căutare MX.",
|
||||
"relay_unknown_only": "Releu doar pentru cutiile poștale inexistente. Cutiile poștale existente vor fi livrate local.",
|
||||
"relayhost": "Transporturi dependente de expeditor",
|
||||
"remove": "Elimină",
|
||||
|
@ -591,7 +584,7 @@
|
|||
"save": "Salvează modificările",
|
||||
"scope": "Scop",
|
||||
"sender_acl": "Permite trimiterea ca",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Verificarea expeditorului este dezactivată</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Verificarea expeditorului este dezactivată</span>",
|
||||
"sender_acl_info": "Dacă utilizatorului A de căsuță poștală îi este permis să trimită ca utilizatorul B, adresa expeditorului nu este afișată automat ca fiind câmp selectabil \"de la\" în SOGo.<br>\r\n Utilizatorul căsuței poștale B trebuie să creeze o delegație în SOGo pentru a permite utilizatorul cutiei poștale A să selecteze adresa ca expeditor. Pentru a delega o cutie poștală în SOGo, utilizați meniul (trei puncte) din dreapta numelui căsuței poștale în stânga sus, în timp ce vă aflați în vizualizarea e-mailului. Acest comportament nu se aplică adreselor alias.",
|
||||
"sieve_desc": "Descriere scurtă",
|
||||
"sieve_type": "Tip filtru",
|
||||
|
@ -649,8 +642,8 @@
|
|||
"administration": "Configurație și detalii",
|
||||
"apps": "Aplicații",
|
||||
"debug": "Informații Sistem",
|
||||
"mailboxes": "Configurare Mail",
|
||||
"mailcow_settings": "Configurație",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Configurație",
|
||||
"quarantine": "Carantină",
|
||||
"restart_netfilter": "Repornire netfilter",
|
||||
"restart_sogo": "Repornire SOGo",
|
||||
|
@ -716,15 +709,19 @@
|
|||
"booking_ltnull": "Nelimitat, dar arată ca ocupat atunci când este rezervat",
|
||||
"booking_lt0_short": "Limită redusă",
|
||||
"catch_all": "Prinde-Tot",
|
||||
"created_on": "Creat în",
|
||||
"daily": "Zilnic",
|
||||
"deactivate": "Deactivează",
|
||||
"description": "Descriere",
|
||||
"disable_login": "Nu permiteți autentificarea",
|
||||
"disable_x": "Dezactivează",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "Lungimea cheii DKIM (biți)",
|
||||
"domain": "Domeniu",
|
||||
"domain_admins": "Administratori domeniu",
|
||||
"domain_aliases": "Aliasuri de domenii",
|
||||
"domain_quota": "Cotă",
|
||||
"domain_quota_total": "Cota totală domeniu",
|
||||
"domains": "Domenii",
|
||||
"edit": "Editează",
|
||||
"empty": "Nici un rezultat",
|
||||
|
@ -733,6 +730,8 @@
|
|||
"filter_table": "Tabel filtre",
|
||||
"filters": "Filtre",
|
||||
"fname": "Nume complet",
|
||||
"force_pw_update": "Forțează o actualizare a parolei la următoarea conectare",
|
||||
"gal": "Lista adreselor globale",
|
||||
"goto_ham": "Învață ca <b>ham</b>",
|
||||
"goto_spam": "Învață ca <b>spam</b>",
|
||||
"hourly": "Din oră în oră",
|
||||
|
@ -741,6 +740,7 @@
|
|||
"insert_preset": "Inserați un exemplu presetat \"%s\"",
|
||||
"kind": "Fel",
|
||||
"last_mail_login": "Ultima autentificare pe mail",
|
||||
"last_modified": "Ultima modificare",
|
||||
"last_pw_change": "Ultima modificare a parolei",
|
||||
"last_run": "Ultima rulare",
|
||||
"last_run_reset": "Programează următorul",
|
||||
|
@ -750,6 +750,9 @@
|
|||
"mailboxes": "Cutii poștale",
|
||||
"mailbox_defaults": "Setări implicite",
|
||||
"mailbox_defaults_info": "Definiți setările implicite pentru cutiile poștale noi.",
|
||||
"max_aliases": "Număr maxim posibil de aliasuri",
|
||||
"max_mailboxes": "Număr maxim posibil de cutii poștale",
|
||||
"max_quota": "Cotă maximă pentru cutia poștală",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Mesaj #",
|
||||
"multiple_bookings": "Rezervări multiple",
|
||||
|
@ -775,6 +778,7 @@
|
|||
"recipient_map_old": "Destinatar original",
|
||||
"recipient_map_old_info": "Destinația originală a hărților destinatarilor trebuie să fie adrese de email valide sau nume de domeniu.",
|
||||
"recipient_maps": "Hărți destinatar",
|
||||
"relay_all": "Retransmite toți destinatarii",
|
||||
"remove": "Elimină",
|
||||
"resources": "Resurse",
|
||||
"running": "Rulare",
|
||||
|
@ -890,6 +894,17 @@
|
|||
"text_plain_content": "Conținut (text/simplu)",
|
||||
"toggle_all": "Comută toate"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Șterge tot",
|
||||
"flush_queue": "Elimină coadă",
|
||||
"queue_ays": "Te rog confirmă că dorești să ștergi toate articolele din coada curentă.",
|
||||
"queue_deliver_mail": "Livrează",
|
||||
"queue_hold_mail": "Blochează",
|
||||
"queue_manager": "Manager de coadă",
|
||||
"queue_unban": "coadă pentru dezactivare interdicție",
|
||||
"queue_unhold_mail": "Deblochează",
|
||||
"queue_show_message": "Arată mesajul"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Dezactivat",
|
||||
"second": "mesaje / sec",
|
||||
|
@ -1108,7 +1123,7 @@
|
|||
"running": "Funcţionare",
|
||||
"save": "Salvează modificările",
|
||||
"save_changes": "Salvează modificările",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Verificarea expeditorului este dezactivată</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Verificarea expeditorului este dezactivată</span>",
|
||||
"shared_aliases": "Adrese alias partajate",
|
||||
"shared_aliases_desc": "Aliasurile partajate nu sunt afectate de setările specifice utilizatorului, cum ar fi filtrul de spam sau politica de criptare. Filtrele de spam corespondente pot fi efectuate numai de către un administrator ca o politică la nivel de domeniu.",
|
||||
"show_sieve_filters": "Afișează filtrul activ al sitei de utilizatori",
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
"relay_all": "Ретрансляция всех получателей",
|
||||
"relay_all_info": "↪<small>Если вы решите <b>не</b> ретранслировать всех получателей, вам нужно будет добавить (\"слепой\") почтовый адрес для каждого получателя, которого следует ретранслировать.</small>",
|
||||
"relay_domain": "Ретрансляция этого домена",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
|
||||
"relay_unknown_only": "Ретрансляция только не существующих почтовых ящиков. Почта к существующим почтовым ящикам будут доставляться локально.",
|
||||
"relayhost_wrapped_tls_info": "Пожалуйста <b>не</b> используйте TLS порты (в основном это 465 порт).<br>\r\nИспользуйте любой <b>не</b> TLS порт который поддерживает STARTTLS. А для защиты от downgrate атак - настройке принудительную политику TLS.",
|
||||
"select": "Пожалуйста, выберите...",
|
||||
|
@ -152,7 +152,6 @@
|
|||
"credentials_transport_warning": "<b>Предупреждение</b>: добавление новой записи перезапишет учетные данные для всех записей с таким же <i>следующим хостом</i>.",
|
||||
"customer_id": "ID клиента",
|
||||
"customize": "Персонализация",
|
||||
"delete_queue": "Удалить все сообщения",
|
||||
"destination": "Назначение",
|
||||
"dkim_add_key": "Добавить ARC/DKIM ключ",
|
||||
"dkim_domains_selector": "Selector",
|
||||
|
@ -189,7 +188,6 @@
|
|||
"f2b_retry_window": "Промежуток времени для следующего бана (в секундах)",
|
||||
"f2b_whitelist": "Белый список подсетей/хостов",
|
||||
"filter_table": "Поиск",
|
||||
"flush_queue": "Отправить все сообщения",
|
||||
"forwarding_hosts": "Переадресация хостов",
|
||||
"forwarding_hosts_add_hint": "Можно указывать: IPv4/IPv6 подсети в нотации CIDR, имена хостов (которые будут разрешаться в IP-адреса) или доменные имена (которые будут решаться с IP-адресами путем запроса SPF записей или, в случае их отсутствия - запросом MX записей).",
|
||||
"forwarding_hosts_hint": "Входящие сообщения безоговорочно принимаются от любых хостов, перечисленных здесь. Эти хосты не проходят проверку DNSBL и graylisting. Спам, полученный от них, никогда не отклоняется, но при желании можно включить спам фильтр и письма с плохим рейтингом будут попадать в Junk. Наиболее распространенное использование - указать почтовые серверы, на которых вы установили правило, которое перенаправляет входящие электронные письма на ваш почтовый сервер mailcow.",
|
||||
|
@ -259,13 +257,6 @@
|
|||
"quarantine_release_format_att": "Как вложение",
|
||||
"quarantine_release_format_raw": "Оригинальное письмо",
|
||||
"quarantine_retention_size": "Количество писем, сохраняемых в карантине на аккаунт:<br><small>0 означает, что карантин <b>отключён</b>.</small>",
|
||||
"queue_ays": "Пожалуйста, подтвердите, что вы хотите удалить все элементы из очереди.",
|
||||
"queue_deliver_mail": "Доставить",
|
||||
"queue_hold_mail": "Поставить на удержание",
|
||||
"queue_manager": "Очередь на отправку",
|
||||
"queue_show_message": "Показать сообщение",
|
||||
"queue_unban": "разблокировать очередь",
|
||||
"queue_unhold_mail": "Снять с удержания",
|
||||
"quota_notification_html": "Шаблон уведомления:<br><small>Оставьте пустым, чтобы восстановить шаблон по умолчанию.</small>",
|
||||
"quota_notification_sender": "Email-адрес для отправки уведомления",
|
||||
"quota_notification_subject": "Тема письма",
|
||||
|
@ -520,6 +511,7 @@
|
|||
"client_id": "ID клиента",
|
||||
"client_secret": "Секретный ключ пользователя",
|
||||
"comment_info": "Приватный комментарий не виден пользователям, а публичный - отображается рядом с псевдонимом в личном кабинете пользователя",
|
||||
"created_on": "Дата создания",
|
||||
"delete1": "Удаление из источника после завершения",
|
||||
"delete2": "Удаление писем по месту назначения, которые не находятся на исходном",
|
||||
"delete2duplicates": "Удаление дубликатов по назначению",
|
||||
|
@ -546,6 +538,7 @@
|
|||
"hostname": "Имя хоста",
|
||||
"inactive": "Неактивный",
|
||||
"kind": "Тип",
|
||||
"last_modified": "Последние изменения",
|
||||
"lookup_mx": "Назначение на основе резовинга MX записи по регулярному выражению (<code>.*\\.example\\.com$</code> для маршрутизации всей почты через этот хост, если MX заканчивающийся на example.com)",
|
||||
"mailbox": "Изменение почтового аккаунта",
|
||||
"mailbox_quota_def": "Квота по умолчанию",
|
||||
|
@ -583,7 +576,7 @@
|
|||
"relay_all": "Ретрансляция всех получателей",
|
||||
"relay_all_info": "↪<small>Если вы решите <b>не</b> ретранслировать всех получателей, вам нужно будет добавить (\"слепой\") почтовый аккаунт для каждого получателя, которого следует ретранслировать.</small>",
|
||||
"relay_domain": "Ретрансляция этого домена",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Инфо</div> Вы можете настроить собственный транспорт для домена. Если такой настройки нет, то доставка будет выполнена на основе MX записей.",
|
||||
"relay_unknown_only": "Ретрансляция только не существующих почтовых ящиков. Почта к существующим почтовым ящикам будут доставляться локально.",
|
||||
"relayhost": "Маршрутизация на основе отправителя",
|
||||
"remove": "Удалить",
|
||||
|
@ -591,7 +584,7 @@
|
|||
"save": "Сохранить изменения",
|
||||
"scope": "Область",
|
||||
"sender_acl": "Разрешить отправлять письма от имени",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Проверка отправителя отключена</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Проверка отправителя отключена</span>",
|
||||
"sender_acl_info": "Учтите, что если пользователю почтового аккаунта A разрешено отправлять от имени пользователя B, то адрес пользователя B не отобразится автоматически в списке \"Отправитель\" при написании писем в SOGo.<br>\r\n Пользователь почтового аккаунта B должен создать делегирование в SOGo, чтобы пользователь почтового аккаунта A мог выбрать его адрес в качестве отправителя. Делегирование находится в меню (троеточие) справа от имени почтового аккаунта в окне почты SOGo. Это поведение не относится к псевдонимам.",
|
||||
"sieve_desc": "Краткое описание",
|
||||
"sieve_type": "Тип фильтра",
|
||||
|
@ -647,8 +640,8 @@
|
|||
"administration": "Настройка сервера",
|
||||
"apps": "Приложения",
|
||||
"debug": "Состояние сервера",
|
||||
"mailboxes": "Настройка почты",
|
||||
"mailcow_settings": "Конфигурация",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Конфигурация",
|
||||
"quarantine": "Карантин",
|
||||
"restart_netfilter": "Перезапустить netfilter",
|
||||
"restart_sogo": "Перезапустить SOGo",
|
||||
|
@ -714,15 +707,19 @@
|
|||
"booking_ltnull": "Неограниченный, занят при бронировании",
|
||||
"booking_lt0_short": "Неограниченный лимит",
|
||||
"catch_all": "Catch-all",
|
||||
"created_on": "Дата создания",
|
||||
"daily": "Раз в день",
|
||||
"deactivate": "Отключить",
|
||||
"description": "Описание",
|
||||
"disable_login": "Вход в систему запрещен",
|
||||
"disable_x": "Отключить",
|
||||
"dkim_domains_selector": "Selector",
|
||||
"dkim_key_length": "Длина DKIM ключа (bits)",
|
||||
"domain": "Домен",
|
||||
"domain_admins": "Администраторы домена",
|
||||
"domain_aliases": "Псевдонимы доменов",
|
||||
"domain_quota": "Квота",
|
||||
"domain_quota_total": "Квота домена",
|
||||
"domains": "Домены",
|
||||
"edit": "Изменить",
|
||||
"empty": "Пусто",
|
||||
|
@ -731,6 +728,8 @@
|
|||
"filter_table": "Поиск",
|
||||
"filters": "Фильтры",
|
||||
"fname": "Полное имя",
|
||||
"force_pw_update": "Требовать смены пароля при следующем входе в систему",
|
||||
"gal": "GAL - Глобальная адресная книга",
|
||||
"goto_ham": "Запомнить как <b>полезную почту</b>",
|
||||
"goto_spam": "Запомнить как <b>спам</b>",
|
||||
"hourly": "Раз в час",
|
||||
|
@ -739,6 +738,7 @@
|
|||
"insert_preset": "Вставить пример \"%s\"",
|
||||
"kind": "Тип",
|
||||
"last_mail_login": "Последний вход",
|
||||
"last_modified": "Последние изменения",
|
||||
"last_pw_change": "Последняя смена пароля",
|
||||
"last_run": "Последний запуск",
|
||||
"last_run_reset": "Следующей запуск",
|
||||
|
@ -748,6 +748,9 @@
|
|||
"mailbox_defquota": "Квота по умолчанию",
|
||||
"mailbox_quota": "Макс. квота почт. ящика",
|
||||
"mailboxes": "Почтовые ящики",
|
||||
"max_aliases": "Максимум псевдонимов",
|
||||
"max_mailboxes": "Максимум почтовых ящиков",
|
||||
"max_quota": "Максимальная квота почтового аккаунта",
|
||||
"mins_interval": "Интервал (в минутах)",
|
||||
"msg_num": "Писем",
|
||||
"multiple_bookings": "Несколько бронирований",
|
||||
|
@ -773,6 +776,7 @@
|
|||
"recipient_map_old": "Получатель",
|
||||
"recipient_map_old_info": "Должен быть валидный почтовым ящиком или доменом.",
|
||||
"recipient_maps": "Перезапись получателя",
|
||||
"relay_all": "Ретрансляция всех получателей",
|
||||
"remove": "Удалить",
|
||||
"resources": "Ресурсы",
|
||||
"running": "В процессе",
|
||||
|
@ -888,6 +892,17 @@
|
|||
"toggle_all": "Выбрать все",
|
||||
"type": "Тип"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Удалить все сообщения",
|
||||
"flush_queue": "Отправить все сообщения",
|
||||
"queue_ays": "Пожалуйста, подтвердите, что вы хотите удалить все элементы из очереди.",
|
||||
"queue_deliver_mail": "Доставить",
|
||||
"queue_hold_mail": "Поставить на удержание",
|
||||
"queue_manager": "Очередь на отправку",
|
||||
"queue_show_message": "Показать сообщение",
|
||||
"queue_unban": "разблокировать очередь",
|
||||
"queue_unhold_mail": "Снять с удержания"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Отключен",
|
||||
"second": "сообщений / секунду",
|
||||
|
@ -1102,7 +1117,7 @@
|
|||
"running": "В процессе",
|
||||
"save": "Сохранить изменения",
|
||||
"save_changes": "Сохранить изменения",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Проверка отправителя отключена</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Проверка отправителя отключена</span>",
|
||||
"shared_aliases": "Общие псевдонимы",
|
||||
"shared_aliases_desc": "На общие псевдонимы не влияют пользовательские настройки, такие как фильтр нежелательной почты, или политика шифрования. Соответствующие фильтры нежелательной почты могут быть созданы только администратором в рамках политики домена.",
|
||||
"show_sieve_filters": "Показать включенные фильтры sieve",
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
"relay_all": "Preposielať všetkým príjemcom",
|
||||
"relay_all_info": "↪ Ak sa rozhodnete <b>nepreposielať ďalej</b> všetkých príjemcov, budete musieť pridať (\"tzv. slepú\") mailovú schránku pre každého príjemcu.",
|
||||
"relay_domain": "Preposielať túto doménu",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Môžete definovať transportné mapy pre vlastné určenie cieľa pre túto doménu. Ak nie sú nastavené, použije sa MX záznam.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Môžete definovať transportné mapy pre vlastné určenie cieľa pre túto doménu. Ak nie sú nastavené, použije sa MX záznam.",
|
||||
"relay_unknown_only": "Preposielať len neexistujúce mailové schránky. Existujúce budú doručené lokálne.",
|
||||
"relayhost_wrapped_tls_info": "Prosím <b>nepoužívajte</b> TLS-wrapped porty (najviac používane na prote 465).<br>\r\nPoužite non-wrapped port a STARTTLS. Vynútené TLS pravidlá môžu byť vytvorené v \"TLS mapách\".",
|
||||
"select": "Prosím vyberte...",
|
||||
|
@ -151,7 +151,6 @@
|
|||
"credentials_transport_warning": "<b>Upozornenie</b>: Pridaním ďalšieho záznamu do transportnej mapy bude mať za následok aktualizovanie údajov pre všetky záznamy so zhodným ďalším skokom.",
|
||||
"customer_id": "ID zákazníka",
|
||||
"customize": "Prispôsobiť",
|
||||
"delete_queue": "Vymazať všetko",
|
||||
"destination": "Cieľ",
|
||||
"dkim_add_key": "Pridať ARC/DKIM kľúč",
|
||||
"dkim_domains_selector": "Selektor",
|
||||
|
@ -188,7 +187,6 @@
|
|||
"f2b_retry_window": "Čas v ktorom je treba uplatniť max. počet pokusov (s)",
|
||||
"f2b_whitelist": "Whitelist sietí/hostiteľov",
|
||||
"filter_table": "Tabuľka filtrov",
|
||||
"flush_queue": "Vyprázdniť frontu",
|
||||
"forwarding_hosts": "Preposielacie servery",
|
||||
"forwarding_hosts_add_hint": "Môžete buď špecifikovať IPv4/IPv6 adresy, siete v CIDR notácii, názvy serverov (ktoré budú preložené na IP adresy), alebo doménové mená (ktoré budú ako IP získané z SPF záznamov, alebo v prípade ich neprítomnosti, pomocou MX záznamov).",
|
||||
"forwarding_hosts_hint": "Prichádzajúce správy sú bezpodmienečne prijaté z uvedených serverov. Nekontroluje sa ich prítomnosť v DNSBL a neaplikuje sa u nich greylisting. Spam z uvedených serverov sa neodmieta, ale občas môže skončiť nevyžiadanej pošte. Najčastejšie sa tu definujú servery ktoré doručujú alebo majú presmerovanú poštu na tento server.",
|
||||
|
@ -258,13 +256,6 @@
|
|||
"quarantine_release_format_att": "Prílohu",
|
||||
"quarantine_release_format_raw": "Nemodifikovaný originál",
|
||||
"quarantine_retention_size": "Počet zadržaných správ pre jednotlivé mailové schránky<br><small>0 znamená <b>neaktívne</b>.</small>",
|
||||
"queue_ays": "Prosím potvrďte vymazanie všetkých položiek z aktuálnej fronty.",
|
||||
"queue_deliver_mail": "Doručiť",
|
||||
"queue_hold_mail": "Pozdržať",
|
||||
"queue_manager": "Správca fronty",
|
||||
"queue_show_message": "Zobraziť správu",
|
||||
"queue_unban": "Odblokovať",
|
||||
"queue_unhold_mail": "Uvoľniť",
|
||||
"quota_notification_html": "Notifikácia email predloha:<br><small>Nechať prázdne pre obnovenie originálnej predlohy.</small>",
|
||||
"quota_notification_sender": "Odosielateľ notifikácií",
|
||||
"quota_notification_subject": "Predmet notifikácií",
|
||||
|
@ -519,6 +510,7 @@
|
|||
"client_id": "ID klienta",
|
||||
"client_secret": "Klientský tajný kľúč",
|
||||
"comment_info": " Súkromný komentár nie je viditeľný používateľovi, na rozdiel od verejného komentára, ktorý je prezentovaný ako popis v prehľade používateľov",
|
||||
"created_on": "Vytvorené",
|
||||
"delete1": "Vymazať zo zdrojovej schránky, po dokončení prenosu",
|
||||
"delete2": "Vymazať správy v cieľovej schránke, ak nie sú v zdrojovej",
|
||||
"delete2duplicates": "Vymazať duplikáty v cieľovej schránke",
|
||||
|
@ -545,6 +537,7 @@
|
|||
"hostname": "Hostiteľ",
|
||||
"inactive": "Neaktívny",
|
||||
"kind": "Druh",
|
||||
"last_modified": "Naposledy upravené",
|
||||
"lookup_mx": "Cieľ je regulárny výraz ktorý sa zhoduje s MX záznamom (<code>.*google\\.com</code> smeruje všetku poštu na MX ktoré sú cieľom pre google.com cez tento skok)",
|
||||
"mailbox": "Upraviť mailovú schránku",
|
||||
"mailbox_quota_def": "Predvolená veľkosť mailovej schránky",
|
||||
|
@ -582,7 +575,7 @@
|
|||
"relay_all": "Preposielať všetkých prijemcov",
|
||||
"relay_all_info": "↪ Ak sa rozhodnete <b>nepreposielať</b> všetkých príjemcov, budete musieť pridať (\"tzv. slepú\") mailovú schránku pre každého príjemcu.",
|
||||
"relay_domain": "Preposielať túto doménu",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Môžete definovať transportné mapy pre vlastné určenie cieľa pre túto doménu. Ak nie sú nastavené, použije sa MX záznam.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Môžete definovať transportné mapy pre vlastné určenie cieľa pre túto doménu. Ak nie sú nastavené, použije sa MX záznam.",
|
||||
"relay_unknown_only": "Preposielať len neexistujúce mailové schránky. Existujúce budú doručené lokálne.",
|
||||
"relayhost": "Transporty závislé na odosielateľovi",
|
||||
"remove": "Odstrániť",
|
||||
|
@ -590,7 +583,7 @@
|
|||
"save": "Uložiť zmeny",
|
||||
"scope": "Rozsah",
|
||||
"sender_acl": "Povoliť odosielanie ako",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odosielateľa vypnutá</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Kontrola odosielateľa vypnutá</span>",
|
||||
"sender_acl_info": "Ak mailový používateľ A má povolenie poslať ako mailový používateľ B, adresa odosielateľa nieje automaticky viditeľná ako voliteľné \"from\" pole v SOGo.<br>\r\n Mailový používateľ B potrebuje vytvoriť delegáciu v SOGo, aby bol schopný mailový používateľ A vybrať jeho adresu ako odosielateľ. Na delegovanie mailovej adresy v SOGo, použite menu (tri bodky) napravo vášho mailového mena v hornom ľavom rohu, v prehľade správ. Toto neplatí pre alias adresy.",
|
||||
"sieve_desc": "Krátky popis",
|
||||
"sieve_type": "Typ filtru",
|
||||
|
@ -649,8 +642,8 @@
|
|||
"administration": "Konfigurácia & Detaily",
|
||||
"apps": "Aplikácie",
|
||||
"debug": "Systémové informácie",
|
||||
"mailboxes": "Nastavenie mailov",
|
||||
"mailcow_settings": "Konfigurácia",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Konfigurácia",
|
||||
"quarantine": "Karanténa",
|
||||
"restart_netfilter": "Reštartovať netfilter",
|
||||
"restart_sogo": "Reštart SOGo",
|
||||
|
@ -716,15 +709,19 @@
|
|||
"booking_ltnull": "Bez limitu, ale zobraziť obsadené po rezervácii",
|
||||
"booking_lt0_short": "Voľný limit",
|
||||
"catch_all": "Doménový kôš",
|
||||
"created_on": "Vytvorené",
|
||||
"daily": "Denný",
|
||||
"deactivate": "Deaktivovať",
|
||||
"description": "Popis",
|
||||
"disable_login": "Zablokovať prihlásenie (nevzťahuje sa na prichádzajúcu poštu)",
|
||||
"disable_x": "Pozastaviť",
|
||||
"dkim_domains_selector": "Selektor",
|
||||
"dkim_key_length": "Dĺžka DKIM kľúča (bity)",
|
||||
"domain": "Doména",
|
||||
"domain_admins": "Administrátori domény",
|
||||
"domain_aliases": "Alias domény",
|
||||
"domain_quota": "Kvóta",
|
||||
"domain_quota_total": "Celkové kvóta domény",
|
||||
"domains": "Domény",
|
||||
"edit": "Upraviť",
|
||||
"empty": "Žiadne výsledky",
|
||||
|
@ -733,6 +730,8 @@
|
|||
"filter_table": "Filtrovať tabuľku",
|
||||
"filters": "Filtre",
|
||||
"fname": "Celé meno",
|
||||
"force_pw_update": "Vynútiť zmenu hesla pri ďalšom prihlásení",
|
||||
"gal": "Globálny zoznam adries",
|
||||
"goto_ham": "Považovať za <b>ham</b>",
|
||||
"goto_spam": "Považovať za <b>spam</b>",
|
||||
"hourly": "Hodinový",
|
||||
|
@ -741,6 +740,7 @@
|
|||
"insert_preset": "Vložiť vzor nastavenia \"%s\"",
|
||||
"kind": "Druh",
|
||||
"last_mail_login": "Posledné prihlásenie",
|
||||
"last_modified": "Naposledy upravené",
|
||||
"last_pw_change": "Naposledy zmenené heslo",
|
||||
"last_run": "Posledné spustenie",
|
||||
"last_run_reset": "Znovu naplánovať",
|
||||
|
@ -750,6 +750,9 @@
|
|||
"mailbox_defquota": "Predvolená veľkosť schránky",
|
||||
"mailbox_quota": "Max. veľkosť schránky",
|
||||
"mailboxes": "Mailové schránky",
|
||||
"max_aliases": "Max. počet aliasov",
|
||||
"max_mailboxes": "Max. počet mailových schránok",
|
||||
"max_quota": "Max. kvóta pre mailovú schránku",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Počet správ",
|
||||
"multiple_bookings": "Viaceré rezervácie",
|
||||
|
@ -775,6 +778,7 @@
|
|||
"recipient_map_old": "Originálny príjemca",
|
||||
"recipient_map_old_info": "Originálny cieľ mapy príjemcu musí byť platná emailová adresa alebo meno domény.",
|
||||
"recipient_maps": "Mapy príjemcov",
|
||||
"relay_all": "Preposielať všetkým príjemcom",
|
||||
"remove": "Odstrániť",
|
||||
"resources": "Zdroje",
|
||||
"running": "Bežiaci",
|
||||
|
@ -890,6 +894,17 @@
|
|||
"toggle_all": "Označiť všetky",
|
||||
"type": "Typ"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Vymazať všetko",
|
||||
"flush_queue": "Vyprázdniť frontu",
|
||||
"queue_ays": "Prosím potvrďte vymazanie všetkých položiek z aktuálnej fronty.",
|
||||
"queue_deliver_mail": "Doručiť",
|
||||
"queue_hold_mail": "Pozdržať",
|
||||
"queue_manager": "Správca fronty",
|
||||
"queue_show_message": "Zobraziť správu",
|
||||
"queue_unban": "Odblokovať",
|
||||
"queue_unhold_mail": "Uvoľniť"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Vypnuté",
|
||||
"second": "správ za sekundu",
|
||||
|
@ -1105,7 +1120,7 @@
|
|||
"running": "Beží",
|
||||
"save": "Uložiť zmeny",
|
||||
"save_changes": "Uložiť zmeny",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odosielateľa je pozastavená</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Kontrola odosielateľa je pozastavená</span>",
|
||||
"shared_aliases": "Zdieľané alias adresy",
|
||||
"shared_aliases_desc": "Zdieľané aliasy nie sú ovplyvnené používateľskými nastaveniami, ako spam filter alebo šifrovacie pravidlá. Zodpovedajúce spam filtre môžu byť vytvorené len administrátorom podľa podmienok domén.",
|
||||
"show_sieve_filters": "Zobraziť sieve filter aktívneho používateľa",
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
"relay_all": "Vidarebefordra alla mottagaradresser",
|
||||
"relay_all_info": "↪ Om <b>inte</b> alla mottagare ska vidarebefordras måste (\"blinda\") postlådor skapas för varje adress som ska vidarebefordras.",
|
||||
"relay_domain": "Vidarebefordra denna domän",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Transportkartor kan skapas för att definiera enskilda destinationer på en relädomän.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Transportkartor kan skapas för att definiera enskilda destinationer på en relädomän.",
|
||||
"relay_unknown_only": "Vidarebefodra endast om det saknas en lokal postlåda. Existerar det en postlåda kommer det levereras lokalt.",
|
||||
"relayhost_wrapped_tls_info": "Använd <b>inte</b> TLS-bundna portar (exempelvis SMTPS via port 465).<br>\r\nTrafiken kommer istället transporteras med TLS genom att använda STARTTLS. En sådan TLS-policy kan skapas under \"TLS-policyföreskrifter\".",
|
||||
"select": "Välj ...",
|
||||
|
@ -145,7 +145,6 @@
|
|||
"credentials_transport_warning": "<b>Varning</b>: När en ny reläserver läggs till uppdateras uppgifterna för alla reläservrar som hör till samma värd.",
|
||||
"customer_id": "Kundnummer",
|
||||
"customize": "Anpassa gränssnittet",
|
||||
"delete_queue": "Ta bort allt",
|
||||
"destination": "Destination",
|
||||
"dkim_add_key": "Lägg till ARC/DKIM-nyckel",
|
||||
"dkim_domains_selector": "Välj",
|
||||
|
@ -182,7 +181,6 @@
|
|||
"f2b_retry_window": "Tidsfönster för antal försök",
|
||||
"f2b_whitelist": "Vitlistade nätverk/värdar",
|
||||
"filter_table": "Filtrera tebellen",
|
||||
"flush_queue": "Kasta kön",
|
||||
"forwarding_hosts": "Värdar för inkommande e-post servrar",
|
||||
"forwarding_hosts_add_hint": "Du kan antingen specifiera IPv4-/IPv6-adresser, nätverk med CIDR betäckning, värdnamn (hämtar IP-adressen), eller domännamn (hämtar IP-adressen från SPF-uppslaget, eller från MX-uppslag).",
|
||||
"forwarding_hosts_hint": "Denna inställning används för att ange e-postservrar som används för att förmedla inkommande e-postmeddelanden till denna Mailcow-server. Inkommande e-postmeddelanden från dessa värdar accepteras oavsätt. Dessa värdar testas därav inte mot DNSBLs eller påverkas av grålistning. Spam som mottas från dessa värdar kastas aldrig, men kan ev filtreras till skräppostsmappen.",
|
||||
|
@ -248,13 +246,6 @@
|
|||
"quarantine_release_format_att": "Som bilaga",
|
||||
"quarantine_release_format_raw": "Oförändrat originalmeddelande",
|
||||
"quarantine_retention_size": "Antal meddelanden att förvara i karantän per postlåda:<br><small>0 indikerar <b>inaktivt</b>.</small>",
|
||||
"queue_ays": "Bekräfta att du verkligen vill ta bort dessa objekt från den aktuella kön.",
|
||||
"queue_deliver_mail": "Leverera",
|
||||
"queue_hold_mail": "Håll kvar",
|
||||
"queue_manager": "Kö-hanteraring",
|
||||
"queue_unban": "schemalägg en borttagning från banlysning",
|
||||
"queue_unhold_mail": "Släpp på",
|
||||
"queue_show_message": "Visa meddelandet",
|
||||
"quota_notification_html": "E-postmall för notifieringar:<br><small>Lämna tomt för att återställa standardmallen.</small>",
|
||||
"quota_notification_sender": "Avsändaradress för notifieringsmeddelande",
|
||||
"quota_notification_subject": "Ämnesrad för notifieringsmeddelande",
|
||||
|
@ -501,6 +492,7 @@
|
|||
"client_id": "Klient-ID",
|
||||
"client_secret": "Klienthemlighet",
|
||||
"comment_info": "En privat kommentar är inte synlig för användaren, medan en offentlig kommentar visas i användaröversikten",
|
||||
"created_on": "Skapad vid",
|
||||
"delete1": "Ta bort meddelande från källservern när överföringen är slutförd.",
|
||||
"delete2": "Ta bort meddelanden från destinationsservern som inte finns på källservern",
|
||||
"delete2duplicates": "Ta bort dubbletter på destinationsservern",
|
||||
|
@ -527,6 +519,7 @@
|
|||
"hostname": "Värdnamn",
|
||||
"inactive": "Inaktiv",
|
||||
"kind": "Typ",
|
||||
"last_modified": "Senast ändrad",
|
||||
"mailbox": "Ändra postlåda",
|
||||
"mailbox_quota_def": "Standard kvot på postlådor",
|
||||
"max_aliases": "Max antal alias",
|
||||
|
@ -560,7 +553,7 @@
|
|||
"relay_all": "Vidarebefordra alla mottagare",
|
||||
"relay_all_info": "↪ Om <b>inte</b> alla mottagare ska vidarebefordras måste (\"blinda\") postlådor skapas för varje adress som ska vidarebefordras.",
|
||||
"relay_domain": "Relädomän",
|
||||
"relay_transport_info": "<div class=\"label label-info\">Info</div> Transportkartor kan skapas för att definiera enskilda destinationer på en relädomän.",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div> Transportkartor kan skapas för att definiera enskilda destinationer på en relädomän.",
|
||||
"relay_unknown_only": "Vidarebefodra endast om det saknas en lokal postlåda. Existerar det en postlåda kommer det levereras lokalt.",
|
||||
"relayhost": "Reläserver",
|
||||
"remove": "Ta bort",
|
||||
|
@ -568,7 +561,7 @@
|
|||
"save": "Spara ändringar",
|
||||
"scope": "Omfattning",
|
||||
"sender_acl": "Tillåt att skicka som",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Avsändarkontroll är avaktiverad</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Avsändarkontroll är avaktiverad</span>",
|
||||
"sender_acl_info": "Om användaren A tillåts skicka som användaren B visas inte avsändaradressen automatiskt i \"från\" fältet i SOGo.<br>\r\n Användaren B måste skapa en delegation i SOGo för att låta användaren A välja Användaren B's adress som avsändare. För att delegera en postlåda i SOGo, gå till menyn (tre punkter) till höger om ditt namn uppe till vänster i postvyn. Detta gäller inte för aliasadresser.",
|
||||
"sieve_desc": "Kort beskrivning",
|
||||
"sieve_type": "Filtertyp",
|
||||
|
@ -607,8 +600,8 @@
|
|||
"administration": "Konfiguration & detaljer",
|
||||
"apps": "Applikationer",
|
||||
"debug": "Systeminformation",
|
||||
"mailboxes": "Ställ in mejl",
|
||||
"mailcow_settings": "Konfiguration",
|
||||
"email": "E-Mail",
|
||||
"mailcow_config": "Konfiguration",
|
||||
"quarantine": "Karantän",
|
||||
"restart_netfilter": "Starta om netfilter",
|
||||
"restart_sogo": "Starta om SOGo",
|
||||
|
@ -672,15 +665,19 @@
|
|||
"booking_custom_short": "Hård gräns",
|
||||
"booking_ltnull": "Obegränsad antal, men visa resursen som upptagen när den är bokad",
|
||||
"booking_lt0_short": "Mjuk gräns",
|
||||
"created_on": "Skapad vid",
|
||||
"daily": "Dagligen",
|
||||
"deactivate": "Inaktivera",
|
||||
"description": "Beskrivning",
|
||||
"disable_login": "Inaktivera inloggning (inkommande post kommer fortfarande tas emot)",
|
||||
"disable_x": "Inaktivera",
|
||||
"dkim_domains_selector": "Välj",
|
||||
"dkim_key_length": "DKIM-nyckellängd (bitar)",
|
||||
"domain": "Domän",
|
||||
"domain_admins": "Domänadministratörer",
|
||||
"domain_aliases": "Domänalias",
|
||||
"domain_quota": "Kvot",
|
||||
"domain_quota_total": "Total kvot per postlåda",
|
||||
"domains": "Domäner",
|
||||
"edit": "Ändra",
|
||||
"empty": "Ingen information",
|
||||
|
@ -689,12 +686,15 @@
|
|||
"filter_table": "Filtrera tabellen",
|
||||
"filters": "Postfilter",
|
||||
"fname": "Fullständigt namn",
|
||||
"force_pw_update": "Kräv uppdatering av lösenordet vid nästa inloggning",
|
||||
"gal": "Global adressbok",
|
||||
"hourly": "Varje timme",
|
||||
"in_use": "Användning (%)",
|
||||
"inactive": "Inaktiv",
|
||||
"insert_preset": "Infoga exempelkoden \"%s\"",
|
||||
"kind": "Sort",
|
||||
"last_mail_login": "Senaste inloggningen",
|
||||
"last_modified": "Senast ändrad",
|
||||
"last_run": "Senaste körningen",
|
||||
"last_run_reset": "Schemalägg nästa",
|
||||
"mailbox": "Postlåda",
|
||||
|
@ -703,6 +703,9 @@
|
|||
"mailboxes": "Postlådor",
|
||||
"mailbox_defaults": "Standardinställningar",
|
||||
"mailbox_defaults_info": "Standardinställningar för nya postlådor.",
|
||||
"max_aliases": "Max antal alias",
|
||||
"max_mailboxes": "Max antal postlådor",
|
||||
"max_quota": "Max. kvot per postlåda",
|
||||
"mins_interval": "Interval (min)",
|
||||
"msg_num": "Antal meddelanden",
|
||||
"multiple_bookings": "Flera bokningar",
|
||||
|
@ -726,6 +729,7 @@
|
|||
"recipient_map_old": "Ursprunglig mottagaren",
|
||||
"recipient_map_old_info": "Den ursprungliga mottagaren måste vara en giltiga e-postadresser eller ett domännamn.",
|
||||
"recipient_maps": "Skriv om mottagaradressen",
|
||||
"relay_all": "Vidarebefordra alla mottagare",
|
||||
"remove": "Ta bort",
|
||||
"resources": "Resurser",
|
||||
"running": "Körs",
|
||||
|
@ -831,6 +835,17 @@
|
|||
"text_plain_content": "Innehåll (text/plain)",
|
||||
"toggle_all": "Markera alla"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Ta bort allt",
|
||||
"flush_queue": "Kasta kön",
|
||||
"queue_ays": "Bekräfta att du verkligen vill ta bort dessa objekt från den aktuella kön.",
|
||||
"queue_deliver_mail": "Leverera",
|
||||
"queue_hold_mail": "Håll kvar",
|
||||
"queue_manager": "Kö-hanteraring",
|
||||
"queue_unban": "schemalägg en borttagning från banlysning",
|
||||
"queue_unhold_mail": "Släpp på",
|
||||
"queue_show_message": "Visa meddelandet"
|
||||
},
|
||||
"start": {
|
||||
"help": "Visa/dölj hjälppanel",
|
||||
"imap_smtp_server_auth_info": "Använd din fullständiga e-postadress och PLAIN-autentiseringsmekanism.<br>\r\nInloggningsuppgifterna överförs krypterat eftersom obligatorisk kryptering sker till servern.",
|
||||
|
@ -1038,7 +1053,7 @@
|
|||
"running": "Kör",
|
||||
"save": "Spara ändringarna",
|
||||
"save_changes": "Spara ändringar",
|
||||
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrollen av avsändaren är inaktiverad</span>",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Kontrollen av avsändaren är inaktiverad</span>",
|
||||
"shared_aliases": "Delade aliasadresses",
|
||||
"shared_aliases_desc": "Delade aliasadresser påverkas inte av användarspecifika inställningar som skräppostfilter eller krypteringspolicy. Motsvarande skräppostfilter kan endast göras av en administratör som en domänövergripande policy.",
|
||||
"show_sieve_filters": "Visa den aktuella användarens sieve-filter",
|
||||
|
|
|
@ -141,7 +141,6 @@
|
|||
"convert_html_to_text": "Перетворити HTML на звичайний текст",
|
||||
"customer_id": "ID клієнта",
|
||||
"customize": "Персоналізація",
|
||||
"delete_queue": "Видалити всі повідомлення",
|
||||
"destination": "Призначення",
|
||||
"dkim_add_key": "Додати ARC/DKIM ключ",
|
||||
"dkim_domains_selector": "Селектор",
|
||||
|
@ -228,12 +227,6 @@
|
|||
"quarantine_release_format_att": "Як додаток",
|
||||
"quarantine_release_format_raw": "Оригінальний лист",
|
||||
"quarantine_retention_size": "Кількість листів, які зберігаються в карантині на обліковий запис:<br><small>0 означає, що карантин <b>відключено</b>.</small>",
|
||||
"queue_deliver_mail": "Доставити",
|
||||
"queue_hold_mail": "Поставити на утримання",
|
||||
"queue_manager": "Черга на відправлення",
|
||||
"queue_show_message": "Показати повідомлення",
|
||||
"queue_unban": "розблокувати чергу",
|
||||
"queue_unhold_mail": "Зняти з утримання",
|
||||
"quota_notification_sender": "Email-адреса для надсилання повідомлення",
|
||||
"quota_notification_subject": "Тема листа",
|
||||
"quota_notifications": "Квота",
|
||||
|
@ -516,6 +509,7 @@
|
|||
"backup_mx_options": "Параметри резервного MX",
|
||||
"client_id": "ID клієнта",
|
||||
"client_secret": "Секретний ключ користувача",
|
||||
"created_on": "Дата створення",
|
||||
"delete1": "Видалити з джерела після завершення",
|
||||
"delete2": "Видалити листи за місцем призначення, яких не має в джерелі",
|
||||
"delete2duplicates": "Видалити дублікати за місцем призначення",
|
||||
|
@ -538,6 +532,7 @@
|
|||
"hostname": "Ім'я хоста",
|
||||
"inactive": "Неактивний",
|
||||
"kind": "Тип",
|
||||
"last_modified": "Останні зміни",
|
||||
"mailbox": "Редагувати поштову скриньку",
|
||||
"max_aliases": "Максимум псевдонімів",
|
||||
"max_mailboxes": "Максимум поштових скриньок",
|
||||
|
@ -650,12 +645,12 @@
|
|||
"administration": "Налаштування сервера",
|
||||
"apps": "Додатки",
|
||||
"debug": "Стан сервера",
|
||||
"mailboxes": "Налаштування пошти",
|
||||
"email": "E-Mail",
|
||||
"quarantine": "Карантин",
|
||||
"restart_netfilter": "Перезапустити netfilter",
|
||||
"restart_sogo": "Перезапустити SOGo",
|
||||
"user_settings": "Налаштування користувача",
|
||||
"mailcow_settings": "Конфігурація"
|
||||
"mailcow_config": "Конфігурація"
|
||||
},
|
||||
"info": {
|
||||
"no_action": "Дій не передбачено",
|
||||
|
@ -711,13 +706,17 @@
|
|||
"booking_ltnull": "Необмежений, зайнятий під час бронювання",
|
||||
"booking_lt0_short": "М’який ліміт",
|
||||
"catch_all": "Catch-all",
|
||||
"created_on": "Дата створення",
|
||||
"daily": "Раз на день",
|
||||
"description": "Опис",
|
||||
"disable_x": "Вимкнути",
|
||||
"dkim_domains_selector": "Селектор",
|
||||
"dkim_key_length": "Довжина ключа DKIM (біт)",
|
||||
"domain": "Домен",
|
||||
"domain_admins": "Адміністратори домену",
|
||||
"domain_aliases": "Псевдоніми доменів",
|
||||
"domain_quota": "Квота",
|
||||
"domain_quota_total": "Загальна квота домену",
|
||||
"domains": "Домени",
|
||||
"edit": "Змінити",
|
||||
"empty": "Пусто",
|
||||
|
@ -726,18 +725,24 @@
|
|||
"filter_table": "Пошук",
|
||||
"filters": "Фильтри",
|
||||
"fname": "Повне ім'я",
|
||||
"gal": "GAL - Глобальна адресна книга",
|
||||
"force_pw_update": "Вимагати зміну пароля при наступному вході до системи",
|
||||
"goto_spam": "Запам'ятати як <b>спам</b>",
|
||||
"hourly": "Щогодини",
|
||||
"in_use": "Використано (%)",
|
||||
"inactive": "Неактивний",
|
||||
"insert_preset": "Вставити приклад \"%s\"",
|
||||
"kind": "Тип",
|
||||
"last_modified": "Останні зміни",
|
||||
"last_pw_change": "Остання зміна пароля",
|
||||
"last_run": "Останній запуск",
|
||||
"last_run_reset": "Наступний запуск",
|
||||
"mailbox": "Поштовий акаунт",
|
||||
"mailbox_defaults_info": "Визначте параметри за замовчуванням для нових поштових акаунтів.",
|
||||
"mailbox_quota": "Макс. квота пошт. ящика",
|
||||
"max_aliases": "Максимум псевдонімів",
|
||||
"max_mailboxes": "Максимум поштових скриньок",
|
||||
"max_quota": "Максимальна квота поштового акаунту",
|
||||
"mins_interval": "Інтервал (у хвилинах)",
|
||||
"msg_num": "Листів",
|
||||
"multiple_bookings": "Декілька бронювань",
|
||||
|
@ -758,6 +763,7 @@
|
|||
"recipient_map_new_info": "Повинен бути чинною поштовою скринькою.",
|
||||
"recipient_map_old": "Одержувач",
|
||||
"recipient_maps": "Перезапис одержувача",
|
||||
"relay_all": "Ретрансляція всіх отримувачів",
|
||||
"remove": "Видалити",
|
||||
"resources": "Ресурси",
|
||||
"running": "В процесі",
|
||||
|
@ -891,6 +897,16 @@
|
|||
"qinfo": "Система карантину зберігатиме відхилені листи в базі даних (у відправника <em>не</em> буде створене враження, що лист доставлений), а також пошту, яка буде доставлена як копія в папку «Спам» поштової скриньки.\n <br>\"Вивчити як спам і видалити\" вивче повідомлення як спам за теоремою Байєса і також обчислювати нечіткі хеші до денних подібних повідомлень у майбутньому.\n <br>Зверніть увагу, що вивчення кількох повідомлень – залежно від вашої системи – може зайняти багато часу.<br>Елементи чорного списку виключаються з карантину.",
|
||||
"table_size_show_n": "Відображати %s полів"
|
||||
},
|
||||
"queue": {
|
||||
"delete_queue": "Видалити всі повідомлення",
|
||||
"flush_queue": "Flush queue",
|
||||
"queue_deliver_mail": "Доставити",
|
||||
"queue_hold_mail": "Поставити на утримання",
|
||||
"queue_manager": "Черга на відправлення",
|
||||
"queue_show_message": "Показати повідомлення",
|
||||
"queue_unban": "розблокувати чергу",
|
||||
"queue_unhold_mail": "Зняти з утримання"
|
||||
},
|
||||
"ratelimit": {
|
||||
"disabled": "Вимкнено",
|
||||
"minute": "повідомлень / хвилину",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue