diff --git a/conf/report.conf.defaults b/conf/report.conf.defaults index 40ab5e07735..c676a323079 100644 --- a/conf/report.conf.defaults +++ b/conf/report.conf.defaults @@ -38,6 +38,7 @@ bindings=start_date,end_date,start_date,end_date,limit has_date_range=enabled has_limit=enabled cursor_type=none +date_fields=start_date,end_date date_limit=24h default_limit=100 charts=scatter|time_bucket:bytes_in:bytes_out:bytes_total @@ -195,6 +196,7 @@ base_conditions_operator=any person_fields=Owner node_fields=MAC Address order_fields=-auth_log.attempted_at +date_fields=Attempted at,Completed at [Authentication::All Failures] type=abstract @@ -210,6 +212,7 @@ node_fields=MAC Address order_fields=-auth_log.attempted_at base_conditions=auth_log.status:=:failed charts=scatter|Attempted at +date_fields=Attempted at,Completed at [Authentication::All Successes] type=abstract @@ -225,6 +228,7 @@ node_fields=MAC Address order_fields=-auth_log.attempted_at base_conditions=auth_log.status:=:completed charts=scatter|Attempted at +date_fields=Attempted at,Completed at [Authentication::Top Failures::Connection Profile to Source] type=sql @@ -616,6 +620,7 @@ date_field=start_time base_conditions_operator=all node_fields=MAC Address charts=scatter@Ip4Log Start Time|Start time,scatter@Ip4Log End Time|End time +date_fields=Start time,End time [Ip4Log::History] type=abstract @@ -632,6 +637,7 @@ base_conditions_operator=all node_fields=MAC Address order_fields=-ip4log_history.start_time charts=scatter@Ip4Log Start Time|Start time,scatter@Ip4Log End Time|End time +date_fields=Start time,End time [Node::Active] type=sql @@ -669,6 +675,7 @@ default_limit=100 node_fields=mac person_fields=pid charts=scatter|regdate +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Node::Inactive] type=sql @@ -706,6 +713,7 @@ cursor_default=00:00:00:00:00:00 default_limit=100 node_fields=mac person_fields=pid +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Node::Registered::Active] type=sql @@ -741,6 +749,7 @@ cursor_default=00:00:00:00:00:00 default_limit=100 node_fields=mac person_fields=pid +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Node::Registered::All] type=sql @@ -775,6 +784,7 @@ cursor_default=00:00:00:00:00:00 default_limit=100 node_fields=mac person_fields=pid +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Node::Unregistered::Active] type=sql @@ -810,6 +820,7 @@ cursor_default=00:00:00:00:00:00 default_limit=100 node_fields=mac person_fields=pid +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Node::Unregistered::All] type=sql @@ -843,6 +854,7 @@ cursor_default=00:00:00:00:00:00 default_limit=100 node_fields=mac person_fields=pid +date_fields=start_time,detect_date,regdate,lastskip,last_arp,last_dhcp [Operating System Class::Active] type=sql @@ -1357,6 +1369,7 @@ person_fields=Owner date_field=start_date base_conditions=security_event.status:=:closed charts=scatter|Release date +date_fields=Release date [Security Events::Open] type=abstract @@ -1374,6 +1387,7 @@ date_field=start_date base_conditions=security_event.status:=:open role_fields=category_id charts=scatter|Event date +date_fields=Event date [Security Events::Open Active] type=sql @@ -1402,6 +1416,7 @@ cursor_type=none node_fields=mac person_fields=owner charts=scatter|start_date +date_fields=start_date [Security Events::Open All] type=sql @@ -1429,6 +1444,7 @@ cursor_type=none node_fields=mac person_fields=owner charts=scatter|start_date +date_fields=start_date [SSID::Active] type=sql @@ -1531,6 +1547,7 @@ base_conditions_operator=all person_fields=Owner node_fields=MAC Address order_fields=-activation.expiration +date_fields=Code expiration,Unreg date [User::Registration::SMS] type=abstract @@ -1547,6 +1564,7 @@ base_conditions_operator=all person_fields=Owner node_fields=MAC Address order_fields=-activation.expiration +date_fields=Code expiration [User::Registration::Sponsor] type=abstract @@ -1561,3 +1579,4 @@ base_conditions=activation.type:=:sponsor base_conditions_operator=all person_fields=Owner node_fields=MAC Address +date_fields=Registration expiration diff --git a/html/pfappserver/root/package-lock.json b/html/pfappserver/root/package-lock.json index 62d84fc6759..194a9c448b0 100644 --- a/html/pfappserver/root/package-lock.json +++ b/html/pfappserver/root/package-lock.json @@ -1,12 +1,12 @@ { "name": "packetfence-admin", - "version": "12.1.0", + "version": "12.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "packetfence-admin", - "version": "12.1.0", + "version": "12.2.0", "dependencies": { "@vue/composition-api": "^1.7.0", "autoprefixer": "10.4.5", @@ -15,7 +15,8 @@ "bootstrap-vue": "2.22.0", "core-js": "3.23.5", "d3-force": "^3.0.0", - "date-fns": "^1.30.1", + "date-fns": "^2.29.3", + "date-fns-tz": "^1.3.7", "messageformat": "^2.3.0", "mime-types": "^2.1.35", "mixpanel-browser": "^2.45.0", @@ -2034,6 +2035,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, "dependencies": { "mkdirp": "^1.0.4", @@ -2905,6 +2907,26 @@ } } }, + "node_modules/@vue/cli-service/node_modules/@vue/vue-loader-v15": { + "name": "vue-loader", + "version": "15.10.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz", + "integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==", + "dev": true, + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + } + }, + "node_modules/@vue/cli-service/node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, "node_modules/@vue/cli-shared-utils": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", @@ -3111,38 +3133,6 @@ } } }, - "node_modules/@vue/vue-loader-v15": { - "name": "vue-loader", - "version": "15.10.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz", - "integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==", - "dev": true, - "dependencies": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - }, - "peerDependencies": { - "css-loader": "*", - "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" - }, - "peerDependenciesMeta": { - "cache-loader": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, - "node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", - "dev": true - }, "node_modules/@vue/web-component-wrapper": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", @@ -5309,9 +5299,24 @@ } }, "node_modules/date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-fns-tz": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.7.tgz", + "integrity": "sha512-1t1b8zyJo+UI8aR+g3iqr5fkUHWpd58VBx8J/ZSQ+w7YrGlw80Ag4sA86qkfCXRBLmMc4I2US+aPMd4uKvwj5g==", + "peerDependencies": { + "date-fns": ">=2.0.0" + } }, "node_modules/de-indent": { "version": "1.0.2", @@ -14843,6 +14848,11 @@ "date-fns": "^1.29.0" } }, + "node_modules/vue-timeago/node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + }, "node_modules/vue2-ace-editor": { "version": "0.0.15", "resolved": "https://registry.npmjs.org/vue2-ace-editor/-/vue2-ace-editor-0.0.15.tgz", @@ -17861,6 +17871,29 @@ "webpack-merge": "^5.7.3", "webpack-virtual-modules": "^0.4.2", "whatwg-fetch": "^3.6.2" + }, + "dependencies": { + "@vue/vue-loader-v15": { + "version": "npm:vue-loader@15.10.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz", + "integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + } + } + } } }, "@vue/cli-shared-utils": { @@ -18022,27 +18055,6 @@ "eslint-import-resolver-webpack": "^0.13.2" } }, - "@vue/vue-loader-v15": { - "version": "npm:vue-loader@15.10.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.0.tgz", - "integrity": "sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg==", - "dev": true, - "requires": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", - "dev": true - } - } - }, "@vue/web-component-wrapper": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", @@ -19668,9 +19680,15 @@ } }, "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, + "date-fns-tz": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.7.tgz", + "integrity": "sha512-1t1b8zyJo+UI8aR+g3iqr5fkUHWpd58VBx8J/ZSQ+w7YrGlw80Ag4sA86qkfCXRBLmMc4I2US+aPMd4uKvwj5g==", + "requires": {} }, "de-indent": { "version": "1.0.2", @@ -26792,6 +26810,13 @@ "integrity": "sha512-lHTRuOXhQzQXa6SC52IlO6UyWBZ5eIyD819QGIep++D61HeCV15h/WZ7M1iEsOWttjztMpg+3wYWHO3i2Ijdzw==", "requires": { "date-fns": "^1.29.0" + }, + "dependencies": { + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + } } }, "vue2-ace-editor": { diff --git a/html/pfappserver/root/package.json b/html/pfappserver/root/package.json index 883db77e465..81286e7d120 100644 --- a/html/pfappserver/root/package.json +++ b/html/pfappserver/root/package.json @@ -17,7 +17,8 @@ "bootstrap-vue": "2.22.0", "core-js": "3.23.5", "d3-force": "^3.0.0", - "date-fns": "^1.30.1", + "date-fns": "^2.29.3", + "date-fns-tz": "^1.3.7", "messageformat": "^2.3.0", "mime-types": "^2.1.35", "mixpanel-browser": "^2.45.0", diff --git a/html/pfappserver/root/src/components/new/BaseFormGroupInputDateTime.vue b/html/pfappserver/root/src/components/new/BaseFormGroupInputDateTime.vue index 0caa7e3ba1c..07c5479e53f 100644 --- a/html/pfappserver/root/src/components/new/BaseFormGroupInputDateTime.vue +++ b/html/pfappserver/root/src/components/new/BaseFormGroupInputDateTime.vue @@ -134,7 +134,7 @@ export const props = { }, dateFormat: { type: String, - default: 'YYYY-MM-DD' + default: 'yyyy-MM-dd' }, timeFormat: { type: String, @@ -223,15 +223,15 @@ export const setup = (props, context) => { const inputValueDate = computed(() => { if (value.value && value.value.charAt(0) !== '0') { - const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`) - return format(parsed, 'YYYY-MM-DD') + const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`, new Date()) + return format(parsed, 'yyyy-MM-dd') } - return format(new Date(), 'YYYY-MM-DD') + return format(new Date(), 'yyyy-MM-dd') }) const inputValueTime = computed(() => { if (value.value) { - const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`) + const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`, new Date()) return format(parsed, 'HH:mm:ss') } return '00:00:00' @@ -239,16 +239,16 @@ export const setup = (props, context) => { const onDate = newDate => { if (newDate && !isFocus.value) { - const parsedDate = parse(newDate, 'YYYY-MM-DD') - const parsedTime = parse(`1970-01-01 ${inputValueTime.value}`, 'YYYY-MM-DD HH:mm:ss') + const parsedDate = parse(newDate, 'yyyy-MM-dd', new Date()) + const parsedTime = parse(`1970-01-01 ${inputValueTime.value}`, 'yyyy-MM-dd HH:mm:ss', new Date()) onInput(`${format(parsedDate, dateFormat.value)} ${format(parsedTime, timeFormat.value)}`) } } const onTime = newTime => { if (newTime && !isFocus.value) { - const parsedDate = parse(inputValueDate.value, 'YYYY-MM-DD') - const parsedTime = parse(`1970-01-01 ${newTime}`, 'YYYY-MM-DD HH:mm:ss') + const parsedDate = parse(inputValueDate.value, 'yyyy-MM-dd', new Date()) + const parsedTime = parse(`1970-01-01 ${newTime}`, 'yyyy-MM-dd HH:mm:ss', new Date()) onInput(`${format(parsedDate, dateFormat.value)} ${format(parsedTime, timeFormat.value)}`) } } diff --git a/html/pfappserver/root/src/components/new/BaseInputGroupDateTime.vue b/html/pfappserver/root/src/components/new/BaseInputGroupDateTime.vue index e1be9e20738..3d52e27e851 100644 --- a/html/pfappserver/root/src/components/new/BaseInputGroupDateTime.vue +++ b/html/pfappserver/root/src/components/new/BaseInputGroupDateTime.vue @@ -103,7 +103,7 @@ export const props = { }, dateFormat: { type: String, - default: 'YYYY-MM-DD' + default: 'yyyy-MM-dd' }, timeFormat: { type: String, @@ -200,24 +200,26 @@ export const setup = (props, context) => { const inputValueDate = computed(() => { if (value.value && value.value.charAt(0) !== '0') { - const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`) - return format(parsed, 'YYYY-MM-DD') + const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`, new Date()) + return format(parsed, 'yyyy-MM-dd') } - return format(new Date(), 'YYYY-MM-DD') + return format(new Date(), 'yyyy-MM-dd') }) const inputValueTime = computed(() => { - if (value.value) { - const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`) - return format(parsed, 'HH:mm:ss') + if (value.value && value.value.charAt(0) !== '0') { + const parsed = parse(value.value, `${dateFormat.value} ${timeFormat.value}`, new Date()) + if (parsed) { + return format(parsed, 'HH:mm:ss') + } } return '00:00:00' }) const onDate = newDate => { if (newDate && !isFocus.value) { - const parsedDate = parse(newDate, 'YYYY-MM-DD') - const parsedTime = parse(`1970-01-01 ${inputValueTime.value}`, 'YYYY-MM-DD HH:mm:ss') + const parsedDate = parse(newDate, 'yyyy-MM-dd', new Date()) + const parsedTime = parse(`1970-01-01 ${inputValueTime.value}`, 'yyyy-MM-dd HH:mm:ss', new Date()) const newValue = `${format(parsedDate, dateFormat.value)} ${format(parsedTime, timeFormat.value)}` if (defer.value) // defer until hidden deferredValue = newValue @@ -228,8 +230,8 @@ export const setup = (props, context) => { const onTime = newTime => { if (newTime && !isFocus.value) { - const parsedDate = parse(inputValueDate.value, 'YYYY-MM-DD') - const parsedTime = parse(`1970-01-01 ${newTime}`, 'YYYY-MM-DD HH:mm:ss') + const parsedDate = parse(inputValueDate.value, 'yyyy-MM-dd', new Date()) + const parsedTime = parse(`1970-01-01 ${newTime}`, 'yyyy-MM-dd HH:mm:ss', new Date()) const newValue = `${format(parsedDate, dateFormat.value)} ${format(parsedTime, timeFormat.value)}` if (defer.value) // defer until hidden deferredValue = newValue diff --git a/html/pfappserver/root/src/globals/mysql.js b/html/pfappserver/root/src/globals/mysql.js index cb66545a34e..fc0a35ae072 100644 --- a/html/pfappserver/root/src/globals/mysql.js +++ b/html/pfappserver/root/src/globals/mysql.js @@ -70,23 +70,23 @@ export const MysqlDatabase = { /* Do not validate backend variable, fixes #5509 detect_date: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, */ regdate: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, unregdate: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, lastskip: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, time_balance: Object.assign( @@ -125,12 +125,12 @@ export const MysqlDatabase = { }, last_arp: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, last_dhcp: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, dhcp_fingerprint: { @@ -212,7 +212,7 @@ export const MysqlDatabase = { ), last_seen: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' } }, @@ -227,12 +227,12 @@ export const MysqlDatabase = { }, valid_from: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, expiration: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '' }, access_duration: { @@ -260,7 +260,7 @@ export const MysqlDatabase = { ), unregdate: { type: MysqlDatetime, - format: 'YYYY-MM-DD HH:mm:ss', + format: 'yyyy-MM-dd HH:mm:ss', default: '0000-00-00 00:00:00' }, login_remaining: Object.assign( @@ -319,13 +319,13 @@ export const MysqlDatabase = { anniversary: { type: MysqlString, maxLength: 255, - format: 'YYYY-MM-DD', + format: 'yyyy-MM-dd', default: null }, birthday: { type: MysqlString, maxLength: 255, - format: 'YYYY-MM-DD', + format: 'yyyy-MM-dd', default: null }, gender: { diff --git a/html/pfappserver/root/src/globals/pfActions.js b/html/pfappserver/root/src/globals/pfActions.js index 3a2d326564b..594b43d0d05 100644 --- a/html/pfappserver/root/src/globals/pfActions.js +++ b/html/pfappserver/root/src/globals/pfActions.js @@ -13,15 +13,15 @@ const setUnregDateTextFn = value => { value = `1970-${m}-${d}` } } - const date = parse(value, 'yyyy-MM-dd') + const date = parse(value, 'yyyy-MM-dd', new Date()) if (date instanceof Date && isValid(date)) { const now = new Date() if (compareAsc(date, now) < 0) { const year = getYear(now) const normalized = setYear(date, year) - let unreg_date = format(normalized, 'YYYY-MM-DD') + let unreg_date = format(normalized, 'yyyy-MM-dd') if (compareAsc(normalized, now) < 0) { - unreg_date = format(setYear(normalized, year + 1), 'YYYY-MM-DD') + unreg_date = format(setYear(normalized, year + 1), 'yyyy-MM-dd') } return i18n.t(`Past dates dynamically increase up to 1 year in the future (eg ${unreg_date}).`, { unreg_date }) } diff --git a/html/pfappserver/root/src/globals/pfFormatters.js b/html/pfappserver/root/src/globals/pfFormatters.js index c58f165c50e..04e92403ee0 100644 --- a/html/pfappserver/root/src/globals/pfFormatters.js +++ b/html/pfappserver/root/src/globals/pfFormatters.js @@ -6,8 +6,8 @@ import store from '@/store' import { format } from 'date-fns' const locales = { - en: require('date-fns/locale/en'), - fr: require('date-fns/locale/fr') + en: require('date-fns/locale/en-US'), + fr: require('date-fns/locale/fr-CA') } export const pfFormatters = { diff --git a/html/pfappserver/root/src/utils/date.js b/html/pfappserver/root/src/utils/date.js new file mode 100644 index 00000000000..c05470aadcd --- /dev/null +++ b/html/pfappserver/root/src/utils/date.js @@ -0,0 +1,26 @@ +import i18n from '@/utils/locale' +import { formatInTimeZone, zonedTimeToUtc } from 'date-fns-tz' + +export const isoDateFormat = 'yyyy-MM-dd' + +export const isoDateMax = '9999-12-12' + +export const isoTimeFormat = 'HH:mm:ss' + +export const isoTimeMax = '23:59:59' + +export const isoDateTimeFormat = `${isoDateFormat} ${isoTimeFormat}` + +export const isoDateTimeMax = `${isoDateMax} ${isoTimeMax}` + +export const isoDateTimeZeroFormat = isoDateTimeFormat.replace(/[0-9]/g,'0') + +export const isoDateTimeFormatTz = `${isoDateFormat} ${isoTimeFormat} zzz` + +export const toUtc = (date, fromZone) => zonedTimeToUtc(date, fromZone) + +export const offsetFormat = (date, fromZone, toZone, _format = isoDateTimeFormat) => formatInTimeZone(toUtc(date, fromZone), toZone, _format) + +export const offsetFormatTz = (date, fromZone, toZone, _format = isoDateTimeFormatTz) => formatInTimeZone(toUtc(date, fromZone), toZone, _format) + +export const offsetLocale = (date, fromZone, toZone, locale = i18n.locale) => new Date(offsetFormat(date, fromZone, toZone)).toLocaleString(locale) \ No newline at end of file diff --git a/html/pfappserver/root/src/utils/filters.js b/html/pfappserver/root/src/utils/filters.js index 6662f4216ee..c09761842b5 100644 --- a/html/pfappserver/root/src/utils/filters.js +++ b/html/pfappserver/root/src/utils/filters.js @@ -1,5 +1,5 @@ import i18n from '@/utils/locale' -import { parse, format, distanceInWordsToNow } from 'date-fns' +import { parse, format, formatDistanceToNow } from 'date-fns' const filters = { longDateTime (value) { @@ -8,10 +8,10 @@ const filters = { } else { let localeObject, localeFormat if (i18n.locale === 'fr') { - localeObject = require('date-fns/locale/fr') + localeObject = require('date-fns/locale/fr-CA') localeFormat = 'dddd, D MMMM, YYYY, HH:mm:ss' } else { - localeObject = require('date-fns/locale/en') + localeObject = require('date-fns/locale/en-US') localeFormat = 'dddd, MMMM D, YYYY, hh:mm:ss a' } return format(parse(value), localeFormat, { locale: localeObject }) @@ -23,10 +23,10 @@ const filters = { } else { let localeObject, localeFormat if (i18n.locale === 'fr') { - localeObject = require('date-fns/locale/fr') + localeObject = require('date-fns/locale/fr-CA') localeFormat = 'DD/MM/YY HH:mm' } else { - localeObject = require('date-fns/locale/en') + localeObject = require('date-fns/locale/en-US') localeFormat = 'MM/DD/YY hh:mm a' } return format(parse(value), localeFormat, { locale: localeObject }) @@ -40,11 +40,11 @@ const filters = { } else { let localeObject if (i18n.locale === 'fr') { - localeObject = require('date-fns/locale/fr') + localeObject = require('date-fns/locale/fr-CA') } else { - localeObject = require('date-fns/locale/en') + localeObject = require('date-fns/locale/en-US') } - return distanceInWordsToNow(parse(value), { locale: localeObject }) + return formatDistanceToNow(parse(value), { locale: localeObject }) } } } diff --git a/html/pfappserver/root/src/utils/yup.js b/html/pfappserver/root/src/utils/yup.js index ce5b451554a..a0fc5515851 100644 --- a/html/pfappserver/root/src/utils/yup.js +++ b/html/pfappserver/root/src/utils/yup.js @@ -192,7 +192,7 @@ yup.addMethod(yup.string, 'isCommonNameOrFQDNOrMAC', function (message) { }) }) -yup.addMethod(yup.string, 'isDateCompare', function (comparison, date = new Date(), dateFormat = 'YYYY-MM-DD HH:mm:ss', message) { +yup.addMethod(yup.string, 'isDateCompare', function (comparison, date = new Date(), dateFormat = 'yyyy-MM-dd HH:mm:ss', message) { return this.test({ name: 'isDateCompare', message: i18n.t('Invalid date.'), @@ -205,9 +205,9 @@ yup.addMethod(yup.string, 'isDateCompare', function (comparison, date = new Date if ([0, '0'].includes(date)) date = new Date(8640000000000000) // round date/value using date-fns format - const _date = format((date instanceof Date && isValid(date) ? date : parse(date)), dateFormat) - const _value = format((value instanceof Date && isValid(value) ? value : parse(value)), dateFormat) - const cmp = compareAsc(parse(_value), parse(_date)) + const _date = format((date instanceof Date && isValid(date) ? date : parse(date, 'yyyy-MM-dd HH:mm:ss', new Date())), dateFormat) + const _value = format((value instanceof Date && isValid(value) ? value : parse(value, 'yyyy-MM-dd HH:mm:ss', new Date())), dateFormat) + const cmp = compareAsc(parse(_value), parse(_date, 'yyyy-MM-dd HH:mm:ss', new Date())) switch (true) { case ['>', 'gt'].includes(comparison) && !(cmp > 0): case ['>=', 'gte'].includes(comparison) && !(cmp >= 0): @@ -224,7 +224,7 @@ yup.addMethod(yup.string, 'isDateCompare', function (comparison, date = new Date }) }) -yup.addMethod(yup.string, 'isDateFormat', function (message, dateFormat = 'YYYY-MM-DD HH:mm:ss') { +yup.addMethod(yup.string, 'isDateFormat', function (message, dateFormat = 'yyyy-MM-dd HH:mm:ss') { return this.test({ name: 'isDateFormat', message: message || i18n.t('Invalid date, use format "{dateFormat}".', { dateFormat }), @@ -237,7 +237,7 @@ yup.addMethod(yup.string, 'isDateFormat', function (message, dateFormat = 'YYYY- }) }) -yup.addMethod(yup.string, 'isDateFormatOrZero', function (message, dateFormat = 'YYYY-MM-DD HH:mm:ss') { +yup.addMethod(yup.string, 'isDateFormatOrZero', function (message, dateFormat = 'yyyy-MM-dd HH:mm:ss') { return this.test({ name: 'isDateFormatOrZero', message: message || i18n.t('Invalid date, use format "{dateFormat}".', { dateFormat }), @@ -447,7 +447,7 @@ yup.addMethod(yup.string, 'mysql', function(columnSchema) { if (['', null, undefined].includes(value)) return true const { type, maxLength, min, max, - format = 'YYYY-MM-DD HH:mm:ss', + format = 'yyyy-MM-dd HH:mm:ss', ['enum']: _enum = [] // reserved word } = columnSchema diff --git a/html/pfappserver/root/src/views/Configuration/accessDurations/_components/BaseAccessDuration.vue b/html/pfappserver/root/src/views/Configuration/accessDurations/_components/BaseAccessDuration.vue index d76b39fa433..8a85e229731 100644 --- a/html/pfappserver/root/src/views/Configuration/accessDurations/_components/BaseAccessDuration.vue +++ b/html/pfappserver/root/src/views/Configuration/accessDurations/_components/BaseAccessDuration.vue @@ -158,7 +158,7 @@ const setup = (props, context) => { case 'M': date = addMonths(date, extendedInterval); break case 'Y': date = addYears(date, extendedInterval); break } - return format(date, 'YYYY-MM-DD HH:mm:ss') + return format(date, 'yyyy-MM-dd HH:mm:ss') }) const intervalComponentRef = ref(null) diff --git a/html/pfappserver/root/src/views/Configuration/bases/_store.js b/html/pfappserver/root/src/views/Configuration/bases/_store.js index 42f383f893d..9575d24a5ac 100644 --- a/html/pfappserver/root/src/views/Configuration/bases/_store.js +++ b/html/pfappserver/root/src/views/Configuration/bases/_store.js @@ -3,7 +3,9 @@ */ import Vue from 'vue' import api from './_api' +import i18n from '@/utils/locale' import store, { types } from '@/store' +import { offsetFormat, offsetFormatTz, offsetLocale, isoDateTimeFormat, isoDateTimeFormatTz } from '@/utils/date' // Default values const state = () => { @@ -17,7 +19,19 @@ const state = () => { const getters = { isWaiting: state => [types.LOADING, types.DELETING].includes(state.itemStatus), isLoading: state => state.itemStatus === types.LOADING, - general: state => state.cache.general + general: state => state.cache.general, + + // client Date() + clientTimezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone, + clientDateToTimezoneFormat: (state, getters) => (date, toZone, format = isoDateTimeFormat) => offsetFormat(date, getters.clientTimezone, toZone, format), + clientDateToTimezoneFormatTz: (state, getters) => (date, toZone, format = isoDateTimeFormatTz) => offsetFormatTz(date, getters.clientTimezone, toZone, format), + clientDateToTimezoneLocale: (state, getters) => (date, toZone, locale = i18n.locale) => offsetLocale(date, getters.clientTimezone, toZone, locale), + + // server Date() + serverTimezone: state => state.cache.general.timezone, + serverDateToTimezoneFormat: (state, getters) => (date, toZone, format = isoDateTimeFormat) => offsetFormat(date, getters.serverTimezone, toZone, format), + serverDateToTimezoneFormatTz: (state, getters) => (date, toZone, format = isoDateTimeFormatTz) => offsetFormatTz(date, getters.serverTimezone, toZone, format), + serverDateToTimezoneLocale: (state, getters) => (date, toZone, locale = i18n.locale) => offsetLocale(date, getters.serverTimezone, toZone, locale), } const actions = { diff --git a/html/pfappserver/root/src/views/Reports/_components/BaseChartScatter.vue b/html/pfappserver/root/src/views/Reports/_components/BaseChartScatter.vue index 7f36c2e672e..2bdbf4f9437 100644 --- a/html/pfappserver/root/src/views/Reports/_components/BaseChartScatter.vue +++ b/html/pfappserver/root/src/views/Reports/_components/BaseChartScatter.vue @@ -109,8 +109,8 @@ const setup = props => { const sFields = fields.value.split(':') return filteredItems.value.reduce((min, item) => { const { [sFields[0]]: value } = item - const parsed = parse(value, 'YYYY-MM-DD HH:mm:ss') - const date = format(parsed, 'YYYY-MM-DD HH:mm:ss') + const parsed = parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()) + const date = format(parsed, 'yyyy-MM-dd HH:mm:ss') return (!min || date < min) ? date : min }, '') }) @@ -119,8 +119,8 @@ const setup = props => { const sFields = fields.value.split(':') return filteredItems.value.reduce((max, item) => { const { [sFields[0]]: value } = item - const parsed = parse(value, 'YYYY-MM-DD HH:mm:ss') - const date = format(parsed, 'YYYY-MM-DD HH:mm:ss') + const parsed = parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()) + const date = format(parsed, 'yyyy-MM-dd HH:mm:ss') return (!max || date > max) ? date : max }, '') }) @@ -137,12 +137,12 @@ const setup = props => { const _standardDim = () => { const sFields = fields.value.split(':') return [ - { name: 'by year', normalize: 'YYYY-01-01 00:00:00' }, - { name: 'by month', normalize: 'YYYY-MM-01 00:00:00' }, - { name: 'by day', normalize: 'YYYY-MM-DD 00:00:00' }, - { name: 'by hour', normalize: 'YYYY-MM-DD HH:00:00' }, - { name: 'by minute', normalize: 'YYYY-MM-DD HH:mm:00' }, - { name: 'by second', normalize: 'YYYY-MM-DD HH:mm:ss' } + { name: 'by year', normalize: 'yyyy-01-01 00:00:00' }, + { name: 'by month', normalize: 'yyyy-MM-01 00:00:00' }, + { name: 'by day', normalize: 'yyyy-MM-dd 00:00:00' }, + { name: 'by hour', normalize: 'yyyy-MM-dd HH:00:00' }, + { name: 'by minute', normalize: 'yyyy-MM-dd HH:mm:00' }, + { name: 'by second', normalize: 'yyyy-MM-dd HH:mm:ss' } ].map((dimension, index) => { const { name, normalize } = dimension const color = colorsFull[index] @@ -158,7 +158,7 @@ const setup = props => { count = 1 } if (value && value[0] !== '0') { // ignore zero dates - const parsed = parse(value, 'YYYY-MM-DD HH:mm:ss') + const parsed = parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()) let date = format(parsed, normalize) if (date < minDate.value) { // limit re-scaled date to within min/max, otherwise date pollutes the charts minimum y-scale diff --git a/html/pfappserver/root/src/views/Reports/_components/BaseInputDateRange.vue b/html/pfappserver/root/src/views/Reports/_components/BaseInputDateRange.vue index 449cb0db810..83d37c6e3c2 100644 --- a/html/pfappserver/root/src/views/Reports/_components/BaseInputDateRange.vue +++ b/html/pfappserver/root/src/views/Reports/_components/BaseInputDateRange.vue @@ -60,21 +60,27 @@ const props = { value: { type: Object, default: () => ({ start_date: undefined, end_date: undefined, date_limit: undefined }) + }, + timezone: { + type: String, + default: 'UTC' } } import { computed, customRef, nextTick, ref, toRefs, watch } from '@vue/composition-api' import { format, parse, addSeconds, subSeconds, differenceInSeconds } from 'date-fns' import i18n from '@/utils/locale' +import { isoDateTimeFormat, isoDateTimeZeroFormat, isoDateTimeMax } from '@/utils/date' import { duration2seconds } from '@/views/Configuration/accessDurations/config' const setup = (props, context) => { const { - value + value, + timezone } = toRefs(props) - const { emit } = context + const { emit, root: { $store } = {} } = context const startDate = customRef((track, trigger) => ({ get() { @@ -83,7 +89,7 @@ const setup = (props, context) => { }, set(start_date) { // only emit valid format - if (start_date.replace(/[0-9]/g, '0') === '0000-00-00 00:00:00') + if (start_date.replace(/[0-9]/g, '0') === isoDateTimeZeroFormat) emit('input', { ...value.value, start_date }) else if (['', null].includes(start_date)) emit('input', { ...value.value, start_date: minStartDate.value }) @@ -93,17 +99,17 @@ const setup = (props, context) => { const minStartDate = computed(() => { const { date_limit } = value.value if (date_limit) { - const date = parse(endDate.value, 'YYYY-MM-DD HH:mm:ss') + const date = parse(endDate.value, isoDateTimeFormat, new Date()) const seconds = duration2seconds(date_limit) const min = subSeconds(date, seconds) - return format(min, 'YYYY-MM-DD HH:mm:ss') + return format(min, isoDateTimeFormat) } - return '0000-00-00 00:00:00' + return isoDateTimeZeroFormat }) const maxStartDate = computed(() => { - if (!endDate.value || endDate.value.replace(/[0-9]/g, '0') === '0000-00-00 00:00:00') + if (!endDate.value || endDate.value.replace(/[0-9]/g, '0') === isoDateTimeZeroFormat) return endDate.value - return '9999-12-12 23:59:59' + return isoDateTimeMax }) const endDate = customRef((track, trigger) => ({ @@ -113,7 +119,7 @@ const setup = (props, context) => { }, set(end_date) { // only emit valid format - if (end_date.replace(/[0-9]/g, '0') === '0000-00-00 00:00:00') + if (end_date.replace(/[0-9]/g, '0') === isoDateTimeZeroFormat) emit('input', { ...value.value, end_date }) else if (['', null].includes(end_date)) emit('input', { ...value.value, end_date: maxEndDate.value }) @@ -121,19 +127,19 @@ const setup = (props, context) => { } })) const minEndDate = computed(() => { - if (!startDate.value || startDate.value.replace(/[0-9]/g, '0') === '0000-00-00 00:00:00') + if (!startDate.value || startDate.value.replace(/[0-9]/g, '0') === isoDateTimeZeroFormat) return startDate.value - return '0000-00-00 00:00:00' + return isoDateTimeZeroFormat }) const maxEndDate = computed(() => { const { date_limit } = value.value if (date_limit) { - const date = parse(startDate.value, 'YYYY-MM-DD HH:mm:ss') + const date = parse(startDate.value, isoDateTimeFormat, new Date()) const seconds = duration2seconds(date_limit) const max = addSeconds(date, seconds) - return format(max, 'YYYY-MM-DD HH:mm:ss') + return format(max, isoDateTimeFormat) } - return '9999-12-12 23:59:59' + return isoDateTimeMax }) const showPeriod = ref(false) @@ -152,20 +158,24 @@ const setup = (props, context) => { { title: i18n.t('6 months'), text: '6M', value: 60 * 60 * 24 * 31 * 6 } , { title: i18n.t('1 year'), text: '1Y', value: 60 * 60 * 24 * 365 } ].filter(({ value }) => { - return !date_limit || value < duration2seconds(date_limit) + return !date_limit || value <= duration2seconds(date_limit) }) }) const setRangeByPeriod = period => { + const start_date = $store.getters['$_bases/clientDateToTimezoneFormat'](subSeconds(new Date(), period), timezone.value) + const end_date = $store.getters['$_bases/clientDateToTimezoneFormat'](new Date(), timezone.value) showPeriod.value = false emit('input', { - start_date: format(subSeconds(new Date(), period), 'YYYY-MM-DD HH:mm:ss'), - end_date: format(new Date(), 'YYYY-MM-DD HH:mm:ss') + ...value.value, + start_date, + end_date }) } const clearRange = () => { emit('input', { + ...value.value, start_date: undefined, end_date: undefined }) @@ -173,7 +183,7 @@ const setup = (props, context) => { const hasDates = computed(() => { const { start_date, end_date } = value.value - return start_date && start_date !== '0000-00-00 00:00:00' && end_date + return start_date && start_date !== isoDateTimeZeroFormat && end_date }) const hasDateLimit = computed(() => { @@ -182,22 +192,22 @@ const setup = (props, context) => { }) const previousRange = () => { - const start = parse(startDate.value, 'YYYY-MM-DD HH:mm:ss') - const end = parse(endDate.value, 'YYYY-MM-DD HH:mm:ss') + const start = parse(startDate.value, isoDateTimeFormat, new Date()) + const end = parse(endDate.value, isoDateTimeFormat, new Date()) const diff = differenceInSeconds(end, start) endDate.value = startDate.value nextTick(() => { - startDate.value = format(subSeconds(start, diff), 'YYYY-MM-DD HH:mm:ss') + startDate.value = format(subSeconds(start, diff), isoDateTimeFormat) }) } const nextRange = () => { - const start = parse(startDate.value, 'YYYY-MM-DD HH:mm:ss') - const end = parse(endDate.value, 'YYYY-MM-DD HH:mm:ss') + const start = parse(startDate.value, isoDateTimeFormat, new Date()) + const end = parse(endDate.value, isoDateTimeFormat, new Date()) const diff = differenceInSeconds(end, start) startDate.value = endDate.value nextTick(() => { - endDate.value = format(addSeconds(end, diff), 'YYYY-MM-DD HH:mm:ss') + endDate.value = format(addSeconds(end, diff), isoDateTimeFormat) }) } @@ -208,7 +218,7 @@ const setup = (props, context) => { isLocked.value = !isLocked.value } const bumpEndDate = () => { - endDate.value = format(addSeconds(new Date(), timerLocked), 'YYYY-MM-DD HH:mm:ss') + endDate.value = format(addSeconds(new Date(), timerLocked), isoDateTimeFormat) } watch(isLocked, () => { if (intervalLocked) { @@ -220,7 +230,7 @@ const setup = (props, context) => { } }) watch(() => value.value.end_date, () => { - const end = parse(endDate.value, 'YYYY-MM-DD HH:mm:ss') + const end = parse(endDate.value, isoDateTimeFormat, new Date()) const diff = Math.abs(differenceInSeconds(new Date(), end)) if (diff <= timerLocked) { isLocked.value = true diff --git a/html/pfappserver/root/src/views/Reports/_components/TheTable.vue b/html/pfappserver/root/src/views/Reports/_components/TheTable.vue index 6a0638557f9..97c8b4f2147 100644 --- a/html/pfappserver/root/src/views/Reports/_components/TheTable.vue +++ b/html/pfappserver/root/src/views/Reports/_components/TheTable.vue @@ -57,6 +57,11 @@ @input="setColumns" /> + +