474 lines
16 KiB
HTML
474 lines
16 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
|
<title>Mail4one Web config</title>
|
|
<script type="application/json" id="m41config">
|
|
{
|
|
"matches": [
|
|
{
|
|
"name": "mydomain",
|
|
"addr_rexs": [
|
|
".*@mydomain.com",
|
|
".*@m.mydomain.com"
|
|
]
|
|
},
|
|
{
|
|
"name": "personal",
|
|
"addrs": [
|
|
"first.last@mydomain.com",
|
|
"secret.name@mydomain.com"
|
|
]
|
|
}
|
|
],
|
|
"boxes": [
|
|
{
|
|
"name": "spam",
|
|
"rules": [
|
|
{
|
|
"match_name": "mydomain",
|
|
"negate": true,
|
|
"stop_check": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "important",
|
|
"rules": [
|
|
{
|
|
"match_name": "personal"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "all",
|
|
"rules": [
|
|
{
|
|
"match_name": "default_match_all"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"users": [
|
|
{
|
|
"username": "mymobile",
|
|
"password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
|
|
"mbox": "important"
|
|
},
|
|
{
|
|
"username": "mydesk",
|
|
"password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
|
|
"mbox": "all"
|
|
}
|
|
]
|
|
}
|
|
</script>
|
|
<style>
|
|
|
|
td {
|
|
padding: 5px;
|
|
}
|
|
|
|
table {
|
|
border: 2px solid;
|
|
}
|
|
|
|
thead {
|
|
background-color: orange;
|
|
}
|
|
|
|
h1.page-title {
|
|
background-color: orange;
|
|
}
|
|
|
|
h3 {
|
|
text-align: center;
|
|
}
|
|
|
|
.outer {
|
|
display: flex;
|
|
justify-content: center;
|
|
background: grey;
|
|
}
|
|
|
|
.inner {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
border: 2px solid;
|
|
background-color: lightyellow;
|
|
padding: 10px;
|
|
justify-content: space-around;
|
|
margin: 10px;
|
|
width: 1200px;
|
|
}
|
|
.m41-box {
|
|
display: grid;
|
|
grid-template-columns: 1fr 3fr;
|
|
margin: 10px;
|
|
// background-color: lightblue;
|
|
}
|
|
|
|
.multiline {
|
|
text-align: left;
|
|
padding: 5px;
|
|
padding-left: 15px;
|
|
}
|
|
|
|
|
|
#web-cfg-matches {
|
|
width: 90%;
|
|
text-align: center;
|
|
}
|
|
|
|
#web-cfg-matches tbody tr:nth-of-type(odd) {
|
|
background: lightblue;
|
|
}
|
|
|
|
#web-cfg-matches tbody tr:nth-of-type(even) {
|
|
background: lightgrey;
|
|
}
|
|
|
|
#web-cfg-boxes {
|
|
text-align: center;
|
|
width: 90%;
|
|
// display: grid;
|
|
// grid-template-columns: 1fr ;
|
|
//justify-content: space-around;
|
|
// justify-content: flex-start;
|
|
// background-color: blue;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:nth-of-type(odd) {
|
|
background: lightblue;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:nth-of-type(even) {
|
|
background: lightgrey;
|
|
}
|
|
|
|
#web-cfg-boxes tbody tr td div.dummy{
|
|
display: none;
|
|
}
|
|
|
|
#web-cfg-boxes tbody tr td div button.dummy {
|
|
display: none;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:first-of-type tr td.box div button.up.dummy {
|
|
display: block;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:first-of-type tr td.box div button.up.real {
|
|
display: none;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:last-of-type tr td.box div button.down.dummy {
|
|
display: block;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:last-of-type tr td.box div button.down.real {
|
|
display: none;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:only-of-type tr td.box div.real {
|
|
display: none;
|
|
}
|
|
|
|
#web-cfg-boxes tbody:only-of-type tr td.box div.dummy {
|
|
display: flex;
|
|
}
|
|
|
|
td.box {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.button-group {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
</style>
|
|
<script type="application/javascript">
|
|
"use strict"
|
|
|
|
// Globals
|
|
let server_config
|
|
let matches_table
|
|
let match_row_template
|
|
let boxes_table
|
|
let box_template
|
|
// let rule_template
|
|
|
|
function initGlobals() {
|
|
|
|
server_config = JSON.parse(document.getElementById('m41config').text)
|
|
matches_table = document.getElementById("web-cfg-matches")
|
|
match_row_template = document.getElementById("web-cfg-matches-row")
|
|
boxes_table = document.getElementById("web-cfg-boxes")
|
|
box_template = document.getElementById("web-cfg-box")
|
|
// rule_template = document.getElementById("web-cfg-boxes-rule-li")
|
|
}
|
|
|
|
function populate_match_table(matches_config) {
|
|
|
|
for (const { name: match_name, addrs, addr_rexs } of matches_config) {
|
|
|
|
const [match_type, match_values] = (() => {
|
|
|
|
if (addrs != undefined) {
|
|
return ["addrs", addrs]
|
|
} else {
|
|
return ["addr_rexs", addr_rexs]
|
|
}
|
|
})()
|
|
|
|
|
|
addMatchRow()
|
|
const last_row = matches_table.tBodies[0].lastElementChild
|
|
const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = last_row.cells
|
|
|
|
name_cell.innerText = match_name
|
|
type_select.value = match_type
|
|
value_cell.innerText = match_values.join("\n")
|
|
}
|
|
}
|
|
|
|
function extract_match_table() {
|
|
|
|
let matches = []
|
|
for (let row of matches_table.tBodies[0].rows) {
|
|
|
|
const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = row.cells
|
|
let m = {"name" : name_cell.innerText}
|
|
switch (type_select.value) {
|
|
case "addrs":
|
|
m["addrs"] = value_cell.innerText.split("\n")
|
|
break
|
|
case "addr_rexs":
|
|
m["addr_rexs"] = value_cell.innerText.split("\n")
|
|
break
|
|
}
|
|
matches.push(m)
|
|
}
|
|
return matches
|
|
}
|
|
|
|
function addMatchRow() {
|
|
|
|
let row_clone = match_row_template.content.cloneNode(true)
|
|
matches_table.tBodies[0].appendChild(row_clone)
|
|
}
|
|
|
|
function populate_boxes_list(boxes_config) {
|
|
|
|
for (const {name:box_name, rules} of boxes_config) {
|
|
|
|
addBox()
|
|
const tbody = boxes_table.lastElementChild
|
|
const box = tbody.firstElementChild
|
|
// console.log(box)
|
|
const [,
|
|
{children: [box_text, ]},
|
|
,
|
|
{firstElementChild: match_select},
|
|
{firstElementChild: negate_check},
|
|
{firstElementChild: stop_check},
|
|
] = box.children
|
|
|
|
box_text.value = box_name
|
|
|
|
const [first_rule, ...rest] = rules
|
|
|
|
const {match_name, negate = false, stop = false} = first_rule
|
|
|
|
match_select.value = match_name
|
|
negate_check.checked = negate
|
|
stop_check.checked = stop
|
|
|
|
for (const {match_name, negate = false, stop_check = false} of rest ) {
|
|
|
|
addRule(box)
|
|
const rule = tbody.lastElementChild
|
|
const [,
|
|
{firstElementChild: match_select},
|
|
{firstElementChild: negateCheck},
|
|
{firstElementChild: stopCheck}
|
|
] = rule.children
|
|
match_select.value = match_name
|
|
negate_check.checked = negate
|
|
stop_check.checked = stop
|
|
}
|
|
}
|
|
}
|
|
|
|
function addRule(box) {
|
|
box.parentElement.appendChild(box.cloneNode(true))
|
|
box.children[0].rowSpan++;
|
|
box.children[1].rowSpan++;
|
|
const newrule = box.parentElement.lastElementChild
|
|
newrule.removeClass("fist-tr")
|
|
newrule.firstElementChild.remove()
|
|
newrule.firstElementChild.remove()
|
|
}
|
|
|
|
function addBox() {
|
|
let box_clone = box_template.content.cloneNode(true)
|
|
boxes_table.appendChild(box_clone)
|
|
}
|
|
|
|
|
|
function moveUp(button) {
|
|
const li = button.parentElement.parentElement.parentElement
|
|
if (li.previousElementSibling != null) {
|
|
li.parentNode.insertBefore(li, li.previousElementSibling)
|
|
}
|
|
}
|
|
|
|
function moveDown(button) {
|
|
const li = button.parentElement.parentElement.parentElement
|
|
if (li.nextElementSibling != null) {
|
|
li.parentNode.insertBefore(li.nextElementSibling, li)
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
|
|
initGlobals()
|
|
populate_match_table(server_config["matches"])
|
|
save()
|
|
document.getElementById("before").innerText = JSON.stringify(server_config["matches"], null, 2)
|
|
populate_boxes_list(server_config["boxes"])
|
|
}
|
|
|
|
function save() {
|
|
|
|
const matches = extract_match_table()
|
|
document.getElementById("after").innerText = JSON.stringify(matches, null, 2)
|
|
}
|
|
|
|
</script>
|
|
</head>
|
|
<body onload="main()">
|
|
<template id="web-cfg-matches-row">
|
|
<tr>
|
|
<td><button onClick="this.parentElement.parentElement.remove()">✗</button></td>
|
|
<td contentEditable></td>
|
|
<td>
|
|
<select>
|
|
<option value="addrs">List of addresses</option>
|
|
<option value="addr_rexs">List of regexes for addresses</option>
|
|
</select>
|
|
</td>
|
|
<td contentEditable class="multiline"></td>
|
|
</tr>
|
|
</template>
|
|
<template id="web-cfg-box">
|
|
<tbody>
|
|
<tr>
|
|
<td class="box">
|
|
<div class="button-group dummy">
|
|
<button disabled>✗</button>
|
|
<button disabled>↑</button>
|
|
<button disabled>↓</button>
|
|
</div>
|
|
<div class="button-group real">
|
|
<button onClick="this.parentElement.parentElement.parentElement.parentElement.remove()">✗</button>
|
|
<button onClick="moveBoxUp(this)" class="real up">↑</button>
|
|
<button disabled class="dummy up">↑</button>
|
|
<button onClick="moveBoxDown(this)" class="real down">↓</button>
|
|
<button disabled class="dummy down">↓</button>
|
|
</div>
|
|
<button onClick="addRule(this.parentElement.parentElement)">+</button>
|
|
</td>
|
|
<td contentEditable>
|
|
<input type="text" contentEditable>
|
|
</td>
|
|
<td class="rule">
|
|
<div class="button-group dummy">
|
|
<button disabled>✗</button>
|
|
<button disabled>↑</button>
|
|
<button disabled>↓</button>
|
|
</div>
|
|
<div class="button-group real">
|
|
<button onClick="this.parentElement.parentElement.parentElement.remove()">✗</button>
|
|
<button onClick="moveRuleUp(this)" class="real up">↑</button>
|
|
<button disabled class="dummy up">↑</button>
|
|
<button onClick="moveRuleDown(this)" class="real down">↓</button>
|
|
<button disabled class="dummy down">↓</button>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<select></select>
|
|
</td>
|
|
<td>
|
|
<input type=checkbox>
|
|
</td>
|
|
<td>
|
|
<input type=checkbox>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</template>
|
|
<div class="outer">
|
|
<div class="inner">
|
|
<h1 class="page-title">Mail4one Web config</h1>
|
|
<div id="top-menu">
|
|
<button onClick="save()">Previous</button>
|
|
<button onClick="save()">Matches</button>
|
|
<button onClick="save()">Boxes</button>
|
|
<button onClick="save()">Users</button>
|
|
<button onClick="save()">JSON</button>
|
|
<button onClick="save()">Next</button>
|
|
</div>
|
|
<div id="match-page">
|
|
<h3> Matches </h3>
|
|
<table id="web-cfg-matches">
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
<button onClick="addMatchRow()">+</button>
|
|
</th>
|
|
<th>Match</th>
|
|
<th>Type</th>
|
|
<th>Values</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div id=box-page">
|
|
<h3>Boxes</h3>
|
|
|
|
<table id="web-cfg-boxes">
|
|
<thead>
|
|
<tr>
|
|
<th><button onClick="addBox()">+</button></th>
|
|
<th>Mailbox</th>
|
|
<th></th>
|
|
<th>Match</th>
|
|
<th>Invert</th>
|
|
<th>Stop</th>
|
|
</tr>
|
|
</thead>
|
|
</table>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<h3>Before</h3>
|
|
<pre id="before"></pre>
|
|
<hr>
|
|
<h3>After</h3>
|
|
<pre id="after"></pre>
|
|
<hr>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|