mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2026-03-04 15:54:48 +01:00
Initial commit of a log capture and reporting feature
This adds a new section to the admin panel called "Activity", that supplies charts, graphs and details about messages entering and leaving the host. A new daemon captures details of system mail activity by monitoring the /var/log/mail.log file, summarizing it into a sqllite database that's kept in user-data.
This commit is contained in:
92
management/ui-common/authentication.js
Normal file
92
management/ui-common/authentication.js
Normal file
@@ -0,0 +1,92 @@
|
||||
class Me {
|
||||
/* construct with return value from GET /me */
|
||||
constructor(me) {
|
||||
Object.assign(this, me);
|
||||
}
|
||||
|
||||
is_authenticated() {
|
||||
return this.api_key || this.user_id;
|
||||
}
|
||||
|
||||
get_email() {
|
||||
return this.user_email || this.user_id;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* axios interceptors for authentication
|
||||
*/
|
||||
|
||||
function init_axios_interceptors() {
|
||||
|
||||
// requests: attach non-session based auth (admin panel)
|
||||
axios.interceptors.request.use(request => {
|
||||
var api_credentials = null;
|
||||
// code from templates/index.html for "recall saved user
|
||||
// credentials" (but, without the split(':'))
|
||||
if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = sessionStorage.getItem("miab-cp-credentials");
|
||||
else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials"))
|
||||
api_credentials = localStorage.getItem("miab-cp-credentials");
|
||||
// end
|
||||
|
||||
if (api_credentials) {
|
||||
request.headers.authorization = 'Basic ' + window.btoa(api_credentials);
|
||||
}
|
||||
return request;
|
||||
});
|
||||
|
||||
|
||||
// reponses: redirect on authorization failure
|
||||
axios.interceptors.response.use(
|
||||
response => {
|
||||
if (response.data &&
|
||||
response.data.status === 'invalid' &&
|
||||
response.config.headers.authorization)
|
||||
{
|
||||
var url = response.config.url;
|
||||
if (response.config.baseURL) {
|
||||
var sep = ( response.config.baseURL.substr(-1) != '/' ?
|
||||
'/' : '' );
|
||||
url = response.config.baseURL + sep + url;
|
||||
}
|
||||
|
||||
if (url == '/admin/me')
|
||||
{
|
||||
// non-session/admin login
|
||||
throw new AuthenticationError(
|
||||
null,
|
||||
'not authenticated',
|
||||
response
|
||||
);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
||||
error => {
|
||||
const auth_required_msg = 'Authentication required - you have been logged out of the server';
|
||||
if (! error.response) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error.response.status == 403 &&
|
||||
error.response.data == 'login_required')
|
||||
{
|
||||
// session login
|
||||
throw new AuthenticationError(error, auth_required_msg);
|
||||
}
|
||||
else if ((error.response.status == 403 ||
|
||||
error.response.status == 401) &&
|
||||
error.response.data &&
|
||||
error.response.data.status == 'error')
|
||||
{
|
||||
// admin
|
||||
throw new AuthenticationError(error, auth_required_msg);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
18
management/ui-common/exceptions.js
Normal file
18
management/ui-common/exceptions.js
Normal file
@@ -0,0 +1,18 @@
|
||||
class ValueError extends Error {
|
||||
constructor(msg) {
|
||||
super(msg);
|
||||
}
|
||||
};
|
||||
|
||||
class AssertionError extends Error {
|
||||
}
|
||||
|
||||
class AuthenticationError extends Error {
|
||||
constructor(caused_by_error, msg, response) {
|
||||
super(msg);
|
||||
this.caused_by = caused_by_error;
|
||||
this.response = response;
|
||||
if (!response && caused_by_error)
|
||||
this.response = caused_by_error.response;
|
||||
}
|
||||
};
|
||||
11
management/ui-common/page-header.html
Normal file
11
management/ui-common/page-header.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="text-center">
|
||||
<h2 class="mb-0">{{ header_text }}</h2>
|
||||
<small class="text-white-50">from the <a href="https://github.com/downtownallday/mailinabox-ldap/" target="_blank" class="text-white-50">MiaB-LDAP project</a></small>
|
||||
<div class="d-flex align-items-center justify-content-between" style="margin-top:-1.5rem">
|
||||
<div class="ml-1" style="min-width:1em">
|
||||
<spinner v-show="loading_counter > 0"></spinner>
|
||||
</div>
|
||||
<slot name="links"><div> </div></slot>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
19
management/ui-common/page-header.js
Normal file
19
management/ui-common/page-header.js
Normal file
@@ -0,0 +1,19 @@
|
||||
Vue.component('spinner', {
|
||||
template: '<span class="spinner-border spinner-border-sm"></span>'
|
||||
});
|
||||
|
||||
Vue.component('page-header', function(resolve, reject) {
|
||||
axios.get('ui-common/page-header.html').then((response) => { resolve({
|
||||
|
||||
props: {
|
||||
header_text: { type: String, required: true },
|
||||
loading_counter: { type: Number, required: true }
|
||||
},
|
||||
|
||||
template: response.data
|
||||
|
||||
})}).catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
|
||||
});
|
||||
8
management/ui-common/page-layout.html
Normal file
8
management/ui-common/page-layout.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<div>
|
||||
<div class="bg-dark text-white p-1">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
<div class="bg-light text-dark p-1">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
10
management/ui-common/page-layout.js
Normal file
10
management/ui-common/page-layout.js
Normal file
@@ -0,0 +1,10 @@
|
||||
Vue.component('page-layout', function(resolve, reject) {
|
||||
axios.get('ui-common/page-layout.html').then((response) => { resolve({
|
||||
|
||||
template: response.data,
|
||||
|
||||
})}).catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
|
||||
});
|
||||
1
management/ui-common/theme/.gitignore
vendored
Normal file
1
management/ui-common/theme/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
35
management/ui-common/theme/build.sh
Executable file
35
management/ui-common/theme/build.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# install bootstrap sources
|
||||
#
|
||||
if [ ! -e "node_modules/bootstrap" ]; then
|
||||
npm install bootstrap
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Installing bootstrap using npm failed. Is npm install on your system?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# install sass compiler
|
||||
#
|
||||
compiler="/usr/bin/sassc"
|
||||
if [ ! -x "$compiler" ]; then
|
||||
sudo apt-get install sassc || exit 1
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# compile our theme
|
||||
#
|
||||
b_dir="node_modules/bootstrap/scss"
|
||||
|
||||
$compiler -I "$b_dir" --sourcemap --style compressed theme.scss ../ui-bootstrap.css
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "SUCCESS - files:"
|
||||
ls -sh ../ui-bootstrap.*
|
||||
fi
|
||||
|
||||
|
||||
14
management/ui-common/theme/package.json
Normal file
14
management/ui-common/theme/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "theme",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.5.3"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "GPL-3.0-or-later"
|
||||
}
|
||||
95
management/ui-common/theme/theme.scss
Normal file
95
management/ui-common/theme/theme.scss
Normal file
@@ -0,0 +1,95 @@
|
||||
/* variable overrides */
|
||||
$white: #fff;
|
||||
$gray-100: #f8f9fa;
|
||||
$gray-200: #e9ecef;
|
||||
$gray-300: #dee2e6;
|
||||
$gray-400: #ced4da;
|
||||
$gray-500: #adb5bd;
|
||||
$gray-600: #6c757d;
|
||||
$gray-700: #495057;
|
||||
$gray-800: #343a40;
|
||||
$gray-900: #212529;
|
||||
$black: #000;
|
||||
|
||||
$blue: cadetblue;
|
||||
|
||||
$primary: #446599; //#96a5b2;
|
||||
$secondary: $gray-600; //#d8dfe5; //#f5f5f5;
|
||||
$success: #b7dfb8;
|
||||
$info: #ffd6b0;
|
||||
$warning: #f0e68c;
|
||||
$danger: #a91409;
|
||||
$light: $gray-100;
|
||||
$dark: #303e45;
|
||||
|
||||
|
||||
|
||||
$body-bg: $gray-100; //$blue;
|
||||
$body-color: $dark;
|
||||
|
||||
$card-color: $gray-900;
|
||||
$card-spacer-x: 0.75rem;
|
||||
$card-spacer-y: 0.25rem;
|
||||
|
||||
$table-color: $dark;
|
||||
$table-cell-padding: 0.375rem; // .75rem;
|
||||
$table-cell-padding-sm: 0.15rem; // .3rem;
|
||||
|
||||
|
||||
$font-size-base: 0.85rem; // Assumes the browser default, typically `16px`
|
||||
|
||||
$input-btn-padding-y: .25rem; // .375rem !default;
|
||||
$input-btn-padding-x: .5rem; // .75rem !default;
|
||||
|
||||
$input-btn-padding-y-sm: .12rem; // .25rem !default;
|
||||
$input-btn-padding-x-sm: .25rem; // .5rem !default;
|
||||
|
||||
//$input-btn-padding-y-lg: .5rem !default;
|
||||
//$input-btn-padding-x-lg: 1rem !default;
|
||||
|
||||
$alert-padding-y: .25rem;
|
||||
$alert-padding-x: .75rem;
|
||||
|
||||
// $list-group-item-padding-y: .75rem !default;
|
||||
// $list-group-item-padding-x: 1.25rem !default;
|
||||
$nav-link-padding-y: 0.20rem;
|
||||
|
||||
|
||||
/* bootstrap styles that we want */
|
||||
@import "functions";
|
||||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "root";
|
||||
@import "reboot";
|
||||
@import "type";
|
||||
@import "images";
|
||||
@import "code";
|
||||
@import "grid";
|
||||
@import "tables";
|
||||
@import "forms";
|
||||
@import "buttons";
|
||||
@import "transitions";
|
||||
@import "dropdown";
|
||||
@import "button-group";
|
||||
@import "input-group";
|
||||
/* @import "custom-forms"; */
|
||||
@import "nav";
|
||||
@import "navbar";
|
||||
@import "card";
|
||||
@import "breadcrumb";
|
||||
@import "pagination";
|
||||
@import "badge";
|
||||
/* @import "jumbotron"; */
|
||||
@import "alert";
|
||||
@import "progress";
|
||||
/* @import "media"; */
|
||||
@import "list-group";
|
||||
@import "close";
|
||||
@import "toasts";
|
||||
@import "modal";
|
||||
@import "tooltip";
|
||||
@import "popover";
|
||||
/* @import "carousel"; */
|
||||
@import "spinners";
|
||||
@import "utilities";
|
||||
/* @import "print"; */
|
||||
3
management/ui-common/ui-bootstrap.css
Normal file
3
management/ui-common/ui-bootstrap.css
Normal file
File diff suppressed because one or more lines are too long
91
management/ui-common/ui-bootstrap.css.map
Normal file
91
management/ui-common/ui-bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
30
management/ui-common/ui.css
Normal file
30
management/ui-common/ui.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:hover {
|
||||
--hover-bg-color: #ccc;
|
||||
}
|
||||
|
||||
/* fix visibility of calendar icon in bootstrap vue component */
|
||||
.b-form-datepicker g {
|
||||
fill: var(--dark);
|
||||
}
|
||||
|
||||
/* make table header sticky at 0 */
|
||||
.sticky-table-header-0 thead {
|
||||
position: sticky;
|
||||
background-color: #fff;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.cursor-default {
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
.clickme {
|
||||
cursor:pointer;
|
||||
}
|
||||
.clickme:hover {
|
||||
background-color: var(--hover-bg-color);
|
||||
}
|
||||
Reference in New Issue
Block a user