From 240b2c63f6d2b544782ad0c661cb589c2231fff2 Mon Sep 17 00:00:00 2001 From: Tom Udding Date: Sat, 24 Dec 2022 17:33:49 +0100 Subject: [PATCH 01/11] Fix timestamps not sorting in datatables Timestamps retrieved from the API were always converted to a browser local format. The format specified for moment.js added in 5160eff29446ba94329116a6ed3787400b03e461 did not work because of this. Additionally, the format specified used `dd` which looks for two letter days, such as "Mo", "Tu", "We", etc. Furthermore, `mm` is used for minutes, not months. Because the locale formatted datetime can vary a lot, it is not easy to get this into moment.js to enable the sorting of datetimes in the datatables. In other words, there is no conversion from an `Intl.DateTimeFormat` specifier string to moment.js. Adding many `$.fn.dataTable.moment(format);` with different `format`s is not useful. I have fixed this rewriting how the timestamps from the API are added to the tables. It still uses the locale of the browser, because not everyone wants to use ISO 8601, but no longer requires moment.js (which has been removed). Two data attributes are added to the `td`s of the timestamps: - `data-order` - `data-sort` The values of these are the timestamps as returned by the server, which are very easily sorted (as they are just UNIX timestamps). Then, when creating the cell in the table, it will be converted to what the locale of the browser specified (this has not changed). --- .../{005-datatables.js => 004-datatables.js} | 0 data/web/js/build/004-moment.min.js | 7 - ...ations.min.js => 005-notifications.min.js} | 0 data/web/js/build/006-datetime-moment.js | 70 - ...-formcache.min.js => 006-formcache.min.js} | 0 .../js/build/{009-chart.js => 007-chart.js} | 0 ...ls.js => 008-chartjs-plugin-datalabels.js} | 0 ...rea.min.js => 009-numberedtextarea.min.js} | 0 .../{012-sha1.min.js => 010-sha1.min.js} | 0 data/web/js/build/{013-api.js => 011-api.js} | 0 ...kdown-it.min.js => 012-markdown-it.min.js} | 0 .../build/{015-mailcow.js => 013-mailcow.js} | 707 ++-- data/web/js/site/debug.js | 3063 ++++++++--------- 13 files changed, 1883 insertions(+), 1964 deletions(-) rename data/web/js/build/{005-datatables.js => 004-datatables.js} (100%) delete mode 100644 data/web/js/build/004-moment.min.js rename data/web/js/build/{007-notifications.min.js => 005-notifications.min.js} (100%) delete mode 100644 data/web/js/build/006-datetime-moment.js rename data/web/js/build/{008-formcache.min.js => 006-formcache.min.js} (100%) rename data/web/js/build/{009-chart.js => 007-chart.js} (100%) rename data/web/js/build/{010-chartjs-plugin-datalabels.js => 008-chartjs-plugin-datalabels.js} (100%) rename data/web/js/build/{011-numberedtextarea.min.js => 009-numberedtextarea.min.js} (100%) rename data/web/js/build/{012-sha1.min.js => 010-sha1.min.js} (100%) rename data/web/js/build/{013-api.js => 011-api.js} (100%) rename data/web/js/build/{014-markdown-it.min.js => 012-markdown-it.min.js} (100%) rename data/web/js/build/{015-mailcow.js => 013-mailcow.js} (96%) diff --git a/data/web/js/build/005-datatables.js b/data/web/js/build/004-datatables.js similarity index 100% rename from data/web/js/build/005-datatables.js rename to data/web/js/build/004-datatables.js diff --git a/data/web/js/build/004-moment.min.js b/data/web/js/build/004-moment.min.js deleted file mode 100644 index 9fb34ee07..000000000 --- a/data/web/js/build/004-moment.min.js +++ /dev/null @@ -1,7 +0,0 @@ -//! moment.js -//! version : 2.8.4 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com -(function(a){function b(a,b,c){switch(arguments.length){case 2:return null!=a?a:b;case 3:return null!=a?a:null!=b?b:c;default:throw new Error("Implement me")}}function c(a,b){return zb.call(a,b)}function d(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function e(a){tb.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+a)}function f(a,b){var c=!0;return m(function(){return c&&(e(a),c=!1),b.apply(this,arguments)},b)}function g(a,b){qc[a]||(e(b),qc[a]=!0)}function h(a,b){return function(c){return p(a.call(this,c),b)}}function i(a,b){return function(c){return this.localeData().ordinal(a.call(this,c),b)}}function j(){}function k(a,b){b!==!1&&F(a),n(this,a),this._d=new Date(+a._d)}function l(a){var b=y(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=tb.localeData(),this._bubble()}function m(a,b){for(var d in b)c(b,d)&&(a[d]=b[d]);return c(b,"toString")&&(a.toString=b.toString),c(b,"valueOf")&&(a.valueOf=b.valueOf),a}function n(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=b._pf),"undefined"!=typeof b._locale&&(a._locale=b._locale),Ib.length>0)for(c in Ib)d=Ib[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function o(a){return 0>a?Math.ceil(a):Math.floor(a)}function p(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&A(a[d])!==A(b[d]))&&g++;return g+f}function x(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=jc[a]||kc[b]||b}return a}function y(a){var b,d,e={};for(d in a)c(a,d)&&(b=x(d),b&&(e[b]=a[d]));return e}function z(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}tb[b]=function(e,f){var g,h,i=tb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=tb().utc().set(d,a);return i.call(tb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function A(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function B(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function C(a,b,c){return hb(tb([a,11,31+b-c]),b,c).week}function D(a){return E(a)?366:365}function E(a){return a%4===0&&a%100!==0||a%400===0}function F(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[Bb]<0||a._a[Bb]>11?Bb:a._a[Cb]<1||a._a[Cb]>B(a._a[Ab],a._a[Bb])?Cb:a._a[Db]<0||a._a[Db]>24||24===a._a[Db]&&(0!==a._a[Eb]||0!==a._a[Fb]||0!==a._a[Gb])?Db:a._a[Eb]<0||a._a[Eb]>59?Eb:a._a[Fb]<0||a._a[Fb]>59?Fb:a._a[Gb]<0||a._a[Gb]>999?Gb:-1,a._pf._overflowDayOfYear&&(Ab>b||b>Cb)&&(b=Cb),a._pf.overflow=b)}function G(b){return null==b._isValid&&(b._isValid=!isNaN(b._d.getTime())&&b._pf.overflow<0&&!b._pf.empty&&!b._pf.invalidMonth&&!b._pf.nullInput&&!b._pf.invalidFormat&&!b._pf.userInvalidated,b._strict&&(b._isValid=b._isValid&&0===b._pf.charsLeftOver&&0===b._pf.unusedTokens.length&&b._pf.bigHour===a)),b._isValid}function H(a){return a?a.toLowerCase().replace("_","-"):a}function I(a){for(var b,c,d,e,f=0;f0;){if(d=J(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&w(e,c,!0)>=b-1)break;b--}f++}return null}function J(a){var b=null;if(!Hb[a]&&Jb)try{b=tb.locale(),require("./locale/"+a),tb.locale(b)}catch(c){}return Hb[a]}function K(a,b){var c,d;return b._isUTC?(c=b.clone(),d=(tb.isMoment(a)||v(a)?+a:+tb(a))-+c,c._d.setTime(+c._d+d),tb.updateOffset(c,!1),c):tb(a).local()}function L(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function M(a){var b,c,d=a.match(Nb);for(b=0,c=d.length;c>b;b++)d[b]=pc[d[b]]?pc[d[b]]:L(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function N(a,b){return a.isValid()?(b=O(b,a.localeData()),lc[b]||(lc[b]=M(b)),lc[b](a)):a.localeData().invalidDate()}function O(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Ob.lastIndex=0;d>=0&&Ob.test(a);)a=a.replace(Ob,c),Ob.lastIndex=0,d-=1;return a}function P(a,b){var c,d=b._strict;switch(a){case"Q":return Zb;case"DDDD":return _b;case"YYYY":case"GGGG":case"gggg":return d?ac:Rb;case"Y":case"G":case"g":return cc;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?bc:Sb;case"S":if(d)return Zb;case"SS":if(d)return $b;case"SSS":if(d)return _b;case"DDD":return Qb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ub;case"a":case"A":return b._locale._meridiemParse;case"x":return Xb;case"X":return Yb;case"Z":case"ZZ":return Vb;case"T":return Wb;case"SSSS":return Tb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?$b:Pb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Pb;case"Do":return d?b._locale._ordinalParse:b._locale._ordinalParseLenient;default:return c=new RegExp(Y(X(a.replace("\\","")),"i"))}}function Q(a){a=a||"";var b=a.match(Vb)||[],c=b[b.length-1]||[],d=(c+"").match(hc)||["-",0,0],e=+(60*d[1])+A(d[2]);return"+"===d[0]?-e:e}function R(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[Bb]=3*(A(b)-1));break;case"M":case"MM":null!=b&&(e[Bb]=A(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b,a,c._strict),null!=d?e[Bb]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[Cb]=A(b));break;case"Do":null!=b&&(e[Cb]=A(parseInt(b.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=A(b));break;case"YY":e[Ab]=tb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[Ab]=A(b);break;case"a":case"A":c._isPm=c._locale.isPM(b);break;case"h":case"hh":c._pf.bigHour=!0;case"H":case"HH":e[Db]=A(b);break;case"m":case"mm":e[Eb]=A(b);break;case"s":case"ss":e[Fb]=A(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Gb]=A(1e3*("0."+b));break;case"x":c._d=new Date(A(b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=Q(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=A(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=tb.parseTwoDigitYear(b)}}function S(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[Ab],hb(tb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[Ab],hb(tb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=ib(d,e,f,h,g),a._a[Ab]=i.year,a._dayOfYear=i.dayOfYear}function T(a){var c,d,e,f,g=[];if(!a._d){for(e=V(a),a._w&&null==a._a[Cb]&&null==a._a[Bb]&&S(a),a._dayOfYear&&(f=b(a._a[Ab],e[Ab]),a._dayOfYear>D(f)&&(a._pf._overflowDayOfYear=!0),d=db(f,0,a._dayOfYear),a._a[Bb]=d.getUTCMonth(),a._a[Cb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];24===a._a[Db]&&0===a._a[Eb]&&0===a._a[Fb]&&0===a._a[Gb]&&(a._nextDay=!0,a._a[Db]=0),a._d=(a._useUTC?db:cb).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()+a._tzm),a._nextDay&&(a._a[Db]=24)}}function U(a){var b;a._d||(b=y(a._i),a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],T(a))}function V(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function W(b){if(b._f===tb.ISO_8601)return void $(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=O(b._f,b._locale).match(Nb)||[],c=0;c0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),pc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),R(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[Db]<=12&&(b._pf.bigHour=a),b._isPm&&b._a[Db]<12&&(b._a[Db]+=12),b._isPm===!1&&12===b._a[Db]&&(b._a[Db]=0),T(b),F(b)}function X(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function Y(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Z(a){var b,c,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,c=b));m(a,c||b)}function $(a){var b,c,d=a._i,e=dc.exec(d);if(e){for(a._pf.iso=!0,b=0,c=fc.length;c>b;b++)if(fc[b][1].exec(d)){a._f=fc[b][0]+(e[6]||" ");break}for(b=0,c=gc.length;c>b;b++)if(gc[b][1].exec(d)){a._f+=gc[b][0];break}d.match(Vb)&&(a._f+="Z"),W(a)}else a._isValid=!1}function _(a){$(a),a._isValid===!1&&(delete a._isValid,tb.createFromInputFallback(a))}function ab(a,b){var c,d=[];for(c=0;ca&&h.setFullYear(a),h}function db(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function eb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function fb(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function gb(a,b,c){var d=tb.duration(a).abs(),e=yb(d.as("s")),f=yb(d.as("m")),g=yb(d.as("h")),h=yb(d.as("d")),i=yb(d.as("M")),j=yb(d.as("y")),k=e0,k[4]=c,fb.apply({},k)}function hb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=tb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ib(a,b,c,d,e){var f,g,h=db(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:D(a-1)+g}}function jb(b){var c,d=b._i,e=b._f;return b._locale=b._locale||tb.localeData(b._l),null===d||e===a&&""===d?tb.invalid({nullInput:!0}):("string"==typeof d&&(b._i=d=b._locale.preparse(d)),tb.isMoment(d)?new k(d,!0):(e?u(e)?Z(b):W(b):bb(b),c=new k(b),c._nextDay&&(c.add(1,"d"),c._nextDay=a),c))}function kb(a,b){var c,d;if(1===b.length&&u(b[0])&&(b=b[0]),!b.length)return tb();for(c=b[0],d=1;d=0?"+":"-";return b+p(Math.abs(a),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return A(this.milliseconds()/100)},SS:function(){return p(A(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+p(A(a/60),2)+":"+p(A(a)%60,2)},ZZ:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+p(A(a/60),2)+p(A(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},qc={},rc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];nc.length;)vb=nc.pop(),pc[vb+"o"]=i(pc[vb],vb);for(;oc.length;)vb=oc.pop(),pc[vb+vb]=h(pc[vb],2);pc.DDDD=h(pc.DDD,3),m(j.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=tb.utc([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=tb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.apply(b,[c]):d},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(a){return a},postformat:function(a){return a},week:function(a){return hb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),tb=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=c,g._l=e,g._strict=f,g._isUTC=!1,g._pf=d(),jb(g)},tb.suppressDeprecationWarnings=!1,tb.createFromInputFallback=f("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),tb.min=function(){var a=[].slice.call(arguments,0);return kb("isBefore",a)},tb.max=function(){var a=[].slice.call(arguments,0);return kb("isAfter",a)},tb.utc=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=c,g._strict=f,g._pf=d(),jb(g).utc()},tb.unix=function(a){return tb(1e3*a)},tb.duration=function(a,b){var d,e,f,g,h=a,i=null;return tb.isDuration(a)?h={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(h={},b?h[b]=a:h.milliseconds=a):(i=Lb.exec(a))?(d="-"===i[1]?-1:1,h={y:0,d:A(i[Cb])*d,h:A(i[Db])*d,m:A(i[Eb])*d,s:A(i[Fb])*d,ms:A(i[Gb])*d}):(i=Mb.exec(a))?(d="-"===i[1]?-1:1,f=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*d},h={y:f(i[2]),M:f(i[3]),d:f(i[4]),h:f(i[5]),m:f(i[6]),s:f(i[7]),w:f(i[8])}):"object"==typeof h&&("from"in h||"to"in h)&&(g=r(tb(h.from),tb(h.to)),h={},h.ms=g.milliseconds,h.M=g.months),e=new l(h),tb.isDuration(a)&&c(a,"_locale")&&(e._locale=a._locale),e},tb.version=wb,tb.defaultFormat=ec,tb.ISO_8601=function(){},tb.momentProperties=Ib,tb.updateOffset=function(){},tb.relativeTimeThreshold=function(b,c){return mc[b]===a?!1:c===a?mc[b]:(mc[b]=c,!0)},tb.lang=f("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return tb.locale(a,b)}),tb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?tb.defineLocale(a,b):tb.localeData(a),c&&(tb.duration._locale=tb._locale=c)),tb._locale._abbr},tb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Hb[a]||(Hb[a]=new j),Hb[a].set(b),tb.locale(a),Hb[a]):(delete Hb[a],null)},tb.langData=f("moment.langData is deprecated. Use moment.localeData instead.",function(a){return tb.localeData(a)}),tb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return tb._locale;if(!u(a)){if(b=J(a))return b;a=[a]}return I(a)},tb.isMoment=function(a){return a instanceof k||null!=a&&c(a,"_isAMomentObject")},tb.isDuration=function(a){return a instanceof l};for(vb=rc.length-1;vb>=0;--vb)z(rc[vb]);tb.normalizeUnits=function(a){return x(a)},tb.invalid=function(a){var b=tb.utc(0/0);return null!=a?m(b._pf,a):b._pf.userInvalidated=!0,b},tb.parseZone=function(){return tb.apply(null,arguments).parseZone()},tb.parseTwoDigitYear=function(a){return A(a)+(A(a)>68?1900:2e3)},m(tb.fn=k.prototype,{clone:function(){return tb(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=tb(this).utc();return 00:!1},parsingFlags:function(){return m({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.zone(0,a)},local:function(a){return this._isUTC&&(this.zone(0,a),this._isUTC=!1,a&&this.add(this._dateTzOffset(),"m")),this},format:function(a){var b=N(this,a||tb.defaultFormat);return this.localeData().postformat(b)},add:s(1,"add"),subtract:s(-1,"subtract"),diff:function(a,b,c){var d,e,f,g=K(a,this),h=6e4*(this.zone()-g.zone());return b=x(b),"year"===b||"month"===b?(d=432e5*(this.daysInMonth()+g.daysInMonth()),e=12*(this.year()-g.year())+(this.month()-g.month()),f=this-tb(this).startOf("month")-(g-tb(g).startOf("month")),f-=6e4*(this.zone()-tb(this).startOf("month").zone()-(g.zone()-tb(g).startOf("month").zone())),e+=f/d,"year"===b&&(e/=12)):(d=this-g,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-h)/864e5:"week"===b?(d-h)/6048e5:d),c?e:o(e)},from:function(a,b){return tb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(tb(),a)},calendar:function(a){var b=a||tb(),c=K(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,tb(b)))},isLeapYear:function(){return E(this.year())},isDST:function(){return this.zone()+a):(c=tb.isMoment(a)?+a:+tb(a),c<+this.clone().startOf(b))},isBefore:function(a,b){var c;return b=x("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=tb.isMoment(a)?a:tb(a),+a>+this):(c=tb.isMoment(a)?+a:+tb(a),+this.clone().endOf(b)a?this:a}),max:f("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=tb.apply(null,arguments),a>this?this:a}),zone:function(a,b){var c,d=this._offset||0;return null==a?this._isUTC?d:this._dateTzOffset():("string"==typeof a&&(a=Q(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._dateTzOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.subtract(c,"m"),d!==a&&(!b||this._changeInProgress?t(this,tb.duration(d-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,tb.updateOffset(this,!0),this._changeInProgress=null)),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(a){return a=a?tb(a).zone():0,(this.zone()-a)%60===0},daysInMonth:function(){return B(this.year(),this.month())},dayOfYear:function(a){var b=yb((tb(this).startOf("day")-tb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")},quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=hb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=hb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=hb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return C(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return C(this.year(),a.dow,a.doy)},get:function(a){return a=x(a),this[a]()},set:function(a,b){return a=x(a),"function"==typeof this[a]&&this[a](b),this},locale:function(b){var c;return b===a?this._locale._abbr:(c=tb.localeData(b),null!=c&&(this._locale=c),this)},lang:f("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(b){return b===a?this.localeData():this.locale(b)}),localeData:function(){return this._locale},_dateTzOffset:function(){return 15*Math.round(this._d.getTimezoneOffset()/15)}}),tb.fn.millisecond=tb.fn.milliseconds=ob("Milliseconds",!1),tb.fn.second=tb.fn.seconds=ob("Seconds",!1),tb.fn.minute=tb.fn.minutes=ob("Minutes",!1),tb.fn.hour=tb.fn.hours=ob("Hours",!0),tb.fn.date=ob("Date",!0),tb.fn.dates=f("dates accessor is deprecated. Use date instead.",ob("Date",!0)),tb.fn.year=ob("FullYear",!0),tb.fn.years=f("years accessor is deprecated. Use year instead.",ob("FullYear",!0)),tb.fn.days=tb.fn.day,tb.fn.months=tb.fn.month,tb.fn.weeks=tb.fn.week,tb.fn.isoWeeks=tb.fn.isoWeek,tb.fn.quarters=tb.fn.quarter,tb.fn.toJSON=tb.fn.toISOString,m(tb.duration.fn=l.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=o(d/1e3),g.seconds=a%60,b=o(a/60),g.minutes=b%60,c=o(b/60),g.hours=c%24,e+=o(c/24),h=o(pb(e)),e-=o(qb(h)),f+=o(e/30),e%=30,h+=o(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return o(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*A(this._months/12)},humanize:function(a){var b=gb(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=tb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=tb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=x(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=x(a),"month"===a||"year"===a)return b=this._days+this._milliseconds/864e5,c=this._months+12*pb(b),"month"===a?c:c/12;switch(b=this._days+Math.round(qb(this._months/12)),a){case"week":return b/7+this._milliseconds/6048e5;case"day":return b+this._milliseconds/864e5;case"hour":return 24*b+this._milliseconds/36e5;case"minute":return 24*b*60+this._milliseconds/6e4;case"second":return 24*b*60*60+this._milliseconds/1e3; -case"millisecond":return Math.floor(24*b*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+a)}},lang:tb.fn.lang,locale:tb.fn.locale,toIsoString:f("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale}}),tb.duration.fn.toString=tb.duration.fn.toISOString;for(vb in ic)c(ic,vb)&&rb(vb.toLowerCase());tb.duration.fn.asMilliseconds=function(){return this.as("ms")},tb.duration.fn.asSeconds=function(){return this.as("s")},tb.duration.fn.asMinutes=function(){return this.as("m")},tb.duration.fn.asHours=function(){return this.as("h")},tb.duration.fn.asDays=function(){return this.as("d")},tb.duration.fn.asWeeks=function(){return this.as("weeks")},tb.duration.fn.asMonths=function(){return this.as("M")},tb.duration.fn.asYears=function(){return this.as("y")},tb.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===A(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),Jb?module.exports=tb:"function"==typeof define&&define.amd?(define("moment",function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(xb.moment=ub),tb}),sb(!0)):sb()}).call(this); \ No newline at end of file diff --git a/data/web/js/build/007-notifications.min.js b/data/web/js/build/005-notifications.min.js similarity index 100% rename from data/web/js/build/007-notifications.min.js rename to data/web/js/build/005-notifications.min.js diff --git a/data/web/js/build/006-datetime-moment.js b/data/web/js/build/006-datetime-moment.js deleted file mode 100644 index 52b537c07..000000000 --- a/data/web/js/build/006-datetime-moment.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This plug-in for DataTables represents the ultimate option in extensibility - * for sorting date / time strings correctly. It uses - * [Moment.js](http://momentjs.com) to create automatic type detection and - * sorting plug-ins for DataTables based on a given format. This way, DataTables - * will automatically detect your temporal information and sort it correctly. - * - * For usage instructions, please see the DataTables blog - * post that [introduces it](//datatables.net/blog/2014-12-18). - * - * @name Ultimate Date / Time sorting - * @summary Sort date and time in any format using Moment.js - * @author [Allan Jardine](//datatables.net) - * @depends DataTables 1.10+, Moment.js 1.7+ - * - * @example - * $.fn.dataTable.moment( 'HH:mm MMM D, YY' ); - * $.fn.dataTable.moment( 'dddd, MMMM Do, YYYY' ); - * - * $('#example').DataTable(); - */ - -(function (factory) { - if (typeof define === "function" && define.amd) { - define(["jquery", "moment", "datatables.net"], factory); - } else { - factory(jQuery, moment); - } -}(function ($, moment) { - -function strip (d) { - if ( typeof d === 'string' ) { - // Strip HTML tags and newline characters if possible - d = d.replace(/(<.*?>)|(\r?\n|\r)/g, ''); - - // Strip out surrounding white space - d = d.trim(); - } - - return d; -} - -$.fn.dataTable.moment = function ( format, locale, reverseEmpties ) { - var types = $.fn.dataTable.ext.type; - - // Add type detection - types.detect.unshift( function ( d ) { - d = strip(d); - - // Null and empty values are acceptable - if ( d === '' || d === null ) { - return 'moment-'+format; - } - - return moment( d, format, locale, true ).isValid() ? - 'moment-'+format : - null; - } ); - - // Add sorting method - use an integer for the sorting - types.order[ 'moment-'+format+'-pre' ] = function ( d ) { - d = strip(d); - - return !moment(d, format, locale, true).isValid() ? - (reverseEmpties ? -Infinity : Infinity) : - parseInt( moment( d, format, locale, true ).format( 'x' ), 10 ); - }; -}; - -})); diff --git a/data/web/js/build/008-formcache.min.js b/data/web/js/build/006-formcache.min.js similarity index 100% rename from data/web/js/build/008-formcache.min.js rename to data/web/js/build/006-formcache.min.js diff --git a/data/web/js/build/009-chart.js b/data/web/js/build/007-chart.js similarity index 100% rename from data/web/js/build/009-chart.js rename to data/web/js/build/007-chart.js diff --git a/data/web/js/build/010-chartjs-plugin-datalabels.js b/data/web/js/build/008-chartjs-plugin-datalabels.js similarity index 100% rename from data/web/js/build/010-chartjs-plugin-datalabels.js rename to data/web/js/build/008-chartjs-plugin-datalabels.js diff --git a/data/web/js/build/011-numberedtextarea.min.js b/data/web/js/build/009-numberedtextarea.min.js similarity index 100% rename from data/web/js/build/011-numberedtextarea.min.js rename to data/web/js/build/009-numberedtextarea.min.js diff --git a/data/web/js/build/012-sha1.min.js b/data/web/js/build/010-sha1.min.js similarity index 100% rename from data/web/js/build/012-sha1.min.js rename to data/web/js/build/010-sha1.min.js diff --git a/data/web/js/build/013-api.js b/data/web/js/build/011-api.js similarity index 100% rename from data/web/js/build/013-api.js rename to data/web/js/build/011-api.js diff --git a/data/web/js/build/014-markdown-it.min.js b/data/web/js/build/012-markdown-it.min.js similarity index 100% rename from data/web/js/build/014-markdown-it.min.js rename to data/web/js/build/012-markdown-it.min.js diff --git a/data/web/js/build/015-mailcow.js b/data/web/js/build/013-mailcow.js similarity index 96% rename from data/web/js/build/015-mailcow.js rename to data/web/js/build/013-mailcow.js index 1532ee54d..c734c8249 100644 --- a/data/web/js/build/015-mailcow.js +++ b/data/web/js/build/013-mailcow.js @@ -1,354 +1,353 @@ -$(document).ready(function() { - // mailcow alert box generator - window.mailcow_alert_box = function(message, type) { - msg = $('').text(message).text(); - if (type == 'danger' || type == 'info') { - auto_hide = 0; - $('#' + localStorage.getItem("add_modal")).modal('show'); - localStorage.removeItem("add_modal"); - } else { - auto_hide = 5000; - } - $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}}); - } - - $(".generate_password").click(function( event ) { - event.preventDefault(); - $('[data-hibp]').trigger('input'); - if (typeof($(this).closest("form").data('pwgen-length')) == "number") { - var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length')) - } - else { - var random_passwd = GPW.pronounceable(8) - } - $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text'); - $(this).closest("form").find('[data-pwgen-field]').val(random_passwd); - }); - function str_rot13(str) { - return (str + '').replace(/[a-z]/gi, function(s){ - return String.fromCharCode(s.charCodeAt(0) + (s.toLowerCase() < 'n' ? 13 : -13)) - }) - } - $(".rot-enc").html(function(){ - return str_rot13($(this).html()) - }); - // https://stackoverflow.com/questions/4399005/implementing-jquerys-shake-effect-with-animate - function shake(div,interval,distance,times) { - if(typeof interval === 'undefined') { - interval = 100; - } - if(typeof distance === 'undefined') { - distance = 10; - } - if(typeof times === 'undefined') { - times = 4; - } - $(div).css('position','relative'); - for(var iter=0;iter<(times+1);iter++){ - $(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval); - } - $(div).animate({ left: 0},interval); - } - - // form cache - $('[data-cached-form="true"]').formcache({key: $(this).data('id')}); - - // tooltips - $(function () { - $('[data-bs-toggle="tooltip"]').tooltip() - }); - - // remember last navigation pill - (function () { - 'use strict'; - // remember desktop tabs - $('button[data-bs-toggle="tab"]').on('click', function (e) { - if ($(this).data('dont-remember') == 1) { - return true; - } - var id = $(this).parents('[role="tablist"]').attr('id'); - var key = 'lastTag'; - if (id) { - key += ':' + id; - } - - var tab_id = $(e.target).attr('data-bs-target').substring(1); - localStorage.setItem(key, tab_id); - }); - // remember mobile tabs - $('button[data-bs-target^="#collapse-tab-"]').on('click', function (e) { - // only remember tab if its being opened - if ($(this).hasClass('collapsed')) return false; - var tab_id = $(this).closest('div[role="tabpanel"]').attr('id'); - - if ($(this).data('dont-remember') == 1) { - return true; - } - var id = $(this).parents('[role="tablist"]').attr('id');; - var key = 'lastTag'; - if (id) { - key += ':' + id; - } - - localStorage.setItem(key, tab_id); - }); - // open last tab - $('[role="tablist"]').each(function (idx, elem) { - var id = $(elem).attr('id'); - var key = 'lastTag'; - if (id) { - key += ':' + id; - } - var lastTab = localStorage.getItem(key); - if (lastTab) { - $('[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 - $('tbody').filter(function (index) { - return $(this).children().length < 1; - }).remove(); - - // selectpicker - $('select').selectpicker({ - 'styleBase': 'btn btn-xs-lg', - 'noneSelectedText': lang_footer.nothing_selected - }); - - // haveibeenpwned and passwd policy - $.ajax({ - url: '/api/v1/get/passwordpolicy/html', - type: 'GET', - success: function(res) { - $(".hibp-out").after(res); - } - }); - $('[data-hibp]').after('

' + lang_footer.hibp_check + '

'); - $('[data-hibp]').on('input', function() { - out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out'); - }); - $('.haveibeenpwned:not(.task-running)').on('click', function() { - var hibp_field = $(this) - $(hibp_field).addClass('task-running'); - var hibp_result = $(hibp_field).next('.hibp-out') - var password_field = $(this).prev('[data-hibp]') - if ($(password_field).val() == '') { - shake(password_field); - } - else { - $(hibp_result).attr('class', 'hibp-out badge fs-5 bg-info'); - $(hibp_result).text(lang_footer.loading); - var password_digest = $.sha1($(password_field).val()) - var digest_five = password_digest.substring(0, 5).toUpperCase(); - var queryURL = "https://api.pwnedpasswords.com/range/" + digest_five; - var compl_digest = password_digest.substring(5, 41).toUpperCase(); - $.ajax({ - url: queryURL, - type: 'GET', - success: function(res) { - if (res.search(compl_digest) > -1){ - $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-danger'); - $(hibp_result).text(lang_footer.hibp_nok) - } else { - $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-success'); - $(hibp_result).text(lang_footer.hibp_ok) - } - $(hibp_field).removeClass('task-running'); - }, - error: function(xhr, status, error) { - $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-warning'); - $(hibp_result).text('API error: ' + xhr.responseText) - $(hibp_field).removeClass('task-running'); - } - }); - } - }); - - // Disable disallowed inputs - $('[data-acl="0"]').each(function(event){ - if ($(this).is("a")) { - $(this).removeAttr("data-bs-toggle"); - $(this).removeAttr("data-bs-target"); - $(this).removeAttr("data-action"); - $(this).click(function(event) { - event.preventDefault(); - }); - } - if ($(this).is("select")) { - $(this).selectpicker('destroy'); - $(this).replaceWith(function() { - return ''; - }); - } - if ($(this).hasClass('btn-group')) { - $(this).find('a').each(function(){ - $(this).removeClass('dropdown-toggle') - .removeAttr('data-bs-toggle') - .removeAttr('data-bs-target') - .removeAttr('data-action') - .removeAttr('id') - .attr("disabled", true); - $(this).click(function(event) { - event.preventDefault(); - return; - }); - }); - $(this).find('button').each(function() { - $(this).attr("disabled", true); - }); - } else if ($(this).hasClass('input-group')) { - $(this).find('input').each(function() { - $(this).removeClass('dropdown-toggle') - .removeAttr('data-bs-toggle') - .attr("disabled", true); - $(this).click(function(event) { - event.preventDefault(); - }); - }); - $(this).find('button').each(function() { - $(this).attr("disabled", true); - }); - } else if ($(this).hasClass('form-group')) { - $(this).find('input').each(function() { - $(this).attr("disabled", true); - }); - } else if ($(this).hasClass('btn')) { - $(this).attr("disabled", true); - } else if ($(this).attr('data-provide') == 'slider') { - $(this).attr('disabled', true); - } else if ($(this).is(':checkbox')) { - $(this).attr("disabled", true); - } - $(this).data("toggle", "tooltip"); - $(this).attr("title", lang_acl.prohibited); - $(this).tooltip(); - }); - - // disable submit after submitting form (not API driven buttons) - $('form').submit(function() { - if ($('form button[type="submit"]').data('submitted') == '1') { - return false; - } else { - $(this).find('button[type="submit"]').first().text(lang_footer.loading); - $('form button[type="submit"]').attr('data-submitted', '1'); - function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); }; - $(document).on("keydown", disableF5); - } - }); - // Textarea line numbers - $(".textarea-code").numberedtextarea({allowTabChar: true}); - // trigger container restart - $('#RestartContainer').on('show.bs.modal', function(e) { - var container = $(e.relatedTarget).data('container'); - $('#containerName').text(container); - $('#triggerRestartContainer').click(function(){ - $(this).prop("disabled",true); - $(this).html('
Loading...
'); - $('#statusTriggerRestartContainer').html(lang_footer.restarting_container); - $.ajax({ - method: 'get', - url: '/inc/ajax/container_ctrl.php', - timeout: docker_timeout, - data: { - 'service': container, - 'action': 'restart' - } - }) - .always( function (data, status) { - $('#statusTriggerRestartContainer').append(data); - var htmlResponse = $.parseHTML(data) - if ($(htmlResponse).find('span').hasClass('text-success')) { - $('#triggerRestartContainer').html(' '); - setTimeout(function(){ - $('#RestartContainer').modal('toggle'); - window.location = window.location.href.split("#")[0]; - }, 1200); - } else { - $('#triggerRestartContainer').html(' '); - } - }) - }); - }) - - // Jquery Datatables, enable responsive plugin and date sort plugin - $.extend($.fn.dataTable.defaults, { - responsive: true - }); - $.fn.dataTable.moment('dd:mm:YYYY'); - - // tag boxes - $('.tag-box .tag-add').click(function(){ - addTag(this); - }); - $(".tag-box .tag-input").keydown(function (e) { - if (e.which == 13){ - e.preventDefault(); - addTag(this); - } - }); - - // 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(''); - $('#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={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} -function unescapeHtml(t){var n={"&":"&","<":"<",">":">",""":'"',"'":"'","/":"/","`":"`","=":"="};return String(t).replace(/&|<|>|"|'|/|`|=/g,function(t){return n[t]})} - -function addTag(tagAddElem, tag = null){ - var tagboxElem = $(tagAddElem).parent(); - var tagInputElem = $(tagboxElem).find(".tag-input")[0]; - var tagValuesElem = $(tagboxElem).find(".tag-values")[0]; - - if (!tag) - tag = $(tagInputElem).val(); - if (!tag) return; - var value_tags = []; - try { - value_tags = JSON.parse($(tagValuesElem).val()); - } catch {} - if (!Array.isArray(value_tags)) value_tags = []; - if (value_tags.includes(tag)) return; - - $(' ' + escapeHtml(tag) + '').insertBefore('.tag-input').click(function(){ - var del_tag = unescapeHtml($(this).text()); - var del_tags = []; - try { - del_tags = JSON.parse($(tagValuesElem).val()); - } catch {} - if (Array.isArray(del_tags)){ - del_tags.splice(del_tags.indexOf(del_tag), 1); - $(tagValuesElem).val(JSON.stringify(del_tags)); - } - $(this).remove(); - }); - - value_tags.push(tag); - $(tagValuesElem).val(JSON.stringify(value_tags)); - $(tagInputElem).val(''); -} \ No newline at end of file +$(document).ready(function() { + // mailcow alert box generator + window.mailcow_alert_box = function(message, type) { + msg = $('').text(message).text(); + if (type == 'danger' || type == 'info') { + auto_hide = 0; + $('#' + localStorage.getItem("add_modal")).modal('show'); + localStorage.removeItem("add_modal"); + } else { + auto_hide = 5000; + } + $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}}); + } + + $(".generate_password").click(function( event ) { + event.preventDefault(); + $('[data-hibp]').trigger('input'); + if (typeof($(this).closest("form").data('pwgen-length')) == "number") { + var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length')) + } + else { + var random_passwd = GPW.pronounceable(8) + } + $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text'); + $(this).closest("form").find('[data-pwgen-field]').val(random_passwd); + }); + function str_rot13(str) { + return (str + '').replace(/[a-z]/gi, function(s){ + return String.fromCharCode(s.charCodeAt(0) + (s.toLowerCase() < 'n' ? 13 : -13)) + }) + } + $(".rot-enc").html(function(){ + return str_rot13($(this).html()) + }); + // https://stackoverflow.com/questions/4399005/implementing-jquerys-shake-effect-with-animate + function shake(div,interval,distance,times) { + if(typeof interval === 'undefined') { + interval = 100; + } + if(typeof distance === 'undefined') { + distance = 10; + } + if(typeof times === 'undefined') { + times = 4; + } + $(div).css('position','relative'); + for(var iter=0;iter<(times+1);iter++){ + $(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval); + } + $(div).animate({ left: 0},interval); + } + + // form cache + $('[data-cached-form="true"]').formcache({key: $(this).data('id')}); + + // tooltips + $(function () { + $('[data-bs-toggle="tooltip"]').tooltip() + }); + + // remember last navigation pill + (function () { + 'use strict'; + // remember desktop tabs + $('button[data-bs-toggle="tab"]').on('click', function (e) { + if ($(this).data('dont-remember') == 1) { + return true; + } + var id = $(this).parents('[role="tablist"]').attr('id'); + var key = 'lastTag'; + if (id) { + key += ':' + id; + } + + var tab_id = $(e.target).attr('data-bs-target').substring(1); + localStorage.setItem(key, tab_id); + }); + // remember mobile tabs + $('button[data-bs-target^="#collapse-tab-"]').on('click', function (e) { + // only remember tab if its being opened + if ($(this).hasClass('collapsed')) return false; + var tab_id = $(this).closest('div[role="tabpanel"]').attr('id'); + + if ($(this).data('dont-remember') == 1) { + return true; + } + var id = $(this).parents('[role="tablist"]').attr('id');; + var key = 'lastTag'; + if (id) { + key += ':' + id; + } + + localStorage.setItem(key, tab_id); + }); + // open last tab + $('[role="tablist"]').each(function (idx, elem) { + var id = $(elem).attr('id'); + var key = 'lastTag'; + if (id) { + key += ':' + id; + } + var lastTab = localStorage.getItem(key); + if (lastTab) { + $('[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 + $('tbody').filter(function (index) { + return $(this).children().length < 1; + }).remove(); + + // selectpicker + $('select').selectpicker({ + 'styleBase': 'btn btn-xs-lg', + 'noneSelectedText': lang_footer.nothing_selected + }); + + // haveibeenpwned and passwd policy + $.ajax({ + url: '/api/v1/get/passwordpolicy/html', + type: 'GET', + success: function(res) { + $(".hibp-out").after(res); + } + }); + $('[data-hibp]').after('

' + lang_footer.hibp_check + '

'); + $('[data-hibp]').on('input', function() { + out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out'); + }); + $('.haveibeenpwned:not(.task-running)').on('click', function() { + var hibp_field = $(this) + $(hibp_field).addClass('task-running'); + var hibp_result = $(hibp_field).next('.hibp-out') + var password_field = $(this).prev('[data-hibp]') + if ($(password_field).val() == '') { + shake(password_field); + } + else { + $(hibp_result).attr('class', 'hibp-out badge fs-5 bg-info'); + $(hibp_result).text(lang_footer.loading); + var password_digest = $.sha1($(password_field).val()) + var digest_five = password_digest.substring(0, 5).toUpperCase(); + var queryURL = "https://api.pwnedpasswords.com/range/" + digest_five; + var compl_digest = password_digest.substring(5, 41).toUpperCase(); + $.ajax({ + url: queryURL, + type: 'GET', + success: function(res) { + if (res.search(compl_digest) > -1){ + $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-danger'); + $(hibp_result).text(lang_footer.hibp_nok) + } else { + $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-success'); + $(hibp_result).text(lang_footer.hibp_ok) + } + $(hibp_field).removeClass('task-running'); + }, + error: function(xhr, status, error) { + $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-warning'); + $(hibp_result).text('API error: ' + xhr.responseText) + $(hibp_field).removeClass('task-running'); + } + }); + } + }); + + // Disable disallowed inputs + $('[data-acl="0"]').each(function(event){ + if ($(this).is("a")) { + $(this).removeAttr("data-bs-toggle"); + $(this).removeAttr("data-bs-target"); + $(this).removeAttr("data-action"); + $(this).click(function(event) { + event.preventDefault(); + }); + } + if ($(this).is("select")) { + $(this).selectpicker('destroy'); + $(this).replaceWith(function() { + return ''; + }); + } + if ($(this).hasClass('btn-group')) { + $(this).find('a').each(function(){ + $(this).removeClass('dropdown-toggle') + .removeAttr('data-bs-toggle') + .removeAttr('data-bs-target') + .removeAttr('data-action') + .removeAttr('id') + .attr("disabled", true); + $(this).click(function(event) { + event.preventDefault(); + return; + }); + }); + $(this).find('button').each(function() { + $(this).attr("disabled", true); + }); + } else if ($(this).hasClass('input-group')) { + $(this).find('input').each(function() { + $(this).removeClass('dropdown-toggle') + .removeAttr('data-bs-toggle') + .attr("disabled", true); + $(this).click(function(event) { + event.preventDefault(); + }); + }); + $(this).find('button').each(function() { + $(this).attr("disabled", true); + }); + } else if ($(this).hasClass('form-group')) { + $(this).find('input').each(function() { + $(this).attr("disabled", true); + }); + } else if ($(this).hasClass('btn')) { + $(this).attr("disabled", true); + } else if ($(this).attr('data-provide') == 'slider') { + $(this).attr('disabled', true); + } else if ($(this).is(':checkbox')) { + $(this).attr("disabled", true); + } + $(this).data("toggle", "tooltip"); + $(this).attr("title", lang_acl.prohibited); + $(this).tooltip(); + }); + + // disable submit after submitting form (not API driven buttons) + $('form').submit(function() { + if ($('form button[type="submit"]').data('submitted') == '1') { + return false; + } else { + $(this).find('button[type="submit"]').first().text(lang_footer.loading); + $('form button[type="submit"]').attr('data-submitted', '1'); + function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); }; + $(document).on("keydown", disableF5); + } + }); + // Textarea line numbers + $(".textarea-code").numberedtextarea({allowTabChar: true}); + // trigger container restart + $('#RestartContainer').on('show.bs.modal', function(e) { + var container = $(e.relatedTarget).data('container'); + $('#containerName').text(container); + $('#triggerRestartContainer').click(function(){ + $(this).prop("disabled",true); + $(this).html('
Loading...
'); + $('#statusTriggerRestartContainer').html(lang_footer.restarting_container); + $.ajax({ + method: 'get', + url: '/inc/ajax/container_ctrl.php', + timeout: docker_timeout, + data: { + 'service': container, + 'action': 'restart' + } + }) + .always( function (data, status) { + $('#statusTriggerRestartContainer').append(data); + var htmlResponse = $.parseHTML(data) + if ($(htmlResponse).find('span').hasClass('text-success')) { + $('#triggerRestartContainer').html(' '); + setTimeout(function(){ + $('#RestartContainer').modal('toggle'); + window.location = window.location.href.split("#")[0]; + }, 1200); + } else { + $('#triggerRestartContainer').html(' '); + } + }) + }); + }) + + // Jquery Datatables, enable responsive plugin + $.extend($.fn.dataTable.defaults, { + responsive: true + }); + + // tag boxes + $('.tag-box .tag-add').click(function(){ + addTag(this); + }); + $(".tag-box .tag-input").keydown(function (e) { + if (e.which == 13){ + e.preventDefault(); + addTag(this); + } + }); + + // 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(''); + $('#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={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} +function unescapeHtml(t){var n={"&":"&","<":"<",">":">",""":'"',"'":"'","/":"/","`":"`","=":"="};return String(t).replace(/&|<|>|"|'|/|`|=/g,function(t){return n[t]})} + +function addTag(tagAddElem, tag = null){ + var tagboxElem = $(tagAddElem).parent(); + var tagInputElem = $(tagboxElem).find(".tag-input")[0]; + var tagValuesElem = $(tagboxElem).find(".tag-values")[0]; + + if (!tag) + tag = $(tagInputElem).val(); + if (!tag) return; + var value_tags = []; + try { + value_tags = JSON.parse($(tagValuesElem).val()); + } catch {} + if (!Array.isArray(value_tags)) value_tags = []; + if (value_tags.includes(tag)) return; + + $(' ' + escapeHtml(tag) + '').insertBefore('.tag-input').click(function(){ + var del_tag = unescapeHtml($(this).text()); + var del_tags = []; + try { + del_tags = JSON.parse($(tagValuesElem).val()); + } catch {} + if (Array.isArray(del_tags)){ + del_tags.splice(del_tags.indexOf(del_tag), 1); + $(tagValuesElem).val(JSON.stringify(del_tags)); + } + $(this).remove(); + }); + + value_tags.push(tag); + $(tagValuesElem).val(JSON.stringify(value_tags)); + $(tagInputElem).val(''); +} diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index 8c4090224..c44cbbc1d 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -1,1533 +1,1530 @@ -$(document).ready(function() { - // Parse seconds ago to date - // Get "now" timestamp - var ts_now = Math.round((new Date()).getTime() / 1000); - $('.parse_s_ago').each(function(i, parse_s_ago) { - var started_s_ago = parseInt($(this).text(), 10); - if (typeof started_s_ago != 'NaN') { - var started_date = new Date((ts_now - started_s_ago) * 1000); - if (started_date instanceof Date && !isNaN(started_date)) { - var started_local_date = started_date.toLocaleDateString(undefined, { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit" - }); - $(this).text(started_local_date); - } else { - $(this).text('-'); - } - } - }); - // Parse general dates - $('.parse_date').each(function(i, parse_date) { - var started_date = new Date(Date.parse($(this).text())); - if (typeof started_date != 'NaN') { - var started_local_date = started_date.toLocaleDateString(undefined, { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit" - }); - $(this).text(started_local_date); - } - }); - - // set update loop container list - containersToUpdate = {} - // set default ChartJs Font Color - Chart.defaults.color = '#999'; - // create host cpu and mem charts - createHostCpuAndMemChart(); - // check for new version - if (mailcow_info.branch === "master"){ - check_update(mailcow_info.version_tag, mailcow_info.project_url); - } - $("#maiclow_version").click(function(){ - if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || - mailcow_info.branch !== "master") - return; - - showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); - }) - // get public ips - get_public_ips(); - update_container_stats(); -}); -jQuery(function($){ - if (localStorage.getItem("current_page") === null) { - var current_page = {}; - } else { - var current_page = JSON.parse(localStorage.getItem('current_page')); - } - // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery - var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; - function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} - function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e 0 && item.symbols[a].score > 0) { - return item.symbols[b].score - item.symbols[a].score - } - return item.symbols[b].score - item.symbols[a].score - }).map(function(key) { - var sym = item.symbols[key]; - if (sym.score < 0) { - sym.score_formatted = '(' + sym.score + ')' - } - else if (sym.score === 0) { - sym.score_formatted = '(' + sym.score + ')' - } - else { - sym.score_formatted = '(' + sym.score + ')' - } - var str = '' + key + ' ' + sym.score_formatted; - if (sym.options) { - str += ' [' + escapeHtml(sym.options.join(", ")) + "]"; - } - return str - }).join('
\n'); - item.subject = escapeHtml(item.subject); - var scan_time = item.time_real.toFixed(3); - if (item.time_virtual) { - scan_time += ' / ' + item.time_virtual.toFixed(3); - } - item.scan_time = { - "options": { - "sortValue": item.time_real - }, - "value": scan_time - }; - if (item.action === 'clean' || item.action === 'no action') { - item.action = "
" + item.action + "
"; - } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') { - item.action = "
" + item.action + "
"; - } else if (item.action === 'spam' || item.action === 'reject') { - item.action = "
" + item.action + "
"; - } else { - item.action = "
" + item.action + "
"; - } - var score_content; - if (item.score < item.required_score) { - score_content = "[ " + item.score.toFixed(2) + " / " + item.required_score + " ]"; - } else { - score_content = "[ " + item.score.toFixed(2) + " / " + item.required_score + " ]"; - } - item.score = { - "options": { - "sortValue": item.score - }, - "value": score_content - }; - if (item.user == null) { - item.user = "none"; - } - }); - } else if (table == 'autodiscover_log') { - $.each(data, function (i, item) { - if (item.ua == null) { - item.ua = 'unknown'; - } else { - item.ua = escapeHtml(item.ua); - } - item.ua = '' + item.ua + ''; - if (item.service == "activesync") { - item.service = 'ActiveSync'; - } - else if (item.service == "imap") { - item.service = 'IMAP, SMTP, Cal-/CardDAV'; - } - else { - item.service = '' + escapeHtml(item.service) + ''; - } - }); - } else if (table == 'watchdog') { - $.each(data, function (i, item) { - if (item.message == null) { - item.message = 'Health level: ' + item.lvl + '% (' + item.hpnow + '/' + item.hptotal + ')'; - if (item.hpdiff < 0) { - item.trend = ' ' + item.hpdiff + ''; - } - else if (item.hpdiff == 0) { - item.trend = ' ' + item.hpdiff + ''; - } - else { - item.trend = ' ' + item.hpdiff + ''; - } - } - else { - item.trend = ''; - item.service = ''; - } - }); - } else if (table == 'mailcow_ui') { - $.each(data, function (i, item) { - if (item === null) { return true; } - item.user = escapeHtml(item.user); - item.call = escapeHtml(item.call); - item.task = '' + item.task + ''; - item.type = '' + item.type + ''; - }); - } else if (table == 'sasl_log_table') { - $.each(data, function (i, item) { - if (item === null) { return true; } - item.username = escapeHtml(item.username); - item.service = '
' + item.service.toUpperCase() + '
'; - }); - } else if (table == 'general_syslog') { - $.each(data, function (i, item) { - if (item === null) { return true; } - if (item.message.match("^base64,")) { - try { - item.message = atob(item.message.slice(7)).replace(/\\n/g, "
"); - } catch(e) { - item.message = item.message.slice(7); - } - } else { - item.message = escapeHtml(item.message); - } - item.call = escapeHtml(item.call); - var danger_class = ["emerg", "alert", "crit", "err"]; - var warning_class = ["warning", "warn"]; - var info_class = ["notice", "info", "debug"]; - if (jQuery.inArray(item.priority, danger_class) !== -1) { - item.priority = '' + item.priority + ''; - } else if (jQuery.inArray(item.priority, warning_class) !== -1) { - item.priority = '' + item.priority + ''; - } else if (jQuery.inArray(item.priority, info_class) !== -1) { - item.priority = '' + item.priority + ''; - } - }); - } else if (table == 'apilog') { - $.each(data, function (i, item) { - if (item === null) { return true; } - if (item.method == 'GET') { - item.method = '' + item.method + ''; - } else if (item.method == 'POST') { - item.method = '' + item.method + ''; - } - item.data = escapeHtml(item.data); - }); - } else if (table == 'rllog') { - $.each(data, function (i, item) { - if (item.user == null) { - item.user = "none"; - } - if (item.rl_hash == null) { - item.rl_hash = "err"; - } - item.indicator = ' '; - if (item.rl_hash != 'err') { - item.action = ' ' + lang.reset_limit + ''; - } - }); - } - return data - }; - $('.add_log_lines').on('click', function (e) { - e.preventDefault(); - var log_table= $(this).data("table") - var new_nrows = $(this).data("nrows") - var post_process = $(this).data("post-process") - var log_url = $(this).data("log-url") - if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) { - console.log("no data-table or data-nrows or log_url or data-post-process attr found"); - return; - } - - if (table = $('#' + log_table).DataTable()) { - var heading = $('#' + log_table).closest('.card').find('.card-header'); - var load_rows = (table.page.len() + 1) + '-' + (table.page.len() + new_nrows) - - $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){ - if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; } - var rows = process_table_data(data, post_process); - var rows_now = (table.page.len() + data.length); - $(heading).children('.table-lines').text(rows_now) - mailcow_alert_box(data.length + lang.additional_rows, "success"); - table.rows.add(rows).draw(); - }); - } - }) - - // detect element visibility changes - function onVisible(element, callback) { - $(document).ready(function() { - element_object = document.querySelector(element); - if (element_object === null) return; - - new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - if(entry.intersectionRatio > 0) { - callback(element_object); - } - }); - }).observe(element_object); - }); - } - // Draw Table if tab is active - onVisible("[id^=postfix_log]", () => draw_postfix_logs()); - onVisible("[id^=dovecot_log]", () => draw_dovecot_logs()); - onVisible("[id^=sogo_log]", () => draw_sogo_logs()); - onVisible("[id^=watchdog_log]", () => draw_watchdog_logs()); - onVisible("[id^=autodiscover_log]", () => draw_autodiscover_logs()); - onVisible("[id^=acme_log]", () => draw_acme_logs()); - onVisible("[id^=api_log]", () => draw_api_logs()); - onVisible("[id^=rl_log]", () => draw_rl_logs()); - onVisible("[id^=ui_logs]", () => draw_ui_logs()); - onVisible("[id^=sasl_logs]", () => draw_sasl_logs()); - onVisible("[id^=netfilter_log]", () => draw_netfilter_logs()); - onVisible("[id^=rspamd_history]", () => draw_rspamd_history()); - onVisible("[id^=rspamd_donut]", () => rspamd_pie_graph()); - - - - // start polling host stats if tab is active - onVisible("[id^=tab-containers]", () => update_stats()); - // start polling container stats if collapse is active - var containerElements = document.querySelectorAll(".container-details-collapse"); - for (let i = 0; i < containerElements.length; i++){ - new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - if(entry.intersectionRatio > 0) { - - if (!containerElements[i].classList.contains("show")){ - var container = containerElements[i].id.replace("Collapse", ""); - var container_id = containerElements[i].getAttribute("data-id"); - - // check if chart exists or needs to be created - if (!Chart.getChart(container + "_DiskIOChart")) - createReadWriteChart(container + "_DiskIOChart", "Read", "Write"); - if (!Chart.getChart(container + "_NetIOChart")) - createReadWriteChart(container + "_NetIOChart", "Recv", "Sent"); - - // add container to polling list - containersToUpdate[container] = { - id: container_id, - state: "idle" - } - - // stop polling if collapse is closed - containerElements[i].addEventListener('hidden.bs.collapse', function () { - var diskIOCtx = Chart.getChart(container + "_DiskIOChart"); - var netIOCtx = Chart.getChart(container + "_NetIOChart"); - - diskIOCtx.data.datasets[0].data = []; - diskIOCtx.data.datasets[1].data = []; - diskIOCtx.data.labels = []; - netIOCtx.data.datasets[0].data = []; - netIOCtx.data.datasets[1].data = []; - netIOCtx.data.labels = []; - - diskIOCtx.update(); - netIOCtx.update(); - - delete containersToUpdate[container]; - }); - } - - } - }); - }).observe(containerElements[i]); - } -}); - - -// update system stats - every 5 seconds if system & container tab is active -function update_stats(timeout=5){ - if (!$('#tab-containers').hasClass('active')) { - // tab not active - dont fetch stats - run again in n seconds - return; - } - - window.fetch("/api/v1/get/status/host", {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(data) { - console.log(data); - - if (data){ - // display table data - $("#host_date").text(data.system_time); - $("#host_uptime").text(formatUptime(data.uptime)); - $("#host_cpu_cores").text(data.cpu.cores); - $("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%"); - $("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB"); - $("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%"); - - // update cpu and mem chart - var cpu_chart = Chart.getChart("host_cpu_chart"); - var mem_chart = Chart.getChart("host_mem_chart"); - - cpu_chart.data.labels.push(data.system_time.split(" ")[1]); - if (cpu_chart.data.labels.length > 30) cpu_chart.data.labels.shift(); - mem_chart.data.labels.push(data.system_time.split(" ")[1]); - if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift(); - - cpu_chart.data.datasets[0].data.push(data.cpu.usage); - if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift(); - mem_chart.data.datasets[0].data.push(data.memory.usage); - if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift(); - - cpu_chart.update(); - mem_chart.update(); - } - - // run again in n seconds - setTimeout(update_stats, timeout * 1000); - }); -} -// update specific container stats - every n (default 5s) seconds -function update_container_stats(timeout=5){ - - if ($('#tab-containers').hasClass('active')) { - for (let container in containersToUpdate){ - container_id = containersToUpdate[container].id; - // check if container update stats is already running - if (containersToUpdate[container].state == "running") - continue; - containersToUpdate[container].state = "running"; - - - window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(data) { - var diskIOCtx = Chart.getChart(container + "_DiskIOChart"); - var netIOCtx = Chart.getChart(container + "_NetIOChart"); - - console.log(container); - console.log(data); - prev_stats = null; - if (data.length >= 2){ - prev_stats = data[data.length -2]; - - // hide spinners if we collected enough data - $('#' + container + "_DiskIOChart").removeClass('d-none'); - $('#' + container + "_DiskIOChart").prev().addClass('d-none'); - $('#' + container + "_NetIOChart").removeClass('d-none'); - $('#' + container + "_NetIOChart").prev().addClass('d-none'); - } - - data = data[data.length -1]; - - if (prev_stats != null){ - // calc time diff - var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000; - - // calc disk io b/s - if ('io_service_bytes_recursive' in prev_stats.blkio_stats && prev_stats.blkio_stats.io_service_bytes_recursive !== null){ - var prev_read_bytes = 0; - var prev_write_bytes = 0; - for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){ - if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read") - prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value; - else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write") - prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value; - } - var read_bytes = 0; - var write_bytes = 0; - for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){ - if (data.blkio_stats.io_service_bytes_recursive[i].op == "read") - read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value; - else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write") - write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value; - } - var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff; - var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff; - } - - // calc net io b/s - if ('networks' in prev_stats){ - var prev_recv_bytes = 0; - var prev_sent_bytes = 0; - for (var key in prev_stats.networks){ - prev_recv_bytes += prev_stats.networks[key].rx_bytes; - prev_sent_bytes += prev_stats.networks[key].tx_bytes; - } - var recv_bytes = 0; - var sent_bytes = 0; - for (var key in data.networks){ - recv_bytes += data.networks[key].rx_bytes; - sent_bytes += data.networks[key].tx_bytes; - } - var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff; - var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff; - } - - addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, ""); - addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, ""); - } - - // run again in n seconds - containersToUpdate[container].state = "idle"; - }).catch(err => { - console.log(err); - }); - } - } - - // run again in n seconds - setTimeout(update_container_stats, timeout * 1000); -} -// get public ips -function get_public_ips(){ - window.fetch("/api/v1/get/status/host/ip", {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(data) { - console.log(data); - - // display host ips - if (data.ipv4) - $("#host_ipv4").text(data.ipv4); - if (data.ipv6) - $("#host_ipv6").text(data.ipv6); - }); -} -// format hosts uptime seconds to readable string -function formatUptime(seconds){ - seconds = Number(seconds); - var d = Math.floor(seconds / (3600*24)); - var h = Math.floor(seconds % (3600*24) / 3600); - var m = Math.floor(seconds % 3600 / 60); - var s = Math.floor(seconds % 60); - - var dFormat = d > 0 ? d + "D " : ""; - var hFormat = h > 0 ? h + "H " : ""; - var mFormat = m > 0 ? m + "M " : ""; - var sFormat = s > 0 ? s + "S" : ""; - return dFormat + hFormat + mFormat + sFormat; -} -// format bytes to readable string -function formatBytes(bytes){ - // b - if (bytes < 1000) return bytes.toFixed(2).toString()+' B/s'; - // b to kb - bytes = bytes / 1024; - if (bytes < 1000) return bytes.toFixed(2).toString()+' KB/s'; - // kb to mb - bytes = bytes / 1024; - if (bytes < 1000) return bytes.toFixed(2).toString()+' MB/s'; - // final mb to gb - return (bytes / 1024).toFixed(2).toString()+' GB/s'; -} -// create read write line chart -function createReadWriteChart(chart_id, read_lable, write_lable){ - var ctx = document.getElementById(chart_id); - - var dataNet = { - labels: [], - datasets: [{ - label: read_lable, - backgroundColor: "rgba(41, 187, 239, 0.3)", - borderColor: "rgba(41, 187, 239, 0.6)", - pointRadius: 1, - pointHitRadius: 6, - borderWidth: 2, - fill: true, - tension: 0.2, - data: [] - }, { - label: write_lable, - backgroundColor: "rgba(239, 60, 41, 0.3)", - borderColor: "rgba(239, 60, 41, 0.6)", - pointRadius: 1, - pointHitRadius: 6, - borderWidth: 2, - fill: true, - tension: 0.2, - data: [] - }] - }; - var optionsNet = { - interaction: { - mode: 'index' - }, - scales: { - yAxis: { - min: 0, - grid: { - display: false - }, - ticks: { - callback: function(i, index, ticks) { - return formatBytes(i); - } - } - }, - xAxis: { - grid: { - display: false - } - } - } - }; - - return new Chart(ctx, { - type: 'line', - data: dataNet, - options: optionsNet - }); -} -// add to read write line chart -function addReadWriteChart(chart_context, read_point, write_point, time, limit = 30){ - // push time label for x-axis - chart_context.data.labels.push(time); - if (chart_context.data.labels.length > limit) chart_context.data.labels.shift(); - - // push datapoints - chart_context.data.datasets[0].data.push(read_point); - chart_context.data.datasets[1].data.push(write_point); - // shift data if more than 20 entires exists - if (chart_context.data.datasets[0].data.length > limit) chart_context.data.datasets[0].data.shift(); - if (chart_context.data.datasets[1].data.length > limit) chart_context.data.datasets[1].data.shift(); - - chart_context.update(); -} -// create host cpu and mem chart -function createHostCpuAndMemChart(){ - var cpu_ctx = document.getElementById("host_cpu_chart"); - var mem_ctx = document.getElementById("host_mem_chart"); - - var dataCpu = { - labels: [], - datasets: [{ - label: "CPU %", - backgroundColor: "rgba(41, 187, 239, 0.3)", - borderColor: "rgba(41, 187, 239, 0.6)", - pointRadius: 1, - pointHitRadius: 6, - borderWidth: 2, - fill: true, - tension: 0.2, - data: [] - }] - }; - var optionsCpu = { - interaction: { - mode: 'index' - }, - scales: { - yAxis: { - min: 0, - grid: { - display: false - }, - ticks: { - callback: function(i, index, ticks) { - return i.toFixed(0).toString() + "%"; - } - } - }, - xAxis: { - grid: { - display: false - } - } - } - }; - - var dataMem = { - labels: [], - datasets: [{ - label: "MEM %", - backgroundColor: "rgba(41, 187, 239, 0.3)", - borderColor: "rgba(41, 187, 239, 0.6)", - pointRadius: 1, - pointHitRadius: 6, - borderWidth: 2, - fill: true, - tension: 0.2, - data: [] - }] - }; - var optionsMem = { - interaction: { - mode: 'index' - }, - scales: { - yAxis: { - min: 0, - grid: { - display: false - }, - ticks: { - callback: function(i, index, ticks) { - return i.toFixed(0).toString() + "%"; - } - } - }, - xAxis: { - grid: { - display: false - } - } - } - }; - - - var net_io_chart = new Chart(cpu_ctx, { - type: 'line', - data: dataCpu, - options: optionsCpu - }); - var disk_io_chart = new Chart(mem_ctx, { - type: 'line', - data: dataMem, - options: optionsMem - }); -} -// check for mailcow updates -function check_update(current_version, github_repo_url){ - if (!current_version || !github_repo_url) return false; - - var github_account = github_repo_url.split("/")[3]; - var github_repo_name = github_repo_url.split("/")[4]; - - // get details about latest release - window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/latest", {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(latest_data) { - // get details about current release - window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/tags/"+current_version, {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(current_data) { - // compare releases - var date_current = new Date(current_data.created_at); - var date_latest = new Date(latest_data.created_at); - if (date_latest.getTime() <= date_current.getTime()){ - // no update available - $("#mailcow_update").removeClass("text-warning text-danger").addClass("text-success"); - $("#mailcow_update").html("" + lang_debug.no_update_available + ""); - } else { - // update available - $("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning"); - $("#mailcow_update").html(lang_debug.update_available + ` `+latest_data.tag_name+``); - $("#mailcow_update_changelog").click(function(){ - if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin") - return; - - showVersionModal("New Release " + latest_data.tag_name, latest_data.tag_name); - }) - } - }).catch(err => { - // err - console.log(err); - $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger"); - $("#mailcow_update").html(""+ lang_debug.update_failed +""); - }); - }).catch(err => { - // err - console.log(err); - $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger"); - $("#mailcow_update").html(""+ lang_debug.update_failed +""); - }); -} -// show version changelog modal -function showVersionModal(title, version){ - $.ajax({ - type: 'GET', - url: 'https://api.github.com/repos/' + mailcow_info.project_owner + '/' + mailcow_info.project_repo + '/releases/tags/' + version, - dataType: 'json', - success: function (data) { - var md = window.markdownit(); - var result = md.render(data.body); - result = parseGithubMarkdownLinks(result); - - $('#showVersionModal').find(".modal-title").html(title); - $('#showVersionModal').find(".modal-body").html(` -

` + data.name + `

- ` + result + ` - Github Link: - ` + version + ` - - `); - - new bootstrap.Modal(document.getElementById("showVersionModal"), { - backdrop: 'static', - keyboard: false - }).show(); - } - }); -} -function parseGithubMarkdownLinks(inputText) { - var replacedText, replacePattern1; - - replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; - replacedText = inputText.replace(replacePattern1, (matched, index, original, input_string) => { - if (matched.includes('github.com')){ - // return short link if it's github link - last_uri_path = matched.split('/'); - last_uri_path = last_uri_path[last_uri_path.length - 1]; - - // adjust Full Changelog link to match last git version and new git version, if link is a compare link - if (matched.includes('/compare/') && mailcow_info.last_version_tag !== ''){ - matched = matched.replace(last_uri_path, mailcow_info.last_version_tag + '...' + mailcow_info.version_tag); - last_uri_path = mailcow_info.last_version_tag + '...' + mailcow_info.version_tag; - } - - return '' + last_uri_path + '
'; - }; - - // if it's not a github link, return complete link - return '' + matched + ''; - }); - - return replacedText; -} \ No newline at end of file +const LOCALE = undefined; +const DATETIME_FORMAT = { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit" +}; + +$(document).ready(function() { + // Parse seconds ago to date + // Get "now" timestamp + var ts_now = Math.round((new Date()).getTime() / 1000); + $('.parse_s_ago').each(function(i, parse_s_ago) { + var started_s_ago = parseInt($(this).text(), 10); + if (typeof started_s_ago != 'NaN') { + var started_date = new Date((ts_now - started_s_ago) * 1000); + if (started_date instanceof Date && !isNaN(started_date)) { + var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT); + $(this).text(started_local_date); + } else { + $(this).text('-'); + } + } + }); + // Parse general dates + $('.parse_date').each(function(i, parse_date) { + var started_date = new Date(Date.parse($(this).text())); + if (typeof started_date != 'NaN') { + var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT); + $(this).text(started_local_date); + } + }); + + // set update loop container list + containersToUpdate = {} + // set default ChartJs Font Color + Chart.defaults.color = '#999'; + // create host cpu and mem charts + createHostCpuAndMemChart(); + // check for new version + if (mailcow_info.branch === "master"){ + check_update(mailcow_info.version_tag, mailcow_info.project_url); + } + $("#maiclow_version").click(function(){ + if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || + mailcow_info.branch !== "master") + return; + + showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); + }) + // get public ips + get_public_ips(); + update_container_stats(); +}); +jQuery(function($){ + if (localStorage.getItem("current_page") === null) { + var current_page = {}; + } else { + var current_page = JSON.parse(localStorage.getItem('current_page')); + } + // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery + var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; + function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} + function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e 0 && item.symbols[a].score > 0) { + return item.symbols[b].score - item.symbols[a].score + } + return item.symbols[b].score - item.symbols[a].score + }).map(function(key) { + var sym = item.symbols[key]; + if (sym.score < 0) { + sym.score_formatted = '(' + sym.score + ')' + } + else if (sym.score === 0) { + sym.score_formatted = '(' + sym.score + ')' + } + else { + sym.score_formatted = '(' + sym.score + ')' + } + var str = '' + key + ' ' + sym.score_formatted; + if (sym.options) { + str += ' [' + escapeHtml(sym.options.join(", ")) + "]"; + } + return str + }).join('
\n'); + item.subject = escapeHtml(item.subject); + var scan_time = item.time_real.toFixed(3); + if (item.time_virtual) { + scan_time += ' / ' + item.time_virtual.toFixed(3); + } + item.scan_time = { + "options": { + "sortValue": item.time_real + }, + "value": scan_time + }; + if (item.action === 'clean' || item.action === 'no action') { + item.action = "
" + item.action + "
"; + } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') { + item.action = "
" + item.action + "
"; + } else if (item.action === 'spam' || item.action === 'reject') { + item.action = "
" + item.action + "
"; + } else { + item.action = "
" + item.action + "
"; + } + var score_content; + if (item.score < item.required_score) { + score_content = "[ " + item.score.toFixed(2) + " / " + item.required_score + " ]"; + } else { + score_content = "[ " + item.score.toFixed(2) + " / " + item.required_score + " ]"; + } + item.score = { + "options": { + "sortValue": item.score + }, + "value": score_content + }; + if (item.user == null) { + item.user = "none"; + } + }); + } else if (table == 'autodiscover_log') { + $.each(data, function (i, item) { + if (item.ua == null) { + item.ua = 'unknown'; + } else { + item.ua = escapeHtml(item.ua); + } + item.ua = '' + item.ua + ''; + if (item.service == "activesync") { + item.service = 'ActiveSync'; + } + else if (item.service == "imap") { + item.service = 'IMAP, SMTP, Cal-/CardDAV'; + } + else { + item.service = '' + escapeHtml(item.service) + ''; + } + }); + } else if (table == 'watchdog') { + $.each(data, function (i, item) { + if (item.message == null) { + item.message = 'Health level: ' + item.lvl + '% (' + item.hpnow + '/' + item.hptotal + ')'; + if (item.hpdiff < 0) { + item.trend = ' ' + item.hpdiff + ''; + } + else if (item.hpdiff == 0) { + item.trend = ' ' + item.hpdiff + ''; + } + else { + item.trend = ' ' + item.hpdiff + ''; + } + } + else { + item.trend = ''; + item.service = ''; + } + }); + } else if (table == 'mailcow_ui') { + $.each(data, function (i, item) { + if (item === null) { return true; } + item.user = escapeHtml(item.user); + item.call = escapeHtml(item.call); + item.task = '' + item.task + ''; + item.type = '' + item.type + ''; + }); + } else if (table == 'sasl_log_table') { + $.each(data, function (i, item) { + if (item === null) { return true; } + item.username = escapeHtml(item.username); + item.service = '
' + item.service.toUpperCase() + '
'; + }); + } else if (table == 'general_syslog') { + $.each(data, function (i, item) { + if (item === null) { return true; } + if (item.message.match("^base64,")) { + try { + item.message = atob(item.message.slice(7)).replace(/\\n/g, "
"); + } catch(e) { + item.message = item.message.slice(7); + } + } else { + item.message = escapeHtml(item.message); + } + item.call = escapeHtml(item.call); + var danger_class = ["emerg", "alert", "crit", "err"]; + var warning_class = ["warning", "warn"]; + var info_class = ["notice", "info", "debug"]; + if (jQuery.inArray(item.priority, danger_class) !== -1) { + item.priority = '' + item.priority + ''; + } else if (jQuery.inArray(item.priority, warning_class) !== -1) { + item.priority = '' + item.priority + ''; + } else if (jQuery.inArray(item.priority, info_class) !== -1) { + item.priority = '' + item.priority + ''; + } + }); + } else if (table == 'apilog') { + $.each(data, function (i, item) { + if (item === null) { return true; } + if (item.method == 'GET') { + item.method = '' + item.method + ''; + } else if (item.method == 'POST') { + item.method = '' + item.method + ''; + } + item.data = escapeHtml(item.data); + }); + } else if (table == 'rllog') { + $.each(data, function (i, item) { + if (item.user == null) { + item.user = "none"; + } + if (item.rl_hash == null) { + item.rl_hash = "err"; + } + item.indicator = ' '; + if (item.rl_hash != 'err') { + item.action = ' ' + lang.reset_limit + ''; + } + }); + } + return data + }; + $('.add_log_lines').on('click', function (e) { + e.preventDefault(); + var log_table= $(this).data("table") + var new_nrows = $(this).data("nrows") + var post_process = $(this).data("post-process") + var log_url = $(this).data("log-url") + if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) { + console.log("no data-table or data-nrows or log_url or data-post-process attr found"); + return; + } + + if (table = $('#' + log_table).DataTable()) { + var heading = $('#' + log_table).closest('.card').find('.card-header'); + var load_rows = (table.page.len() + 1) + '-' + (table.page.len() + new_nrows) + + $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){ + if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; } + var rows = process_table_data(data, post_process); + var rows_now = (table.page.len() + data.length); + $(heading).children('.table-lines').text(rows_now) + mailcow_alert_box(data.length + lang.additional_rows, "success"); + table.rows.add(rows).draw(); + }); + } + }) + + // detect element visibility changes + function onVisible(element, callback) { + $(document).ready(function() { + element_object = document.querySelector(element); + if (element_object === null) return; + + new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if(entry.intersectionRatio > 0) { + callback(element_object); + } + }); + }).observe(element_object); + }); + } + // Draw Table if tab is active + onVisible("[id^=postfix_log]", () => draw_postfix_logs()); + onVisible("[id^=dovecot_log]", () => draw_dovecot_logs()); + onVisible("[id^=sogo_log]", () => draw_sogo_logs()); + onVisible("[id^=watchdog_log]", () => draw_watchdog_logs()); + onVisible("[id^=autodiscover_log]", () => draw_autodiscover_logs()); + onVisible("[id^=acme_log]", () => draw_acme_logs()); + onVisible("[id^=api_log]", () => draw_api_logs()); + onVisible("[id^=rl_log]", () => draw_rl_logs()); + onVisible("[id^=ui_logs]", () => draw_ui_logs()); + onVisible("[id^=sasl_logs]", () => draw_sasl_logs()); + onVisible("[id^=netfilter_log]", () => draw_netfilter_logs()); + onVisible("[id^=rspamd_history]", () => draw_rspamd_history()); + onVisible("[id^=rspamd_donut]", () => rspamd_pie_graph()); + + + + // start polling host stats if tab is active + onVisible("[id^=tab-containers]", () => update_stats()); + // start polling container stats if collapse is active + var containerElements = document.querySelectorAll(".container-details-collapse"); + for (let i = 0; i < containerElements.length; i++){ + new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if(entry.intersectionRatio > 0) { + + if (!containerElements[i].classList.contains("show")){ + var container = containerElements[i].id.replace("Collapse", ""); + var container_id = containerElements[i].getAttribute("data-id"); + + // check if chart exists or needs to be created + if (!Chart.getChart(container + "_DiskIOChart")) + createReadWriteChart(container + "_DiskIOChart", "Read", "Write"); + if (!Chart.getChart(container + "_NetIOChart")) + createReadWriteChart(container + "_NetIOChart", "Recv", "Sent"); + + // add container to polling list + containersToUpdate[container] = { + id: container_id, + state: "idle" + } + + // stop polling if collapse is closed + containerElements[i].addEventListener('hidden.bs.collapse', function () { + var diskIOCtx = Chart.getChart(container + "_DiskIOChart"); + var netIOCtx = Chart.getChart(container + "_NetIOChart"); + + diskIOCtx.data.datasets[0].data = []; + diskIOCtx.data.datasets[1].data = []; + diskIOCtx.data.labels = []; + netIOCtx.data.datasets[0].data = []; + netIOCtx.data.datasets[1].data = []; + netIOCtx.data.labels = []; + + diskIOCtx.update(); + netIOCtx.update(); + + delete containersToUpdate[container]; + }); + } + + } + }); + }).observe(containerElements[i]); + } +}); + + +// update system stats - every 5 seconds if system & container tab is active +function update_stats(timeout=5){ + if (!$('#tab-containers').hasClass('active')) { + // tab not active - dont fetch stats - run again in n seconds + return; + } + + window.fetch("/api/v1/get/status/host", {method:'GET',cache:'no-cache'}).then(function(response) { + return response.json(); + }).then(function(data) { + console.log(data); + + if (data){ + // display table data + $("#host_date").text(data.system_time); + $("#host_uptime").text(formatUptime(data.uptime)); + $("#host_cpu_cores").text(data.cpu.cores); + $("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%"); + $("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB"); + $("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%"); + + // update cpu and mem chart + var cpu_chart = Chart.getChart("host_cpu_chart"); + var mem_chart = Chart.getChart("host_mem_chart"); + + cpu_chart.data.labels.push(data.system_time.split(" ")[1]); + if (cpu_chart.data.labels.length > 30) cpu_chart.data.labels.shift(); + mem_chart.data.labels.push(data.system_time.split(" ")[1]); + if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift(); + + cpu_chart.data.datasets[0].data.push(data.cpu.usage); + if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift(); + mem_chart.data.datasets[0].data.push(data.memory.usage); + if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift(); + + cpu_chart.update(); + mem_chart.update(); + } + + // run again in n seconds + setTimeout(update_stats, timeout * 1000); + }); +} +// update specific container stats - every n (default 5s) seconds +function update_container_stats(timeout=5){ + + if ($('#tab-containers').hasClass('active')) { + for (let container in containersToUpdate){ + container_id = containersToUpdate[container].id; + // check if container update stats is already running + if (containersToUpdate[container].state == "running") + continue; + containersToUpdate[container].state = "running"; + + + window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) { + return response.json(); + }).then(function(data) { + var diskIOCtx = Chart.getChart(container + "_DiskIOChart"); + var netIOCtx = Chart.getChart(container + "_NetIOChart"); + + console.log(container); + console.log(data); + prev_stats = null; + if (data.length >= 2){ + prev_stats = data[data.length -2]; + + // hide spinners if we collected enough data + $('#' + container + "_DiskIOChart").removeClass('d-none'); + $('#' + container + "_DiskIOChart").prev().addClass('d-none'); + $('#' + container + "_NetIOChart").removeClass('d-none'); + $('#' + container + "_NetIOChart").prev().addClass('d-none'); + } + + data = data[data.length -1]; + + if (prev_stats != null){ + // calc time diff + var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000; + + // calc disk io b/s + if ('io_service_bytes_recursive' in prev_stats.blkio_stats && prev_stats.blkio_stats.io_service_bytes_recursive !== null){ + var prev_read_bytes = 0; + var prev_write_bytes = 0; + for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){ + if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read") + prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value; + else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write") + prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value; + } + var read_bytes = 0; + var write_bytes = 0; + for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){ + if (data.blkio_stats.io_service_bytes_recursive[i].op == "read") + read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value; + else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write") + write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value; + } + var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff; + var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff; + } + + // calc net io b/s + if ('networks' in prev_stats){ + var prev_recv_bytes = 0; + var prev_sent_bytes = 0; + for (var key in prev_stats.networks){ + prev_recv_bytes += prev_stats.networks[key].rx_bytes; + prev_sent_bytes += prev_stats.networks[key].tx_bytes; + } + var recv_bytes = 0; + var sent_bytes = 0; + for (var key in data.networks){ + recv_bytes += data.networks[key].rx_bytes; + sent_bytes += data.networks[key].tx_bytes; + } + var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff; + var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff; + } + + addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, ""); + addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, ""); + } + + // run again in n seconds + containersToUpdate[container].state = "idle"; + }).catch(err => { + console.log(err); + }); + } + } + + // run again in n seconds + setTimeout(update_container_stats, timeout * 1000); +} +// get public ips +function get_public_ips(){ + window.fetch("/api/v1/get/status/host/ip", {method:'GET',cache:'no-cache'}).then(function(response) { + return response.json(); + }).then(function(data) { + console.log(data); + + // display host ips + if (data.ipv4) + $("#host_ipv4").text(data.ipv4); + if (data.ipv6) + $("#host_ipv6").text(data.ipv6); + }); +} +// format hosts uptime seconds to readable string +function formatUptime(seconds){ + seconds = Number(seconds); + var d = Math.floor(seconds / (3600*24)); + var h = Math.floor(seconds % (3600*24) / 3600); + var m = Math.floor(seconds % 3600 / 60); + var s = Math.floor(seconds % 60); + + var dFormat = d > 0 ? d + "D " : ""; + var hFormat = h > 0 ? h + "H " : ""; + var mFormat = m > 0 ? m + "M " : ""; + var sFormat = s > 0 ? s + "S" : ""; + return dFormat + hFormat + mFormat + sFormat; +} +// format bytes to readable string +function formatBytes(bytes){ + // b + if (bytes < 1000) return bytes.toFixed(2).toString()+' B/s'; + // b to kb + bytes = bytes / 1024; + if (bytes < 1000) return bytes.toFixed(2).toString()+' KB/s'; + // kb to mb + bytes = bytes / 1024; + if (bytes < 1000) return bytes.toFixed(2).toString()+' MB/s'; + // final mb to gb + return (bytes / 1024).toFixed(2).toString()+' GB/s'; +} +// create read write line chart +function createReadWriteChart(chart_id, read_lable, write_lable){ + var ctx = document.getElementById(chart_id); + + var dataNet = { + labels: [], + datasets: [{ + label: read_lable, + backgroundColor: "rgba(41, 187, 239, 0.3)", + borderColor: "rgba(41, 187, 239, 0.6)", + pointRadius: 1, + pointHitRadius: 6, + borderWidth: 2, + fill: true, + tension: 0.2, + data: [] + }, { + label: write_lable, + backgroundColor: "rgba(239, 60, 41, 0.3)", + borderColor: "rgba(239, 60, 41, 0.6)", + pointRadius: 1, + pointHitRadius: 6, + borderWidth: 2, + fill: true, + tension: 0.2, + data: [] + }] + }; + var optionsNet = { + interaction: { + mode: 'index' + }, + scales: { + yAxis: { + min: 0, + grid: { + display: false + }, + ticks: { + callback: function(i, index, ticks) { + return formatBytes(i); + } + } + }, + xAxis: { + grid: { + display: false + } + } + } + }; + + return new Chart(ctx, { + type: 'line', + data: dataNet, + options: optionsNet + }); +} +// add to read write line chart +function addReadWriteChart(chart_context, read_point, write_point, time, limit = 30){ + // push time label for x-axis + chart_context.data.labels.push(time); + if (chart_context.data.labels.length > limit) chart_context.data.labels.shift(); + + // push datapoints + chart_context.data.datasets[0].data.push(read_point); + chart_context.data.datasets[1].data.push(write_point); + // shift data if more than 20 entires exists + if (chart_context.data.datasets[0].data.length > limit) chart_context.data.datasets[0].data.shift(); + if (chart_context.data.datasets[1].data.length > limit) chart_context.data.datasets[1].data.shift(); + + chart_context.update(); +} +// create host cpu and mem chart +function createHostCpuAndMemChart(){ + var cpu_ctx = document.getElementById("host_cpu_chart"); + var mem_ctx = document.getElementById("host_mem_chart"); + + var dataCpu = { + labels: [], + datasets: [{ + label: "CPU %", + backgroundColor: "rgba(41, 187, 239, 0.3)", + borderColor: "rgba(41, 187, 239, 0.6)", + pointRadius: 1, + pointHitRadius: 6, + borderWidth: 2, + fill: true, + tension: 0.2, + data: [] + }] + }; + var optionsCpu = { + interaction: { + mode: 'index' + }, + scales: { + yAxis: { + min: 0, + grid: { + display: false + }, + ticks: { + callback: function(i, index, ticks) { + return i.toFixed(0).toString() + "%"; + } + } + }, + xAxis: { + grid: { + display: false + } + } + } + }; + + var dataMem = { + labels: [], + datasets: [{ + label: "MEM %", + backgroundColor: "rgba(41, 187, 239, 0.3)", + borderColor: "rgba(41, 187, 239, 0.6)", + pointRadius: 1, + pointHitRadius: 6, + borderWidth: 2, + fill: true, + tension: 0.2, + data: [] + }] + }; + var optionsMem = { + interaction: { + mode: 'index' + }, + scales: { + yAxis: { + min: 0, + grid: { + display: false + }, + ticks: { + callback: function(i, index, ticks) { + return i.toFixed(0).toString() + "%"; + } + } + }, + xAxis: { + grid: { + display: false + } + } + } + }; + + + var net_io_chart = new Chart(cpu_ctx, { + type: 'line', + data: dataCpu, + options: optionsCpu + }); + var disk_io_chart = new Chart(mem_ctx, { + type: 'line', + data: dataMem, + options: optionsMem + }); +} +// check for mailcow updates +function check_update(current_version, github_repo_url){ + if (!current_version || !github_repo_url) return false; + + var github_account = github_repo_url.split("/")[3]; + var github_repo_name = github_repo_url.split("/")[4]; + + // get details about latest release + window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/latest", {method:'GET',cache:'no-cache'}).then(function(response) { + return response.json(); + }).then(function(latest_data) { + // get details about current release + window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/tags/"+current_version, {method:'GET',cache:'no-cache'}).then(function(response) { + return response.json(); + }).then(function(current_data) { + // compare releases + var date_current = new Date(current_data.created_at); + var date_latest = new Date(latest_data.created_at); + if (date_latest.getTime() <= date_current.getTime()){ + // no update available + $("#mailcow_update").removeClass("text-warning text-danger").addClass("text-success"); + $("#mailcow_update").html("" + lang_debug.no_update_available + ""); + } else { + // update available + $("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning"); + $("#mailcow_update").html(lang_debug.update_available + ` `+latest_data.tag_name+``); + $("#mailcow_update_changelog").click(function(){ + if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin") + return; + + showVersionModal("New Release " + latest_data.tag_name, latest_data.tag_name); + }) + } + }).catch(err => { + // err + console.log(err); + $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger"); + $("#mailcow_update").html(""+ lang_debug.update_failed +""); + }); + }).catch(err => { + // err + console.log(err); + $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger"); + $("#mailcow_update").html(""+ lang_debug.update_failed +""); + }); +} +// show version changelog modal +function showVersionModal(title, version){ + $.ajax({ + type: 'GET', + url: 'https://api.github.com/repos/' + mailcow_info.project_owner + '/' + mailcow_info.project_repo + '/releases/tags/' + version, + dataType: 'json', + success: function (data) { + var md = window.markdownit(); + var result = md.render(data.body); + result = parseGithubMarkdownLinks(result); + + $('#showVersionModal').find(".modal-title").html(title); + $('#showVersionModal').find(".modal-body").html(` +

` + data.name + `

+ ` + result + ` + Github Link: + ` + version + ` + + `); + + new bootstrap.Modal(document.getElementById("showVersionModal"), { + backdrop: 'static', + keyboard: false + }).show(); + } + }); +} +function parseGithubMarkdownLinks(inputText) { + var replacedText, replacePattern1; + + replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; + replacedText = inputText.replace(replacePattern1, (matched, index, original, input_string) => { + if (matched.includes('github.com')){ + // return short link if it's github link + last_uri_path = matched.split('/'); + last_uri_path = last_uri_path[last_uri_path.length - 1]; + + // adjust Full Changelog link to match last git version and new git version, if link is a compare link + if (matched.includes('/compare/') && mailcow_info.last_version_tag !== ''){ + matched = matched.replace(last_uri_path, mailcow_info.last_version_tag + '...' + mailcow_info.version_tag); + last_uri_path = mailcow_info.last_version_tag + '...' + mailcow_info.version_tag; + } + + return '' + last_uri_path + '
'; + }; + + // if it's not a github link, return complete link + return '' + matched + ''; + }); + + return replacedText; +} + +function convertTimestampToLocalFormat(timestamp) { + var date = new Date(timestamp ? timestamp * 1000 : 0); + return date.toLocaleDateString(LOCALE, DATETIME_FORMAT); +} From eefce62f017be3a13c2ff6d9fee51a31689829d2 Mon Sep 17 00:00:00 2001 From: Tom Udding Date: Sat, 24 Dec 2022 18:10:57 +0100 Subject: [PATCH 02/11] Fix incorrect datetime for Rspamd logs --- data/web/js/site/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index c44cbbc1d..d15f6e1e9 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -731,7 +731,7 @@ jQuery(function($){ columns: [ { title: lang.time, - data: 'time', + data: 'unix_time', defaultContent: '', createdCell: function(td, cellData) { createSortableDate(td, cellData) From 136cc2e3fff2276074de7e51cd2e5a66f4659ef1 Mon Sep 17 00:00:00 2001 From: Tom Udding Date: Sat, 24 Dec 2022 18:18:28 +0100 Subject: [PATCH 03/11] Fix missing score and scan time Rspamd logs --- data/web/js/site/debug.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index d15f6e1e9..296886f9b 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -765,7 +765,14 @@ jQuery(function($){ { title: 'Score', data: 'score', - defaultContent: '' + defaultContent: '', + createdCell: function(td, cellData) { + $(td).attr({ + "data-order": cellData.sortBy, + "data-sort": cellData.sortBy + }); + $(td).html(cellData.value); + } }, { title: 'Subject', @@ -786,7 +793,14 @@ jQuery(function($){ { title: 'Scan Time', data: 'scan_time', - defaultContent: '' + defaultContent: '', + createdCell: function(td, cellData) { + $(td).attr({ + "data-order": cellData.sortBy, + "data-sort": cellData.sortBy + }); + $(td).html(cellData.value); + } }, { title: 'ID', @@ -843,9 +857,7 @@ jQuery(function($){ scan_time += ' / ' + item.time_virtual.toFixed(3); } item.scan_time = { - "options": { - "sortValue": item.time_real - }, + "sortBy": item.time_real, "value": scan_time }; if (item.action === 'clean' || item.action === 'no action') { @@ -864,9 +876,7 @@ jQuery(function($){ score_content = "[ " + item.score.toFixed(2) + " / " + item.required_score + " ]"; } item.score = { - "options": { - "sortValue": item.score - }, + "sortBy": item.score, "value": score_content }; if (item.user == null) { From 82c80a9682f29d69a935f93dd26b2b1ed1b107cf Mon Sep 17 00:00:00 2001 From: Tom Udding Date: Sat, 24 Dec 2022 18:29:46 +0100 Subject: [PATCH 04/11] Make default ordering of Rspamd table consistent --- data/web/js/site/debug.js | 1 + 1 file changed, 1 insertion(+) diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index 296886f9b..1996600af 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -721,6 +721,7 @@ jQuery(function($){ processing: true, serverSide: false, language: lang_datatables, + order: [[0, 'desc']], ajax: { type: "GET", url: "/api/v1/get/logs/rspamd-history", From 8070db96e9d752be0c0e2b6574a840d219a2a1be Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Sat, 24 Dec 2022 22:25:42 +0100 Subject: [PATCH 05/11] [UI] Fixed Wrong Table content in Qurantine (sender instead of subject) --- data/web/js/site/quarantine.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/js/site/quarantine.js b/data/web/js/site/quarantine.js index d838b0fb7..34531b0d3 100644 --- a/data/web/js/site/quarantine.js +++ b/data/web/js/site/quarantine.js @@ -97,7 +97,7 @@ jQuery(function($){ }, { title: lang.subj, - data: 'sender', + data: 'subject', defaultContent: '' }, { From 3281b97ea9123bcda388c261013e96aa7bdaf6a4 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Sat, 24 Dec 2022 23:25:52 +0100 Subject: [PATCH 06/11] [UI] Removed solr informations if container is disabled --- data/web/lang/lang.de-de.json | 1 + data/web/lang/lang.en-gb.json | 1 + data/web/templates/debug.twig | 12 +++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index b6229491a..7b4b1f46f 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -488,6 +488,7 @@ "chart_this_server": "Chart (dieser Server)", "containers_info": "Container-Information", "container_running": "Läuft", + "container_disabled": "Container gestoppt oder deaktiviert", "container_stopped": "Angehalten", "cores": "Kerne", "current_time": "Systemzeit", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index ce6e2cf8e..00b14f07a 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -491,6 +491,7 @@ "chart_this_server": "Chart (this server)", "containers_info": "Container information", "container_running": "Running", + "container_disabled": "Container stopped or disabled", "container_stopped": "Stopped", "cores": "Cores", "current_time": "System Time", diff --git a/data/web/templates/debug.twig b/data/web/templates/debug.twig index eb48d54e8..6c96de880 100644 --- a/data/web/templates/debug.twig +++ b/data/web/templates/debug.twig @@ -160,8 +160,14 @@
solr-mailcow + {% if containers["solr-mailcow"].State.Running == 1 %} ({{ containers["solr-mailcow"].Config.Image }}) + {% endif %} + {% if containers["solr-mailcow"].State.Running == 1 %} ({{ lang.debug.started_on }} {{ containers["solr-mailcow"].State.StartedAtHR }}) + {% elseif containers["solr-mailcow"].State.Running != 1 %} + {{ lang.debug.container_disabled }} + {% endif %} {% if containers["solr-mailcow"].State.Running == 1 %} {{ lang.debug.container_running }} @@ -169,19 +175,22 @@ . . - {% elseif containers["solr-mailcow"].State %} + {% elseif containers["solr-mailcow"].State.Running != 1 %} {{ lang.debug.container_stopped }} {% endif %}
+ {% if containers["solr-mailcow"].State.Running == 1 %}
+ {% endif %}
+ {% if containers["solr-mailcow"].State.Running == 1 %}
@@ -238,6 +247,7 @@
+ {% endif %} From 13bdd4ad0bd6c1f417386192683d5fc36e06ec69 Mon Sep 17 00:00:00 2001 From: Tomy Hsieh Date: Sun, 25 Dec 2022 16:56:43 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=9B=A0=20fix:=20Locale=20decision?= =?UTF-8?q?=20algorithm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/web/inc/prerequisites.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index 754d98d55..b3b1cc13d 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -234,7 +234,7 @@ if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) { // Try suggest match // e.g. suggest en-gb when only en-us is provided - if (!isset($_COOKIE['mailcow_locale'])) { + 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)]; From dabf4d4383bbc6adaa61d49c8d68ce83dfe1af0e Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Sun, 25 Dec 2022 14:44:00 +0100 Subject: [PATCH 08/11] [UI] Show Restart SOGo only when permission = admin --- data/web/templates/base.twig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/web/templates/base.twig b/data/web/templates/base.twig index 743a2b2da..06c47bd2c 100644 --- a/data/web/templates/base.twig +++ b/data/web/templates/base.twig @@ -80,7 +80,9 @@ {% if mailcow_cc_role == 'admin' %}
  • {{ lang.queue.queue_manager }}
  • {% endif %} + {% if mailcow_cc_role == 'admin' %}
  • {{ lang.header.restart_sogo }}
  • + {% endif %} {% endif %} From e7a929a947291ce8ae3c47d33a3da7640cc0f396 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Mon, 26 Dec 2022 11:35:18 +0100 Subject: [PATCH 09/11] [Web] add missing tag in edit/mailbox.twig --- data/web/templates/edit/mailbox.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig index ce01a659e..289638d6f 100644 --- a/data/web/templates/edit/mailbox.twig +++ b/data/web/templates/edit/mailbox.twig @@ -274,7 +274,7 @@

    {{ lang.user.pushover_info|format(mailbox)|raw }}

    -

    {{ lang.edit.pushover_vars|raw }}: {SUBJECT}, {SENDER}, {SENDER_ADDRESS}, {SENDER_NAME}, {TO_NAME}, {TO_ADDRESS}, {MSG_ID}

    +

    {{ lang.edit.pushover_vars|raw }}: {SUBJECT}, {SENDER}, {SENDER_ADDRESS}, {SENDER_NAME}, {TO_NAME}, {TO_ADDRESS}, {MSG_ID}

    From 0cf59159cd8e92e3699615e1bbe64071b3a5fa79 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Mon, 26 Dec 2022 12:03:51 +0100 Subject: [PATCH 10/11] [Web] fix SAL display --- data/web/admin.php | 4 ---- data/web/debug.php | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/data/web/admin.php b/data/web/admin.php index e53d18fd7..a3b908b74 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -10,9 +10,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php'; $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; $tfa_data = get_tfa(); $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/presets/rspamd.js'); @@ -89,7 +86,6 @@ $template_data = [ 'tfa_id' => @$_SESSION['tfa_id'], 'fido2_cid' => @$_SESSION['fido2_cid'], 'fido2_data' => $fido2_data, - 'gal' => @$_SESSION['gal'], 'api' => [ 'ro' => admin_api('ro', 'get'), 'rw' => admin_api('rw', 'get'), diff --git a/data/web/debug.php b/data/web/debug.php index 5618ec00b..45c4456ce 100644 --- a/data/web/debug.php +++ b/data/web/debug.php @@ -11,6 +11,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; $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; + +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'); // vmail df @@ -54,6 +59,7 @@ $template_data = [ 'vmail_df' => $vmail_df, 'hostname' => $hostname, 'timezone' => $timezone, + 'gal' => @$_SESSION['gal'], 'license_guid' => license('guid'), 'solr_status' => $solr_status, 'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60), From 48310034e5f2fa072788ea17110caecdc1706533 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 26 Dec 2022 14:33:15 +0100 Subject: [PATCH 11/11] [Compose Updater] Corrected syntax errors --- helper-scripts/update_compose.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/helper-scripts/update_compose.sh b/helper-scripts/update_compose.sh index 01be926fe..ae2d6ab14 100755 --- a/helper-scripts/update_compose.sh +++ b/helper-scripts/update_compose.sh @@ -42,8 +42,6 @@ echo -e "\e[32mTrying to determine GLIBC version...\e[0m" elif [[ $(curl -sL -w "%{http_code}" https://github.com/docker/compose/releases/latest -o /dev/null) == "200" ]]; then LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release LATEST_COMPOSE=${LATEST_COMPOSE##*/} #get the latest version from the redirect, inlcuding the "v" prefix - if [ $DC_DL_SUFFIX]; then - LATEST_COMPOSE=1.27.4 # force 1.27.4 for legacy systems, tag is not prefixed by "v" COMPOSE_VERSION=$(docker-compose version --short) if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then COMPOSE_PATH=$(command -v docker-compose) @@ -71,4 +69,4 @@ elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then else echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m" exit 1 -fi +fi \ No newline at end of file