Merge branch 'master' into gnous

This commit is contained in:
thopic committed 2023-03-02 18:36:01 +01:00
commit 86d8ac5742
217 files changed
+62214 -7433

No files matched your search

+1 -1
View File
@@ -1 +1 @@
custom: https://mailcow.github.io/mailcow-dockerized-docs/#help-mailcow custom: ["https://www.servercow.de/mailcow?lang=en#sal"]
+112 -50
View File
@@ -26,70 +26,132 @@ body:
attributes: attributes:
label: Description label: Description
description: Please provide a brief description of the bug in 1-2 sentences. If applicable, add screenshots to help explain your problem. Very useful for bugs in mailcow UI. description: Please provide a brief description of the bug in 1-2 sentences. If applicable, add screenshots to help explain your problem. Very useful for bugs in mailcow UI.
render: plain text
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Logs label: "Logs:"
description: Please take a look at the [official documentation](https://mailcow.github.io/mailcow-dockerized-docs/debug-logs/) and post the last few lines of logs, when the error occurs. For example, docker container logs of affected containers. This will be automatically formatted into code, so no need for backticks. description: "Please take a look at the [official documentation](https://docs.mailcow.email/troubleshooting/debug-logs/) and post the last few lines of logs, when the error occurs. For example, docker container logs of affected containers. This will be automatically formatted into code, so no need for backticks."
render: bash render: plain text
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Steps to reproduce label: "Steps to reproduce:"
description: Please describe the steps to reproduce the bug. Screenshots can be added, if helpful. description: "Please describe the steps to reproduce the bug. Screenshots can be added, if helpful."
render: plain text
placeholder: |- placeholder: |-
1. ... 1. ...
2. ... 2. ...
3. ... 3. ...
validations: validations:
required: true required: true
- type: textarea - type: markdown
attributes: attributes:
label: System information value: |
description: In this stage we would kindly ask you to attach general system information about your setup. ## System information
value: |- ### In this stage we would kindly ask you to attach general system information about your setup.
| Question | Answer | - type: dropdown
| --- | --- | attributes:
| My operating system | I_DO_REPLY_HERE | label: "Which branch are you using?"
| Is Apparmor, SELinux or similar active? | I_DO_REPLY_HERE | description: "#### `git rev-parse --abbrev-ref HEAD`"
| Virtualization technology (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE | multiple: false
| Server/VM specifications (Memory, CPU Cores) | I_DO_REPLY_HERE | options:
| Docker version (`docker version`) | I_DO_REPLY_HERE | - master
| docker-compose version (`docker-compose version`) | I_DO_REPLY_HERE | - nightly
| mailcow version (```git describe --tags `git rev-list --tags --max-count=1` ```) | I_DO_REPLY_HERE | validations:
| Reverse proxy (custom solution) | I_DO_REPLY_HERE | required: true
- type: input
Output of `git diff origin/master`, any other changes to the code? If so, **please post them**: attributes:
``` label: "Operating System:"
YOUR OUTPUT GOES HERE placeholder: "e.g. Ubuntu 22.04 LTS"
``` validations:
required: true
All third-party firewalls and custom iptables rules are unsupported. **Please check the Docker docs about how to use Docker with your own ruleset**. Nevertheless, iptabels output can help us to help you: - type: input
iptables -L -vn: attributes:
``` label: "Server/VM specifications:"
YOUR OUTPUT GOES HERE placeholder: "Memory, CPU Cores"
``` validations:
required: true
ip6tables -L -vn: - type: input
``` attributes:
YOUR OUTPUT GOES HERE label: "Is Apparmor, SELinux or similar active?"
``` placeholder: "yes/no"
validations:
iptables -L -vn -t nat: required: true
``` - type: input
YOUR OUTPUT GOES HERE attributes:
``` label: "Virtualization technology:"
placeholder: "KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported**"
ip6tables -L -vn -t nat: validations:
``` required: true
YOUR OUTPUT GOES HERE - type: input
``` attributes:
label: "Docker version:"
DNS problems? Please run `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network) and post the output: description: "#### `docker version`"
``` placeholder: "20.10.21"
YOUR OUTPUT GOES HERE validations:
``` required: true
- type: input
attributes:
label: "docker-compose version or docker compose version:"
description: "#### `docker-compose version` or `docker compose version`"
placeholder: "v2.12.2"
validations:
required: true
- type: input
attributes:
label: "mailcow version:"
description: "#### ```git describe --tags `git rev-list --tags --max-count=1` ```"
placeholder: "2022-08"
validations:
required: true
- type: input
attributes:
label: "Reverse proxy:"
placeholder: "e.g. Nginx/Traefik"
validations:
required: true
- type: textarea
attributes:
label: "Logs of git diff:"
description: "#### Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of iptables -L -vn:"
description: "#### Output of `iptables -L -vn`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of ip6tables -L -vn:"
description: "#### Output of `ip6tables -L -vn`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of iptables -L -vn -t nat:"
description: "#### Output of `iptables -L -vn -t nat`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of ip6tables -L -vn -t nat:"
description: "#### Output of `ip6tables -L -vn -t nat`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "DNS check:"
description: "#### Output of `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network)"
render: plain text
validations: validations:
required: true required: true
@@ -0,0 +1,13 @@
## :memo: Brief description
<!-- Diff summary - START -->
<!-- Diff summary - END -->
## :computer: Commits
<!-- Diff commits - START -->
<!-- Diff commits - END -->
## :file_folder: Modified files
<!-- Diff files - START -->
<!-- Diff files - END -->
+13
View File
@@ -0,0 +1,13 @@
{
"enabled": true,
"timezone": "Europe/Berlin",
"dependencyDashboard": false,
"dependencyDashboardTitle": "Renovate Dashboard",
"commitBody": "Signed-off-by: milkmaker <milkmaker@mailcow.de>",
"rebaseWhen": "auto",
"assignees": [
"@magiccc"
],
"baseBranches": ["staging"],
"enabledManagers": ["github-actions"]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

@@ -0,0 +1,33 @@
name: Check PRs if on staging
on:
pull_request_target:
types: [opened, edited]
permissions: {}
jobs:
is_not_staging:
runs-on: ubuntu-latest
if: github.event.pull_request.base.ref != 'staging' #check if the target branch is not staging
steps:
- name: Send message
uses: thollander/actions-comment-pull-request@main
with:
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
message: |
Thanks for contributing!
I noticed that you didn't select `staging` as your base branch. Please change the base branch to `staging`.
See the attached picture on how to change the base branch to `staging`:
![check_prs_if_on_staging.png](https://raw.githubusercontent.com/mailcow/mailcow-dockerized/master/.github/workflows/assets/check_prs_if_on_staging.png)
- name: Fail #we want to see failed checks in the PR
if: ${{ success() }} #set exit code to 1 even if commenting somehow failed
run: exit 1
is_staging:
runs-on: ubuntu-latest
if: github.event.pull_request.base.ref == 'staging' #check if the target branch is staging
steps:
- name: Success
run: exit 0
@@ -14,7 +14,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️ - name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v6.0.0 uses: actions/stale@v6.0.1
with: with:
repo-token: ${{ secrets.STALE_ACTION_PAT }} repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60 days-before-stale: 60
+1 -3
View File
@@ -33,13 +33,11 @@ jobs:
run: | run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
sudo service docker start sudo service docker start
sudo curl -L https://github.com/docker/compose/releases/download/v$(curl -Ls https://www.servercow.de/docker-compose/latest.php)/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
- name: Prepair Image Builds - name: Prepair Image Builds
run: | run: |
cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml
- name: Build Docker Images - name: Build Docker Images
run: | run: |
docker-compose build ${image} docker compose build ${image}
env: env:
image: ${{ matrix.images }} image: ${{ matrix.images }}
+25
View File
@@ -0,0 +1,25 @@
name: Create PR to merge to nightly from staging
on:
push:
branches:
- staging
jobs:
action-pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Run the Action
uses: devops-infra/action-pull-request@v0.5.3
with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
assignee: DerLinkman
source_branch: staging
target_branch: nightly
reviewer: DerLinkman
label: upstream
template: .github/ISSUE_TEMPLATE/pr_to_nighty_template.yml
get_diff: true
@@ -0,0 +1,34 @@
name: Build mailcow backup image
on:
schedule:
# At 00:00 on Sunday
- cron: "0 0 * * 0"
workflow_dispatch: # Allow to run workflow manually
jobs:
docker_image_build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }}
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
file: data/Dockerfiles/backup/Dockerfile
push: true
tags: mailcow/backup:latest
@@ -4,9 +4,12 @@ on:
types: [published] types: [published]
jobs: jobs:
build: tweet:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "Get Release Tag"
run: |
RELEASE_TAG=$(curl https://api.github.com/repos/mailcow/mailcow-dockerized/releases/latest | jq -r '.tag_name')
- name: Tweet-trigger-publish-release - name: Tweet-trigger-publish-release
uses: mugi111/tweet-trigger-release@v1.1 uses: mugi111/tweet-trigger-release@v1.1
with: with:
@@ -14,4 +17,4 @@ jobs:
consumer_secret: ${{ secrets.CONSUMER_SECRET }} consumer_secret: ${{ secrets.CONSUMER_SECRET }}
access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }} access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }}
access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }} access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }}
tweet_body: 'A new mailcow-dockerized Release has been Released on GitHub! Checkout our GitHub Page for the latest Release: github.com/mailcow/mailcow-dockerized/releases/latest' tweet_body: 'A new mailcow update has just been released! Checkout the GitHub Page for changelog and more informations: https://github.com/mailcow/mailcow-dockerized/releases/latest'
+6 -2
View File
@@ -1,7 +1,5 @@
# mailcow: dockerized - 🐮 + 🐋 = 💕 # mailcow: dockerized - 🐮 + 🐋 = 💕
## We stand with 🇺🇦
[![Mailcow Integration Tests](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml/badge.svg?branch=master)](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml) [![Mailcow Integration Tests](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml/badge.svg?branch=master)](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml)
[![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/) [![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/)
[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/mailcow_email.svg?style=social&label=Follow%20%40mailcow_email)](https://twitter.com/mailcow_email) [![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/mailcow_email.svg?style=social&label=Follow%20%40mailcow_email)](https://twitter.com/mailcow_email)
@@ -36,3 +34,9 @@ Telegram desktop clients are available for [multiple platforms](https://desktop.
**Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow. **Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow.
Any part of mailcow itself is released under **GNU General Public License, Version 3**. Any part of mailcow itself is released under **GNU General Public License, Version 3**.
mailcow is a registered word mark of The Infrastructure Company GmbH, Parkstr. 42, 47877 Willich, Germany.
The project is managed and maintained by The Infrastructure Company GmbH.
Originated from @andryyy (André)
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
+3
View File
@@ -0,0 +1,3 @@
FROM debian:bullseye-slim
RUN apt update && apt install pigz
+1 -1
View File
@@ -1,4 +1,4 @@
FROM clamav/clamav:0.105.1_base FROM clamav/clamav:1.0_base
LABEL maintainer "André Peters <andre.peters@servercow.de>" LABEL maintainer "André Peters <andre.peters@servercow.de>"
+8 -5
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
@@ -8,11 +8,14 @@ RUN apk add --update --no-cache python3 \
py3-pip \ py3-pip \
openssl \ openssl \
tzdata \ tzdata \
py3-psutil \
&& pip3 install --upgrade pip \ && pip3 install --upgrade pip \
docker \ fastapi \
flask \ uvicorn \
flask-restful aiodocker \
redis
COPY docker-entrypoint.sh /app/
COPY dockerapi.py /app/ COPY dockerapi.py /app/
CMD ["python3", "-u", "/app/dockerapi.py"] ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
+9
View File
@@ -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`
+486 -282
View File
@@ -1,419 +1,623 @@
#!/usr/bin/env python3 from fastapi import FastAPI, Response, Request
import aiodocker
from flask import Flask import psutil
from flask_restful import Resource, Api import sys
from flask import jsonify import re
from flask import Response
from flask import request
from threading import Thread
import docker
import uuid
import signal
import time import time
import os import os
import re import json
import sys import asyncio
import ssl import redis
import socket from datetime import datetime
import subprocess
import traceback
docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
app = Flask(__name__)
api = Api(app)
class containers_get(Resource): containerIds_to_update = []
def get(self): host_stats_isUpdating = False
containers = {} app = FastAPI()
try:
for container in docker_client.containers.list(all=True):
containers.update({container.attrs['Id']: container.attrs})
return containers
except Exception as e:
return jsonify(type='danger', msg=str(e))
class container_get(Resource):
def get(self, container_id): @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(): if container_id and container_id.isalnum():
try: try:
for container in docker_client.containers.list(all=True, filters={"id": container_id}): for container in (await async_docker_client.containers.list()):
return container.attrs 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: 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: else:
return jsonify(type='danger', msg='no or invalid id defined') res = {
"type": "danger",
"msg": "no or invalid id defined"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
@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")
@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 = {}
class container_post(Resource):
def post(self, container_id, post_action):
if container_id and container_id.isalnum() and post_action: if container_id and container_id.isalnum() and post_action:
try: try:
"""Dispatch container_post api call""" """Dispatch container_post api call"""
if post_action == 'exec': if post_action == 'exec':
if not request.json or not 'cmd' in request.json: if not request_json or not 'cmd' in request_json:
return jsonify(type='danger', msg='cmd is missing') res = {
if not request.json or not 'task' in request.json: "type": "danger",
return jsonify(type='danger', msg='task is missing') "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_name = '__'.join(['container_post', str(post_action), str(request.json['cmd']), str(request.json['task']) ]) api_call_method_name = '__'.join(['container_post', str(post_action), str(request_json['cmd']), str(request_json['task']) ])
else: else:
api_call_method_name = '__'.join(['container_post', str(post_action) ]) api_call_method_name = '__'.join(['container_post', str(post_action) ])
api_call_method = getattr(self, api_call_method_name, lambda container_id: jsonify(type='danger', msg='container_post - unknown api call')) 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)) print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
return api_call_method(container_id) return await api_call_method(container_id, request_json)
except Exception as e: except Exception as e:
print("error - container_post: %s" % str(e)) print("error - container_post: %s" % str(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: else:
return jsonify(type='danger', msg='invalid container id or missing action') 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 # api call: container_post - post_action: stop
def container_post__stop(self, container_id): async def container_post__stop(self, container_id, request_json):
for container in docker_client.containers.list(all=True, filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
container.stop() if container._id == container_id:
return jsonify(type='success', msg='command completed successfully') 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 # api call: container_post - post_action: start
def container_post__start(self, container_id): async def container_post__start(self, container_id, request_json):
for container in docker_client.containers.list(all=True, filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
container.start() if container._id == container_id:
return jsonify(type='success', msg='command completed successfully') 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 # api call: container_post - post_action: restart
def container_post__restart(self, container_id): async def container_post__restart(self, container_id, request_json):
for container in docker_client.containers.list(all=True, filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
container.restart() if container._id == container_id:
return jsonify(type='success', msg='command completed successfully') 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 # api call: container_post - post_action: top
def container_post__top(self, container_id): async def container_post__top(self, container_id, request_json):
for container in docker_client.containers.list(all=True, filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
return jsonify(type='success', msg=container.top()) 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()
exec_details = await ps_exec.inspect()
# api call: container_post - post_action: stats if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
def container_post__stats(self, container_id): res = {
for container in docker_client.containers.list(all=True, filters={"id": container_id}): 'type': 'success',
for stat in container.stats(decode=True, stream=True): 'msg': ps_return.data.decode('utf-8')
return jsonify(type='success', msg=stat ) }
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 # api call: container_post - post_action: exec - cmd: mailq - task: delete
def container_post__exec__mailq__delete(self, container_id): async def container_post__exec__mailq__delete(self, container_id, request_json):
if 'items' in request.json: if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$") 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: if filtered_qids:
flagged_qids = ['-d %s' % i for i in 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}): for container in (await self.docker_client.containers.list()):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string]) if container._id == container_id:
return exec_run_handler('generic', postsuper_r) 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 # api call: container_post - post_action: exec - cmd: mailq - task: hold
def container_post__exec__mailq__hold(self, container_id): async def container_post__exec__mailq__hold(self, container_id, request_json):
if 'items' in request.json: if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$") 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: if filtered_qids:
flagged_qids = ['-h %s' % i for i in 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}): for container in (await self.docker_client.containers.list()):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string]) if container._id == container_id:
return exec_run_handler('generic', postsuper_r) 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 # api call: container_post - post_action: exec - cmd: mailq - task: cat
def container_post__exec__mailq__cat(self, container_id): async def container_post__exec__mailq__cat(self, container_id, request_json):
if 'items' in request.json: if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$") 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: 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}): for container in (await self.docker_client.containers.list()):
postcat_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix') if container._id == container_id:
if not postcat_return: postcat_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
postcat_return = 'err: invalid' return await exec_run_handler('utf8_text_only', postcat_exec)
return exec_run_handler('utf8_text_only', postcat_return)
# api call: container_post - post_action: exec - cmd: mailq - task: unhold # api call: container_post - post_action: exec - cmd: mailq - task: unhold
def container_post__exec__mailq__unhold(self, container_id): async def container_post__exec__mailq__unhold(self, container_id, request_json):
if 'items' in request.json: if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$") 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: if filtered_qids:
flagged_qids = ['-H %s' % i for i in 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}): for container in (await self.docker_client.containers.list()):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string]) if container._id == container_id:
return exec_run_handler('generic', postsuper_r) 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 # api call: container_post - post_action: exec - cmd: mailq - task: deliver
def container_post__exec__mailq__deliver(self, container_id): async def container_post__exec__mailq__deliver(self, container_id, request_json):
if 'items' in request.json: if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$") 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: if filtered_qids:
flagged_qids = ['-i %s' % i for i in filtered_qids] flagged_qids = ['-i %s' % i for i in filtered_qids]
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
if container._id == container_id:
for i in flagged_qids: for i in flagged_qids:
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix') 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 # todo: check each exit code
return jsonify(type='success', msg=str("Scheduled immediate delivery")) 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 # api call: container_post - post_action: exec - cmd: mailq - task: list
def container_post__exec__mailq__list(self, container_id): async def container_post__exec__mailq__list(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix') if container._id == container_id:
return exec_run_handler('utf8_text_only', mailq_return) 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 # api call: container_post - post_action: exec - cmd: mailq - task: flush
def container_post__exec__mailq__flush(self, container_id): async def container_post__exec__mailq__flush(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix') if container._id == container_id:
return exec_run_handler('generic', postqueue_r) 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 # api call: container_post - post_action: exec - cmd: mailq - task: super_delete
def container_post__exec__mailq__super_delete(self, container_id): async def container_post__exec__mailq__super_delete(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"]) if container._id == container_id:
return exec_run_handler('generic', postsuper_r) 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 # api call: container_post - post_action: exec - cmd: system - task: fts_rescan
def container_post__exec__system__fts_rescan(self, container_id): async def container_post__exec__system__fts_rescan(self, container_id, request_json):
if 'username' in request.json: if 'username' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request.json['username'].replace("'", "'\\''") + "'"], user='vmail') if container._id == container_id:
if rescan_return.exit_code == 0: rescan_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request_json['username'].replace("'", "'\\''") + "'"], user='vmail')
return jsonify(type='success', msg='fts_rescan: rescan triggered') async with rescan_exec.start(detach=False) as stream:
else: rescan_return = await stream.read_out()
return jsonify(type='warning', msg='fts_rescan error')
if 'all' in request.json: exec_details = await rescan_exec.inspect()
for container in docker_client.containers.list(filters={"id": container_id}): if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail') res = {
if rescan_return.exit_code == 0: 'type': 'success',
return jsonify(type='success', msg='fts_rescan: rescan triggered') 'msg': 'fts_rescan: rescan triggered'
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else: else:
return jsonify(type='warning', msg='fts_rescan error') 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 # api call: container_post - post_action: exec - cmd: system - task: df
def container_post__exec__system__df(self, container_id): async def container_post__exec__system__df(self, container_id, request_json):
if 'dir' in request.json: if 'dir' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
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 container._id == container_id:
if df_return.exit_code == 0: 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')
return df_return.output.decode('utf-8').rstrip() 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: else:
return "0,0,0,0,0,0" return "0,0,0,0,0,0"
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade # api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
def container_post__exec__system__mysql_upgrade(self, container_id): async def container_post__exec__system__mysql_upgrade(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql') if container._id == container_id:
if sql_return.exit_code == 0: 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 matched = False
for line in sql_return.output.decode('utf-8').split("\n"): for line in sql_return.data.decode('utf-8').split("\n"):
if 'is already upgraded to' in line: if 'is already upgraded to' in line:
matched = True matched = True
if matched: if matched:
return jsonify(type='success', msg='mysql_upgrade: already upgraded', text=sql_return.output.decode('utf-8')) 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: else:
container.restart() await container.restart()
return jsonify(type='warning', msg='mysql_upgrade: upgrade was applied', text=sql_return.output.decode('utf-8')) 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: 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 # 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): async def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
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 container._id == container_id:
if sql_return.exit_code == 0: 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')
return jsonify(type='info', msg='mysql_tzinfo_to_sql: command completed successfully', text=sql_return.output.decode('utf-8')) 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: else:
return jsonify(type='error', msg='mysql_tzinfo_to_sql: error running command', text=sql_return.output.decode('utf-8')) 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 # api call: container_post - post_action: exec - cmd: reload - task: dovecot
def container_post__exec__reload__dovecot(self, container_id): async def container_post__exec__reload__dovecot(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/dovecot reload"]) if container._id == container_id:
return exec_run_handler('generic', reload_return) 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 # api call: container_post - post_action: exec - cmd: reload - task: postfix
def container_post__exec__reload__postfix(self, container_id): async def container_post__exec__reload__postfix(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postfix reload"]) if container._id == container_id:
return exec_run_handler('generic', reload_return) 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 # api call: container_post - post_action: exec - cmd: reload - task: nginx
def container_post__exec__reload__nginx(self, container_id): async def container_post__exec__reload__nginx(self, container_id, request_json):
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
reload_return = container.exec_run(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"]) if container._id == container_id:
return exec_run_handler('generic', reload_return) 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 # api call: container_post - post_action: exec - cmd: sieve - task: list
def container_post__exec__sieve__list(self, container_id): async def container_post__exec__sieve__list(self, container_id, request_json):
if 'username' in request.json: if 'username' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"]) if container._id == container_id:
return exec_run_handler('utf8_text_only', sieve_return) 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 # api call: container_post - post_action: exec - cmd: sieve - task: print
def container_post__exec__sieve__print(self, container_id): async def container_post__exec__sieve__print(self, container_id, request_json):
if 'username' in request.json and 'script_name' in request.json: if 'username' in request_json and 'script_name' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"] if container._id == container_id:
sieve_return = container.exec_run(cmd) cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
return exec_run_handler('utf8_text_only', sieve_return) 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 # api call: container_post - post_action: exec - cmd: maildir - task: cleanup
def container_post__exec__maildir__cleanup(self, container_id): async def container_post__exec__maildir__cleanup(self, container_id, request_json):
if 'maildir' in request.json: if 'maildir' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
sane_name = re.sub(r'\W+', '', request.json['maildir']) if container._id == container_id:
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"] sane_name = re.sub(r'\W+', '', request_json['maildir'])
maildir_cleanup = container.exec_run(cmd, user='vmail') 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"]
return exec_run_handler('generic', maildir_cleanup) 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 # api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
def container_post__exec__rspamd__worker_password(self, container_id): async def container_post__exec__rspamd__worker_password(self, container_id, request_json):
if 'raw' in request.json: if 'raw' in request_json:
for container in docker_client.containers.list(filters={"id": container_id}): for container in (await self.docker_client.containers.list()):
cmd = "/usr/bin/rspamadm pw -e -p '" + request.json['raw'].replace("'", "'\\''") + "' 2> /dev/null" if container._id == container_id:
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
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()
matched = False matched = False
for line in cmd_response.split("\n"): if "OK" in rspamd_password_return.data.decode('utf-8'):
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())
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")
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
container.restart()
matched = True matched = True
await container.restart()
if matched: if matched:
return jsonify(type='success', msg='command completed successfully') res = {
'type': 'success',
'msg': 'command completed successfully'
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else: else:
return jsonify(type='danger', msg='command did not complete') res = {
'type': 'danger',
'msg': 'command did not complete'
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
def exec_cmd_container(container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
def recv_socket_data(c_socket, timeout):
c_socket.setblocking(0) async def exec_run_handler(type, exec_obj):
total_data=[]; async with exec_obj.start(detach=False) as stream:
data=''; exec_return = await stream.read_out()
begin=time.time()
while True: if exec_return == None:
if total_data and time.time()-begin > timeout: exec_return = ""
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: else:
#sleep for sometime to indicate a gap exec_return = exec_return.data.decode('utf-8')
time.sleep(0.1)
break
except:
pass
return ''.join(total_data)
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
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 type == 'generic':
if output.exit_code == 0: exec_details = await exec_obj.inspect()
return jsonify(type='success', msg='command completed successfully') 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: 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': if type == 'utf8_text_only':
r = Response(response=output.output.decode('utf-8'), status=200, mimetype="text/plain") return Response(content=exec_return, media_type="text/plain")
r.headers["Content-Type"] = "text/plain; charset=utf-8"
return r
class GracefulKiller: async def get_host_stats(wait=5):
kill_now = False global host_stats_isUpdating
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
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: try:
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) system_time = datetime.now()
ctx.check_hostname = False host_stats = {
ctx.load_cert_chain(certfile='/app/dockerapi_cert.pem', keyfile='/app/dockerapi_key.pem') "cpu": {
except: "cores": psutil.cpu_count(),
print ("Cannot initialize TLS, retrying in 5s...") "usage": psutil.cpu_percent()
time.sleep(5) },
app.run(debug=False, host='0.0.0.0', port=443, threaded=True, ssl_context=ctx) "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') redis_client.set('host_stats', json.dumps(host_stats), ex=10)
api.add_resource(container_get, '/containers/<string:container_id>/json') except Exception as e:
api.add_resource(container_post, '/containers/<string:container_id>/<string:post_action>') res = {
"type": "danger",
"msg": str(e)
}
print(json.dumps(res, indent=4))
if __name__ == '__main__': await asyncio.sleep(wait)
api_thread = Thread(target=startFlaskAPI) host_stats_isUpdating = False
api_thread.daemon = True
api_thread.start()
killer = GracefulKiller() async def get_container_stats(container_id, wait=5, stop=False):
while True: global containerIds_to_update
time.sleep(1)
if killer.kill_now: if container_id and container_id.isalnum():
break try:
print ("Stopping dockerapi-mailcow") 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')
+2 -8
View File
@@ -166,17 +166,11 @@ while ($row = $sth->fetchrow_arrayref()) {
$success = 1; $success = 1;
} }
$keep_job_active = 1; $update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
if (defined $exit_status && $exit_status eq "EXIT_AUTHENTICATION_FAILURE_USER1") {
$keep_job_active = 0;
}
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ?, active = ? WHERE id = ?");
$update->bind_param( 1, ${stdout} ); $update->bind_param( 1, ${stdout} );
$update->bind_param( 2, ${success} ); $update->bind_param( 2, ${success} );
$update->bind_param( 3, ${exit_status} ); $update->bind_param( 3, ${exit_status} );
$update->bind_param( 4, ${keep_job_active} ); $update->bind_param( 4, ${id} );
$update->bind_param( 5, ${id} );
$update->execute(); $update->execute();
} catch { } catch {
$update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?"); $update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ENV XTABLES_LIBDIR /usr/lib/xtables ENV XTABLES_LIBDIR /usr/lib/xtables
+20 -11
View File
@@ -97,9 +97,9 @@ def refreshF2bregex():
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+' f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+' f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+' f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
f2bregex[6] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),' f2bregex[6] = '-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
f2bregex[7] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' f2bregex[7] = '-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
f2bregex[8] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+' f2bregex[8] = '-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked' f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+' f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False)) r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
@@ -346,6 +346,8 @@ def snat4(snat_target):
rule.dst = '!' + rule.src rule.dst = '!' + rule.src
target = rule.create_target("SNAT") target = rule.create_target("SNAT")
target.to_source = snat_target target.to_source = snat_target
match = rule.create_match("comment")
match.comment = f'{int(round(time.time()))}'
return rule return rule
while not quit_now: while not quit_now:
@@ -356,15 +358,22 @@ def snat4(snat_target):
table.refresh() table.refresh()
chain = iptc.Chain(table, 'POSTROUTING') chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False table.autocommit = False
if get_snat4_rule() not in chain.rules: new_rule = get_snat4_rule()
logCrit('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat4_rule().src, snat_target)) for position, rule in enumerate(chain.rules):
chain.insert_rule(get_snat4_rule()) match = all((
table.commit() new_rule.get_src() == rule.get_src(),
new_rule.get_dst() == rule.get_dst(),
new_rule.target.parameters == rule.target.parameters,
new_rule.target.name == rule.target.name
))
if position == 0:
if not match:
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else: else:
for position, item in enumerate(chain.rules): if match:
if item == get_snat4_rule(): logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
if position != 0: chain.delete_rule(rule)
chain.delete_rule(get_snat4_rule())
table.commit() table.commit()
table.autocommit = True table.autocommit = True
except: except:
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
WORKDIR /app WORKDIR /app
+25 -11
View File
@@ -1,12 +1,12 @@
FROM php:8.0-fpm-alpine3.16 FROM php:8.1-fpm-alpine3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ENV APCU_PECL 5.1.21 ENV APCU_PECL 5.1.22
ENV IMAGICK_PECL 3.7.0 ENV IMAGICK_PECL 3.7.0
# Mailparse is pulled from master branch ENV MAILPARSE_PECL 3.1.4
#ENV MAILPARSE_PECL 3.0.2
ENV MEMCACHED_PECL 3.2.0 ENV MEMCACHED_PECL 3.2.0
ENV REDIS_PECL 5.3.7 ENV REDIS_PECL 5.3.7
ENV COMPOSER 2.4.4
RUN apk add -U --no-cache autoconf \ RUN apk add -U --no-cache autoconf \
aspell-dev \ aspell-dev \
@@ -18,6 +18,7 @@ RUN apk add -U --no-cache autoconf \
freetype-dev \ freetype-dev \
g++ \ g++ \
git \ git \
gettext \
gettext-dev \ gettext-dev \
gmp-dev \ gmp-dev \
gnupg \ gnupg \
@@ -27,8 +28,11 @@ RUN apk add -U --no-cache autoconf \
imagemagick-dev \ imagemagick-dev \
imap-dev \ imap-dev \
jq \ jq \
libavif \
libavif-dev \
libjpeg-turbo \ libjpeg-turbo \
libjpeg-turbo-dev \ libjpeg-turbo-dev \
libmemcached \
libmemcached-dev \ libmemcached-dev \
libpng \ libpng \
libpng-dev \ libpng-dev \
@@ -38,7 +42,9 @@ RUN apk add -U --no-cache autoconf \
libtool \ libtool \
libwebp-dev \ libwebp-dev \
libxml2-dev \ libxml2-dev \
libxpm \
libxpm-dev \ libxpm-dev \
libzip \
libzip-dev \ libzip-dev \
make \ make \
mysql-client \ mysql-client \
@@ -49,22 +55,24 @@ RUN apk add -U --no-cache autoconf \
samba-client \ samba-client \
zlib-dev \ zlib-dev \
tzdata \ tzdata \
&& git clone https://github.com/php/pecl-mail-mailparse \ && pecl install mailparse-${MAILPARSE_PECL} \
&& cd pecl-mail-mailparse \ && pecl install redis-${REDIS_PECL} \
&& pecl install package.xml \ && pecl install memcached-${MEMCACHED_PECL} \
&& cd .. \ && pecl install APCu-${APCU_PECL} \
&& rm -r pecl-mail-mailparse \ && pecl install imagick-${IMAGICK_PECL} \
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} \
&& docker-php-ext-enable apcu imagick memcached mailparse redis \ && docker-php-ext-enable apcu imagick memcached mailparse redis \
&& pecl clear-cache \ && pecl clear-cache \
&& docker-php-ext-configure intl \ && docker-php-ext-configure intl \
&& docker-php-ext-configure exif \ && docker-php-ext-configure exif \
&& docker-php-ext-configure gd --with-freetype=/usr/include/ \ && docker-php-ext-configure gd --with-freetype=/usr/include/ \
--with-jpeg=/usr/include/ \ --with-jpeg=/usr/include/ \
--with-webp \
--with-xpm \
--with-avif \
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \ && docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \ && docker-php-ext-configure imap --with-imap --with-imap-ssl \
&& docker-php-ext-install -j 4 imap \ && docker-php-ext-install -j 4 imap \
&& curl --silent --show-error https://getcomposer.org/installer | php \ && curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER} \
&& mv composer.phar /usr/local/bin/composer \ && mv composer.phar /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer \ && chmod +x /usr/local/bin/composer \
&& apk del --purge autoconf \ && apk del --purge autoconf \
@@ -72,15 +80,21 @@ RUN apk add -U --no-cache autoconf \
cyrus-sasl-dev \ cyrus-sasl-dev \
freetype-dev \ freetype-dev \
g++ \ g++ \
gettext-dev \
icu-dev \ icu-dev \
imagemagick-dev \ imagemagick-dev \
imap-dev \ imap-dev \
libavif-dev \
libjpeg-turbo-dev \ libjpeg-turbo-dev \
libmemcached-dev \
libpng-dev \ libpng-dev \
libressl-dev \ libressl-dev \
libwebp-dev \ libwebp-dev \
libxml2-dev \ libxml2-dev \
libxpm-dev \
libzip-dev \
make \ make \
openldap-dev \
pcre-dev \ pcre-dev \
zlib-dev zlib-dev
+1
View File
@@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y \
COPY settings.conf /etc/rspamd/settings.conf COPY settings.conf /etc/rspamd/settings.conf
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua 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 COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"] ENTRYPOINT ["/docker-entrypoint.sh"]
+12
View File
@@ -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
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.17
LABEL maintainer "André Peters <andre.peters@servercow.de>" LABEL maintainer "André Peters <andre.peters@servercow.de>"
# Installation # Installation
-1
View File
@@ -3,7 +3,6 @@
/.*episerver.*/i /.*episerver.*/i
/.*supergewinne.*/i /.*supergewinne.*/i
/List-Unsubscribe.*nbps\.eu/i /List-Unsubscribe.*nbps\.eu/i
/X-Mailer: AWeber.*/i
/.*regiofinder.*/i /.*regiofinder.*/i
/.*EmailSocket.*/i /.*EmailSocket.*/i
/List-Unsubscribe:.*respread.*/i /List-Unsubscribe:.*respread.*/i
@@ -16,8 +16,7 @@ rules {
backend = "http"; backend = "http";
url = "http://nginx:9081/pushover.php"; url = "http://nginx:9081/pushover.php";
selector = "mailcow_rcpt"; selector = "mailcow_rcpt";
# Only return msgid, do not parse the full message formatter = "json";
formatter = "msgid";
meta_headers = true; meta_headers = true;
} }
} }
+25 -2
View File
@@ -47,12 +47,14 @@ if (!function_exists('getallheaders')) {
} }
$headers = getallheaders(); $headers = getallheaders();
$json_body = json_decode(file_get_contents('php://input'));
$qid = $headers['X-Rspamd-Qid']; $qid = $headers['X-Rspamd-Qid'];
$rcpts = $headers['X-Rspamd-Rcpt']; $rcpts = $headers['X-Rspamd-Rcpt'];
$sender = $headers['X-Rspamd-From']; $sender = $headers['X-Rspamd-From'];
$ip = $headers['X-Rspamd-Ip']; $ip = $headers['X-Rspamd-Ip'];
$subject = $headers['X-Rspamd-Subject']; $subject = $headers['X-Rspamd-Subject'];
$messageid= $json_body->message_id;
$priority = 0; $priority = 0;
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true); $symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
@@ -65,6 +67,20 @@ if (is_array($symbols_array)) {
} }
} }
$sender_address = $json_body->header_from[0];
$sender_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
$sender_address = $matches['address'];
$sender_name = trim($matches['name'], '"\' ');
}
$to_address = $json_body->header_to[0];
$to_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
$to_address = $matches['address'];
$to_name = trim($matches['name'], '"\' ');
}
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Loop through all rcpts // Loop through all rcpts
@@ -229,9 +245,16 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
$post_fields = array( $post_fields = array(
"token" => $api_data['token'], "token" => $api_data['token'],
"user" => $api_data['key'], "user" => $api_data['key'],
"title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $title)), "title" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title)
),
"priority" => $priority, "priority" => $priority,
"message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $text)) "message" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text)
),
"sound" => $attributes['sound'] ?? "pushover"
); );
if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) { if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
$post_fields['expire'] = 600; $post_fields['expire'] = 600;
+3 -3
View File
@@ -13,12 +13,12 @@
Please check the logs or contact support if the error persists.</p> Please check the logs or contact support if the error persists.</p>
<h2>Quick debugging</h2> <h2>Quick debugging</h2>
<p>Check Nginx and PHP logs:</p> <p>Check Nginx and PHP logs:</p>
<pre>docker-compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre> <pre>docker compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre>
<p>Make sure your SQL credentials in mailcow.conf (a link to .env) do fit your initialized SQL volume. If you see an access denied, you might have the wrong mailcow.conf:</p> <p>Make sure your SQL credentials in mailcow.conf (a link to .env) do fit your initialized SQL volume. If you see an access denied, you might have the wrong mailcow.conf:</p>
<pre>source mailcow.conf ; docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre> <pre>source mailcow.conf ; docker compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre>
<p>In case of a previous failed installation, create a backup of your existing data, followed by removing all volumes and starting over (<b>NEVER</b> do this with a production system, it will remove <b>ALL</b> data):</p> <p>In case of a previous failed installation, create a backup of your existing data, followed by removing all volumes and starting over (<b>NEVER</b> do this with a production system, it will remove <b>ALL</b> data):</p>
<pre>BACKUP_LOCATION=/tmp/ ./helper-scripts/backup_and_restore.sh backup all</pre> <pre>BACKUP_LOCATION=/tmp/ ./helper-scripts/backup_and_restore.sh backup all</pre>
<pre>docker-compose down --volumes ; docker-compose up -d</pre> <pre>docker compose down --volumes ; docker compose up -d</pre>
<p>Make sure your timezone is correct. Use "America/New_York" for example, do not use spaces. Check <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">here</a> for a list.</p> <p>Make sure your timezone is correct. Use "America/New_York" for example, do not use spaces. Check <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">here</a> for a list.</p>
<br>Click to learn more about <a style="color:red;text-decoration:none;" href="https://mailcow.github.io/mailcow-dockerized-docs/#get-support" target="_blank">getting support.</a> <br>Click to learn more about <a style="color:red;text-decoration:none;" href="https://mailcow.github.io/mailcow-dockerized-docs/#get-support" target="_blank">getting support.</a>
</body> </body>
+1 -6
View File
@@ -10,9 +10,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI']; $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$tfa_data = get_tfa(); $tfa_data = get_tfa();
$fido2_data = fido2(array("action" => "get_friendly_names")); $fido2_data = fido2(array("action" => "get_friendly_names"));
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/admin.js'); $js_minifier->add('/web/js/site/admin.js');
$js_minifier->add('/web/js/presets/rspamd.js'); $js_minifier->add('/web/js/presets/rspamd.js');
@@ -83,15 +80,12 @@ foreach ($RSPAMD_MAPS['regex'] as $rspamd_regex_desc => $rspamd_regex_map) {
]; ];
} }
$template = 'admin.twig'; $template = 'admin.twig';
$template_data = [ $template_data = [
'tfa_data' => $tfa_data, 'tfa_data' => $tfa_data,
'tfa_id' => @$_SESSION['tfa_id'], 'tfa_id' => @$_SESSION['tfa_id'],
'fido2_cid' => @$_SESSION['fido2_cid'], 'fido2_cid' => @$_SESSION['fido2_cid'],
'fido2_data' => $fido2_data, 'fido2_data' => $fido2_data,
'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'),
'api' => [ 'api' => [
'ro' => admin_api('ro', 'get'), 'ro' => admin_api('ro', 'get'),
'rw' => admin_api('rw', 'get'), 'rw' => admin_api('rw', 'get'),
@@ -112,6 +106,7 @@ $template_data = [
'password_complexity' => password_complexity('get'), 'password_complexity' => password_complexity('get'),
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'], 'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
'lang_admin' => json_encode($lang['admin']), 'lang_admin' => json_encode($lang['admin']),
'lang_datatables' => json_encode($lang['datatables'])
]; ];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
+59
View File
@@ -3349,6 +3349,7 @@ paths:
evaluate_x_prio: "0" evaluate_x_prio: "0"
key: 21e8918e1jksdjcpis712 key: 21e8918e1jksdjcpis712
only_x_prio: "0" only_x_prio: "0"
sound: "pushover"
senders: "" senders: ""
senders_regex: "" senders_regex: ""
text: "" text: ""
@@ -3392,6 +3393,7 @@ paths:
evaluate_x_prio: "0" evaluate_x_prio: "0"
key: 21e8918e1jksdjcpis712 key: 21e8918e1jksdjcpis712
only_x_prio: "0" only_x_prio: "0"
sound: "pushover"
senders: "" senders: ""
senders_regex: "" senders_regex: ""
text: "" text: ""
@@ -3413,6 +3415,9 @@ paths:
only_x_prio: only_x_prio:
description: Only send push for prio mails description: Only send push for prio mails
type: number type: number
sound:
description: Set notification sound
type: string
senders: senders:
description: Only send push for emails from these senders description: Only send push for emails from these senders
type: string type: string
@@ -5501,6 +5506,60 @@ paths:
attr: attr:
spam_score: "8,15" spam_score: "8,15"
summary: Edit mailbox spam filter score summary: Edit mailbox spam filter score
"/api/v1/get/mailbox/all/{domain}":
get:
parameters:
- description: name of domain
in: path
name: domain
required: false
schema:
type: string
- description: e.g. api-key-string
example: api-key-string
in: header
name: X-API-Key
required: false
schema:
type: string
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
- active: "1"
attributes:
force_pw_update: "0"
mailbox_format: "maildir:"
quarantine_notification: never
sogo_access: "1"
tls_enforce_in: "0"
tls_enforce_out: "0"
domain: domain3.tld
is_relayed: 0
local_part: info
max_new_quota: 10737418240
messages: 0
name: Full name
percent_class: success
percent_in_use: 0
quota: 3221225472
quota_used: 0
rl: false
spam_aliases: 0
username: info@domain3.tld
tags: ["tag1", "tag2"]
description: OK
headers: {}
tags:
- Mailboxes
description: You can list all mailboxes existing in system for a specific domain.
operationId: Get mailboxes of a domain
summary: Get mailboxes of a domain
tags: tags:
- name: Domains - name: Domains
-11
View File
@@ -1,11 +0,0 @@
/*!
* bootswatch v3.4.1
* Homepage: http://bootswatch.com
* Copyright 2012-2019 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v3.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*{box-sizing:border-box}:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Source Sans Pro","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#158cba;text-decoration:none}a:focus,a:hover{color:#158cba;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:5px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #eee;border-radius:4px;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:400;line-height:1.1;color:#333}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#999}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-Line truncated
+1 -1
View File
@@ -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}}
+487
View File
@@ -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 */
-6
View File
@@ -1,6 +0,0 @@
/*!
* Bootstrap-select v1.12.2 (http://silviomoreto.github.io/bootstrap-select)
*
* Copyright 2013-2017 bootstrap-select
* Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
*/select.bs-select-hidden,select.selectpicker{display:none!important}.bootstrap-select{width:220px\9}.bootstrap-select>.dropdown-toggle{width:100%;padding-right:25px;z-index:1}.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:#999}.bootstrap-select>select{position:absolute!important;bottom:0;left:50%;display:block!important;width:.5px!important;height:100%!important;padding:0!important;opacity:0!important;border:none}.bootstrap-select>select.mobile-device{top:0;left:0;display:block!important;width:100%!important;z-index:2}.error .bootstrap-select .dropdown-toggle,.has-error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select.fit-width{width:auto!important}.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn){width:220px}.bootstrap-select .dropdown-toggle:focus{outline:thin dotted #333!important;outline:5px auto -webkit-focus-ring-color!important;outline-offset:-2px}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:none}.bootstrap-select.form-control:not([class*=col-]){width:100%}.bootstrap-select.form-control.input-group-btn{z-index:auto}.bootstrap-select.form-control.input-group-btn:not(:first-child):not(:last-child)>.btn{border-radius:0}.bootstrap-select.btn-group:not(.input-group-btn),.bootstrap-select.btn-group[class*=col-]{float:none;display:inline-block;margin-left:0}.bootstrap-select.btn-group.dropdown-menu-right,.bootstrap-select.btn-group[class*=col-].dropdown-menu-right,.row .bootstrap-select.btn-group[class*=col-].dropdown-menu-right{float:right}.form-group .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group{margin-bottom:0}.form-group-lg .bootstrap-select.btn-group.form-control,.form-group-sm .bootstrap-select.btn-group.form-control{padding:0}.form-group-lg .bootstrap-select.btn-group.form-control .dropdown-toggle,.form-group-sm .bootstrap-select.btn-group.form-control .dropdown-toggle{height:100%;font-size:inherit;line-height:inherit;border-radius:inherit}.form-inline .bootstrap-select.btn-group .form-control{width:100%}.bootstrap-select.btn-group.disabled,.bootstrap-select.btn-group>.disabled{cursor:not-allowed}.bootstrap-select.btn-group.disabled:focus,.bootstrap-select.btn-group>.disabled:focus{outline:0!important}.bootstrap-select.btn-group.bs-container{position:absolute;height:0!important;padding:0!important}.bootstrap-select.btn-group.bs-container .dropdown-menu{z-index:1060}.bootstrap-select.btn-group .dropdown-toggle .filter-option{display:inline-block;overflow:hidden;width:100%;text-align:left}.bootstrap-select.btn-group .dropdown-toggle .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group[class*=col-] .dropdown-toggle{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .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.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li.active small{color:#fff}.bootstrap-select.btn-group .dropdown-menu li.disabled a{cursor:not-allowed}.bootstrap-select.btn-group .dropdown-menu li a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.bootstrap-select.btn-group .dropdown-menu li a.opt{position:relative;padding-left:2.25em}.bootstrap-select.btn-group .dropdown-menu li a span.check-mark{display:none}.bootstrap-select.btn-group .dropdown-menu li a span.text{display:inline-block}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:.5em}.bootstrap-select.btn-group .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,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .no-results{padding:3px;background:#f5f5f5;margin:0 5px;white-space:nowrap}.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option{position:static}.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret{position:static;top:auto;margin-top:-1px}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark{position:absolute;display:inline-block;right:15px;margin-top:5px}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle{z-index:1061}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';border-left:7px solidLine truncated
-323
View File
@@ -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;
}
+1 -1
View File
@@ -1 +1 @@
.flag-icon-background{background-size:contain;background-position:50%;background-repeat:no-repeat}.flag-icon{background-size:contain;background-position:50%;background-repeat:no-repeat;position:relative;display:inline-block;width:1.33333333em;line-height:1em}.flag-icon:before{content:'\00a0'}.flag-icon.flag-icon-squared{width:1em}.flag-icon-ad{background-image:url(../flags/4x3/ad.svg)}.flag-icon-ad.flag-icon-squared{background-image:url(../flags/1x1/ad.svg)}.flag-icon-ae{background-image:url(../flags/4x3/ae.svg)}.flag-icon-ae.flag-icon-squared{background-image:url(../flags/1x1/ae.svg)}.flag-icon-af{background-image:url(../flags/4x3/af.svg)}.flag-icon-af.flag-icon-squared{background-image:url(../flags/1x1/af.svg)}.flag-icon-ag{background-image:url(../flags/4x3/ag.svg)}.flag-icon-ag.flag-icon-squared{background-image:url(../flags/1x1/ag.svg)}.flag-icon-ai{background-image:url(../flags/4x3/ai.svg)}.flag-icon-ai.flag-icon-squared{background-image:url(../flags/1x1/ai.svg)}.flag-icon-al{background-image:url(../flags/4x3/al.svg)}.flag-icon-al.flag-icon-squared{background-image:url(../flags/1x1/al.svg)}.flag-icon-am{background-image:url(../flags/4x3/am.svg)}.flag-icon-am.flag-icon-squared{background-image:url(../flags/1x1/am.svg)}.flag-icon-ao{background-image:url(../flags/4x3/ao.svg)}.flag-icon-ao.flag-icon-squared{background-image:url(../flags/1x1/ao.svg)}.flag-icon-aq{background-image:url(../flags/4x3/aq.svg)}.flag-icon-aq.flag-icon-squared{background-image:url(../flags/1x1/aq.svg)}.flag-icon-ar{background-image:url(../flags/4x3/ar.svg)}.flag-icon-ar.flag-icon-squared{background-image:url(../flags/1x1/ar.svg)}.flag-icon-as{background-image:url(../flags/4x3/as.svg)}.flag-icon-as.flag-icon-squared{background-image:url(../flags/1x1/as.svg)}.flag-icon-at{background-image:url(../flags/4x3/at.svg)}.flag-icon-at.flag-icon-squared{background-image:url(../flags/1x1/at.svg)}.flag-icon-au{background-image:url(../flags/4x3/au.svg)}.flag-icon-au.flag-icon-squared{background-image:url(../flags/1x1/au.svg)}.flag-icon-aw{background-image:url(../flags/4x3/aw.svg)}.flag-icon-aw.flag-icon-squared{background-image:url(../flags/1x1/aw.svg)}.flag-icon-ax{background-image:url(../flags/4x3/ax.svg)}.flag-icon-ax.flag-icon-squared{background-image:url(../flags/1x1/ax.svg)}.flag-icon-az{background-image:url(../flags/4x3/az.svg)}.flag-icon-az.flag-icon-squared{background-image:url(../flags/1x1/az.svg)}.flag-icon-ba{background-image:url(../flags/4x3/ba.svg)}.flag-icon-ba.flag-icon-squared{background-image:url(../flags/1x1/ba.svg)}.flag-icon-bb{background-image:url(../flags/4x3/bb.svg)}.flag-icon-bb.flag-icon-squared{background-image:url(../flags/1x1/bb.svg)}.flag-icon-bd{background-image:url(../flags/4x3/bd.svg)}.flag-icon-bd.flag-icon-squared{background-image:url(../flags/1x1/bd.svg)}.flag-icon-be{background-image:url(../flags/4x3/be.svg)}.flag-icon-be.flag-icon-squared{background-image:url(../flags/1x1/be.svg)}.flag-icon-bf{background-image:url(../flags/4x3/bf.svg)}.flag-icon-bf.flag-icon-squared{background-image:url(../flags/1x1/bf.svg)}.flag-icon-bg{background-image:url(../flags/4x3/bg.svg)}.flag-icon-bg.flag-icon-squared{background-image:url(../flags/1x1/bg.svg)}.flag-icon-bh{background-image:url(../flags/4x3/bh.svg)}.flag-icon-bh.flag-icon-squared{background-image:url(../flags/1x1/bh.svg)}.flag-icon-bi{background-image:url(../flags/4x3/bi.svg)}.flag-icon-bi.flag-icon-squared{background-image:url(../flags/1x1/bi.svg)}.flag-icon-bj{background-image:url(../flags/4x3/bj.svg)}.flag-icon-bj.flag-icon-squared{background-image:url(../flags/1x1/bj.svg)}.flag-icon-bl{background-image:url(../flags/4x3/bl.svg)}.flag-icon-bl.flag-icon-squared{background-image:url(../flags/1x1/bl.svg)}.flag-icon-bm{background-image:url(../flags/4x3/bm.svg)}.flag-icon-bm.flag-icon-squared{background-image:url(../flags/1x1/bm.svg)}.flag-icon-bn{background-image:url(../flags/4x3/bn.svg)}.flag-icon-bn.flag-icon-squared{background-image:url(../flags/1x1/bn.svg)}.flag-icon-bo{background-image:url(../flags/4x3/bo.svg)}.flag-icon-bo.flag-icon-squared{background-image:url(../flags/1x1/bo.svg)}.flag-icon-bq{background-image:url(../flags/4x3/bq.svg)}.flag-icon-bq.flag-icon-squared{background-image:url(../flags/1x1/bq.svg)}.flag-icon-br{background-image:url(../flags/4x3/br.svg)}.flag-icon-br.flag-icon-squared{background-image:url(../flags/1x1/br.svg)}.flag-icon-bs{background-image:url(../flags/4x3/bs.svg)}.flag-icon-bs.flag-icon-squared{background-image:url(../flags/1x1/bs.svg)}.flag-icon-bt{background-image:url(../flags/4x3/bt.svg)}.flag-icon-bt.flag-icon-squared{background-image:url(../flags/1x1/bt.svg)}.flag-icon-bv{background-image:url(../flags/4x3/bv.svg)}.flag-icon-bv.flag-icon-squared{background-image:url(../flags/1x1/bv.svg)}.flag-icon-bw{background-image:url(../flags/4x3/bw.svg)}.flag-icon-bw.flag-icon-squared{background-image:url(../flags/1x1/bw.svg)}.flag-icon-by{background-image:url(../flags/4x3/by.svg)}.flag-icon-by.flag-icon-squared{background-image:url(../flagsLine truncated .flag-icon-background{background-size:contain;background-position:50%;background-repeat:no-repeat}.flag-icon{background-size:contain;background-position:50%;background-repeat:no-repeat;position:relative;display:inline-block;width:1.33333333em;line-height:1em}.flag-icon:before{content:'\00a0'}.flag-icon.flag-icon-squared{width:1em}.flag-icon-ad{background-image:url(../flags/4x3/ad.svg)}.flag-icon-ad.flag-icon-squared{background-image:url(../flags/1x1/ad.svg)}.flag-icon-ae{background-image:url(../flags/4x3/ae.svg)}.flag-icon-ae.flag-icon-squared{background-image:url(../flags/1x1/ae.svg)}.flag-icon-af{background-image:url(../flags/4x3/af.svg)}.flag-icon-af.flag-icon-squared{background-image:url(../flags/1x1/af.svg)}.flag-icon-ag{background-image:url(../flags/4x3/ag.svg)}.flag-icon-ag.flag-icon-squared{background-image:url(../flags/1x1/ag.svg)}.flag-icon-ai{background-image:url(../flags/4x3/ai.svg)}.flag-icon-ai.flag-icon-squared{background-image:url(../flags/1x1/ai.svg)}.flag-icon-al{background-image:url(../flags/4x3/al.svg)}.flag-icon-al.flag-icon-squared{background-image:url(../flags/1x1/al.svg)}.flag-icon-am{background-image:url(../flags/4x3/am.svg)}.flag-icon-am.flag-icon-squared{background-image:url(../flags/1x1/am.svg)}.flag-icon-ao{background-image:url(../flags/4x3/ao.svg)}.flag-icon-ao.flag-icon-squared{background-image:url(../flags/1x1/ao.svg)}.flag-icon-aq{background-image:url(../flags/4x3/aq.svg)}.flag-icon-aq.flag-icon-squared{background-image:url(../flags/1x1/aq.svg)}.flag-icon-ar{background-image:url(../flags/4x3/ar.svg)}.flag-icon-ar.flag-icon-squared{background-image:url(../flags/1x1/ar.svg)}.flag-icon-as{background-image:url(../flags/4x3/as.svg)}.flag-icon-as.flag-icon-squared{background-image:url(../flags/1x1/as.svg)}.flag-icon-at{background-image:url(../flags/4x3/at.svg)}.flag-icon-at.flag-icon-squared{background-image:url(../flags/1x1/at.svg)}.flag-icon-au{background-image:url(../flags/4x3/au.svg)}.flag-icon-au.flag-icon-squared{background-image:url(../flags/1x1/au.svg)}.flag-icon-aw{background-image:url(../flags/4x3/aw.svg)}.flag-icon-aw.flag-icon-squared{background-image:url(../flags/1x1/aw.svg)}.flag-icon-ax{background-image:url(../flags/4x3/ax.svg)}.flag-icon-ax.flag-icon-squared{background-image:url(../flags/1x1/ax.svg)}.flag-icon-az{background-image:url(../flags/4x3/az.svg)}.flag-icon-az.flag-icon-squared{background-image:url(../flags/1x1/az.svg)}.flag-icon-ba{background-image:url(../flags/4x3/ba.svg)}.flag-icon-ba.flag-icon-squared{background-image:url(../flags/1x1/ba.svg)}.flag-icon-bb{background-image:url(../flags/4x3/bb.svg)}.flag-icon-bb.flag-icon-squared{background-image:url(../flags/1x1/bb.svg)}.flag-icon-bd{background-image:url(../flags/4x3/bd.svg)}.flag-icon-bd.flag-icon-squared{background-image:url(../flags/1x1/bd.svg)}.flag-icon-be{background-image:url(../flags/4x3/be.svg)}.flag-icon-be.flag-icon-squared{background-image:url(../flags/1x1/be.svg)}.flag-icon-bf{background-image:url(../flags/4x3/bf.svg)}.flag-icon-bf.flag-icon-squared{background-image:url(../flags/1x1/bf.svg)}.flag-icon-bg{background-image:url(../flags/4x3/bg.svg)}.flag-icon-bg.flag-icon-squared{background-image:url(../flags/1x1/bg.svg)}.flag-icon-bh{background-image:url(../flags/4x3/bh.svg)}.flag-icon-bh.flag-icon-squared{background-image:url(../flags/1x1/bh.svg)}.flag-icon-bi{background-image:url(../flags/4x3/bi.svg)}.flag-icon-bi.flag-icon-squared{background-image:url(../flags/1x1/bi.svg)}.flag-icon-bj{background-image:url(../flags/4x3/bj.svg)}.flag-icon-bj.flag-icon-squared{background-image:url(../flags/1x1/bj.svg)}.flag-icon-bl{background-image:url(../flags/4x3/bl.svg)}.flag-icon-bl.flag-icon-squared{background-image:url(../flags/1x1/bl.svg)}.flag-icon-bm{background-image:url(../flags/4x3/bm.svg)}.flag-icon-bm.flag-icon-squared{background-image:url(../flags/1x1/bm.svg)}.flag-icon-bn{background-image:url(../flags/4x3/bn.svg)}.flag-icon-bn.flag-icon-squared{background-image:url(../flags/1x1/bn.svg)}.flag-icon-bo{background-image:url(../flags/4x3/bo.svg)}.flag-icon-bo.flag-icon-squared{background-image:url(../flags/1x1/bo.svg)}.flag-icon-bq{background-image:url(../flags/4x3/bq.svg)}.flag-icon-bq.flag-icon-squared{background-image:url(../flags/1x1/bq.svg)}.flag-icon-br{background-image:url(../flags/4x3/br.svg)}.flag-icon-br.flag-icon-squared{background-image:url(../flags/1x1/br.svg)}.flag-icon-bs{background-image:url(../flags/4x3/bs.svg)}.flag-icon-bs.flag-icon-squared{background-image:url(../flags/1x1/bs.svg)}.flag-icon-bt{background-image:url(../flags/4x3/bt.svg)}.flag-icon-bt.flag-icon-squared{background-image:url(../flags/1x1/bt.svg)}.flag-icon-bv{background-image:url(../flags/4x3/bv.svg)}.flag-icon-bv.flag-icon-squared{background-image:url(../flags/1x1/bv.svg)}.flag-icon-bw{background-image:url(../flags/4x3/bw.svg)}.flag-icon-bw.flag-icon-squared{background-image:url(../flags/1x1/bw.svg)}.flag-icon-by{background-image:url(../flags/4x3/by.svg)}.flag-icon-by.flag-icon-squared{background-image:url(../flagsLine truncated
File renamed without changes.
File renamed without changes.
+687
View File
@@ -0,0 +1,687 @@
/*
* 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.13.1/r-2.4.0/sl-1.5.0
*
* Included libraries:
* DataTables 1.13.1, Responsive 2.4.0, Select 1.5.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.8em;
}
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 > tbody > tr.selected a {
color: #090a0b;
}
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_wrapper div.dt-row {
position: relative;
}
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.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 > tr > td.select-checkbox,
table.dataTable > tbody > tr > th.select-checkbox {
position: relative;
}
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after,
table.dataTable > tbody > tr > th.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:after {
display: block;
position: absolute;
top: 1.2em;
left: 50%;
width: 12px;
height: 12px;
box-sizing: border-box;
}
table.dataTable > tbody > tr > td.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:before {
content: " ";
margin-top: -5px;
margin-left: -6px;
border: 1px solid black;
border-radius: 3px;
}
table.dataTable > tbody > tr.selected > td.select-checkbox:before,
table.dataTable > tbody > tr.selected > th.select-checkbox:before {
border: 1px solid white;
}
table.dataTable > tbody > tr.selected > td.select-checkbox:after,
table.dataTable > tbody > 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 > tr > td.select-checkbox:before,
table.dataTable.compact > tbody > tr > th.select-checkbox:before {
margin-top: -12px;
}
table.dataTable.compact > tbody > tr.selected > td.select-checkbox:after,
table.dataTable.compact > tbody > 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
View File
@@ -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-face {
font-family: "bootstrap-icons"; font-family: "bootstrap-icons";
src: url("/fonts/bootstrap-icons.woff2?45695e8b569b2b0178db2713ca47065c") format("woff2"), src: url("/fonts/bootstrap-icons.woff2?524846017b983fc8ded9325d94ed40f3") format("woff2"),
url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff"); url("/fonts/bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff");
} }
.bi::before, .bi::before,
@@ -19,6 +19,7 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.bi-123::before { content: "\f67f"; }
.bi-alarm-fill::before { content: "\f101"; } .bi-alarm-fill::before { content: "\f101"; }
.bi-alarm::before { content: "\f102"; } .bi-alarm::before { content: "\f102"; }
.bi-align-bottom::before { content: "\f103"; } .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-fill::before { content: "\f67c"; }
.bi-webcam::before { content: "\f67d"; } .bi-webcam::before { content: "\f67d"; }
.bi-yin-yang::before { content: "\f67e"; } .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 { .navbar-nav {
margin: 0; 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-bottom .navbar-collapse,
.navbar-fixed-top .navbar-collapse { .navbar-fixed-top .navbar-collapse {
max-height: 1000px max-height: 1000px
@@ -75,6 +86,12 @@
display: inline-block; display: inline-block;
font-size: inherit; font-size: inherit;
} }
.btn-group-xs > .btn, .btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: 1rem;
border-radius: .2rem;
}
.icon-spin { .icon-spin {
animation-name: spin; animation-name: spin;
animation-duration: 2000ms; animation-duration: 2000ms;
@@ -105,13 +122,22 @@
transform: rotate(359deg); transform: rotate(359deg);
} }
} }
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;} @keyframes blink {
.footable-sortable { 50% {
-webkit-user-select: none; color: transparent
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} }
}
.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 */ /* Fix modal moving content left */
body.modal-open { body.modal-open {
overflow: inherit; overflow: inherit;
@@ -166,19 +192,11 @@ legend {
top: 0; right: 0; bottom: 0; left: 0; top: 0; right: 0; bottom: 0; left: 0;
opacity: 0.7; opacity: 0.7;
} }
#top {
padding-top: 70px;
}
.bootstrap-select.btn-group .no-results { .bootstrap-select.btn-group .no-results {
display: none; display: none;
} }
.dropdown-desc { .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
display: block; color: rgb(197, 197, 197) !important;
padding: 3px 10px;
clear: both;
font-weight: bold;
color: #5a5a5a;
white-space: nowrap;
} }
.haveibeenpwned { .haveibeenpwned {
cursor: pointer; cursor: pointer;
@@ -225,15 +243,8 @@ legend {
.btn-input-missing:active:hover, .btn-input-missing:active:hover,
.btn-input-missing:active:focus { .btn-input-missing:active:focus {
color: #000 !important; color: #000 !important;
background-color: #ff4136; background-color: #ff2f24 !important;
border-color: #ff291c; border-color: #e21207 !important;
}
table.footable>tbody>tr.footable-empty>td {
font-style:italic;
font-size: 1rem;
}
table>tbody>tr>td>span.footable-toggle {
opacity: 0.75;
} }
.navbar-nav > li { .navbar-nav > li {
font-size: 1rem !important; font-size: 1rem !important;
@@ -260,18 +271,11 @@ code {
margin-right: 5px; margin-right: 5px;
} }
.list-group-item.webauthn-authenticator-selection, .dropdown-header {
.list-group-item.totp-authenticator-selection, font-weight: 600;
.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;
} }
.tag-box { .tag-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -295,7 +299,7 @@ code {
} }
.tag-input { .tag-input {
margin-left: 10px; margin-left: 10px;
border: 0; border: 0 !important;
flex: 1; flex: 1;
height: 24px; height: 24px;
min-width: 150px; min-width: 150px;
@@ -308,3 +312,61 @@ code {
align-items: center; align-items: center;
display: inline-flex; 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;
}
+56 -150
View File
@@ -1,7 +1,3 @@
.space20 {
margin-bottom: 20px;
}
.btn-xs-lg>.lang-sm:after { .btn-xs-lg>.lang-sm:after {
margin-left: 4px; margin-left: 4px;
} }
@@ -10,100 +6,57 @@
max-width: 350px; max-width: 350px;
} }
.panel-login .apps .btn { .card-login .apps .btn {
width: auto; width: auto;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
margin-top: auto; margin-top: auto;
} }
.panel-login .apps .btn:hover { .card-login .apps .btn:hover {
margin-top: 1px !important; margin-top: 1px !important;
border-bottom-width: 3px; 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) { @media (max-width: 767px) {
.panel-login .apps .btn { .responsive-tabs .tab-pane {
display: block !important;
opacity: 1;
}
.card-login .apps .btn {
width: 100%; width: 100%;
float: none; float: none;
margin-bottom: 10px; margin-bottom: 10px;
} }
.panel-login .apps .btn { .card-login .apps .btn {
border-bottom-width: 4px; 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 { .xs-show {
display: block !important; 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 { .recent-login-success {
font-size: 14px; font-size: 14px;
margin-top: 10px !important; margin-top: 10px !important;
@@ -125,33 +78,26 @@
font-weight: normal; font-weight: normal;
text-align: justify; text-align: justify;
} }
.help-block { .btn.d-block {
text-align: justify;
}
.btn.visible-xs-block {
width: 100%; width: 100%;
float: none;
white-space: normal; white-space: normal;
} }
.btn-group.footable-actions .btn.btn-xs-half, .btn.btn-xs-half,
.btn.visible-xs-block.btn-xs-half { .btn.d-block.btn-xs-half {
width: 50%; width: 50%;
float: left;
} }
.btn-group.footable-actions .btn.btn-xs-third, .btn.btn-xs-third,
.btn.visible-xs-block.btn-xs-third { .btn.d-block.btn-xs-third {
width: 33.33%; width: 33.33%;
float: left;
} }
.btn-group.footable-actions .btn.btn-xs-quart, .btn.btn-xs-quart,
.btn.visible-xs-block.btn-xs-quart { .btn.d-block.btn-xs-quart {
width: 25%; width: 25%;
float: left;
} }
.btn.visible-xs-block.btn-sm, .btn.d-block.btn-sm,
.btn-xs-lg { .btn-xs-lg {
padding: 15px 16px 13px; padding: .5rem 1rem;
line-height: 15px; line-height: 20px;
} }
.input-xs-lg { .input-xs-lg {
height: 47px; height: 47px;
@@ -167,14 +113,14 @@
.btn-group.nowrap .dropdown-menu { .btn-group.nowrap .dropdown-menu {
width: 100%; width: 100%;
} }
.panel-login .btn-group { .card-login .btn-group {
display: block; display: block;
} }
.mass-actions-user .btn-group { .mass-actions-user .btn-group {
float: none; float: none;
} }
div[class^='mass-actions'] .dropdown-menu, div[class^='mass-actions'] .dropdown-menu,
.panel-xs-lg .dropdown-menu, .card-xs-lg .dropdown-menu,
.dropdown-menu.login { .dropdown-menu.login {
width: 100%; width: 100%;
} }
@@ -183,11 +129,11 @@
} }
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu, div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
div.mass-actions-quarantine .btn-group .dropdown-menu, div.mass-actions-quarantine .btn-group .dropdown-menu,
.panel-xs-lg .dropdown-menu { .card-xs-lg .dropdown-menu {
top: 100%; top: 100%;
} }
div[class^='mass-actions'] .dropdown-menu>li>a, 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 { .dropdown-menu.login>li>a {
padding: 8px 20px; padding: 8px 20px;
} }
@@ -195,9 +141,6 @@
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
.space20 {
margin-bottom: 10px;
}
.top100 { .top100 {
top: 100% !important; top: 100% !important;
} }
@@ -210,34 +153,17 @@
.btn-xs-lg>.lang-sm:after { .btn-xs-lg>.lang-sm:after {
top: 1px; 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 { .pagination {
margin-bottom: 5px; margin-bottom: 5px;
} }
tr.footable-filtering>th>form {
width: 270px;
}
.mass-actions-mailbox { .mass-actions-mailbox {
padding: 0; padding: 0;
} }
.panel-xs-lg .panel-heading { .card-xs-lg .card-header {
height: 66px; height: 66px;
line-height: 47px; line-height: 47px;
} }
.panel-xs-lg .btn-group .btn { .card-xs-lg .btn-group .btn {
padding-right: 5px; padding-right: 5px;
padding-left: 5px; padding-left: 5px;
} }
@@ -250,35 +176,10 @@
.bootstrap-select { .bootstrap-select {
max-width: 100%; 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 { .bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
margin-right: 14px; margin-right: 14px;
white-space: normal; white-space: normal;
} }
.clearfix {
flex-basis: 100%;
height: 0;
}
.btn-group > .btn-group { .btn-group > .btn-group {
flex-basis: 100%; flex-basis: 100%;
} }
@@ -290,15 +191,14 @@
.btn-group .btn i { .btn-group .btn i {
margin-right: 5px; margin-right: 5px;
} }
.btn-group .btn .caret { .card-login .btn-group .btn {
margin-left: 5px;
}
.panel-login .btn-group .btn {
display: block !important; display: block !important;
} }
.panel-login .clearfix {
height: auto; .dt-sm-head-hidden .dtr-title {
display: none !important;
} }
} }
@media (max-width: 350px) { @media (max-width: 350px) {
@@ -306,3 +206,9 @@
max-width: 250px; max-width: 250px;
} }
} }
@media (min-width: 1400px) {
.container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
max-width: 1600px;
}
}
+80
View File
@@ -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;
}
-1
View File
@@ -25,7 +25,6 @@ body.modal-open {
} }
.mass-actions-admin { .mass-actions-admin {
user-select: none; user-select: none;
padding:10px 0 10px 0;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
-1
View File
@@ -26,7 +26,6 @@
} }
.mass-actions-debug { .mass-actions-debug {
user-select: none; user-select: none;
padding:10px 0 10px 10px;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
-1
View File
@@ -21,7 +21,6 @@
} }
.mass-actions-user { .mass-actions-user {
user-select: none; user-select: none;
padding:10px 0 10px 0;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
-1
View File
@@ -32,7 +32,6 @@
} }
.mass-actions-mailbox { .mass-actions-mailbox {
user-select: none; user-select: none;
padding:10px 0 10px 10px;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
-1
View File
@@ -35,7 +35,6 @@
.mass-actions-quarantine { .mass-actions-quarantine {
user-select: none; user-select: none;
padding: 10px;
} }
.inputMissingAttr { .inputMissingAttr {
-1
View File
@@ -21,7 +21,6 @@
} }
.mass-actions-user { .mass-actions-user {
user-select: none; user-select: none;
padding:10px 0;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
File diff suppressed because it is too large. Load diff
+360
View File
@@ -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;
}
+15
View File
@@ -11,6 +11,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status(); $solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true; $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/debug.js'); $js_minifier->add('/web/js/site/debug.js');
// vmail df // vmail df
@@ -44,15 +49,25 @@ foreach ($containers as $container => $container_info) {
$containers[$container]['State']['StartedAtHR'] = $started; $containers[$container]['State']['StartedAtHR'] = $started;
} }
// get mailcow data
$hostname = getenv('MAILCOW_HOSTNAME');
$timezone = getenv('TZ');
$template = 'debug.twig'; $template = 'debug.twig';
$template_data = [ $template_data = [
'log_lines' => getenv('LOG_LINES'), 'log_lines' => getenv('LOG_LINES'),
'vmail_df' => $vmail_df, 'vmail_df' => $vmail_df,
'hostname' => $hostname,
'timezone' => $timezone,
'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'),
'solr_status' => $solr_status, 'solr_status' => $solr_status,
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60), 'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
'clamd_status' => $clamd_status, 'clamd_status' => $clamd_status,
'containers' => $containers, 'containers' => $containers,
'lang_admin' => json_encode($lang['admin']), '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'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
+29 -3
View File
@@ -38,9 +38,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
$template = 'edit/admin.twig'; $template = 'edit/admin.twig';
$template_data = ['admin' => $admin]; $template_data = ['admin' => $admin];
} }
elseif (isset($_GET['domain']) && elseif (isset($_GET['domain'])) {
is_valid_domain_name($_GET["domain"]) && if (is_valid_domain_name($_GET["domain"]) &&
!empty($_GET["domain"])) { !empty($_GET["domain"])) {
// edit domain
$domain = $_GET["domain"]; $domain = $_GET["domain"];
$result = mailbox('get', 'domain_details', $domain); $result = mailbox('get', 'domain_details', $domain);
$quota_notification_bcc = quota_notification_bcc('get', $domain); $quota_notification_bcc = quota_notification_bcc('get', $domain);
@@ -57,6 +58,27 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'domain_details' => $result, 'domain_details' => $result,
]; ];
} }
}
elseif (isset($_GET["template"])){
$domain_template = mailbox('get', 'domain_templates', $_GET["template"]);
if ($domain_template){
$template_data = [
'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']) && elseif (isset($_GET['oauth2client']) &&
is_numeric($_GET["oauth2client"]) && is_numeric($_GET["oauth2client"]) &&
!empty($_GET["oauth2client"])) { !empty($_GET["oauth2client"])) {
@@ -79,7 +101,9 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'dkim' => dkim('details', $alias_domain), 'dkim' => dkim('details', $alias_domain),
]; ];
} }
elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) { 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"])); $mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
$result = mailbox('get', 'mailbox_details', $mailbox); $result = mailbox('get', 'mailbox_details', $mailbox);
$rl = ratelimit('get', 'mailbox', $mailbox); $rl = ratelimit('get', 'mailbox', $mailbox);
@@ -103,6 +127,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'mailbox_details' => $result 'mailbox_details' => $result
]; ];
} }
}
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) { elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
$relayhost = intval($_GET["relayhost"]); $relayhost = intval($_GET["relayhost"]);
$result = relayhost('details', $relayhost); $result = relayhost('details', $relayhost);
@@ -189,5 +214,6 @@ $js_minifier->add('/web/js/site/pwgen.js');
$template_data['result'] = $result; $template_data['result'] = $result;
$template_data['return_to'] = $_SESSION['return_to']; $template_data['return_to'] = $_SESSION['return_to'];
$template_data['lang_user'] = json_encode($lang['user']); $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'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
Binary file not shown.
Binary file not shown.
File renamed without changes.

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

+1 -1
View File
@@ -436,7 +436,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
} }
?> ?>
</table> </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> <script>
var zonefile_dl_link = document.getElementById('download-zonefile'); var zonefile_dl_link = document.getElementById('download-zonefile');
var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile')); var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile'));
+1
View File
@@ -127,6 +127,7 @@ elseif (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
$data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']); $data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']);
// Get text/plain content // Get text/plain content
$data['text_plain'] = $mail_parser->getMessageBody('text'); $data['text_plain'] = $mail_parser->getMessageBody('text');
if (!json_encode($data['text_plain'])) $data['text_plain'] = '';
// Get html content and convert to text // Get html content and convert to text
$data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html')); $data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html'));
if (empty($data['text_plain']) && empty($data['text_html'])) { if (empty($data['text_plain']) && empty($data['text_html'])) {
+29
View File
@@ -2,8 +2,18 @@
function customize($_action, $_item, $_data = null) { function customize($_action, $_item, $_data = null) {
global $redis; global $redis;
global $lang; global $lang;
switch ($_action) { switch ($_action) {
case 'add': 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") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
@@ -72,6 +82,15 @@ function customize($_action, $_item, $_data = null) {
} }
break; break;
case 'edit': 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") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
@@ -116,6 +135,7 @@ function customize($_action, $_item, $_data = null) {
$ui_announcement_text = $_data['ui_announcement_text']; $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_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); $ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
try { try {
$redis->set('TITLE_NAME', htmlspecialchars($title_name)); $redis->set('TITLE_NAME', htmlspecialchars($title_name));
$redis->set('MAIN_NAME', htmlspecialchars($main_name)); $redis->set('MAIN_NAME', htmlspecialchars($main_name));
@@ -143,6 +163,15 @@ function customize($_action, $_item, $_data = null) {
} }
break; break;
case 'delete': 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") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
+46
View File
@@ -1,6 +1,7 @@
<?php <?php
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) { function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
global $DOCKER_TIMEOUT; global $DOCKER_TIMEOUT;
global $redis;
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' )); 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 // 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; return false;
break;
case 'containers': case 'containers':
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 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'))) { 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']]['State'] = $container['State'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config']; $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']); unset($container['Config']['Env']);
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State']; $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']]['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']); 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']]['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']]['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; 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;
} }
} }
+6 -3
View File
@@ -251,7 +251,7 @@ function password_check($password1, $password2) {
return true; 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 $pdo;
global $redis; global $redis;
$sasl_limit_days = intval($sasl_limit_days); $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` $stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login" WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
AND JSON_EXTRACT(`call`, "$[1]") = :username AND JSON_EXTRACT(`call`, "$[1]") = :username
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET 1'); AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET :offset');
$stmt->execute(array(':username' => $username)); $stmt->execute(array(
':username' => $username,
':offset' => $ui_offset
));
$ui = $stmt->fetch(PDO::FETCH_ASSOC); $ui = $stmt->fetch(PDO::FETCH_ASSOC);
} }
else { else {
+577
View File
@@ -1020,6 +1020,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if (empty($name)) { if (empty($name)) {
$name = $local_part; $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']); $active = intval($_data['active']);
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']); $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']); $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, ':domain' => $domain,
':active' => $active ':active' => $active
)); ));
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 = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
$stmt->execute(array( $stmt->execute(array(
':username' => $username ':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( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), '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)) 'msg' => array('resource_added', htmlspecialchars($name))
); );
break; 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; break;
case 'edit': case 'edit':
@@ -2472,6 +2716,79 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
} }
} }
break; 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': case 'mailbox':
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
@@ -2814,6 +3131,110 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
} }
break; 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': case 'resource':
if (!is_array($_data['name'])) { if (!is_array($_data['name'])) {
$names = array(); $names = array();
@@ -3606,6 +4027,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`mailboxes`, `mailboxes`,
`defquota`, `defquota`,
`maxquota`, `maxquota`,
`created`,
`modified`,
`quota`, `quota`,
`relayhost`, `relayhost`,
`relay_all_recipients`, `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_all_recipients_int'] = $row['relay_all_recipients'];
$domaindata['relay_unknown_only'] = $row['relay_unknown_only']; $domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
$domaindata['relay_unknown_only_int'] = $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` $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)) WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
AND `address` NOT IN ( AND `address` NOT IN (
@@ -3711,6 +4136,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return $domaindata; return $domaindata;
break; 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': case 'mailbox_details':
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
@@ -3725,6 +4187,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`mailbox`.`domain`, `mailbox`.`domain`,
`mailbox`.`local_part`, `mailbox`.`local_part`,
`mailbox`.`quota`, `mailbox`.`quota`,
`mailbox`.`created`,
`mailbox`.`modified`,
`quota2`.`bytes`, `quota2`.`bytes`,
`attributes`, `attributes`,
`quota2`.`messages` `quota2`.`messages`
@@ -3743,6 +4207,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`mailbox`.`domain`, `mailbox`.`domain`,
`mailbox`.`local_part`, `mailbox`.`local_part`,
`mailbox`.`quota`, `mailbox`.`quota`,
`mailbox`.`created`,
`mailbox`.`modified`,
`quota2replica`.`bytes`, `quota2replica`.`bytes`,
`attributes`, `attributes`,
`quota2replica`.`messages` `quota2replica`.`messages`
@@ -3769,6 +4235,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$mailboxdata['attributes'] = json_decode($row['attributes'], true); $mailboxdata['attributes'] = json_decode($row['attributes'], true);
$mailboxdata['quota_used'] = intval($row['bytes']); $mailboxdata['quota_used'] = intval($row['bytes']);
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100); $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'] === '- ') { if ($mailboxdata['percent_in_use'] === '- ') {
$mailboxdata['percent_class'] = "info"; $mailboxdata['percent_class'] = "info";
@@ -3856,6 +4324,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return $mailboxdata; return $mailboxdata;
break; 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': case 'resource_details':
$resourcedata = array(); $resourcedata = array();
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
@@ -4224,6 +4729,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
} }
break; 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': case 'alias':
if (!is_array($_data['id'])) { if (!is_array($_data['id'])) {
$ids = array(); $ids = array();
@@ -4518,6 +5059,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
} }
break; 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': case 'resource':
if (!is_array($_data['name'])) { if (!is_array($_data['name'])) {
$names = array(); $names = array();
+3 -1
View File
@@ -51,6 +51,7 @@ function pushover($_action, $_data = null) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio']; $evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio'];
$only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio']; $only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio'];
$sound = (isset($_data['sound'])) ? $_data['sound'] : $is_now['sound'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@@ -101,7 +102,8 @@ function pushover($_action, $_data = null) {
$po_attributes = json_encode( $po_attributes = json_encode(
array( array(
'evaluate_x_prio' => strval(intval($evaluate_x_prio)), 'evaluate_x_prio' => strval(intval($evaluate_x_prio)),
'only_x_prio' => strval(intval($only_x_prio)) 'only_x_prio' => strval(intval($only_x_prio)),
'sound' => strval($sound)
) )
); );
$stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`) $stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`)
+1 -1
View File
@@ -39,7 +39,6 @@ $globalVariables = [
'dual_login' => @$_SESSION['dual-login'], 'dual_login' => @$_SESSION['dual-login'],
'ui_texts' => $UI_TEXTS, 'ui_texts' => $UI_TEXTS,
'css_path' => '/cache/'.basename($CSSPath), 'css_path' => '/cache/'.basename($CSSPath),
'theme' => strtolower(trim($DEFAULT_THEME)),
'logo' => customize('get', 'main_logo'), 'logo' => customize('get', 'main_logo'),
'available_languages' => $AVAILABLE_LANGUAGES, 'available_languages' => $AVAILABLE_LANGUAGES,
'lang' => $lang, 'lang' => $lang,
@@ -49,6 +48,7 @@ $globalVariables = [
'app_links' => customize('get', 'app_links'), 'app_links' => customize('get', 'app_links'),
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'), 'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
'uri' => $_SERVER['REQUEST_URI'], 'uri' => $_SERVER['REQUEST_URI'],
'last_login' => last_login('get', $_SESSION['mailcow_cc_username'], 7, 0)['ui']['time']
]; ];
foreach ($globalVariables as $globalVariableName => $globalVariableValue) { foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
+107 -1
View File
@@ -3,7 +3,7 @@ function init_db_schema() {
try { try {
global $pdo; global $pdo;
$db_version = "25072022_2300"; $db_version = "23122022_1445";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $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" "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( "domain" => array(
// Todo: Move some attributes to json // Todo: Move some attributes to json
"cols" => array( "cols" => array(
@@ -1264,6 +1280,7 @@ function init_db_schema() {
$pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;"); $pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;"); $pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;");
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;"); $pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.sound', \"pushover\") WHERE JSON_VALUE(`attributes`, '$.sound') IS NULL;");
// mailbox // mailbox
$pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;");
@@ -1292,6 +1309,95 @@ function init_db_schema() {
// Fix domain_admins // Fix domain_admins
$pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';"); $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") { if (php_sapi_name() == "cli") {
echo "DB initialization completed" . PHP_EOL; echo "DB initialization completed" . PHP_EOL;
} else { } else {
+88 -19
View File
@@ -2,6 +2,8 @@
// check for development mode // check for development mode
$DEV_MODE = (getenv('DEV_MODE') == 'y'); $DEV_MODE = (getenv('DEV_MODE') == 'y');
// check for demo mode
$DEMO_MODE = (getenv('DEMO_MODE') == 'y');
// Slave does not serve UI // Slave does not serve UI
/* if (!preg_match('/y|yes/i', getenv('MASTER'))) { /* 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'; 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 API + T/HOTP API
// u2f - deprecated, should be removed // u2f - deprecated, should be removed
$u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']); $u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']);
@@ -195,9 +182,65 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
// Set language // Set language
if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) { if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) {
if ($DETECT_LANGUAGE && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { if ($DETECT_LANGUAGE && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$header_lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2)); // regex inspired from @GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language
if (array_key_exists($header_lang, $AVAILABLE_LANGUAGES)) { preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
$_SESSION['mailcow_locale'] = $header_lang;
$langs = $lang_parse[1];
$ranks = $lang_parse[4];
// (create an associative array 'language' => 'preference')
$lang2pref = array();
for ($i=0; $i<count($langs); $i++) {
$lang2pref[strtolower($langs[$i])] = (float) (!empty($ranks[$i]) ? $ranks[$i] : 1);
}
// (comparison function for uksort)
$cmpLangs = function ($a, $b) use ($lang2pref) {
if ($lang2pref[$a] > $lang2pref[$b])
return -1;
elseif ($lang2pref[$a] < $lang2pref[$b])
return 1;
elseif (strlen($a) > strlen($b))
return -1;
elseif (strlen($a) < strlen($b))
return 1;
else
return 0;
};
// sort the languages by prefered language and by the most specific region
uksort($lang2pref, $cmpLangs);
// generate language array without the region part
$AVAILABLE_BASE_LANGUAGES=array();
foreach ($AVAILABLE_LANGUAGES as $code => $lang) {
$base_code = substr($code, 0, 2);
if (!array_key_exists($base_code, $AVAILABLE_BASE_LANGUAGES)) {
$AVAILABLE_BASE_LANGUAGES[$base_code] = $code;
}
}
// Find a perfect match or partial match
// Match en-gb or en
foreach ($lang2pref as $lang => $q) {
if (array_key_exists($lang, $AVAILABLE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $lang;
break;
} elseif (array_key_exists($lang, $AVAILABLE_BASE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $AVAILABLE_BASE_LANGUAGES[$lang];
break;
}
}
// Try suggest match
// e.g. suggest en-gb when only en-us is provided
if (!isset($_SESSION['mailcow_locale'])) {
foreach ($lang2pref as $lang => $q) {
if (array_key_exists(substr($lang, 0, 2), $AVAILABLE_BASE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $AVAILABLE_BASE_LANGUAGES[substr($lang, 0, 2)];
break;
}
}
} }
} }
else { else {
@@ -215,13 +258,14 @@ if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $AVAILABLE_LANGUAGES
/* /*
* load language * load language
*/ */
$lang = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.json'), true); $lang = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en-gb.json'), true);
$langFile = $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.json'; $langFile = $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.json';
if(file_exists($langFile)) { if(file_exists($langFile)) {
$lang = array_merge_real($lang, json_decode(file_get_contents($langFile), true)); $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.acl.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php';
@@ -256,4 +300,29 @@ if (isset($_SESSION['mailcow_cc_role'])) {
// } // }
acl('to_session'); 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'); $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);
}
+29 -29
View File
@@ -76,41 +76,41 @@ $autodiscover_config = array(
$DETECT_LANGUAGE = true; $DETECT_LANGUAGE = true;
// Change default language // Change default language
$DEFAULT_LANG = 'en'; $DEFAULT_LANG = 'en-gb';
// Available languages // Available languages
// https://www.iso.org/obp/ui/#search // https://www.iso.org/obp/ui/#search
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes // https://en.wikipedia.org/wiki/IETF_language_tag
$AVAILABLE_LANGUAGES = array( $AVAILABLE_LANGUAGES = array(
'cs' => 'Čeština (Czech)', // 'ca-es' => 'Català (Catalan)',
'da' => 'Danish (Dansk)', 'cs-cz' => 'Čeština (Czech)',
'de' => 'Deutsch (German)', 'da-dk' => 'Danish (Dansk)',
'en' => 'English', 'de-de' => 'Deutsch (German)',
'es' => 'Español (Spanish)', 'en-gb' => 'English',
'fi' => 'Suomi (Finish)', 'es-es' => 'Español (Spanish)',
'fr' => 'Français (French)', 'fi-fi' => 'Suomi (Finish)',
'hu' => 'Magyar (Hungarian)', 'fr-fr' => 'Français (French)',
'it' => 'Italiano (Italian)', 'hu-hu' => 'Magyar (Hungarian)',
'ko' => '한국어 (Korean)', 'it-it' => 'Italiano (Italian)',
'lv' => 'latviešu (Latvian)', 'ko-kr' => '한국어 (Korean)',
'nl' => 'Nederlands (Dutch)', 'lv-lv' => 'latviešu (Latvian)',
'pl' => 'Język Polski (Polish)', 'nl-nl' => 'Nederlands (Dutch)',
'pt' => 'Português (Portuguese)', 'pl-pl' => 'Język Polski (Polish)',
'ro' => 'Română (Romanian)', 'pt-pt' => 'Português (Portuguese)',
'ru' => 'Pусский (Russian)', 'ro-ro' => 'Română (Romanian)',
'sk' => 'Slovenčina (Slovak)', 'ru-ru' => 'Pусский (Russian)',
'sv' => 'Svenska (Swedish)', 'sk-sk' => 'Slovenčina (Slovak)',
'tr' => 'Türkçe (Turkish)', 'sv-se' => 'Svenska (Swedish)',
'uk' => 'Українська (Ukrainian)', 'tr-tr' => 'Türkçe (Turkish)',
'zh' => '中文 (Chinese)' 'uk-ua' => 'Українська (Ukrainian)',
'zh-cn' => '简体中文 (Simplified Chinese)',
'zh-tw' => '繁體中文 (Traditional Chinese)',
); );
// Change theme (default: lumen) // default theme is lumen
// Needs to be one of those: cerulean, cosmo, cyborg, darkly, flatly, journal, lumen, paper, readable, sandstone, // additional themes can be found here: https://bootswatch.com/
// simplex, slate, spacelab, superhero, united, yeti // copy them to data/web/css/themes/{THEME-NAME}-bootstrap.css
// See https://bootswatch.com/ $UI_THEME = "lumen";
// WARNING: Only lumen is loaded locally. Enabling any other theme, will download external sources.
$DEFAULT_THEME = 'lumen';
// Show DKIM private keys - false by default // Show DKIM private keys - false by default
$SHOW_DKIM_PRIV_KEYS = false; $SHOW_DKIM_PRIV_KEYS = false;
+1 -1
View File
@@ -8,7 +8,7 @@ if (isset($_SESSION['mailcow_cc_role']) && isset($_SESSION['oauth2_request'])) {
exit(); exit();
} }
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin') { elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin') {
header('Location: /admin'); header('Location: /debug');
exit(); exit();
} }
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') { elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
+2
View File
@@ -0,0 +1,2 @@
/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^Line truncated
-4
View File
@@ -1,4 +0,0 @@
/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(p,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k="sizzle"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",$=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",F=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+Line truncated
/*! jQuery Migrate v3.1.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e,window)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery"),window):t(jQuery,window)}(function(s,n){"use strict";function e(e){return 0<=function(e,t){for(var r=/^(\d+)\.(\d+)\.(\d+)/,n=r.exec(e)||[],o=r.exec(t)||[],i=1;i<=3;i++){if(+n[i]>+o[i])return 1;if(+n[i]<+o[i])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.1.0",n.console&&n.console.log&&(s&&e("3.0.0")||n.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),s.migrateWarnings&&n.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),n.console.log("JQMIGRATE: Migrate is installed"+(s.migrateMute?"":" with logging active")+", version "+s.migrateVersion));var r={};function u(e){var t=n.console;r[e]||(r[e]=!0,s.migrateWarnings.push(e),t&&t.warn&&!s.migrateMute&&(t.warn("JQMIGRATE: "+e),s.migrateTrace&&t.trace&&t.trace()))}function t(e,t,r,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n),r},set:function(e){u(n),r=e}})}function o(e,t,r,n){e[t]=function(){return u(n),r.apply(this,arguments)}}s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){r={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("jQuery is not compatible with Quirks Mode");var i,a=s.fn.init,c=s.isNumeric,d=s.find,l=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,p=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;for(i in s.fn.init=function(e){var t=Array.prototype.slice.call(arguments);return"string"==typeof e&&"#"===e&&(u("jQuery( '#' ) is not a valid selector"),t[0]=[]),a.apply(this,t)},s.fn.init.prototype=s.fn,s.find=function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&l.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(p,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("Attribute selector with '#' was not fixed: "+r[0])}}return d.apply(this,r)},d)Object.prototype.hasOwnProperty.call(d,i)&&(s.find[i]=d[i]);s.fn.size=function(){return u("jQuery.fn.size() is deprecated and removed; use the .length property"),this.length},s.parseJSON=function(){return u("jQuery.parseJSON is deprecated; use JSON.parse"),JSON.parse.apply(null,arguments)},s.isNumeric=function(e){var t,r,n=c(e),o=(r=(t=e)&&t.toString(),!s.isArray(t)&&0<=r-parseFloat(r)+1);return n!==o&&u("jQuery.isNumeric() should not be called on constructed objects"),o},e("3.3.0")&&o(s,"isWindow",function(e){return null!=e&&e===e.window},"jQuery.isWindow() is deprecated"),o(s,"holdReady",s.holdReady,"jQuery.holdReady is deprecated"),o(s,"unique",s.uniqueSort,"jQuery.unique is deprecated; use jQuery.uniqueSort"),t(s.expr,"filters",s.expr.pseudos,"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),t(s.expr,":",s.expr.pseudos,"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.2.0")&&o(s,"nodeName",s.nodeName,"jQuery.nodeName is deprecated");var f=s.ajax;s.ajax=function(){var e=f.apply(this,arguments);return e.promise&&(o(e,"success",e.done,"jQXHR.success is deprecated and removed"),o(e,"error",e.fail,"jQXHR.error is deprecated and removed"),o(e,"complete",e.always,"jQXHR.complete is deprecated and removed")),e};var y=s.fn.removeAttr,m=s.fn.toggleClass,h=/\S+/g;s.fn.removeAttr=function(e){var r=this;return s.each(e.match(h),function(e,t){s.expr.match.bool.test(t)&&(u("jQuery.fn.removeAttr no longer sets boolean properties: "+t),r.prop(t,!1))}),y.apply(this,arguments)};var g=!(s.fn.toggleClass=function(t){return void 0!==t&&"boolean"!=typeof t?m.apply(this,arguments):(u("jQuery.fn.toggleClass( boolean ) is deprecated"),this.each(function(){var e=this.getAttribute&&this.getAttribute("class")||"";e&&s.data(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===t?"":s.data(this,"__className__")||"")}))});s.swap&&s.each(["height","width","reliableMarginRight"],function(e,t){var r=s.cssHooks[t]&&s.cssHooks[t].get;r&&(s.cssHooks[t].get=function(){var e;return g=!0,e=r.apply(this,arguments),g=!1,e})}),s.swap=function(e,t,r,n){var o,i,a={};for(i in g||u("jQuery.swap() is undocumented and deprecated"),t)a[i]=e.style[i],e.style[i]=t[i];for(i in o=r.apply(e,n||[]),t)e.style[i]=a[i];return o};var v=s.data;s.data=function(e,t,r){var n;if(t&&"object"==typeof t&&2===arguments.length){n=s.hasData(e)&&v.call(this,e);var o={};for(var i in t)i!==s.camelCase(i)?(u("jQuery.data() always sets/gets camelCased names: "+i),n[i]=t[i]):o[i]=t[i];return v.call(this,e,o),t}return t&&"string"==typeof t&&t!==s.camelCase(t)&&(n=s.hasData(e)&&v.call(this,e))&&t in n?(u("jQuery.data() always sets/gets camelCased names: "+t),2<arguments.length&&(n[t]=r),n[t]):v.apply(this,arguments)};function j(e){return e}var Q=s.Tween.prototype.run;s.Tween.prototype.run=function(){1<s.easing[this.easing].length&&(u("'jLine truncated
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;s<o;s++){const o=t[n[s]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function S(t,e,i){const n="string"==typeof e,s=n?i:e;let o=P(t);return k.has(o)||(o=t),[n,s,o]}function N(t,e,i,n,s){if("string"!=typeof e||!t)return;if(i||(i=n,n=null),C.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!Line truncated
//# sourceMappingURL=bootstrap.bundle.min.js.map
-7
View File
@@ -1,7 +0,0 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:tLine truncated
this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
File renamed without changes.
File diff suppressed because it is too large. Load diff
-8
View File
@@ -1,8 +0,0 @@
/*!
* Bootstrap-select v1.12.2 (http://silviomoreto.github.io/bootstrap-select)
*
* Copyright 2013-2017 bootstrap-select
* Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
*/
!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){"use strict";function b(b){var c=[{re:/[\xC0-\xC6]/g,ch:"A"},{re:/[\xE0-\xE6]/g,ch:"a"},{re:/[\xC8-\xCB]/g,ch:"E"},{re:/[\xE8-\xEB]/g,ch:"e"},{re:/[\xCC-\xCF]/g,ch:"I"},{re:/[\xEC-\xEF]/g,ch:"i"},{re:/[\xD2-\xD6]/g,ch:"O"},{re:/[\xF2-\xF6]/g,ch:"o"},{re:/[\xD9-\xDC]/g,ch:"U"},{re:/[\xF9-\xFC]/g,ch:"u"},{re:/[\xC7-\xE7]/g,ch:"c"},{re:/[\xD1]/g,ch:"N"},{re:/[\xF1]/g,ch:"n"}];return a.each(c,function(){b=b?b.replace(this.re,this.ch):""}),b}function c(b){var c=arguments,d=b;[].shift.apply(c);var e,f=this.each(function(){var b=a(this);if(b.is("select")){var f=b.data("selectpicker"),g="object"==typeof d&&d;if(f){if(g)for(var h in g)g.hasOwnProperty(h)&&(f.options[h]=g[h])}else{var i=a.extend({},k.DEFAULTS,a.fn.selectpicker.defaults||{},b.data(),g);i.template=a.extend({},k.DEFAULTS.template,a.fn.selectpicker.defaults?a.fn.selectpicker.defaults.template:{},b.data().template,g.template),b.data("selectpicker",f=new k(this,i))}"string"==typeof d&&(e=f[d]instanceof Function?f[d].apply(f,c):f.options[d])}});return"undefined"!=typeof e?e:f}String.prototype.includes||!function(){var a={}.toString,b=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),c="".indexOf,d=function(b){if(null==this)throw new TypeError;var d=String(this);if(b&&"[object RegExp]"==a.call(b))throw new TypeError;var e=d.length,f=String(b),g=f.length,h=arguments.length>1?arguments[1]:void 0,i=h?Number(h):0;i!=i&&(i=0);var j=Math.min(Math.max(i,0),e);return!(g+j>e)&&c.call(d,f,i)!=-1};b?b(String.prototype,"includes",{value:d,configurable:!0,writable:!0}):String.prototype.includes=d}(),String.prototype.startsWith||!function(){var a=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),b={}.toString,c=function(a){if(null==this)throw new TypeError;var c=String(this);if(a&&"[object RegExp]"==b.call(a))throw new TypeError;var d=c.length,e=String(a),f=e.length,g=arguments.length>1?arguments[1]:void 0,h=g?Number(g):0;h!=h&&(h=0);var i=Math.min(Math.max(h,0),d);if(f+i>d)return!1;for(var j=-1;++j<f;)if(c.charCodeAt(i+j)!=e.charCodeAt(j))return!1;return!0};a?a(String.prototype,"startsWith",{value:c,configurable:!0,writable:!0}):String.prototype.startsWith=c}(),Object.keys||(Object.keys=function(a,b,c){c=[];for(b in a)c.hasOwnProperty.call(a,b)&&c.push(b);return c});var d={useDefault:!1,_set:a.valHooks.select.set};a.valHooks.select.set=function(b,c){return c&&!d.useDefault&&a(b).data("selected",!0),d._set.apply(this,arguments)};var e=null;a.fn.triggerNative=function(a){var b,c=this[0];c.dispatchEvent?("function"==typeof Event?b=new Event(a,{bubbles:!0}):(b=document.createEvent("Event"),b.initEvent(a,!0,!1)),c.dispatchEvent(b)):c.fireEvent?(b=document.createEventObject(),b.eventType=a,c.fireEvent("on"+a,b)):this.trigger(a)},a.expr.pseudos.icontains=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.text()).toString().toUpperCase();return f.includes(d[3].toUpperCase())},a.expr.pseudos.ibegins=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.text()).toString().toUpperCase();return f.startsWith(d[3].toUpperCase())},a.expr.pseudos.aicontains=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.data("normalizedText")||e.text()).toString().toUpperCase();return f.includes(d[3].toUpperCase())},a.expr.pseudos.aibegins=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.data("normalizedText")||e.text()).toString().toUpperCase();return f.startsWith(d[3].toUpperCase())};var f={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},g={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#x27;":"'","&#x60;":"`"},h=function(a){var b=function(b){return a[b]},c="(?:"+Object.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}},i=h(f),j=h(g),k=function(b,c){d.useDefault||(a.valHooks.select.set=d._set,d.useDefault=!0),this.$element=a(b),this.$newElement=null,this.$button=null,this.$menu=null,this.$lis=null,this.options=c,null===this.options.title&&(this.options.title=this.$element.attr("title"));var e=this.options.windowPadding;"number"==typeof e&&(this.options.windowPadding=[e,e,e,e]),this.val=k.prototype.val,this.render=k.prototype.render,this.refresh=k.prototype.refresh,this.setStyle=k.prototype.setStyle,this.selectAll=k.prototype.selectAll,this.deselectAll=k.prototype.deselectAll,this.destroy=k.prototype.destroy,this.remove=k.prototype.remove,this.show=k.prototype.show,this.hide=k.prototype.hide,this.init()};k.VERSION="1.12.2",k.DEFAULTS={noneSelectedText:"Nothing selected",noneResultsText:"No results matched {0}",countSelectedText:function(a,b){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){return[1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==b?"Group limit reached ({nLine truncated
m.focus());else{var u=a(":focus");u.click(),u.focus(),c.preventDefault(),a(document).data("spaceSelect",!0)}a(document).data("keycount",0)}(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(o.multiple||o.options.liveSearch)||/(27)/.test(c.keyCode.toString(10))&&!l)&&(o.$menu.parent().removeClass("open"),o.options.container&&o.$newElement.removeClass("open"),o.$button.focus())}},mobile:function(){this.$element.addClass("mobile-device")},refresh:function(){this.$lis=null,this.liObj={},this.reloadLi(),this.render(),this.checkDisabled(),this.liHeight(!0),this.setStyle(),this.setWidth(),this.$lis&&this.$searchbox.trigger("propertychange"),this.$element.trigger("refreshed.bs.select")},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()},destroy:function(){this.$newElement.before(this.$element).remove(),this.$bsContainer?this.$bsContainer.remove():this.$menu.remove(),this.$element.off(".bs.select").removeData("selectpicker").removeClass("bs-select-hidden selectpicker")}};var l=a.fn.selectpicker;a.fn.selectpicker=c,a.fn.selectpicker.Constructor=k,a.fn.selectpicker.noConflict=function(){return a.fn.selectpicker=l,this},a(document).data("keycount",0).on("keydown.bs.select",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',k.prototype.keydown).on("focusin.modal",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',function(a){a.stopPropagation()}),a(window).on("load.bs.select.data-api",function(){a(".selectpicker").each(function(){var b=a(this);c.call(b,b.data())})})}(a)});
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(h,b,d){var f,e,g={content:{message:"object"==typeof b?b.message:b,title:b.title?b.title:"",icon:b.icon?b.icon:"",url:b.url?b.url:"#",target:b.target?b.target:"-"}};d=a.extend(!0,{},g,d),this.settings=a.extend(!0,{},c,d),this._defaults=c,"-"===this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),!this.settings.allow_duplicates&&(this.settings.allow_duplicates||(f=this,e=!1,a('[data-notify="container"]').each(function(k,c){var b=a(c),d=b.find('[data-notify="title"]').text().trim(),g=b.find('[data-notify="message"]').html().trim(),h=d===a("<div>"+f.settings.content.title+"</div>").html().trim(),i=g===a("<div>"+f.settings.content.message+"</div>").html().trim(),j=b.hasClass("alert-"+f.settings.type);return h&&i&&j&&(e=!0),!e}),e))||this.init()}var c={element:"body",position:null,type:"info",allow_dismiss:!0,allow_duplicates:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:'<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="btn-close" data-notify="dismiss"></button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'};String.format=function(){for(var b=arguments[0],a=1;a<arguments.length;a++)b=b.replace(RegExp("\\{"+(a-1)+"\\}","gm"),arguments[a]);return b},a.extend(b.prototype,{init:function(){var a=this;this.buildNotify(),this.settings.content.icon&&this.setIcon(),"#"!=this.settings.content.url&&this.styleURL(),this.styleDismiss(),this.placement(),this.bind(),this.notify={$ele:this.$ele,update:function(e,f){var b={};for(var c in"string"==typeof e?b[e]=f:b=e,b)switch(c){case"type":this.$ele.removeClass("alert-"+a.settings.type),this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass("progress-bar-"+a.settings.type),a.settings.type=b[c],this.$ele.addClass("alert-"+b[c]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+b[c]);break;case"icon":var d=this.$ele.find('[data-notify="icon"]');"class"===a.settings.icon_type.toLowerCase()?d.removeClass(a.settings.content.icon).addClass(b[c]):(d.is("img")||d.find("img"),d.attr("src",b[c]));break;case"progress":var g=a.settings.delay-a.settings.delay*(b[c]/100);this.$ele.data("notify-delay",g),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",b[c]).css("width",b[c]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",b[c]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",b[c]);break;default:this.$ele.find('[data-notify="'+c+'"]').html(b[c])}var h=this.$ele.outerHeight()+parseInt(a.settings.spacing)+parseInt(a.settings.offset.y);a.reposition(h)},close:function(){a.close()}}},buildNotify:function(){var b=this.settings.content;this.$ele=a(String.format(this.settings.template,this.settings.type,b.title,b.message,b.url,b.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(!(this.settings.delay<=0)||this.settings.showProgressbar)&&this.settings.showProgressbar||this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"===this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('<img src="'+this.settings.content.icon+'" alt="Notify Icon" />')},styleDismiss:function(){this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:0,position:"absolute",top:0,width:"100%",zIndex:this.settings.z_index+1})},placement:function(){var d=this,b=this.settings.Line truncated
File renamed without changes.
-1
View File
@@ -1 +0,0 @@
!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function s(s){var e=!1;return t('[data-notify="container"]').each(function(i,n){var a=t(n),o=a.find('[data-notify="title"]').text().trim(),r=a.find('[data-notify="message"]').html().trim(),l=o===t("<div>"+s.settings.content.title+"</div>").html().trim(),d=r===t("<div>"+s.settings.content.message+"</div>").html().trim(),g=a.hasClass("alert-"+s.settings.type);return l&&d&&g&&(e=!0),!e}),e}function e(e,n,a){var o={content:{message:"object"==typeof n?n.message:n,title:n.title?n.title:"",icon:n.icon?n.icon:"",url:n.url?n.url:"#",target:n.target?n.target:"-"}};a=t.extend(!0,{},o,a),this.settings=t.extend(!0,{},i,a),this._defaults=i,"-"===this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),(this.settings.allow_duplicates||!this.settings.allow_duplicates&&!s(this))&&this.init()}var i={element:"body",position:null,type:"info",allow_dismiss:!0,allow_duplicates:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:'<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">&times;</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'};String.format=function(){for(var t=arguments[0],s=1;s<arguments.length;s++)t=t.replace(RegExp("\\{"+(s-1)+"\\}","gm"),arguments[s]);return t},t.extend(e.prototype,{init:function(){var t=this;this.buildNotify(),this.settings.content.icon&&this.setIcon(),"#"!=this.settings.content.url&&this.styleURL(),this.styleDismiss(),this.placement(),this.bind(),this.notify={$ele:this.$ele,update:function(s,e){var i={};"string"==typeof s?i[s]=e:i=s;for(var n in i)switch(n){case"type":this.$ele.removeClass("alert-"+t.settings.type),this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass("progress-bar-"+t.settings.type),t.settings.type=i[n],this.$ele.addClass("alert-"+i[n]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+i[n]);break;case"icon":var a=this.$ele.find('[data-notify="icon"]');"class"===t.settings.icon_type.toLowerCase()?a.removeClass(t.settings.content.icon).addClass(i[n]):(a.is("img")||a.find("img"),a.attr("src",i[n]));break;case"progress":var o=t.settings.delay-t.settings.delay*(i[n]/100);this.$ele.data("notify-delay",o),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i[n]).css("width",i[n]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",i[n]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",i[n]);break;default:this.$ele.find('[data-notify="'+n+'"]').html(i[n])}var r=this.$ele.outerHeight()+parseInt(t.settings.spacing)+parseInt(t.settings.offset.y);t.reposition(r)},close:function(){t.close()}}},buildNotify:function(){var s=this.settings.content;this.$ele=t(String.format(this.settings.template,this.settings.type,s.title,s.message,s.url,s.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(this.settings.delay<=0&&!this.settings.showProgressbar||!this.settings.showProgressbar)&&this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"===this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('<img src="'+this.settings.content.icon+'" alt="Notify Icon" />')},styleDismiss:function(){this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:0,position:"absolute",top:0,width:"100%",zIndex:this.settings.z_index+1})},placement:function(){varLine truncated
File diff suppressed because it is too large. Load diff
-7
View File
@@ -1,7 +0,0 @@
/*!
* Chart.js v2.9.2
* https://www.chartjs.org
* (c) 2019 Chart.js Contributors
* Released under the MIT License
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(function(){try{return require("moment")}catch(t){}}()):"function"==typeof define&&define.amd?define(["require"],(function(t){return e(function(){try{return t("moment")}catch(t){}}())})):(t=t||self).Chart=e(t.moment)}(this,(function(t){"use strict";t=t&&t.hasOwnProperty("default")?t.default:t;var e={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},n=function(t,e){return t(e={exports:{}},e.exports),e.exports}((function(t){var n={};for(var i in e)e.hasOwnProperty(i)&&(n[e[i]]=i);var a=t.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var r in a)if(a.hasOwnProperty(r)){if(!("channels"in a[r]))throw new Error("missing channels property: "+r);if(!("labels"in a[r]))throw new Error("missing channel labels property: "+r);if(a[r].labels.length!==a[r].channels)throw new Error("channel and label counts mismatch: "+r);var o=a[r].channels,s=a[r].labels;delete a[r].channels,delete a[r].labels,Object.defineProperty(a[r],"channels",{value:o}),Object.defineProperty(a[r],"labels",{value:s})}a.rgb.hsl=function(t){var e,n,i=t[0]/255,a=t[1]/255,r=t[2]/255,o=Math.min(i,a,r),s=Math.max(i,a,r),l=s-o;Line truncated
@@ -1,7 +0,0 @@
/*!
* chartjs-plugin-datalabels v0.7.0
* https://chartjs-plugin-datalabels.netlify.com
* (c) 2019 Chart.js Contributors
* Released under the MIT license
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js"],e):(t=t||self).ChartDataLabels=e(t.Chart)}(this,function(t){"use strict";var e=(t=t&&t.hasOwnProperty("default")?t.default:t).helpers,r=function(){if("undefined"!=typeof window){if(window.devicePixelRatio)return window.devicePixelRatio;var t=window.screen;if(t)return(t.deviceXDPI||1)/(t.logicalXDPI||1)}return 1}(),n={toTextLines:function(t){var r,n=[];for(t=[].concat(t);t.length;)"string"==typeof(r=t.pop())?n.unshift.apply(n,r.split("\n")):Array.isArray(r)?t.push.apply(t,r):e.isNullOrUndef(t)||n.unshift(""+r);return n},toFontString:function(t){return!t||e.isNullOrUndef(t.size)||e.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family},textSize:function(t,e,r){var n,i=[].concat(e),o=i.length,a=t.font,l=0;for(t.font=r.string,n=0;n<o;++n)l=Math.max(t.measureText(i[n]).width,l);return t.font=a,{height:o*r.lineHeight,width:l}},parseFont:function(r){var i=t.defaults.global,o=e.valueOrDefault(r.size,i.defaultFontSize),a={family:e.valueOrDefault(r.family,i.defaultFontFamily),lineHeight:e.options.toLineHeight(r.lineHeight,o),size:o,style:e.valueOrDefault(r.style,i.defaultFontStyle),weight:e.valueOrDefault(r.weight,null),string:""};return a.string=n.toFontString(a),a},bound:function(t,e,r){return Math.max(t,Math.min(e,r))},arrayDiff:function(t,e){var r,n,i,o,a=t.slice(),l=[];for(r=0,i=e.length;r<i;++r)o=e[r],-1===(n=a.indexOf(o))?l.push([o,1]):a.splice(n,1);for(r=0,i=a.length;r<i;++r)l.push([a[r],-1]);return l},rasterize:function(t){return Math.round(t*r)/r}};function i(t,e){var r=e.x,n=e.y;if(null===r)return{x:0,y:-1};if(null===n)return{x:1,y:0};var i=t.x-r,o=t.y-n,a=Math.sqrt(i*i+o*o);return{x:a?i/a:0,y:a?o/a:-1}}var o=0,a=1,l=2,s=4,u=8;function f(t,e,r){var n=o;return t<r.left?n|=a:t>r.right&&(n|=l),e<r.top?n|=u:e>r.bottom&&(n|=s),n}function d(t,e){var r,n,i=e.anchor,o=t;return e.clamp&&(o=function(t,e){for(var r,n,i,o=t.x0,d=t.y0,c=t.x1,h=t.y1,x=f(o,d,e),y=f(c,h,e);x|y&&!(x&y);)(r=x||y)&u?(n=o+(c-o)*(e.top-d)/(h-d),i=e.top):r&s?(n=o+(c-o)*(e.bottom-d)/(h-d),i=e.bottom):r&l?(i=d+(h-d)*(e.right-o)/(c-o),n=e.right):r&a&&(i=d+(h-d)*(e.left-o)/(c-o),n=e.left),r===x?x=f(o=n,d=i,e):y=f(c=n,h=i,e);return{x0:o,x1:c,y0:d,y1:h}}(o,e.area)),"start"===i?(r=o.x0,n=o.y0):"end"===i?(r=o.x1,n=o.y1):(r=(o.x0+o.x1)/2,n=(o.y0+o.y1)/2),function(t,e,r,n,i){switch(i){case"center":r=n=0;break;case"bottom":r=0,n=1;break;case"right":r=1,n=0;break;case"left":r=-1,n=0;break;case"top":r=0,n=-1;break;case"start":r=-r,n=-n;break;case"end":break;default:i*=Math.PI/180,r=Math.cos(i),n=Math.sin(i)}return{x:t,y:e,vx:r,vy:n}}(r,n,t.vx,t.vy,e.align)}var c={arc:function(t,e){var r=(t.startAngle+t.endAngle)/2,n=Math.cos(r),i=Math.sin(r),o=t.innerRadius,a=t.outerRadius;return d({x0:t.x+n*o,y0:t.y+i*o,x1:t.x+n*a,y1:t.y+i*a,vx:n,vy:i},e)},point:function(t,e){var r=i(t,e.origin),n=r.x*t.radius,o=r.y*t.radius;return d({x0:t.x-n,y0:t.y-o,x1:t.x+n,y1:t.y+o,vx:r.x,vy:r.y},e)},rect:function(t,e){var r=i(t,e.origin),n=t.x,o=t.y,a=0,l=0;return t.horizontal?(n=Math.min(t.x,t.base),a=Math.abs(t.base-t.x)):(o=Math.min(t.y,t.base),l=Math.abs(t.base-t.y)),d({x0:n,y0:o+l,x1:n+a,y1:o,vx:r.x,vy:r.y},e)},fallback:function(t,e){var r=i(t,e.origin);return d({x0:t.x,y0:t.y,x1:t.x,y1:t.y,vx:r.x,vy:r.y},e)}},h=t.helpers,x=n.rasterize;function y(t){var e=t._model.horizontal,r=t._scale||e&&t._xScale||t._yScale;if(!r)return null;if(void 0!==r.xCenter&&void 0!==r.yCenter)return{x:r.xCenter,y:r.yCenter};var n=r.getBasePixel();return e?{x:n,y:null}:{x:null,y:n}}function v(t,e,r){var n=t.shadowBlur,i=r.stroked,o=x(r.x),a=x(r.y),l=x(r.w);i&&t.strokeText(e,o,a,l),r.filled&&(n&&i&&(t.shadowBlur=0),t.fillText(e,o,a,l),n&&i&&(t.shadowBlur=n))}var _=function(t,e,r,n){var i=this;i._config=t,i._index=n,i._model=null,i._rects=null,i._ctx=e,i._el=r};h.extend(_.prototype,{_modelize:function(e,r,i,o){var a,l=this._index,s=h.options.resolve,u=n.parseFont(s([i.font,{}],o,l)),f=s([i.color,t.defaults.global.defaultFontColor],o,l);return{align:s([i.align,"center"],o,l),anchor:s([i.anchor,"center"],o,l),area:o.chart.chartArea,backgroundColor:s([i.backgroundColor,null],o,l),borderColor:s([i.borderColor,null],o,l),borderRadius:s([i.borderRadius,0],o,l),borderWidth:s([i.borderWidth,0],o,l),clamp:s([i.clamp,!1],o,l),clip:s([i.clip,!1],o,l),color:f,display:e,font:u,lines:r,offset:s([i.offset,0],o,l),opacity:s([i.opacity,1],o,l),origin:y(this._el),padding:h.options.toPadding(s([i.padding,0],o,l)),positioner:(a=this._el,a instanceof t.elements.Arc?c.arc:a instanceof t.elements.Point?c.point:a instanceof t.elements.Rectangle?c.rect:c.fallback),rotation:s([i.rotation,0],o,l)*(Math.PI/180),size:n.textSize(this._ctx,r,u),textAlign:s([i.textAlign,"start"],o,l),textShadowBlur:s([i.textShadowBlur,0],o,l),textShadowColor:s([i.textShadowColor,f],o,l),textStrokeColor:s([i.textStrokeColor,f],o,l),textStrokeWiLine truncated
@@ -0,0 +1,7 @@
/*!
* chartjs-plugin-datalabels v2.0.0
* https://chartjs-plugin-datalabels.netlify.app
* (c) 2017-2021 chartjs-plugin-datalabels contributors
* Released under the MIT license
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js/helpers"),require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js/helpers","chart.js"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).ChartDataLabels=e(t.Chart.helpers,t.Chart)}(this,(function(t,e){"use strict";var r=function(){if("undefined"!=typeof window){if(window.devicePixelRatio)return window.devicePixelRatio;var t=window.screen;if(t)return(t.deviceXDPI||1)/(t.logicalXDPI||1)}return 1}(),a=function(e){var r,a=[];for(e=[].concat(e);e.length;)"string"==typeof(r=e.pop())?a.unshift.apply(a,r.split("\n")):Array.isArray(r)?e.push.apply(e,r):t.isNullOrUndef(e)||a.unshift(""+r);return a},o=function(t,e,r){var a,o=[].concat(e),n=o.length,i=t.font,l=0;for(t.font=r.string,a=0;a<n;++a)l=Math.max(t.measureText(o[a]).width,l);return t.font=i,{height:n*r.lineHeight,width:l}},n=function(t,e,r){return Math.max(t,Math.min(e,r))},i=function(t,e){var r,a,o,n,i=t.slice(),l=[];for(r=0,o=e.length;r<o;++r)n=e[r],-1===(a=i.indexOf(n))?l.push([n,1]):i.splice(a,1);for(r=0,o=i.length;r<o;++r)l.push([i[r],-1]);return l};function l(t,e){var r=e.x,a=e.y;if(null===r)return{x:0,y:-1};if(null===a)return{x:1,y:0};var o=t.x-r,n=t.y-a,i=Math.sqrt(o*o+n*n);return{x:i?o/i:0,y:i?n/i:-1}}function s(t,e,r){var a=0;return t<r.left?a|=1:t>r.right&&(a|=2),e<r.top?a|=8:e>r.bottom&&(a|=4),a}function u(t,e){var r,a,o=e.anchor,n=t;return e.clamp&&(n=function(t,e){for(var r,a,o,n=t.x0,i=t.y0,l=t.x1,u=t.y1,d=s(n,i,e),c=s(l,u,e);d|c&&!(d&c);)8&(r=d||c)?(a=n+(l-n)*(e.top-i)/(u-i),o=e.top):4&r?(a=n+(l-n)*(e.bottom-i)/(u-i),o=e.bottom):2&r?(o=i+(u-i)*(e.right-n)/(l-n),a=e.right):1&r&&(o=i+(u-i)*(e.left-n)/(l-n),a=e.left),r===d?d=s(n=a,i=o,e):c=s(l=a,u=o,e);return{x0:n,x1:l,y0:i,y1:u}}(n,e.area)),"start"===o?(r=n.x0,a=n.y0):"end"===o?(r=n.x1,a=n.y1):(r=(n.x0+n.x1)/2,a=(n.y0+n.y1)/2),function(t,e,r,a,o){switch(o){case"center":r=a=0;break;case"bottom":r=0,a=1;break;case"right":r=1,a=0;break;case"left":r=-1,a=0;break;case"top":r=0,a=-1;break;case"start":r=-r,a=-a;break;case"end":break;default:o*=Math.PI/180,r=Math.cos(o),a=Math.sin(o)}return{x:t,y:e,vx:r,vy:a}}(r,a,t.vx,t.vy,e.align)}var d=function(t,e){var r=(t.startAngle+t.endAngle)/2,a=Math.cos(r),o=Math.sin(r),n=t.innerRadius,i=t.outerRadius;return u({x0:t.x+a*n,y0:t.y+o*n,x1:t.x+a*i,y1:t.y+o*i,vx:a,vy:o},e)},c=function(t,e){var r=l(t,e.origin),a=r.x*t.options.radius,o=r.y*t.options.radius;return u({x0:t.x-a,y0:t.y-o,x1:t.x+a,y1:t.y+o,vx:r.x,vy:r.y},e)},h=function(t,e){var r=l(t,e.origin),a=t.x,o=t.y,n=0,i=0;return t.horizontal?(a=Math.min(t.x,t.base),n=Math.abs(t.base-t.x)):(o=Math.min(t.y,t.base),i=Math.abs(t.base-t.y)),u({x0:a,y0:o+i,x1:a+n,y1:o,vx:r.x,vy:r.y},e)},f=function(t,e){var r=l(t,e.origin);return u({x0:t.x,y0:t.y,x1:t.x,y1:t.y,vx:r.x,vy:r.y},e)},x=function(t){return Math.round(t*r)/r};function y(t,e){var r=e.chart.getDatasetMeta(e.datasetIndex).vScale;if(!r)return null;if(void 0!==r.xCenter&&void 0!==r.yCenter)return{x:r.xCenter,y:r.yCenter};var a=r.getBasePixel();return t.horizontal?{x:a,y:null}:{x:null,y:a}}function v(t,e,r){var a=r.backgroundColor,o=r.borderColor,n=r.borderWidth;(a||o&&n)&&(t.beginPath(),function(t,e,r,a,o,n){var i=Math.PI/2;if(n){var l=Math.min(n,o/2,a/2),s=e+l,u=r+l,d=e+a-l,c=r+o-l;t.moveTo(e,u),s<d&&u<c?(t.arc(s,u,l,-Math.PI,-i),t.arc(d,u,l,-i,0),t.arc(d,c,l,0,i),t.arc(s,c,l,i,Math.PI)):s<d?(t.moveTo(s,r),t.arc(d,u,l,-i,i),t.arc(s,u,l,i,Math.PI+i)):u<c?(t.arc(s,u,l,-Math.PI,0),t.arc(s,c,l,0,Math.PI)):t.arc(s,u,l,-Math.PI,Math.PI),t.closePath(),t.moveTo(e,r)}else t.rect(e,r,a,o)}(t,x(e.x)+n/2,x(e.y)+n/2,x(e.w)-n,x(e.h)-n,r.borderRadius),t.closePath(),a&&(t.fillStyle=a,t.fill()),o&&n&&(t.strokeStyle=o,t.lineWidth=n,t.lineJoin="miter",t.stroke()))}function b(t,e,r){var a=t.shadowBlur,o=r.stroked,n=x(r.x),i=x(r.y),l=x(r.w);o&&t.strokeText(e,n,i,l),r.filled&&(a&&o&&(t.shadowBlur=0),t.fillText(e,n,i,l),a&&o&&(t.shadowBlur=a))}var _=function(t,e,r,a){var o=this;o._config=t,o._index=a,o._model=null,o._rects=null,o._ctx=e,o._el=r};t.merge(_.prototype,{_modelize:function(r,a,n,i){var l,s=this,u=s._index,x=t.toFont(t.resolve([n.font,{}],i,u)),v=t.resolve([n.color,e.defaults.color],i,u);return{align:t.resolve([n.align,"center"],i,u),anchor:t.resolve([n.anchor,"center"],i,u),area:i.chart.chartArea,backgroundColor:t.resolve([n.backgroundColor,null],i,u),borderColor:t.resolve([n.borderColor,null],i,u),borderRadius:t.resolve([n.borderRadius,0],i,u),borderWidth:t.resolve([n.borderWidth,0],i,u),clamp:t.resolve([n.clamp,!1],i,u),clip:t.resolve([n.clip,!1],i,u),color:v,display:r,font:x,lines:a,offset:t.resolve([n.offset,0],i,u),opacity:t.resolve([n.opacity,1],i,u),origin:y(s._el,i),padding:t.toPadding(t.resolve([n.padding,0],i,u)),positioner:(l=s._el,l instanceof e.ArcElement?d:l instanceof e.PointElement?c:l instanceof e.BarElement?h:f),rotation:t.resolve([n.rotation,0],i,u)*(Math.PI/180),size:o(s._ctx,a,x),textAlign:t.resolve([n.textAlign,"start"],i,u),teLine truncated
@@ -11,7 +11,7 @@ $(document).ready(function() {
} else { } else {
var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent(); var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent();
if (parent_btn_grp.hasClass('btn-group')) { 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).text(lang_footer.loading);
$(elem).attr('data-submitted', '1'); $(elem).attr('data-submitted', '1');
@@ -355,11 +355,8 @@ $(document).ready(function() {
data_array[i] = decodeURIComponent(data_array[i]); data_array[i] = decodeURIComponent(data_array[i]);
$("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>"); $("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
} }
});
$('#ConfirmDeleteModal').modal({
backdrop: 'static',
keyboard: false
}) })
$('#ConfirmDeleteModal').modal('show')
.one('click', '#IsConfirmed', function(e) { .one('click', '#IsConfirmed', function(e) {
if (is_active($('#IsConfirmed'))) { return false; } if (is_active($('#IsConfirmed'))) { return false; }
$.ajax({ $.ajax({
@@ -383,4 +380,18 @@ $(document).ready(function() {
$('#ConfirmDeleteModal').modal('hide'); $('#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');
});
}); });
-778
View File
@@ -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));
+3
View File
@@ -0,0 +1,3 @@
/*! markdown-it 13.0.1 https://github.com/markdown-it/markdown-it @license MIT */
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownit=r()}(this,(function(){"use strict";function e(e){if(e.__esModule)return e;var r=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(e).forEach((function(t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})})),r}var r={Aacute:"\xc1",aacute:"\xe1",Abreve:"\u0102",abreve:"\u0103",ac:"\u223e",acd:"\u223f",acE:"\u223e\u0333",Acirc:"\xc2",acirc:"\xe2",acute:"\xb4",Acy:"\u0410",acy:"\u0430",AElig:"\xc6",aelig:"\xe6",af:"\u2061",Afr:"\ud835\udd04",afr:"\ud835\udd1e",Agrave:"\xc0",agrave:"\xe0",alefsym:"\u2135",aleph:"\u2135",Alpha:"\u0391",alpha:"\u03b1",Amacr:"\u0100",amacr:"\u0101",amalg:"\u2a3f",amp:"&",AMP:"&",andand:"\u2a55",And:"\u2a53",and:"\u2227",andd:"\u2a5c",andslope:"\u2a58",andv:"\u2a5a",ang:"\u2220",ange:"\u29a4",angle:"\u2220",angmsdaa:"\u29a8",angmsdab:"\u29a9",angmsdac:"\u29aa",angmsdad:"\u29ab",angmsdae:"\u29ac",angmsdaf:"\u29ad",angmsdag:"\u29ae",angmsdah:"\u29af",angmsd:"\u2221",angrt:"\u221f",angrtvb:"\u22be",angrtvbd:"\u299d",angsph:"\u2222",angst:"\xc5",angzarr:"\u237c",Aogon:"\u0104",aogon:"\u0105",Aopf:"\ud835\udd38",aopf:"\ud835\udd52",apacir:"\u2a6f",ap:"\u2248",apE:"\u2a70",ape:"\u224a",apid:"\u224b",apos:"'",ApplyFunction:"\u2061",approx:"\u2248",approxeq:"\u224a",Aring:"\xc5",aring:"\xe5",Ascr:"\ud835\udc9c",ascr:"\ud835\udcb6",Assign:"\u2254",ast:"*",asymp:"\u2248",asympeq:"\u224d",Atilde:"\xc3",atilde:"\xe3",Auml:"\xc4",auml:"\xe4",awconint:"\u2233",awint:"\u2a11",backcong:"\u224c",backepsilon:"\u03f6",backprime:"\u2035",backsim:"\u223d",backsimeq:"\u22cd",Backslash:"\u2216",Barv:"\u2ae7",barvee:"\u22bd",barwed:"\u2305",Barwed:"\u2306",barwedge:"\u2305",bbrk:"\u23b5",bbrktbrk:"\u23b6",bcong:"\u224c",Bcy:"\u0411",bcy:"\u0431",bdquo:"\u201e",becaus:"\u2235",because:"\u2235",Because:"\u2235",bemptyv:"\u29b0",bepsi:"\u03f6",bernou:"\u212c",Bernoullis:"\u212c",Beta:"\u0392",beta:"\u03b2",beth:"\u2136",between:"\u226c",Bfr:"\ud835\udd05",bfr:"\ud835\udd1f",bigcap:"\u22c2",bigcirc:"\u25ef",bigcup:"\u22c3",bigodot:"\u2a00",bigoplus:"\u2a01",bigotimes:"\u2a02",bigsqcup:"\u2a06",bigstar:"\u2605",bigtriangledown:"\u25bd",bigtriangleup:"\u25b3",biguplus:"\u2a04",bigvee:"\u22c1",bigwedge:"\u22c0",bkarow:"\u290d",blacklozenge:"\u29eb",blacksquare:"\u25aa",blacktriangle:"\u25b4",blacktriangledown:"\u25be",blacktriangleleft:"\u25c2",blacktriangleright:"\u25b8",blank:"\u2423",blk12:"\u2592",blk14:"\u2591",blk34:"\u2593",block:"\u2588",bne:"=\u20e5",bnequiv:"\u2261\u20e5",bNot:"\u2aed",bnot:"\u2310",Bopf:"\ud835\udd39",bopf:"\ud835\udd53",bot:"\u22a5",bottom:"\u22a5",bowtie:"\u22c8",boxbox:"\u29c9",boxdl:"\u2510",boxdL:"\u2555",boxDl:"\u2556",boxDL:"\u2557",boxdr:"\u250c",boxdR:"\u2552",boxDr:"\u2553",boxDR:"\u2554",boxh:"\u2500",boxH:"\u2550",boxhd:"\u252c",boxHd:"\u2564",boxhD:"\u2565",boxHD:"\u2566",boxhu:"\u2534",boxHu:"\u2567",boxhU:"\u2568",boxHU:"\u2569",boxminus:"\u229f",boxplus:"\u229e",boxtimes:"\u22a0",boxul:"\u2518",boxuL:"\u255b",boxUl:"\u255c",boxUL:"\u255d",boxur:"\u2514",boxuR:"\u2558",boxUr:"\u2559",boxUR:"\u255a",boxv:"\u2502",boxV:"\u2551",boxvh:"\u253c",boxvH:"\u256a",boxVh:"\u256b",boxVH:"\u256c",boxvl:"\u2524",boxvL:"\u2561",boxVl:"\u2562",boxVL:"\u2563",boxvr:"\u251c",boxvR:"\u255e",boxVr:"\u255f",boxVR:"\u2560",bprime:"\u2035",breve:"\u02d8",Breve:"\u02d8",brvbar:"\xa6",bscr:"\ud835\udcb7",Bscr:"\u212c",bsemi:"\u204f",bsim:"\u223d",bsime:"\u22cd",bsolb:"\u29c5",bsol:"\\",bsolhsub:"\u27c8",bull:"\u2022",bullet:"\u2022",bump:"\u224e",bumpE:"\u2aae",bumpe:"\u224f",Bumpeq:"\u224e",bumpeq:"\u224f",Cacute:"\u0106",cacute:"\u0107",capand:"\u2a44",capbrcup:"\u2a49",capcap:"\u2a4b",cap:"\u2229",Cap:"\u22d2",capcup:"\u2a47",capdot:"\u2a40",CapitalDifferentialD:"\u2145",caps:"\u2229\ufe00",caret:"\u2041",caron:"\u02c7",Cayleys:"\u212d",ccaps:"\u2a4d",Ccaron:"\u010c",ccaron:"\u010d",Ccedil:"\xc7",ccedil:"\xe7",Ccirc:"\u0108",ccirc:"\u0109",Cconint:"\u2230",ccups:"\u2a4c",ccupssm:"\u2a50",Cdot:"\u010a",cdot:"\u010b",cedil:"\xb8",Cedilla:"\xb8",cemptyv:"\u29b2",cent:"\xa2",centerdot:"\xb7",CenterDot:"\xb7",cfr:"\ud835\udd20",Cfr:"\u212d",CHcy:"\u0427",chcy:"\u0447",check:"\u2713",checkmark:"\u2713",Chi:"\u03a7",chi:"\u03c7",circ:"\u02c6",circeq:"\u2257",circlearrowleft:"\u21ba",circlearrowright:"\u21bb",circledast:"\u229b",circledcirc:"\u229a",circleddash:"\u229d",CircleDot:"\u2299",circledR:"\xae",circledS:"\u24c8",CircleMinus:"\u2296",CirclePlus:"\u2295",CircleTimes:"\u2297",cir:"\u25cb",cirE:"\u29c3",cire:"\u2257",cirfnint:"\u2a10",cirmid:"\u2aef",cirscir:"\u29c2",ClockwiseContourIntegral:"\u2232",CloseCurlyDoubleQuote:"\u201d",CloseCurlyQuote:"\u2019",clubs:"\u2663",clubsuit:"\u2663",colon:":",Colon:"\u2237",Colone:"\u2a74",colone:"\u2254",coloneq:"\u2254",comma:",",commat:"@",comp:"\u2201",compfn:"\u22Line truncated
/*! https://mths.be/punycode v1.4.1 by @mathias */function Lr(e){throw new RangeError(qr[e])}function zr(e,r){for(var t=e.length,n=[];t--;)n[t]=r(e[t]);return n}function Tr(e,r){var t=e.split("@"),n="";return t.length>1&&(n=t[0]+"@",e=t[1]),n+zr((e=e.replace(Er,".")).split("."),r).join(".")}function Ir(e){for(var r,t,n=[],s=0,o=e.length;s<o;)(r=e.charCodeAt(s++))>=55296&&r<=56319&&s<o?56320==(64512&(t=e.charCodeAt(s++)))?n.push(((1023&r)<<10)+(1023&t)+65536):(n.push(r),s--):n.push(r);return n}function Mr(e){return zr(e,(function(e){var r="";return e>65535&&(r+=Fr((e-=65536)>>>10&1023|55296),e=56320|1023&e),r+=Fr(e)})).join("")}function Rr(e,r){return e+22+75*(e<26)-((0!=r)<<5)}function Br(e,r,t){var n=0;for(e=t?Sr(e/700):e>>1,e+=Sr(e/r);e>455;n+=xr)e=Sr(e/35);return Sr(n+36*e/(e+38))}function Nr(e){var r,t,n,s,o,i,a,c,l,u,p,h=[],f=e.length,d=0,m=128,g=72;for((t=e.lastIndexOf("-"))<0&&(t=0),n=0;n<t;++n)e.charCodeAt(n)>=128&&Lr("not-basic"),h.push(e.charCodeAt(n));for(s=t>0?t+1:0;s<f;){for(o=d,i=1,a=xr;s>=f&&Lr("invalid-input"),((c=(p=e.charCodeAt(s++))-48<10?p-22:p-65<26?p-65:p-97<26?p-97:xr)>=xr||c>Sr((Ar-d)/i))&&Lr("overflow"),d+=c*i,!(c<(l=a<=g?1:a>=g+26?26:a-g));a+=xr)i>Sr(Ar/(u=xr-l))&&Lr("overflow"),i*=u;g=Br(d-o,r=h.length+1,0==o),Sr(d/r)>Ar-m&&Lr("overflow"),m+=Sr(d/r),d%=r,h.splice(d++,0,m)}return Mr(h)}function Or(e){var r,t,n,s,o,i,a,c,l,u,p,h,f,d,m,g=[];for(h=(e=Ir(e)).length,r=128,t=0,o=72,i=0;i<h;++i)(p=e[i])<128&&g.push(Fr(p));for(n=s=g.length,s&&g.push("-");n<h;){for(a=Ar,i=0;i<h;++i)(p=e[i])>=r&&p<a&&(a=p);for(a-r>Sr((Ar-t)/(f=n+1))&&Lr("overflow"),t+=(a-r)*f,r=a,i=0;i<h;++i)if((p=e[i])<r&&++t>Ar&&Lr("overflow"),p==r){for(c=t,l=xr;!(c<(u=l<=o?1:l>=o+26?26:l-o));l+=xr)m=c-u,d=xr-u,g.push(Fr(Rr(u+m%d,0))),c=Sr(m/d);g.push(Fr(Rr(c,0))),o=Br(t,f,n==s),t=0,++n}++t,++r}return g.join("")}function Pr(e){return Tr(e,(function(e){return Dr.test(e)?Nr(e.slice(4).toLowerCase()):e}))}function jr(e){return Tr(e,(function(e){return wr.test(e)?"xn--"+Or(e):e}))}var Ur="1.4.1",Vr={decode:Ir,encode:Mr},Zr={version:Ur,ucs2:Vr,toASCII:jr,toUnicode:Pr,encode:Or,decode:Nr},$r=e(Object.freeze({__proto__:null,decode:Nr,encode:Or,toUnicode:Pr,toASCII:jr,version:Ur,ucs2:Vr,default:Zr})),Gr={default:{options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}},zero:{options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline","text_join"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","fragments_join"]}}},commonmark:{options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline","text_join"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","fragments_join"]}}}},Hr=/^(vbscript|javascript|file|data):/,Jr=/^data:image\/(gif|png|jpeg|webp);/;function Wr(e){var r=e.trim().toLowerCase();return!Hr.test(r)||!!Jr.test(r)}var Yr=["http:","https:","mailto:"];function Kr(e){var r=C.parse(e,!0);if(r.hostname&&(!r.protocol||Yr.indexOf(r.protocol)>=0))try{r.hostname=$r.toASCII(r.hostname)}catch(e){}return C.encode(C.format(r))}function Qr(e){var r=C.parse(e,!0);if(r.hostname&&(!r.protocol||Yr.indexOf(r.protocol)>=0))try{r.hostname=$r.toUnicode(r.hostname)}catch(e){}return C.decode(C.format(r),C.decode.defaultChars+"%")}function Xr(e,r){if(!(this instanceof Xr))return new Xr(e,r);r||w.isString(e)||(r=e||{},e="default"),this.inline=new ur,this.block=new ze,this.core=new ue,this.renderer=new B,this.linkify=new yr,this.validateLink=Wr,this.normalizeLink=Kr,this.normalizeLinkText=Qr,this.utils=w,this.helpers=w.assign({},L),this.options={},this.configure(e),r&&this.set(r)}return Xr.prototype.set=function(e){return w.assign(this.options,e),this},Xr.prototype.configure=function(e){var r,t=this;if(w.isString(e)&&!(e=Gr[r=e]))throw new Error('Wrong `markdown-it` preset "'+r+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&t.set(e.options),e.components&&Object.keys(e.components).forEach((function(r){e.components[r].rules&&t[r].ruler.enableOnly(e.components[r].rules),e.components[r].rules2&&t[r].ruler2.enableOnly(e.components[r].rules2)})),this},Xr.prototype.enable=function(e,r){var t=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(r){t=t.concat(this[r].ruler.enable(e,!0))}),this),t=t.concat(this.inline.ruler2.enable(e,!0));var n=e.filter((function(e){return t.indexOf(e)<0}));if(n.length&&!r)throw new Error("MarkdLine truncated
@@ -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);
-10
View File
@@ -1,10 +0,0 @@
/*
* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
* @version 3.1.6
* @link http://fooplugins.com
* @copyright Steven Usher & Brad Vincent 2015
* @license Released under the GPLv3 license.
*/
!function(a,b){window.console=window.console||{log:function(){},error:function(){}},a.fn.footable=function(a,c){return a=a||{},this.filter("table").each(function(d,e){b.init(e,a,c)})};var c={events:[]};b.__debug__=JSON.parse(localStorage.getItem("footable_debug"))||!1,b.__debug_options__=JSON.parse(localStorage.getItem("footable_debug_options"))||c,b.debug=function(d,e){return b.is["boolean"](d)?(b.__debug__=d,void(b.__debug__?(localStorage.setItem("footable_debug",JSON.stringify(b.__debug__)),b.__debug_options__=a.extend(!0,{},c,e||{}),b.is.hash(e)&&localStorage.setItem("footable_debug_options",JSON.stringify(b.__debug_options__))):(localStorage.removeItem("footable_debug"),localStorage.removeItem("footable_debug_options")))):b.__debug__},b.get=function(b){return a(b).first().data("__FooTable__")},b.init=function(a,c,d){var e=b.get(a);return e instanceof b.Table&&e.destroy(),new b.Table(a,c,d)},b.getRow=function(b){var c=a(b).closest("tr");return c.hasClass("footable-detail-row")&&(c=c.prev()),c.data("__FooTableRow__")}}(jQuery,FooTable=window.FooTable||{}),function(a){var b=function(){return!0};a.arr={},a.arr.each=function(b,c){if(a.is.array(b)&&a.is.fn(c))for(var d=0,e=b.length;e>d&&c(b[d],d)!==!1;d++);},a.arr.get=function(b,c){var d=[];if(!a.is.array(b))return d;if(!a.is.fn(c))return b;for(var e=0,f=b.length;f>e;e++)c(b[e],e)&&d.push(b[e]);return d},a.arr.any=function(c,d){if(!a.is.array(c))return!1;d=a.is.fn(d)?d:b;for(var e=0,f=c.length;f>e;e++)if(d(c[e],e))return!0;return!1},a.arr.contains=function(b,c){if(!a.is.array(b)||a.is.undef(c))return!1;for(var d=0,e=b.length;e>d;d++)if(b[d]==c)return!0;return!1},a.arr.first=function(c,d){if(!a.is.array(c))return null;d=a.is.fn(d)?d:b;for(var e=0,f=c.length;f>e;e++)if(d(c[e],e))return c[e];return null},a.arr.map=function(b,c){var d=[],e=null;if(!a.is.array(b)||!a.is.fn(c))return d;for(var f=0,g=b.length;g>f;f++)null!=(e=c(b[f],f))&&d.push(e);return d},a.arr.remove=function(b,c){var d=[],e=[];if(!a.is.array(b)||!a.is.fn(c))return e;for(var f=0,g=b.length;g>f;f++)c(b[f],f,e)&&(d.push(f),e.push(b[f]));for(d.sort(function(a,b){return b-a}),f=0,g=d.length;g>f;f++){var h=d[f]-f;b.splice(h,1)}return e},a.arr["delete"]=function(b,c){var d=-1,e=null;if(!a.is.array(b)||a.is.undef(c))return e;for(var f=0,g=b.length;g>f;f++)if(b[f]==c){d=f,e=b[f];break}return-1!=d&&b.splice(d,1),e},a.arr.replace=function(a,b,c){var d=a.indexOf(b);-1!==d&&(a[d]=c)}}(FooTable),function(a){a.is={},a.is.type=function(a,b){return typeof a===b},a.is.defined=function(a){return"undefined"!=typeof a},a.is.undef=function(a){return"undefined"==typeof a},a.is.array=function(a){return"[object Array]"===Object.prototype.toString.call(a)},a.is.date=function(a){return"[object Date]"===Object.prototype.toString.call(a)&&!isNaN(a.getTime())},a.is["boolean"]=function(a){return"[object Boolean]"===Object.prototype.toString.call(a)},a.is.string=function(a){return"[object String]"===Object.prototype.toString.call(a)},a.is.number=function(a){return"[object Number]"===Object.prototype.toString.call(a)&&!isNaN(a)},a.is.fn=function(b){return a.is.defined(window)&&b===window.alert||"[object Function]"===Object.prototype.toString.call(b)},a.is.error=function(a){return"[object Error]"===Object.prototype.toString.call(a)},a.is.object=function(a){return"[object Object]"===Object.prototype.toString.call(a)},a.is.hash=function(b){return a.is.object(b)&&b.constructor===Object&&!b.nodeType&&!b.setInterval},a.is.element=function(a){return"object"==typeof HTMLElement?a instanceof HTMLElement:a&&"object"==typeof a&&null!==a&&1===a.nodeType&&"string"==typeof a.nodeName},a.is.promise=function(b){return a.is.object(b)&&a.is.fn(b.then)&&a.is.fn(b.promise)},a.is.jq=function(b){return a.is.defined(window.jQuery)&&b instanceof jQuery&&b.length>0},a.is.moment=function(b){return a.is.defined(window.moment)&&a.is.object(b)&&a.is["boolean"](b._isAMomentObject)},a.is.emptyObject=function(b){if(!a.is.hash(b))return!1;for(var c in b)if(b.hasOwnProperty(c))return!1;return!0},a.is.emptyArray=function(b){return a.is.array(b)?0===b.length:!0},a.is.emptyString=function(b){return a.is.string(b)?0===b.length:!0}}(FooTable),function(a){a.str={},a.str.contains=function(b,c,d){return a.is.emptyString(b)||a.is.emptyString(c)?!1:c.length<=b.length&&-1!==(d?b.toUpperCase().indexOf(c.toUpperCase()):b.indexOf(c))},a.str.containsExact=function(b,c,d){return a.is.emptyString(b)||a.is.emptyString(c)||c.length>b.length?!1:new RegExp("\\b"+a.str.escapeRegExp(c)+"\\b",d?"i":"").test(b)},a.str.containsWord=function(b,c,d){if(a.is.emptyString(b)||a.is.emptyString(c)||b.length<c.length)return!1;for(var e=b.split(/\W/),f=0,g=e.length;g>f;f++)if(d?e[f].toUpperCase()==c.toUpperCase():e[f]==c)return!0;return!1},a.str.from=function(b,c){return a.is.emptyString(b)?b:a.str.contains(b,c)?b.substring(b.indexOf(c)+1):b},a.str.startsWith=function(b,c){return a.is.emptyString(b)?b==c:b.slice(0,c.length)==c},a.str.toCamelCase=function(b){return a.is.emptyString(b)?b:b.toUppLine truncated
return a.index-b.index}),a.resolve(f))},preinit:function(a){var c=this;return c.ft.raise("preinit.ft.columns",[a]).then(function(){return c.parse(a).then(function(d){c.array=d,c.showHeader=b.is["boolean"](a.showHeader)?a.showHeader:c.showHeader})})},init:function(){var a=this;return this.ft.raise("init.ft.columns",[a.array]).then(function(){a.$create()})},destroy:function(){var a=this;this.ft.raise("destroy.ft.columns").then(function(){a._fromHTML||a.$header.remove()})},predraw:function(){var a=this,c=!0;a.visibleColspan=0,a.firstVisibleIndex=0,a.lastVisibleIndex=0,a.hasHidden=!1,b.arr.each(a.array,function(b){b.hidden=!a.ft.breakpoints.visible(b.breakpoints),!b.hidden&&b.visible&&(c&&(a.firstVisibleIndex=b.index,c=!1),a.lastVisibleIndex=b.index,a.visibleColspan++),b.hidden&&(a.hasHidden=!0)}),a.ft.$el.toggleClass("breakpoint",a.hasHidden)},draw:function(){b.arr.each(this.array,function(a){a.$el.css("display",a.hidden||!a.visible?"none":"table-cell")}),!this.showHeader&&b.is.jq(this.$header.parent())&&this.$header.detach()},$create:function(){var c=this;c.$header=b.is.jq(c.$header)?c.$header:a("<tr/>",{"class":"footable-header"}),c.$header.children("th,td").detach(),b.arr.each(c.array,function(a){c.$header.append(a.$el)}),c.showHeader&&!b.is.jq(c.$header.parent())&&c.ft.$el.children("thead").append(c.$header)},get:function(a){return a instanceof b.Column?a:b.is.string(a)?b.arr.first(this.array,function(b){return b.name==a}):b.is.number(a)?b.arr.first(this.array,function(b){return b.index==a}):b.is.fn(a)?b.arr.get(this.array,a):null},ensure:function(a){var c=this,d=[];return b.is.array(a)?(b.arr.each(a,function(a){d.push(c.get(a))}),d):d}}),b.components.register("columns",b.Columns,900)}(jQuery,FooTable),function(a){a.Defaults.prototype.columns=[],a.Defaults.prototype.showHeader=!0}(FooTable),function(a,b){b.Rows=b.Component.extend({construct:function(a){this._super(a,!0),this.o=a.o,this.array=[],this.all=[],this.showToggle=a.o.showToggle,this.toggleSelector=a.o.toggleSelector,this.toggleColumn=a.o.toggleColumn,this.emptyString=a.o.empty,this.expandFirst=a.o.expandFirst,this.expandAll=a.o.expandAll,this.$empty=null,this._fromHTML=b.is.emptyArray(a.o.rows)&&!b.is.promise(a.o.rows)},parse:function(){var c=this;return a.Deferred(function(a){var d=c.ft.$el.children("tbody").children("tr");b.is.array(c.o.rows)&&c.o.rows.length>0?c.parseFinalize(a,c.o.rows):b.is.promise(c.o.rows)?c.o.rows.then(function(b){c.parseFinalize(a,b)},function(b){a.reject(Error("Rows ajax request error: "+b.status+" ("+b.statusText+")"))}):b.is.jq(d)?(c.parseFinalize(a,d),d.detach()):c.parseFinalize(a,[])})},parseFinalize:function(c,d){var e=this,f=a.map(d,function(a){return new b.Row(e.ft,e.ft.columns.array,a)});c.resolve(f)},preinit:function(a){var c=this;return c.ft.raise("preinit.ft.rows",[a]).then(function(){return c.parse().then(function(d){c.all=d,c.array=c.all.slice(0),c.showToggle=b.is["boolean"](a.showToggle)?a.showToggle:c.showToggle,c.toggleSelector=b.is.string(a.toggleSelector)?a.toggleSelector:c.toggleSelector,c.toggleColumn=b.is.string(a.toggleColumn)?a.toggleColumn:c.toggleColumn,"first"!=c.toggleColumn&&"last"!=c.toggleColumn&&(c.toggleColumn="first"),c.emptyString=b.is.string(a.empty)?a.empty:c.emptyString,c.expandFirst=b.is["boolean"](a.expandFirst)?a.expandFirst:c.expandFirst,c.expandAll=b.is["boolean"](a.expandAll)?a.expandAll:c.expandAll})})},init:function(){var a=this;return a.ft.raise("init.ft.rows",[a.all]).then(function(){a.$create()})},destroy:function(){var a=this;this.ft.raise("destroy.ft.rows").then(function(){b.arr.each(a.array,function(b){b.predraw(!a._fromHTML)}),a.all=a.array=[]})},predraw:function(){b.arr.each(this.array,function(a){a.predraw()}),this.array=this.all.slice(0)},$create:function(){this.$empty=a("<tr/>",{"class":"footable-empty"}).append(a("<td/>").text(this.emptyString))},draw:function(){var a=this,c=a.ft.$el.children("tbody"),d=!0;a.array.length>0?(a.$empty.detach(),b.arr.each(a.array,function(b){(a.expandFirst&&d||a.expandAll)&&(b.expanded=!0,d=!1),b.draw(c)})):(a.$empty.children("td").attr("colspan",a.ft.columns.visibleColspan),c.append(a.$empty))},load:function(c,d){var e=this,f=a.map(c,function(a){return new b.Row(e.ft,e.ft.columns.array,a)});b.arr.each(this.array,function(a){a.predraw()}),this.all=(b.is["boolean"](d)?d:!1)?this.all.concat(f):f,this.array=this.all.slice(0),this.ft.draw()},expand:function(){b.arr.each(this.array,function(a){a.expand()})},collapse:function(){b.arr.each(this.array,function(a){a.collapse()})}}),b.components.register("rows",b.Rows,800)}(jQuery,FooTable),function(a){a.Defaults.prototype.rows=[],a.Defaults.prototype.empty="No results",a.Defaults.prototype.showToggle=!0,a.Defaults.prototype.toggleSelector="tr,td,.footable-toggle",a.Defaults.prototype.toggleColumn="first",a.Defaults.prototype.expandFirst=!1,a.Defaults.prototype.expandAll=!1}(FooTable),function(a){a.Table.prototype.loadRows=function(a,b){this.rows.load(a,b)}}(FooTable),function(a){a.Filter=a.ClLine truncated
a&&this.$pagination.children("li.footable-page").removeClass("active").filter('li[data-page="'+this.current+'"]').addClass("active")},_setVisible:function(a,b){if(this.limit>0&&this.total>this.limit){if(!this.$pagination.children('li.footable-page[data-page="'+a+'"]').hasClass("visible")){var c=0,d=0;1==b?(d=a>this.total?this.total:a,c=d-this.limit):(c=1>a?0:a-1,d=c+this.limit),0>c&&(c=0,d=this.limit>this.total?this.total:this.limit),d>this.total&&(d=this.total,c=this.total-this.limit<0?0:this.total-this.limit),this.$pagination.children("li.footable-page").removeClass("visible").slice(c,d).addClass("visible")}}else this.$pagination.children("li.footable-page").removeClass("visible").slice(0,this.total).addClass("visible")},_onPageClicked:function(b){if(b.preventDefault(),!a(b.target).closest("li").is(".active,.disabled")){var c=b.data.self,d=a(this).data("page");switch(d){case"first":return void c.first();case"prev":return void c.prev();case"next":return void c.next();case"last":return void c.last();case"prev-limit":return void c.prevPages();case"next-limit":return void c.nextPages();default:return void c._set(d)}}}}),b.components.register("paging",b.Paging,400)}(jQuery,FooTable),function(a){a.Defaults.prototype.paging={enabled:!1,countFormat:"{CP} of {TP}",current:1,limit:5,position:"center",size:10,container:null,strings:{first:"&laquo;",prev:"&lsaquo;",next:"&rsaquo;",last:"&raquo;",prevPages:"...",nextPages:"..."}}}(FooTable),function(a){a.Table.prototype.gotoPage=function(b){return this.use(a.Paging)["goto"](b)},a.Table.prototype.nextPage=function(){return this.use(a.Paging).next()},a.Table.prototype.prevPage=function(){return this.use(a.Paging).prev()},a.Table.prototype.firstPage=function(){return this.use(a.Paging).first()},a.Table.prototype.lastPage=function(){return this.use(a.Paging).last()},a.Table.prototype.nextPages=function(){return this.use(a.Paging).nextPages()},a.Table.prototype.prevPages=function(){return this.use(a.Paging).prevPages()},a.Table.prototype.pageSize=function(b){return this.use(a.Paging).pageSize(b)}}(FooTable),function(a,b){b.Editing=b.Component.extend({construct:function(c){this._super(c,c.o.editing.enabled),this.pageToNew=c.o.editing.pageToNew,this.alwaysShow=c.o.editing.alwaysShow,this.column=a.extend(!0,{},c.o.editing.column,{visible:this.alwaysShow}),this.position=c.o.editing.position,this.showText=c.o.editing.showText,this.hideText=c.o.editing.hideText,this.addText=c.o.editing.addText,this.editText=c.o.editing.editText,this.deleteText=c.o.editing.deleteText,this.viewText=c.o.editing.viewText,this.allowAdd=c.o.editing.allowAdd,this.allowEdit=c.o.editing.allowEdit,this.allowDelete=c.o.editing.allowDelete,this.allowView=c.o.editing.allowView,this._$buttons=null,this.callbacks={addRow:b.checkFnValue(this,c.o.editing.addRow),editRow:b.checkFnValue(this,c.o.editing.editRow),deleteRow:b.checkFnValue(this,c.o.editing.deleteRow),viewRow:b.checkFnValue(this,c.o.editing.viewRow)}},preinit:function(c){var d=this;this.ft.raise("preinit.ft.editing",[c]).then(function(){if(d.ft.$el.hasClass("footable-editing")&&(d.enabled=!0),d.enabled=b.is["boolean"](c.editing)?c.editing:d.enabled,d.enabled){if(d.pageToNew=b.is["boolean"](c.editingPageToNew)?c.editingPageToNew:d.pageToNew,d.alwaysShow=b.is["boolean"](c.editingAlwaysShow)?c.editingAlwaysShow:d.alwaysShow,d.position=b.is.string(c.editingPosition)?c.editingPosition:d.position,d.showText=b.is.string(c.editingShowText)?c.editingShowText:d.showText,d.hideText=b.is.string(c.editingHideText)?c.editingHideText:d.hideText,d.addText=b.is.string(c.editingAddText)?c.editingAddText:d.addText,d.editText=b.is.string(c.editingEditText)?c.editingEditText:d.editText,d.deleteText=b.is.string(c.editingDeleteText)?c.editingDeleteText:d.deleteText,d.viewText=b.is.string(c.editingViewText)?c.editingViewText:d.viewText,d.allowAdd=b.is["boolean"](c.editingAllowAdd)?c.editingAllowAdd:d.allowAdd,d.allowEdit=b.is["boolean"](c.editingAllowEdit)?c.editingAllowEdit:d.allowEdit,d.allowDelete=b.is["boolean"](c.editingAllowDelete)?c.editingAllowDelete:d.allowDelete,d.allowView=b.is["boolean"](c.editingAllowView)?c.editingAllowView:d.allowView,d.column=new b.EditingColumn(d.ft,d,a.extend(!0,{},d.column,c.editingColumn,{visible:d.alwaysShow})),d.ft.$el.hasClass("footable-editing-left")&&(d.position="left"),d.ft.$el.hasClass("footable-editing-right")&&(d.position="right"),"right"===d.position)d.column.index=d.ft.columns.array.length;else{d.column.index=0;for(var e=0,f=d.ft.columns.array.length;f>e;e++)d.ft.columns.array[e].index+=1}d.ft.columns.array.push(d.column),d.ft.columns.array.sort(function(a,b){return a.index-b.index}),d.callbacks.addRow=b.checkFnValue(d,c.editingAddRow,d.callbacks.addRow),d.callbacks.editRow=b.checkFnValue(d,c.editingEditRow,d.callbacks.editRow),d.callbacks.deleteRow=b.checkFnValue(d,c.editingDeleteRow,d.callbacks.deleteRow),d.callbacks.viewRow=b.checkFnValue(d,c.editingViewRow,d.callbacks.viewRow)}},function(){d.enabled=!1})},init:function(){vLine truncated
@@ -55,14 +55,14 @@ $(document).ready(function() {
// tooltips // tooltips
$(function () { $(function () {
$('[data-toggle="tooltip"]').tooltip() $('[data-bs-toggle="tooltip"]').tooltip()
}); });
// remember last navigation pill // remember last navigation pill
(function () { (function () {
'use strict'; 'use strict';
if ($('a[data-toggle="tab"]').length) { // remember desktop tabs
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $('button[data-bs-toggle="tab"]').on('click', function (e) {
if ($(this).data('dont-remember') == 1) { if ($(this).data('dont-remember') == 1) {
return true; return true;
} }
@@ -71,8 +71,28 @@ $(document).ready(function() {
if (id) { if (id) {
key += ':' + 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) { $('[role="tablist"]').each(function (idx, elem) {
var id = $(elem).attr('id'); var id = $(elem).attr('id');
var key = 'lastTag'; var key = 'lastTag';
@@ -81,10 +101,11 @@ $(document).ready(function() {
} }
var lastTab = localStorage.getItem(key); var lastTab = localStorage.getItem(key);
if (lastTab) { 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 // IE fix to hide scrollbars when table body is empty
@@ -119,7 +140,7 @@ $(document).ready(function() {
shake(password_field); shake(password_field);
} }
else { 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); $(hibp_result).text(lang_footer.loading);
var password_digest = $.sha1($(password_field).val()) var password_digest = $.sha1($(password_field).val())
var digest_five = password_digest.substring(0, 5).toUpperCase(); var digest_five = password_digest.substring(0, 5).toUpperCase();
@@ -130,16 +151,16 @@ $(document).ready(function() {
type: 'GET', type: 'GET',
success: function(res) { success: function(res) {
if (res.search(compl_digest) > -1){ 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) $(hibp_result).text(lang_footer.hibp_nok)
} else { } 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_result).text(lang_footer.hibp_ok)
} }
$(hibp_field).removeClass('task-running'); $(hibp_field).removeClass('task-running');
}, },
error: function(xhr, status, error) { 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_result).text('API error: ' + xhr.responseText)
$(hibp_field).removeClass('task-running'); $(hibp_field).removeClass('task-running');
} }
@@ -150,8 +171,8 @@ $(document).ready(function() {
// Disable disallowed inputs // Disable disallowed inputs
$('[data-acl="0"]').each(function(event){ $('[data-acl="0"]').each(function(event){
if ($(this).is("a")) { if ($(this).is("a")) {
$(this).removeAttr("data-toggle"); $(this).removeAttr("data-bs-toggle");
$(this).removeAttr("data-target"); $(this).removeAttr("data-bs-target");
$(this).removeAttr("data-action"); $(this).removeAttr("data-action");
$(this).click(function(event) { $(this).click(function(event) {
event.preventDefault(); event.preventDefault();
@@ -166,8 +187,8 @@ $(document).ready(function() {
if ($(this).hasClass('btn-group')) { if ($(this).hasClass('btn-group')) {
$(this).find('a').each(function(){ $(this).find('a').each(function(){
$(this).removeClass('dropdown-toggle') $(this).removeClass('dropdown-toggle')
.removeAttr('data-toggle') .removeAttr('data-bs-toggle')
.removeAttr('data-target') .removeAttr('data-bs-target')
.removeAttr('data-action') .removeAttr('data-action')
.removeAttr('id') .removeAttr('id')
.attr("disabled", true); .attr("disabled", true);
@@ -182,7 +203,7 @@ $(document).ready(function() {
} else if ($(this).hasClass('input-group')) { } else if ($(this).hasClass('input-group')) {
$(this).find('input').each(function() { $(this).find('input').each(function() {
$(this).removeClass('dropdown-toggle') $(this).removeClass('dropdown-toggle')
.removeAttr('data-toggle') .removeAttr('data-bs-toggle')
.attr("disabled", true); .attr("disabled", true);
$(this).click(function(event) { $(this).click(function(event) {
event.preventDefault(); event.preventDefault();
@@ -226,7 +247,7 @@ $(document).ready(function() {
$('#containerName').text(container); $('#containerName').text(container);
$('#triggerRestartContainer').click(function(){ $('#triggerRestartContainer').click(function(){
$(this).prop("disabled",true); $(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); $('#statusTriggerRestartContainer').html(lang_footer.restarting_container);
$.ajax({ $.ajax({
method: 'get', method: 'get',
@@ -253,25 +274,9 @@ $(document).ready(function() {
}); });
}) })
// responsive tabs // Jquery Datatables, enable responsive plugin
$('.responsive-tabs').tabCollapse({ $.extend($.fn.dataTable.defaults, {
tabsClass: 'hidden-xs', responsive: true
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);
}
}
}); });
// tag boxes // tag boxes
@@ -284,12 +289,43 @@ $(document).ready(function() {
addTag(this); addTag(this);
} }
}); });
function addTag(tagAddElem){
// 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');
}
}
});
// https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
function escapeHtml(n){var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function unescapeHtml(t){var n={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#x2F;":"/","&#x60;":"`","&#x3D;":"="};return String(t).replace(/&amp;|&lt;|&gt;|&quot;|&#39;|&#x2F|&#x60|&#x3D;/g,function(t){return n[t]})}
function addTag(tagAddElem, tag = null){
var tagboxElem = $(tagAddElem).parent(); var tagboxElem = $(tagAddElem).parent();
var tagInputElem = $(tagboxElem).find(".tag-input")[0]; var tagInputElem = $(tagboxElem).find(".tag-input")[0];
var tagValuesElem = $(tagboxElem).find(".tag-values")[0]; var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
var tag = escapeHtml($(tagInputElem).val()); if (!tag)
tag = $(tagInputElem).val();
if (!tag) return; if (!tag) return;
var value_tags = []; var value_tags = [];
try { try {
@@ -298,7 +334,7 @@ $(document).ready(function() {
if (!Array.isArray(value_tags)) value_tags = []; if (!Array.isArray(value_tags)) value_tags = [];
if (value_tags.includes(tag)) return; 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(){ $('<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_tag = unescapeHtml($(this).text());
var del_tags = []; var del_tags = [];
try { try {
@@ -311,13 +347,7 @@ $(document).ready(function() {
$(this).remove(); $(this).remove();
}); });
value_tags.push($(tagInputElem).val()); value_tags.push(tag);
$(tagValuesElem).val(JSON.stringify(value_tags)); $(tagValuesElem).val(JSON.stringify(value_tags));
$(tagInputElem).val(''); $(tagInputElem).val('');
} }
});
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
function escapeHtml(n){var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function unescapeHtml(t){var n={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#x2F;":"/","&#x60;":"`","&#x3D;":"="};return String(t).replace(/&amp;|&lt;|&gt;|&quot;|&#39;|&#x2F|&#x60|&#x3D;/g,function(t){return n[t]})}
+418 -230
View File
@@ -53,237 +53,426 @@ jQuery(function($){
$("#show_rspamd_global_filters").click(function() { $("#show_rspamd_global_filters").click(function() {
$.get("inc/ajax/show_rspamd_global_filters.php"); $.get("inc/ajax/show_rspamd_global_filters.php");
$("#confirm_show_rspamd_global_filters").hide(); $("#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); }); $("#super_delete").click(function() { return confirm(lang.queue_ays); });
$(".refresh_table").on('click', function(e) { $(".refresh_table").on('click', function(e) {
e.preventDefault(); e.preventDefault();
var table_name = $(this).data('table'); var table_name = $(this).data('table');
$('#' + table_name).find("tr.footable-empty").remove(); $('#' + table_name).DataTable().ajax.reload();
draw_table = $(this).data('draw');
eval(draw_table + '()');
}); });
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() { function draw_domain_admins() {
ft_domainadmins = FooTable.init('#domainadminstable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#domainadminstable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, $('#domainadminstable').DataTable().columns.adjust().responsive.recalc();
{"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}}, return;
{"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>';}}, $('#domainadminstable').DataTable({
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} processing: true,
], serverSide: false,
"rows": $.ajax({ language: lang_datatables,
dataType: 'json', ajax: {
url: '/api/v1/get/domain-admin/all', type: "GET",
jsonp: false, url: "/api/v1/get/domain-admin/all",
error: function () { dataSrc: function(data){
console.log('Cannot draw domain admin table');
},
success: function (data) {
return process_table_data(data, 'domainadminstable'); return process_table_data(data, 'domainadminstable');
} }
}), },
"empty": lang.empty, columns: [
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, {
"state": {"enabled": true}, // placeholder, so checkbox will not block child row toggle
"filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table}, title: '',
"sorting": {"enabled": true}, data: null,
"toggleSelector": "table tbody span.footable-toggle" 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() { function draw_oauth2_clients() {
ft_oauth2clientstable = FooTable.init('#oauth2clientstable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"}, $('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc();
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, return;
{"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"}, $('#oauth2clientstable').DataTable({
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} processing: true,
], serverSide: false,
"rows": $.ajax({ language: lang_datatables,
dataType: 'json', ajax: {
url: '/api/v1/get/oauth2-client/all', type: "GET",
jsonp: false, url: "/api/v1/get/oauth2-client/all",
error: function () { dataSrc: function(data){
console.log('Cannot draw oauth2 clients table');
},
success: function (data) {
return process_table_data(data, 'oauth2clientstable'); return process_table_data(data, 'oauth2clientstable');
} }
}), },
"empty": lang.empty, columns: [
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, {
"sorting": {"enabled": true}, // placeholder, so checkbox will not block child row toggle
"toggleSelector": "table tbody span.footable-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() { function draw_admins() {
ft_admins = FooTable.init('#adminstable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#adminstable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, $('#adminstable').DataTable().columns.adjust().responsive.recalc();
{"sorted": true,"name":"usr","title":lang.username,"style":{"width":"250px"}}, return;
{"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"} $('#adminstable').DataTable({
], processing: true,
"rows": $.ajax({ serverSide: false,
dataType: 'json', language: lang_datatables,
url: '/api/v1/get/admin/all', ajax: {
jsonp: false, type: "GET",
error: function () { url: "/api/v1/get/admin/all",
console.log('Cannot draw admin table'); dataSrc: function(data){
},
success: function (data) {
return process_table_data(data, 'adminstable'); return process_table_data(data, 'adminstable');
} }
}), },
"empty": lang.empty, columns: [
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, {
"filtering": {"enabled": false}, // placeholder, so checkbox will not block child row toggle
"state": {"enabled": true}, title: '',
"sorting": {"enabled": true}, data: null,
"toggleSelector": "table tbody span.footable-toggle" 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() { function draw_fwd_hosts() {
ft_forwardinghoststable = FooTable.init('#forwardinghoststable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, $('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc();
{"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}}, return;
{"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"} $('#forwardinghoststable').DataTable({
], processing: true,
"rows": $.ajax({ serverSide: false,
dataType: 'json', language: lang_datatables,
url: '/api/v1/get/fwdhost/all', ajax: {
jsonp: false, type: "GET",
error: function () { url: "/api/v1/get/fwdhost/all",
console.log('Cannot draw forwarding hosts table'); dataSrc: function(data){
},
success: function (data) {
return process_table_data(data, 'forwardinghoststable'); return process_table_data(data, 'forwardinghoststable');
} }
}), },
"empty": lang.empty, columns: [
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, {
"sorting": {"enabled": true}, // placeholder, so checkbox will not block child row toggle
"toggleSelector": "table tbody span.footable-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() { function draw_relayhosts() {
ft_relayhoststable = FooTable.init('#relayhoststable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#relayhoststable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, $('#relayhoststable').DataTable().columns.adjust().responsive.recalc();
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, return;
{"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"}, $('#relayhoststable').DataTable({
{"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>';}}, processing: true,
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} serverSide: false,
], language: lang_datatables,
"rows": $.ajax({ ajax: {
dataType: 'json', type: "GET",
url: '/api/v1/get/relayhost/all', url: "/api/v1/get/relayhost/all",
jsonp: false, dataSrc: function(data){
error: function () {
console.log('Cannot draw forwarding hosts table');
},
success: function (data) {
return process_table_data(data, 'relayhoststable'); return process_table_data(data, 'relayhoststable');
} }
}), },
"empty": lang.empty, columns: [
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, {
"sorting": {"enabled": true}, // placeholder, so checkbox will not block child row toggle
"toggleSelector": "table tbody span.footable-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() { function draw_transport_maps() {
ft_transportstable = FooTable.init('#transportstable', { // just recalc width if instance already exists
"columns": [ if ($.fn.DataTable.isDataTable('#transportstable') ) {
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, $('#transportstable').DataTable().columns.adjust().responsive.recalc();
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, return;
{"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"}, $('#transportstable').DataTable({
{"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>';}}, processing: true,
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} serverSide: false,
], language: lang_datatables,
"rows": $.ajax({ ajax: {
dataType: 'json', type: "GET",
url: '/api/v1/get/transport/all', url: "/api/v1/get/transport/all",
jsonp: false, dataSrc: function(data){
error: function () {
console.log('Cannot draw transports table');
},
success: function (data) {
return process_table_data(data, 'transportstable'); 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) { columns: [
return process_table_data(data, 'queuetable'); {
} // placeholder, so checkbox will not block child row toggle
}), title: '',
"empty": lang.empty, data: null,
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, searchable: false,
"sorting": {"enabled": true}, orderable: false,
"toggleSelector": "table tbody span.footable-toggle", defaultContent: ''
"on": { },
"ready.ft.table": function(e, ft){ {
table_admin_ready(ft, 'queuetable'); 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) { function process_table_data(data, table) {
if (table == 'relayhoststable') { if (table == 'relayhoststable') {
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group footable-actions">' + item.action = '<div class="btn-group">' +
'<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="#" 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-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + '<a href="#" data-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>'; '</div>';
if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; } if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
@@ -294,14 +483,14 @@ jQuery(function($){
} else if (table == 'transportstable') { } else if (table == 'transportstable') {
$.each(data, function (i, item) { $.each(data, function (i, item) {
if (item.is_mx_based) { 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) { if (item.username) {
item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + 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">' + item.action = '<div class="btn-group">' +
'<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="#" 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-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + '<a href="#" data-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>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
@@ -313,21 +502,21 @@ jQuery(function($){
return escapeHtml(i); return escapeHtml(i);
}); });
item.recipients = rcpts.join('<hr style="margin:1px!important">'); item.recipients = rcpts.join('<hr style="margin:1px!important">');
item.action = '<div class="btn-group footable-actions">' + item.action = '<div class="btn-group">' +
'<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>' + '<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>'; '</div>';
}); });
} else if (table == 'forwardinghoststable') { } else if (table == 'forwardinghoststable') {
$.each(data, function (i, item) { $.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>' + '<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>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />'; item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
}); });
} else if (table == 'oauth2clientstable') { } else if (table == 'oauth2clientstable') {
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group footable-actions">' + item.action = '<div class="btn-group">' +
'<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>' + '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + '<a href="#" 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>'; '</div>';
item.scope = "profile"; item.scope = "profile";
@@ -339,8 +528,8 @@ jQuery(function($){
item.selected_domains = escapeHtml(item.selected_domains); item.selected_domains = escapeHtml(item.selected_domains);
item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>"); item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>");
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />'; item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group footable-actions">' + item.action = '<div class="btn-group">' +
'<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>' + '<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="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' + '<a href="/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>'; '</div>';
@@ -353,22 +542,38 @@ jQuery(function($){
item.usr = item.username; item.usr = item.username;
} }
item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />'; item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group footable-actions">' + item.action = '<div class="btn-group">' +
'<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>' + '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + '<a href="#" 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>'; '</div>';
}); });
} }
return data return data
}; };
// Initial table drawings
draw_domain_admins(); // detect element visibility changes
draw_admins(); function onVisible(element, callback) {
draw_fwd_hosts(); $(document).ready(function() {
draw_relayhosts(); element_object = document.querySelector(element);
draw_oauth2_clients(); if (element_object === null) return;
draw_transport_maps();
draw_queue(); 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 () { $('body').on('click', 'span.footable-toggle', function () {
event.stopPropagation(); event.stopPropagation();
@@ -427,27 +632,11 @@ jQuery(function($){
$('#transport_type').val(button.data('transport-type')); $('#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) { $('#test_transport').on('click', function (e) {
e.preventDefault(); e.preventDefault();
prev = $('#test_transport').text(); prev = $('#test_transport').text();
$(this).prop("disabled",true); $(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({ $.ajax({
type: 'GET', type: 'GET',
url: 'inc/ajax/transport_check.php', url: 'inc/ajax/transport_check.php',
@@ -483,11 +672,11 @@ jQuery(function($){
if (type == "app_link") { 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="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><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><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") { } 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 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><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><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); row.append(cols);
table_id.append(row); table_id.append(row);
@@ -507,4 +696,3 @@ jQuery(function($){
add_table_row($('#f2b_regex_table'), "f2b_regex"); add_table_row($('#f2b_regex_table'), "f2b_regex");
}); });
}); });
+1168 -437
View File
File diff suppressed because it is too large. Load diff
+112 -46
View File
@@ -57,6 +57,17 @@ $(document).ready(function() {
$("#multiple_bookings_custom").bind("change keypress keyup blur", function() { $("#multiple_bookings_custom").bind("change keypress keyup blur", function() {
$('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); $('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($){ jQuery(function($){
@@ -66,22 +77,14 @@ jQuery(function($){
return re.test(email); return re.test(email);
} }
function draw_wl_policy_domain_table() { function draw_wl_policy_domain_table() {
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_domain_table', { $('#wl_policy_domain_table').DataTable({
"columns": [ processing: true,
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"}, serverSide: false,
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false}, language: lang_datatables,
{"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule}, ajax: {
{"name":"object","title":"Scope"} type: "GET",
],
"empty": lang_user.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/policy_wl_domain/' + table_for_domain, url: '/api/v1/get/policy_wl_domain/' + table_for_domain,
jsonp: false, dataSrc: function(data){
error: function () {
console.log('Cannot draw mailbox policy wl table');
},
success: function (data) {
$.each(data, function (i, item) { $.each(data, function (i, item) {
if (!validateEmail(item.object)) { if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />'; item.chkbox = '<input type="checkbox" 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 + '" />'; item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />';
} }
}); });
return data;
} }
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
}, },
"sorting": { columns: [
"enabled": true {
// 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() { function draw_bl_policy_domain_table() {
ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_domain_table', { $('#bl_policy_domain_table').DataTable({
"columns": [ processing: true,
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"}, serverSide: false,
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false}, language: lang_datatables,
{"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule}, ajax: {
{"name":"object","title":"Scope"} type: "GET",
],
"empty": lang_user.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/policy_bl_domain/' + table_for_domain, url: '/api/v1/get/policy_bl_domain/' + table_for_domain,
jsonp: false, dataSrc: function(data){
error: function () {
console.log('Cannot draw mailbox policy bl table');
},
success: function (data) {
$.each(data, function (i, item) { $.each(data, function (i, item) {
if (!validateEmail(item.object)) { if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />'; item.chkbox = '<input type="checkbox" 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 + '" />'; item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />';
} }
}); });
return data;
} }
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
}, },
"sorting": { columns: [
"enabled": true {
// 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());
}); });
+2
View File
@@ -1,3 +1,5 @@
$(document).ready(function() { $(document).ready(function() {
var theme = localStorage.getItem("theme");
localStorage.clear(); localStorage.clear();
localStorage.setItem("theme", theme);
}); });
+1739 -766
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 217 files, more files were not shown because too many files have changed in this diff. Show more