diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/DeviceManagementAdminService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/DeviceManagementAdminService.java index 641c399d0..30dcb4704 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/DeviceManagementAdminService.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/java/org/wso2/carbon/mdm/services/android/services/DeviceManagementAdminService.java @@ -1123,7 +1123,7 @@ public interface DeviceManagementAdminService { message = "Internal Server Error. \n " + "Server error occurred while adding a new send notification operation.") }) - @Permission(name = "Send Notifications", permission = "/device-mgt/devices/owning-device/operations/android/notification") + @Permission(name = "Send Notifications", permission = "/device-mgt/devices/owning-device/operations/android/send-notification") Response sendNotification( @ApiParam(name = "notificationBeanWrapper", value = "Notification Configurations and device Ids") @@ -1284,7 +1284,7 @@ public interface DeviceManagementAdminService { message = "Internal Server Error. \n " + "Server error occurred while adding a new change lock code operation.") }) - @Permission(name = "Change Password of Device", permission = "/device-mgt/devices/owning-device/operations/android/change-lock") + @Permission(name = "Change Password of Device", permission = "/device-mgt/devices/owning-device/operations/android/change-lock-code") Response changeLockCode( @ApiParam(name = "lockCodeBeanWrapper", value = "Configurations and device Ids need to be done change lock code") diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.hbs new file mode 100644 index 000000000..d1787fd27 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.hbs @@ -0,0 +1,25 @@ +{{! + Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + + WSO2 Inc. licenses this file to you under the Apache License, + Version 2.0 (the "License"); you may not use this file except + in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +}} +{{#zone "topCss"}} + {{css "css/daterangepicker.css"}} +{{/zone}} + +{{#zone "bottomJs"}} + {{js "js/moment.min.js"}} + {{js "js/daterangepicker.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.js new file mode 100644 index 000000000..82648b301 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +function onRequest() { + return ""; +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.json new file mode 100644 index 000000000..688e93980 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/date-range-picker.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/css/daterangepicker.css b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/css/daterangepicker.css new file mode 100644 index 000000000..b1b44916b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/css/daterangepicker.css @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +.date-picker { + width: 170px; + height: 25px; + padding: 0; + border: 0; + line-height: 25px; + padding-left: 10px; + font-size: 12px; + font-family: Arial; + font-weight: bold; + cursor: pointer; + color: #303030; + position: relative; + z-index: 2; +} + +.date-picker-wrapper { + position: absolute; + z-index: 1; + border: 1px solid #bfbfbf; + background-color: #efefef; + width: 448px; + padding: 5px 12px; + font-size: 12px; + line-height: 20px; + color: #aaa; + font-family: Arial; + box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5); +} + +.date-picker-wrapper.single-date { + width: auto; +} + +.date-picker-wrapper.no-shortcuts { + padding-bottom: 12px; +} + +.date-picker-wrapper .footer { + display: none; + font-size: 11px; + padding-top: 3px; +} + +.date-picker-wrapper b { + color: #666; + font-weight: 700; +} + +.date-picker-wrapper a { + color: rgb(107, 180, 214); + text-decoration: underline; +} + +.date-picker-wrapper .month-wrapper { + border: 1px solid #bfbfbf; + border-radius: 3px; + background-color: #fff; + padding: 5px; + cursor: default; + position: relative; + _overflow: hidden; +} + +.date-picker-wrapper .month-wrapper table { + width: 190px; + float: left; +} + +.date-picker-wrapper .month-wrapper table.month2 { + width: 190px; + float: right; +} + +.date-picker-wrapper .month-wrapper table th, +.date-picker-wrapper .month-wrapper table td { + vertical-align: middle; + text-align: center; + line-height: 14px; + margin: 0px; + padding: 0px; +} + +.date-picker-wrapper .month-wrapper table .day { + height: 19px; + line-height: 19px; + font-size: 12px; + margin-bottom: 1px; + color: #999; + cursor: default; +} + +.date-picker-wrapper .month-wrapper table div.day.lastMonth, +.date-picker-wrapper .month-wrapper table div.day.nextMonth { + color: #999; + cursor: default; +} + +.date-picker-wrapper .month-wrapper table .day.checked { + background-color: rgb(156, 219, 247); +} + +.date-picker-wrapper .month-wrapper table .week-name { + height: 20px; + line-height: 20px; + font-weight: 100; +} + +.date-picker-wrapper .month-wrapper table .day.has-tooltip { + cursor: help !important; +} + +.date-picker-wrapper .month-wrapper table .day.toMonth.valid { + color: #333; + cursor: pointer; +} + +.date-picker-wrapper .month-wrapper table .day.real-today { + background-color: rgb(255, 230, 132); +} + +.date-picker-wrapper .month-wrapper table .day.real-today.checked { + background-color: rgb(112, 204, 213); +} + +.date-picker-wrapper table .caption { + height: 40px; +} + +.date-picker-wrapper table .caption .next, +.date-picker-wrapper table .caption .prev { + padding: 0 5px; + cursor: pointer; +} + +.date-picker-wrapper table .caption .next:hover, +.date-picker-wrapper table .caption .prev:hover { + background-color: #ccc; + color: white; +} + +.date-picker-wrapper .gap { + position: absolute; + display: none; + top: 0px; + left: 204px; + z-index: 1; + width: 15px; + height: 100%; + background-color: red; + font-size: 0; + line-height: 0; +} + +.date-picker-wrapper .gap .gap-lines { + height: 100%; + overflow: hidden; +} + +.date-picker-wrapper .gap .gap-line { + height: 15px; + width: 15px; + position: relative; +} + +.date-picker-wrapper .gap .gap-line .gap-1 { + z-index: 1; + height: 0; + border-left: 8px solid white; + border-top: 8px solid #eee; + border-bottom: 8px solid #eee; +} + +.date-picker-wrapper .gap .gap-line .gap-2 { + position: absolute; + right: 0; + top: 0px; + z-index: 2; + height: 0; + border-left: 8px solid transparent; + border-top: 8px solid white; +} + +.date-picker-wrapper .gap .gap-line .gap-3 { + position: absolute; + right: 0; + top: 8px; + z-index: 2; + height: 0; + border-left: 8px solid transparent; + border-bottom: 8px solid white; +} + +.date-picker-wrapper .gap .gap-top-mask { + width: 6px; + height: 1px; + position: absolute; + top: -1px; + left: 1px; + background-color: #eee; + z-index: 3; +} + +.date-picker-wrapper .gap .gap-bottom-mask { + width: 6px; + height: 1px; + position: absolute; + bottom: -1px; + left: 7px; + background-color: #eee; + z-index: 3; +} + +.date-picker-wrapper .selected-days { + display: none; +} + +.date-picker-wrapper .drp_top-bar { + line-height: 40px; + height: 40px; + position: relative; +} + +.date-picker-wrapper .drp_top-bar .error-top { + display: none; +} + +.date-picker-wrapper .drp_top-bar .normal-top { + display: none; +} + +.date-picker-wrapper .drp_top-bar .default-top { + display: block; +} + +.date-picker-wrapper .drp_top-bar.error .default-top { + display: none; +} + +.date-picker-wrapper .drp_top-bar.error .error-top { + display: block; + color: red; +} + +.date-picker-wrapper .drp_top-bar.normal .default-top { + display: none; +} + +.date-picker-wrapper .drp_top-bar.normal .normal-top { + display: block; +} + +.date-picker-wrapper .drp_top-bar .apply-btn { + position: absolute; + right: 0px; + top: 6px; + padding: 3px 5px; + margin: 0; + font-size: 12px; + border-radius: 4px; + cursor: pointer; + + color: #d9eef7; + border: solid 1px #0076a3; + background: #0095cd; + background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)); + background: -moz-linear-gradient(top, #00adee, #0078a5); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5'); + color: white; +} + +.date-picker-wrapper .drp_top-bar .apply-btn.disabled { + pointer-events: none; + color: #606060; + border: solid 1px #b7b7b7; + background: #fff; + background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed)); + background: -moz-linear-gradient(top, #fff, #ededed); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed'); +} + +/*time styling*/ +.time { + position: relative; +} + +.time input[type=range] { + vertical-align: middle; +} + +.time1, .time2 { + width: 180px; + padding: 0 5px; + text-align: center; +} + +.time1 { + float: left; +} + +.time2 { + float: right; +} + +.hour, .minute { + text-align: left; +} + +.hide { + display: none; +} + +input.hour-range, input.minute-range { + width: 150px; +} + +#dateRangePickerContainer .date-range, #dateRangePickerContainer .input-append { + background: none !important; +} + +#date-range { + padding-right: 30px; + width: 300px; + height: 100%; + display: inline-block; +} + +#dateRangePickerContainer { + float: right; +} + +.date-range { + border: 1px solid #ccc; +} + +#dateRangePickerContainer button.active { + background-color: #e6e6e6 !important; +} + +#dateRangePickerContainer .btn-default:hover { + background-color: #b2b2b2; + border-color: #000000; +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/daterangepicker.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/daterangepicker.js new file mode 100644 index 000000000..b218d58bf --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/daterangepicker.js @@ -0,0 +1,1542 @@ +/** +* @version: 2.1.19 +* @author: Dan Grossman http://www.dangrossman.info/ +* @copyright: Copyright (c) 2012-2015 Dan Grossman. All rights reserved. +* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php +* @website: https://www.improvely.com/ +*/ + +(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(['moment', 'jquery', 'exports'], function(momentjs, $, exports) { + root.daterangepicker = factory(root, exports, momentjs, $); + }); + + } else if (typeof exports !== 'undefined') { + var momentjs = require('moment'); + var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined; //isomorphic issue + if (!jQuery) { + try { + jQuery = require('jquery'); + if (!jQuery.fn) jQuery.fn = {}; //isomorphic issue + } catch (err) { + if (!jQuery) throw new Error('jQuery dependency not found'); + } + } + + factory(root, exports, momentjs, jQuery); + + // Finally, as a browser global. + } else { + root.daterangepicker = factory(root, {}, root.moment || moment, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +}(this || {}, function(root, daterangepicker, moment, $) { // 'this' doesn't exist on a server + + var DateRangePicker = function(element, options, cb) { + + //default settings for options + this.parentEl = 'body'; + this.element = $(element); + this.startDate = moment().startOf('day'); + this.endDate = moment().endOf('day'); + this.minDate = false; + this.maxDate = false; + this.dateLimit = false; + this.autoApply = false; + this.singleDatePicker = false; + this.showDropdowns = false; + this.showWeekNumbers = false; + this.showISOWeekNumbers = false; + this.timePicker = false; + this.timePicker24Hour = false; + this.timePickerIncrement = 1; + this.timePickerSeconds = false; + this.linkedCalendars = true; + this.autoUpdateInput = true; + this.alwaysShowCalendars = false; + this.ranges = {}; + + this.opens = 'right'; + if (this.element.hasClass('pull-right')) + this.opens = 'left'; + + this.drops = 'down'; + if (this.element.hasClass('dropup')) + this.drops = 'up'; + + this.buttonClasses = 'btn btn-sm'; + this.applyClass = 'btn-success'; + this.cancelClass = 'btn-default'; + + this.locale = { + format: 'MM/DD/YYYY', + separator: ' - ', + applyLabel: 'Apply', + cancelLabel: 'Cancel', + weekLabel: 'W', + customRangeLabel: 'Custom Range', + daysOfWeek: moment.weekdaysMin(), + monthNames: moment.monthsShort(), + firstDay: moment.localeData().firstDayOfWeek() + }; + + this.callback = function() { }; + + //some state information + this.isShowing = false; + this.leftCalendar = {}; + this.rightCalendar = {}; + + //custom options from user + if (typeof options !== 'object' || options === null) + options = {}; + + //allow setting options with data attributes + //data-api options will be overwritten with custom javascript options + options = $.extend(this.element.data(), options); + + //html template for the picker UI + if (typeof options.template !== 'string' && !(options.template instanceof $)) + options.template = ''; + + this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); + this.container = $(options.template).appendTo(this.parentEl); + + // + // handle all the possible options overriding defaults + // + + if (typeof options.locale === 'object') { + + if (typeof options.locale.format === 'string') + this.locale.format = options.locale.format; + + if (typeof options.locale.separator === 'string') + this.locale.separator = options.locale.separator; + + if (typeof options.locale.daysOfWeek === 'object') + this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); + + if (typeof options.locale.monthNames === 'object') + this.locale.monthNames = options.locale.monthNames.slice(); + + if (typeof options.locale.firstDay === 'number') + this.locale.firstDay = options.locale.firstDay; + + if (typeof options.locale.applyLabel === 'string') + this.locale.applyLabel = options.locale.applyLabel; + + if (typeof options.locale.cancelLabel === 'string') + this.locale.cancelLabel = options.locale.cancelLabel; + + if (typeof options.locale.weekLabel === 'string') + this.locale.weekLabel = options.locale.weekLabel; + + if (typeof options.locale.customRangeLabel === 'string') + this.locale.customRangeLabel = options.locale.customRangeLabel; + + } + + if (typeof options.startDate === 'string') + this.startDate = moment(options.startDate, this.locale.format); + + if (typeof options.endDate === 'string') + this.endDate = moment(options.endDate, this.locale.format); + + if (typeof options.minDate === 'string') + this.minDate = moment(options.minDate, this.locale.format); + + if (typeof options.maxDate === 'string') + this.maxDate = moment(options.maxDate, this.locale.format); + + if (typeof options.startDate === 'object') + this.startDate = moment(options.startDate); + + if (typeof options.endDate === 'object') + this.endDate = moment(options.endDate); + + if (typeof options.minDate === 'object') + this.minDate = moment(options.minDate); + + if (typeof options.maxDate === 'object') + this.maxDate = moment(options.maxDate); + + // sanity check for bad options + if (this.minDate && this.startDate.isBefore(this.minDate)) + this.startDate = this.minDate.clone(); + + // sanity check for bad options + if (this.maxDate && this.endDate.isAfter(this.maxDate)) + this.endDate = this.maxDate.clone(); + + if (typeof options.applyClass === 'string') + this.applyClass = options.applyClass; + + if (typeof options.cancelClass === 'string') + this.cancelClass = options.cancelClass; + + if (typeof options.dateLimit === 'object') + this.dateLimit = options.dateLimit; + + if (typeof options.opens === 'string') + this.opens = options.opens; + + if (typeof options.drops === 'string') + this.drops = options.drops; + + if (typeof options.showWeekNumbers === 'boolean') + this.showWeekNumbers = options.showWeekNumbers; + + if (typeof options.showISOWeekNumbers === 'boolean') + this.showISOWeekNumbers = options.showISOWeekNumbers; + + if (typeof options.buttonClasses === 'string') + this.buttonClasses = options.buttonClasses; + + if (typeof options.buttonClasses === 'object') + this.buttonClasses = options.buttonClasses.join(' '); + + if (typeof options.showDropdowns === 'boolean') + this.showDropdowns = options.showDropdowns; + + if (typeof options.singleDatePicker === 'boolean') { + this.singleDatePicker = options.singleDatePicker; + if (this.singleDatePicker) + this.endDate = this.startDate.clone(); + } + + if (typeof options.timePicker === 'boolean') + this.timePicker = options.timePicker; + + if (typeof options.timePickerSeconds === 'boolean') + this.timePickerSeconds = options.timePickerSeconds; + + if (typeof options.timePickerIncrement === 'number') + this.timePickerIncrement = options.timePickerIncrement; + + if (typeof options.timePicker24Hour === 'boolean') + this.timePicker24Hour = options.timePicker24Hour; + + if (typeof options.autoApply === 'boolean') + this.autoApply = options.autoApply; + + if (typeof options.autoUpdateInput === 'boolean') + this.autoUpdateInput = options.autoUpdateInput; + + if (typeof options.linkedCalendars === 'boolean') + this.linkedCalendars = options.linkedCalendars; + + if (typeof options.isInvalidDate === 'function') + this.isInvalidDate = options.isInvalidDate; + + if (typeof options.alwaysShowCalendars === 'boolean') + this.alwaysShowCalendars = options.alwaysShowCalendars; + + // update day names order to firstDay + if (this.locale.firstDay != 0) { + var iterator = this.locale.firstDay; + while (iterator > 0) { + this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); + iterator--; + } + } + + var start, end, range; + + //if no start/end dates set, check if an input element contains initial values + if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { + if ($(this.element).is('input[type=text]')) { + var val = $(this.element).val(), + split = val.split(this.locale.separator); + + start = end = null; + + if (split.length == 2) { + start = moment(split[0], this.locale.format); + end = moment(split[1], this.locale.format); + } else if (this.singleDatePicker && val !== "") { + start = moment(val, this.locale.format); + end = moment(val, this.locale.format); + } + if (start !== null && end !== null) { + this.setStartDate(start); + this.setEndDate(end); + } + } + } + + if (typeof options.ranges === 'object') { + for (range in options.ranges) { + + if (typeof options.ranges[range][0] === 'string') + start = moment(options.ranges[range][0], this.locale.format); + else + start = moment(options.ranges[range][0]); + + if (typeof options.ranges[range][1] === 'string') + end = moment(options.ranges[range][1], this.locale.format); + else + end = moment(options.ranges[range][1]); + + // If the start or end date exceed those allowed by the minDate or dateLimit + // options, shorten the range to the allowable period. + if (this.minDate && start.isBefore(this.minDate)) + start = this.minDate.clone(); + + var maxDate = this.maxDate; + if (this.dateLimit && start.clone().add(this.dateLimit).isAfter(maxDate)) + maxDate = start.clone().add(this.dateLimit); + if (maxDate && end.isAfter(maxDate)) + end = maxDate.clone(); + + // If the end of the range is before the minimum or the start of the range is + // after the maximum, don't display this range option at all. + if ((this.minDate && end.isBefore(this.minDate)) || (maxDate && start.isAfter(maxDate))) + continue; + + //Support unicode chars in the range names. + var elem = document.createElement('textarea'); + elem.innerHTML = range; + var rangeHtml = elem.value; + + this.ranges[rangeHtml] = [start, end]; + } + + var list = ''; + this.container.find('.ranges').prepend(list); + } + + if (typeof cb === 'function') { + this.callback = cb; + } + + if (!this.timePicker) { + this.startDate = this.startDate.startOf('day'); + this.endDate = this.endDate.endOf('day'); + this.container.find('.calendar-time').hide(); + } + + //can't be used together for now + if (this.timePicker && this.autoApply) + this.autoApply = false; + + if (this.autoApply && typeof options.ranges !== 'object') { + this.container.find('.ranges').hide(); + } else if (this.autoApply) { + this.container.find('.applyBtn, .cancelBtn').addClass('hide'); + } + + if (this.singleDatePicker) { + this.container.addClass('single'); + this.container.find('.calendar.left').addClass('single'); + this.container.find('.calendar.left').show(); + this.container.find('.calendar.right').hide(); + this.container.find('.daterangepicker_input input, .daterangepicker_input i').hide(); + if (!this.timePicker) { + this.container.find('.ranges').hide(); + } + } + + if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) { + this.container.addClass('show-calendar'); + } + + this.container.addClass('opens' + this.opens); + + //swap the position of the predefined ranges if opens right + if (typeof options.ranges !== 'undefined' && this.opens == 'right') { + var ranges = this.container.find('.ranges'); + var html = ranges.clone(); + ranges.remove(); + this.container.find('.calendar.left').parent().prepend(html); + } + + //apply CSS classes and labels to buttons + this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses); + if (this.applyClass.length) + this.container.find('.applyBtn').addClass(this.applyClass); + if (this.cancelClass.length) + this.container.find('.cancelBtn').addClass(this.cancelClass); + this.container.find('.applyBtn').html(this.locale.applyLabel); + this.container.find('.cancelBtn').html(this.locale.cancelLabel); + + // + // event listeners + // + + this.container.find('.calendar') + .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) + .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) + .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) + .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) + .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this)) + .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this)) + .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this)) + .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this)) + .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this)) + //.on('keyup.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this)) + .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this)); + + this.container.find('.ranges') + .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) + .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)) + .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)) + .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this)) + .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this)); + + if (this.element.is('input')) { + this.element.on({ + 'click.daterangepicker': $.proxy(this.show, this), + 'focus.daterangepicker': $.proxy(this.show, this), + 'keyup.daterangepicker': $.proxy(this.elementChanged, this), + 'keydown.daterangepicker': $.proxy(this.keydown, this) + }); + } else { + this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); + } + + // + // if attached to a text input, set the initial value + // + + if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); + this.element.trigger('change'); + } else if (this.element.is('input') && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format)); + this.element.trigger('change'); + } + + }; + + DateRangePicker.prototype = { + + constructor: DateRangePicker, + + setStartDate: function(startDate) { + if (typeof startDate === 'string') + this.startDate = moment(startDate, this.locale.format); + + if (typeof startDate === 'object') + this.startDate = moment(startDate); + + if (!this.timePicker) + this.startDate = this.startDate.startOf('day'); + + if (this.timePicker && this.timePickerIncrement) + this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + + if (this.minDate && this.startDate.isBefore(this.minDate)) + this.startDate = this.minDate; + + if (this.maxDate && this.startDate.isAfter(this.maxDate)) + this.startDate = this.maxDate; + + if (!this.isShowing) + this.updateElement(); + + this.updateMonthsInView(); + }, + + setEndDate: function(endDate) { + if (typeof endDate === 'string') + this.endDate = moment(endDate, this.locale.format); + + if (typeof endDate === 'object') + this.endDate = moment(endDate); + + if (!this.timePicker) + this.endDate = this.endDate.endOf('day'); + + if (this.timePicker && this.timePickerIncrement) + this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + + if (this.endDate.isBefore(this.startDate)) + this.endDate = this.startDate.clone(); + + if (this.maxDate && this.endDate.isAfter(this.maxDate)) + this.endDate = this.maxDate; + + if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate)) + this.endDate = this.startDate.clone().add(this.dateLimit); + + this.previousRightTime = this.endDate.clone(); + + if (!this.isShowing) + this.updateElement(); + + this.updateMonthsInView(); + }, + + isInvalidDate: function() { + return false; + }, + + updateView: function() { + if (this.timePicker) { + this.renderTimePicker('left'); + this.renderTimePicker('right'); + if (!this.endDate) { + this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled'); + } else { + this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled'); + } + } + if (this.endDate) { + this.container.find('input[name="daterangepicker_end"]').removeClass('active'); + this.container.find('input[name="daterangepicker_start"]').addClass('active'); + } else { + this.container.find('input[name="daterangepicker_end"]').addClass('active'); + this.container.find('input[name="daterangepicker_start"]').removeClass('active'); + } + this.updateMonthsInView(); + this.updateCalendars(); + this.updateFormInputs(); + }, + + updateMonthsInView: function() { + if (this.endDate) { + + //if both dates are visible already, do nothing + if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && + (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) + && + (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) + ) { + return; + } + + this.leftCalendar.month = this.startDate.clone().date(2); + if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) { + this.rightCalendar.month = this.endDate.clone().date(2); + } else { + this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); + } + + } else { + if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) { + this.leftCalendar.month = this.startDate.clone().date(2); + this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); + } + } + }, + + updateCalendars: function() { + + if (this.timePicker) { + var hour, minute, second; + if (this.endDate) { + hour = parseInt(this.container.find('.left .hourselect').val(), 10); + minute = parseInt(this.container.find('.left .minuteselect').val(), 10); + second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; + if (!this.timePicker24Hour) { + var ampm = this.container.find('.left .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + } else { + hour = parseInt(this.container.find('.right .hourselect').val(), 10); + minute = parseInt(this.container.find('.right .minuteselect').val(), 10); + second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; + if (!this.timePicker24Hour) { + var ampm = this.container.find('.right .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + } + this.leftCalendar.month.hour(hour).minute(minute).second(second); + this.rightCalendar.month.hour(hour).minute(minute).second(second); + } + + this.renderCalendar('left'); + this.renderCalendar('right'); + + //highlight any predefined range matching the current start and end dates + this.container.find('.ranges li').removeClass('active'); + if (this.endDate == null) return; + + this.calculateChosenLabel(); + }, + + renderCalendar: function(side) { + + // + // Build the matrix of dates that will populate the calendar + // + + var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar; + var month = calendar.month.month(); + var year = calendar.month.year(); + var hour = calendar.month.hour(); + var minute = calendar.month.minute(); + var second = calendar.month.second(); + var daysInMonth = moment([year, month]).daysInMonth(); + var firstDay = moment([year, month, 1]); + var lastDay = moment([year, month, daysInMonth]); + var lastMonth = moment(firstDay).subtract(1, 'month').month(); + var lastYear = moment(firstDay).subtract(1, 'month').year(); + var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); + var dayOfWeek = firstDay.day(); + + //initialize a 6 rows x 7 columns array for the calendar + var calendar = []; + calendar.firstDay = firstDay; + calendar.lastDay = lastDay; + + for (var i = 0; i < 6; i++) { + calendar[i] = []; + } + + //populate the calendar with date objects + var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; + if (startDay > daysInLastMonth) + startDay -= 7; + + if (dayOfWeek == this.locale.firstDay) + startDay = daysInLastMonth - 6; + + var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]); + + var col, row; + for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { + if (i > 0 && col % 7 === 0) { + col = 0; + row++; + } + calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second); + curDate.hour(12); + + if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { + calendar[row][col] = this.minDate.clone(); + } + + if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { + calendar[row][col] = this.maxDate.clone(); + } + + } + + //make the calendar object available to hoverDate/clickDate + if (side == 'left') { + this.leftCalendar.calendar = calendar; + } else { + this.rightCalendar.calendar = calendar; + } + + // + // Display the calendar + // + + var minDate = side == 'left' ? this.minDate : this.startDate; + var maxDate = this.maxDate; + var selected = side == 'left' ? this.startDate : this.endDate; + + var html = ''; + html += ''; + html += ''; + + // add empty cell for week number + if (this.showWeekNumbers || this.showISOWeekNumbers) + html += ''; + + if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) { + html += ''; + } else { + html += ''; + } + + var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); + + if (this.showDropdowns) { + var currentMonth = calendar[1][1].month(); + var currentYear = calendar[1][1].year(); + var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); + var minYear = (minDate && minDate.year()) || (currentYear - 50); + var inMinYear = currentYear == minYear; + var inMaxYear = currentYear == maxYear; + + var monthHtml = '"; + + var yearHtml = ''; + + dateHtml = monthHtml + yearHtml; + } + + html += ''; + if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) { + html += ''; + } else { + html += ''; + } + + html += ''; + html += ''; + + // add week number label + if (this.showWeekNumbers || this.showISOWeekNumbers) + html += ''; + + $.each(this.locale.daysOfWeek, function(index, dayOfWeek) { + html += ''; + }); + + html += ''; + html += ''; + html += ''; + + //adjust maxDate to reflect the dateLimit setting in order to + //grey out end dates beyond the dateLimit + if (this.endDate == null && this.dateLimit) { + var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day'); + if (!maxDate || maxLimit.isBefore(maxDate)) { + maxDate = maxLimit; + } + } + + for (var row = 0; row < 6; row++) { + html += ''; + + // add week number + if (this.showWeekNumbers) + html += ''; + else if (this.showISOWeekNumbers) + html += ''; + + for (var col = 0; col < 7; col++) { + + var classes = []; + + //highlight today's date + if (calendar[row][col].isSame(new Date(), "day")) + classes.push('today'); + + //highlight weekends + if (calendar[row][col].isoWeekday() > 5) + classes.push('weekend'); + + //grey out the dates in other months displayed at beginning and end of this calendar + if (calendar[row][col].month() != calendar[1][1].month()) + classes.push('off'); + + //don't allow selection of dates before the minimum date + if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day')) + classes.push('off', 'disabled'); + + //don't allow selection of dates after the maximum date + if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) + classes.push('off', 'disabled'); + + //don't allow selection of date if a custom function decides it's invalid + if (this.isInvalidDate(calendar[row][col])) + classes.push('off', 'disabled'); + + //highlight the currently selected start date + if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) + classes.push('active', 'start-date'); + + //highlight the currently selected end date + if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) + classes.push('active', 'end-date'); + + //highlight dates in-between the selected dates + if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) + classes.push('in-range'); + + var cname = '', disabled = false; + for (var i = 0; i < classes.length; i++) { + cname += classes[i] + ' '; + if (classes[i] == 'disabled') + disabled = true; + } + if (!disabled) + cname += 'available'; + + html += ''; + + } + html += ''; + } + + html += ''; + html += '
' + dateHtml + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].week() + '' + calendar[row][0].isoWeek() + '' + calendar[row][col].date() + '
'; + + this.container.find('.calendar.' + side + ' .calendar-table').html(html); + + }, + + renderTimePicker: function(side) { + + var html, selected, minDate, maxDate = this.maxDate; + + if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate))) + maxDate = this.startDate.clone().add(this.dateLimit); + + if (side == 'left') { + selected = this.startDate.clone(); + minDate = this.minDate; + } else if (side == 'right') { + selected = this.endDate ? this.endDate.clone() : this.previousRightTime.clone(); + minDate = this.startDate; + + //Preserve the time already selected + var timeSelector = this.container.find('.calendar.right .calendar-time div'); + if (timeSelector.html() != '') { + + selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour()); + selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute()); + selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second()); + + if (!this.timePicker24Hour) { + var ampm = timeSelector.find('.ampmselect option:selected').val(); + if (ampm === 'PM' && selected.hour() < 12) + selected.hour(selected.hour() + 12); + if (ampm === 'AM' && selected.hour() === 12) + selected.hour(0); + } + + if (selected.isBefore(this.startDate)) + selected = this.startDate.clone(); + + if (maxDate && selected.isAfter(maxDate)) + selected = maxDate.clone(); + + } + } + + // + // hours + // + + html = ' '; + + // + // minutes + // + + html += ': '; + + // + // seconds + // + + if (this.timePickerSeconds) { + html += ': '; + } + + // + // AM/PM + // + + if (!this.timePicker24Hour) { + html += ''; + } + + this.container.find('.calendar.' + side + ' .calendar-time div').html(html); + + }, + + updateFormInputs: function() { + + //ignore mouse movements while an above-calendar text input has focus + if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + return; + + this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format)); + if (this.endDate) + this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format)); + + if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { + this.container.find('button.applyBtn').removeAttr('disabled'); + } else { + this.container.find('button.applyBtn').attr('disabled', 'disabled'); + } + + }, + + move: function() { + var parentOffset = { top: 0, left: 0 }, + containerTop; + var parentRightEdge = $(window).width(); + if (!this.parentEl.is('body')) { + parentOffset = { + top: this.parentEl.offset().top - this.parentEl.scrollTop(), + left: this.parentEl.offset().left - this.parentEl.scrollLeft() + }; + parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; + } + + if (this.drops == 'up') + containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; + else + containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; + this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup'); + + if (this.opens == 'left') { + this.container.css({ + top: containerTop, + right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), + left: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else if (this.opens == 'center') { + this.container.css({ + top: containerTop, + left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 + - this.container.outerWidth() / 2, + right: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else { + this.container.css({ + top: containerTop, + left: this.element.offset().left - parentOffset.left, + right: 'auto' + }); + if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { + this.container.css({ + left: 'auto', + right: 0 + }); + } + } + }, + + show: function(e) { + if (this.isShowing) return; + + // Create a click proxy that is private to this instance of datepicker, for unbinding + this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this); + + // Bind global datepicker mousedown for hiding and + $(document) + .on('mousedown.daterangepicker', this._outsideClickProxy) + // also support mobile devices + .on('touchend.daterangepicker', this._outsideClickProxy) + // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them + .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) + // and also close when focus changes to outside the picker (eg. tabbing between controls) + .on('focusin.daterangepicker', this._outsideClickProxy); + + // Reposition the picker if the window is resized while it's open + $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this)); + + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + this.previousRightTime = this.endDate.clone(); + + this.updateView(); + this.container.show(); + this.move(); + this.element.trigger('show.daterangepicker', this); + this.isShowing = true; + }, + + hide: function(e) { + if (!this.isShowing) return; + + //incomplete date selection, revert to last values + if (!this.endDate) { + this.startDate = this.oldStartDate.clone(); + this.endDate = this.oldEndDate.clone(); + } + + //if a new date range was selected, invoke the user callback function + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) + this.callback(this.startDate, this.endDate, this.chosenLabel); + + //if picker is attached to a text input, update it + this.updateElement(); + + $(document).off('.daterangepicker'); + $(window).off('.daterangepicker'); + this.container.hide(); + this.element.trigger('hide.daterangepicker', this); + this.isShowing = false; + }, + + toggle: function(e) { + if (this.isShowing) { + this.hide(); + } else { + this.show(); + } + }, + + outsideClick: function(e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button + // itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-table').length + ) return; + this.hide(); + }, + + showCalendars: function() { + this.container.addClass('show-calendar'); + this.move(); + this.element.trigger('showCalendar.daterangepicker', this); + }, + + hideCalendars: function() { + this.container.removeClass('show-calendar'); + this.element.trigger('hideCalendar.daterangepicker', this); + }, + + hoverRange: function(e) { + + //ignore mouse movements while an above-calendar text input has focus + if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + return; + + var label = e.target.innerHTML; + if (label == this.locale.customRangeLabel) { + this.updateView(); + } else { + var dates = this.ranges[label]; + this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format)); + this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format)); + } + + }, + + clickRange: function(e) { + var label = e.target.innerHTML; + this.chosenLabel = label; + if (label == this.locale.customRangeLabel) { + this.showCalendars(); + } else { + var dates = this.ranges[label]; + this.startDate = dates[0]; + this.endDate = dates[1]; + + if (!this.timePicker) { + this.startDate.startOf('day'); + this.endDate.endOf('day'); + } + + if (!this.alwaysShowCalendars) + this.hideCalendars(); + this.clickApply(); + } + }, + + clickPrev: function(e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.subtract(1, 'month'); + if (this.linkedCalendars) + this.rightCalendar.month.subtract(1, 'month'); + } else { + this.rightCalendar.month.subtract(1, 'month'); + } + this.updateCalendars(); + }, + + clickNext: function(e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.add(1, 'month'); + } else { + this.rightCalendar.month.add(1, 'month'); + if (this.linkedCalendars) + this.leftCalendar.month.add(1, 'month'); + } + this.updateCalendars(); + }, + + hoverDate: function(e) { + + //ignore mouse movements while an above-calendar text input has focus + if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + return; + + //ignore dates that can't be selected + if (!$(e.target).hasClass('available')) return; + + //have the text inputs above calendars reflect the date being hovered over + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + + if (this.endDate) { + this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format)); + } else { + this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format)); + } + + //highlight the dates between the start date and the date being hovered as a potential end date + var leftCalendar = this.leftCalendar; + var rightCalendar = this.rightCalendar; + var startDate = this.startDate; + if (!this.endDate) { + this.container.find('.calendar td').each(function(index, el) { + + //skip week numbers, only look at dates + if ($(el).hasClass('week')) return; + + var title = $(el).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(el).parents('.calendar'); + var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col]; + + if (dt.isAfter(startDate) && dt.isBefore(date)) { + $(el).addClass('in-range'); + } else { + $(el).removeClass('in-range'); + } + + }); + } + + }, + + clickDate: function(e) { + + if (!$(e.target).hasClass('available')) return; + + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + + // + // this function needs to do a few things: + // * alternate between selecting a start and end date for the range, + // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date + // * if autoapply is enabled, and an end date was chosen, apply the selection + // * if single date picker mode, and time picker isn't enabled, apply the selection immediately + // + + if (this.endDate || date.isBefore(this.startDate, 'day')) { + if (this.timePicker) { + var hour = parseInt(this.container.find('.left .hourselect').val(), 10); + if (!this.timePicker24Hour) { + var ampm = this.container.find('.left .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; + date = date.clone().hour(hour).minute(minute).second(second); + } + this.endDate = null; + this.setStartDate(date.clone()); + } else if (!this.endDate && date.isBefore(this.startDate)) { + //special case: clicking the same date for start/end, + //but the time of the end date is before the start date + this.setEndDate(this.startDate.clone()); + } else { + if (this.timePicker) { + var hour = parseInt(this.container.find('.right .hourselect').val(), 10); + if (!this.timePicker24Hour) { + var ampm = this.container.find('.right .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; + date = date.clone().hour(hour).minute(minute).second(second); + } + this.setEndDate(date.clone()); + if (this.autoApply) { + this.calculateChosenLabel(); + this.clickApply(); + } + } + + if (this.singleDatePicker) { + this.setEndDate(this.startDate); + if (!this.timePicker) + this.clickApply(); + } + + this.updateView(); + + }, + + calculateChosenLabel: function() { + var customRange = true; + var i = 0; + for (var range in this.ranges) { + if (this.timePicker) { + if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); + break; + } + } else { + //ignore times when comparing dates if time picker is not enabled + if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); + break; + } + } + i++; + } + if (customRange) { + this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html(); + this.showCalendars(); + } + }, + + clickApply: function(e) { + this.hide(); + this.element.trigger('apply.daterangepicker', this); + }, + + clickCancel: function(e) { + this.startDate = this.oldStartDate; + this.endDate = this.oldEndDate; + this.hide(); + this.element.trigger('cancel.daterangepicker', this); + }, + + monthOrYearChanged: function(e) { + var isLeft = $(e.target).closest('.calendar').hasClass('left'), + leftOrRight = isLeft ? 'left' : 'right', + cal = this.container.find('.calendar.'+leftOrRight); + + // Month must be Number for new moment versions + var month = parseInt(cal.find('.monthselect').val(), 10); + var year = cal.find('.yearselect').val(); + + if (!isLeft) { + if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { + month = this.startDate.month(); + year = this.startDate.year(); + } + } + + if (this.minDate) { + if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { + month = this.minDate.month(); + year = this.minDate.year(); + } + } + + if (this.maxDate) { + if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { + month = this.maxDate.month(); + year = this.maxDate.year(); + } + } + + if (isLeft) { + this.leftCalendar.month.month(month).year(year); + if (this.linkedCalendars) + this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month'); + } else { + this.rightCalendar.month.month(month).year(year); + if (this.linkedCalendars) + this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month'); + } + this.updateCalendars(); + }, + + timeChanged: function(e) { + + var cal = $(e.target).closest('.calendar'), + isLeft = cal.hasClass('left'); + + var hour = parseInt(cal.find('.hourselect').val(), 10); + var minute = parseInt(cal.find('.minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0; + + if (!this.timePicker24Hour) { + var ampm = cal.find('.ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + + if (isLeft) { + var start = this.startDate.clone(); + start.hour(hour); + start.minute(minute); + start.second(second); + this.setStartDate(start); + if (this.singleDatePicker) { + this.endDate = this.startDate.clone(); + } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) { + this.setEndDate(start.clone()); + } + } else if (this.endDate) { + var end = this.endDate.clone(); + end.hour(hour); + end.minute(minute); + end.second(second); + this.setEndDate(end); + } + + //update the calendars so all clickable dates reflect the new time component + this.updateCalendars(); + + //update the form inputs above the calendars with the new time + this.updateFormInputs(); + + //re-render the time pickers because changing one selection can affect what's enabled in another + this.renderTimePicker('left'); + this.renderTimePicker('right'); + + }, + + formInputsChanged: function(e) { + var isRight = $(e.target).closest('.calendar').hasClass('right'); + var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format); + var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format); + + if (start.isValid() && end.isValid()) { + + if (isRight && end.isBefore(start)) + start = end.clone(); + + this.setStartDate(start); + this.setEndDate(end); + + if (isRight) { + this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format)); + } else { + this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format)); + } + + } + + this.updateCalendars(); + if (this.timePicker) { + this.renderTimePicker('left'); + this.renderTimePicker('right'); + } + }, + + elementChanged: function() { + if (!this.element.is('input')) return; + if (!this.element.val().length) return; + if (this.element.val().length < this.locale.format.length) return; + + var dateString = this.element.val().split(this.locale.separator), + start = null, + end = null; + + if (dateString.length === 2) { + start = moment(dateString[0], this.locale.format); + end = moment(dateString[1], this.locale.format); + } + + if (this.singleDatePicker || start === null || end === null) { + start = moment(this.element.val(), this.locale.format); + end = start; + } + + if (!start.isValid() || !end.isValid()) return; + + this.setStartDate(start); + this.setEndDate(end); + this.updateView(); + }, + + keydown: function(e) { + //hide on tab or enter + if ((e.keyCode === 9) || (e.keyCode === 13)) { + this.hide(); + } + }, + + updateElement: function() { + if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); + this.element.trigger('change'); + } else if (this.element.is('input') && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format)); + this.element.trigger('change'); + } + }, + + remove: function() { + this.container.remove(); + this.element.off('.daterangepicker'); + this.element.removeData(); + } + + }; + + $.fn.daterangepicker = function(options, callback) { + this.each(function() { + var el = $(this); + if (el.data('daterangepicker')) + el.data('daterangepicker').remove(); + el.data('daterangepicker', new DateRangePicker(el, options, callback)); + }); + return this; + }; + + return DateRangePicker; + +})); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/moment.min.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/moment.min.js new file mode 100644 index 000000000..05199bd3b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.date-range-picker/public/js/moment.min.js @@ -0,0 +1,7 @@ +//! moment.js +//! version : 2.10.3 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Dc.apply(null,arguments)}function b(a){Dc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c0)for(c in Fc)d=Fc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(b){m(this,b),this._d=new Date(+b._d),Gc===!1&&(Gc=!0,a.updateOffset(this),Gc=!1)}function o(a){return a instanceof n||null!=a&&null!=a._isAMomentObject}function p(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function q(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&p(a[d])!==p(b[d]))&&g++;return g+f}function r(){}function s(a){return a?a.toLowerCase().replace("_","-"):a}function t(a){for(var b,c,d,e,f=0;f0;){if(d=u(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&q(e,c,!0)>=b-1)break;b--}f++}return null}function u(a){var b=null;if(!Hc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Ec._abbr,require("./locale/"+a),v(b)}catch(c){}return Hc[a]}function v(a,b){var c;return a&&(c="undefined"==typeof b?x(a):w(a,b),c&&(Ec=c)),Ec._abbr}function w(a,b){return null!==b?(b.abbr=a,Hc[a]||(Hc[a]=new r),Hc[a].set(b),v(a),Hc[a]):(delete Hc[a],null)}function x(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Ec;if(!c(a)){if(b=u(a))return b;a=[a]}return t(a)}function y(a,b){var c=a.toLowerCase();Ic[c]=Ic[c+"s"]=Ic[b]=a}function z(a){return"string"==typeof a?Ic[a]||Ic[a.toLowerCase()]:void 0}function A(a){var b,c,d={};for(c in a)f(a,c)&&(b=z(c),b&&(d[b]=a[c]));return d}function B(b,c){return function(d){return null!=d?(D(this,b,d),a.updateOffset(this,c),this):C(this,b)}}function C(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function D(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function E(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=z(a),"function"==typeof this[a])return this[a](b);return this}function F(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthb;b++)Mc[d[b]]?d[b]=Mc[d[b]]:d[b]=H(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 J(a,b){return a.isValid()?(b=K(b,a.localeData()),Lc[b]||(Lc[b]=I(b)),Lc[b](a)):a.localeData().invalidDate()}function K(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Kc.lastIndex=0;d>=0&&Kc.test(a);)a=a.replace(Kc,c),Kc.lastIndex=0,d-=1;return a}function L(a,b,c){_c[a]="function"==typeof b?b:function(a){return a&&c?c:b}}function M(a,b){return f(_c,a)?_c[a](b._strict,b._locale):new RegExp(N(a))}function N(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function O(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=p(a)}),c=0;cd;d++){if(e=h([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}}function V(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),R(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function W(b){return null!=b?(V(this,b),a.updateOffset(this,!0),this):C(this,"Month")}function X(){return R(this.year(),this.month())}function Y(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[cd]<0||c[cd]>11?cd:c[dd]<1||c[dd]>R(c[bd],c[cd])?dd:c[ed]<0||c[ed]>24||24===c[ed]&&(0!==c[fd]||0!==c[gd]||0!==c[hd])?ed:c[fd]<0||c[fd]>59?fd:c[gd]<0||c[gd]>59?gd:c[hd]<0||c[hd]>999?hd:-1,j(a)._overflowDayOfYear&&(bd>b||b>dd)&&(b=dd),j(a).overflow=b),a}function Z(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function $(a,b){var c=!0,d=a+"\n"+(new Error).stack;return g(function(){return c&&(Z(d),c=!1),b.apply(this,arguments)},b)}function _(a,b){kd[a]||(Z(b),kd[a]=!0)}function aa(a){var b,c,d=a._i,e=ld.exec(d);if(e){for(j(a).iso=!0,b=0,c=md.length;c>b;b++)if(md[b][1].exec(d)){a._f=md[b][0]+(e[6]||" ");break}for(b=0,c=nd.length;c>b;b++)if(nd[b][1].exec(d)){a._f+=nd[b][0];break}d.match(Yc)&&(a._f+="Z"),ta(a)}else a._isValid=!1}function ba(b){var c=od.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(aa(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ca(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function da(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function ea(a){return fa(a)?366:365}function fa(a){return a%4===0&&a%100!==0||a%400===0}function ga(){return fa(this.year())}function ha(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=Aa(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ia(a){return ha(a,this._week.dow,this._week.doy).week}function ja(){return this._week.dow}function ka(){return this._week.doy}function la(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function ma(a){var b=ha(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function na(a,b,c,d,e){var f,g,h=da(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:ea(a-1)+g}}function oa(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function pa(a,b,c){return null!=a?a:null!=b?b:c}function qa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function ra(a){var b,c,d,e,f=[];if(!a._d){for(d=qa(a),a._w&&null==a._a[dd]&&null==a._a[cd]&&sa(a),a._dayOfYear&&(e=pa(a._a[bd],d[bd]),a._dayOfYear>ea(e)&&(j(a)._overflowDayOfYear=!0),c=da(e,0,a._dayOfYear),a._a[cd]=c.getUTCMonth(),a._a[dd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[ed]&&0===a._a[fd]&&0===a._a[gd]&&0===a._a[hd]&&(a._nextDay=!0,a._a[ed]=0),a._d=(a._useUTC?da:ca).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[ed]=24)}}function sa(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=pa(b.GG,a._a[bd],ha(Aa(),1,4).year),d=pa(b.W,1),e=pa(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=pa(b.gg,a._a[bd],ha(Aa(),f,g).year),d=pa(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=na(c,d,e,g,f),a._a[bd]=h.year,a._dayOfYear=h.dayOfYear}function ta(b){if(b._f===a.ISO_8601)return void aa(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=K(b._f,b._locale).match(Jc)||[],c=0;c0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Mc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),Q(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[ed]<=12&&b._a[ed]>0&&(j(b).bigHour=void 0),b._a[ed]=ua(b._locale,b._a[ed],b._meridiem),ra(b),Y(b)}function ua(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function va(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(0/0));for(e=0;ef)&&(d=f,c=b));g(a,c||b)}function wa(a){if(!a._d){var b=A(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],ra(a)}}function xa(a){var b,e=a._i,f=a._f;return a._locale=a._locale||x(a._l),null===e||void 0===f&&""===e?l({nullInput:!0}):("string"==typeof e&&(a._i=e=a._locale.preparse(e)),o(e)?new n(Y(e)):(c(f)?va(a):f?ta(a):d(e)?a._d=e:ya(a),b=new n(Y(a)),b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b))}function ya(b){var f=b._i;void 0===f?b._d=new Date:d(f)?b._d=new Date(+f):"string"==typeof f?ba(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ra(b)):"object"==typeof f?wa(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function za(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,xa(f)}function Aa(a,b,c,d){return za(a,b,c,d,!1)}function Ba(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Aa();for(d=b[0],e=1;ea&&(a=-a,c="-"),c+F(~~(a/60),2)+b+F(~~a%60,2)})}function Ha(a){var b=(a||"").match(Yc)||[],c=b[b.length-1]||[],d=(c+"").match(td)||["-",0,0],e=+(60*d[1])+p(d[2]);return"+"===d[0]?e:-e}function Ia(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(o(b)||d(b)?+b:+Aa(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Aa(b).local();return c._isUTC?Aa(b).zone(c._offset||0):Aa(b).local()}function Ja(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ka(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ha(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ja(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?$a(this,Va(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ja(this)}function La(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Ma(a){return this.utcOffset(0,a)}function Na(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ja(this),"m")),this}function Oa(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ha(this._i)),this}function Pa(a){return a=a?Aa(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Qa(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ra(){if(this._a){var a=this._isUTC?h(this._a):Aa(this._a);return this.isValid()&&q(this._a,a.toArray())>0}return!1}function Sa(){return!this._isUTC}function Ta(){return this._isUTC}function Ua(){return this._isUTC&&0===this._offset}function Va(a,b){var c,d,e,g=a,h=null;return Fa(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=ud.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:p(h[dd])*c,h:p(h[ed])*c,m:p(h[fd])*c,s:p(h[gd])*c,ms:p(h[hd])*c}):(h=vd.exec(a))?(c="-"===h[1]?-1:1,g={y:Wa(h[2],c),M:Wa(h[3],c),d:Wa(h[4],c),h:Wa(h[5],c),m:Wa(h[6],c),s:Wa(h[7],c),w:Wa(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Ya(Aa(g.from),Aa(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ea(g),Fa(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Wa(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Xa(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Ya(a,b){var c;return b=Ia(b,a),a.isBefore(b)?c=Xa(a,b):(c=Xa(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function Za(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(_(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Va(c,d),$a(this,e,a),this}}function $a(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&D(b,"Date",C(b,"Date")+g*d),h&&V(b,C(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function _a(a){var b=a||Aa(),c=Ia(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,Aa(b)))}function ab(){return new n(this)}function bb(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Aa(a),+this>+a):(c=o(a)?+a:+Aa(a),c<+this.clone().startOf(b))}function cb(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Aa(a),+a>+this):(c=o(a)?+a:+Aa(a),+this.clone().endOf(b)a?Math.ceil(a):Math.floor(a)}function gb(a,b,c){var d,e,f=Ia(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=z(b),"year"===b||"month"===b||"quarter"===b?(e=hb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:fb(e)}function hb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function ib(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function jb(){var a=this.clone().utc();return 0b;b++)if(this._weekdaysParse[b]||(c=Aa([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}function Mb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Hb(a,this.localeData()),this.add(a-b,"d")):b}function Nb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ob(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Pb(a,b){G(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Qb(a,b){return b._meridiemParse}function Rb(a){return"p"===(a+"").toLowerCase().charAt(0)}function Sb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Tb(a){G(0,[a,3],0,"millisecond")}function Ub(){return this._isUTC?"UTC":""}function Vb(){return this._isUTC?"Coordinated Universal Time":""}function Wb(a){return Aa(1e3*a)}function Xb(){return Aa.apply(null,arguments).parseZone()}function Yb(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function Zb(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}function $b(){return this._invalidDate}function _b(a){return this._ordinal.replace("%d",a)}function ac(a){return a}function bc(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function cc(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function dc(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)}function ec(a,b,c,d){var e=x(),f=h().set(d,b);return e[c](f,a)}function fc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return ec(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=ec(a,f,c,e);return g}function gc(a,b){return fc(a,b,"months",12,"month")}function hc(a,b){return fc(a,b,"monthsShort",12,"month")}function ic(a,b){return fc(a,b,"weekdays",7,"day")}function jc(a,b){return fc(a,b,"weekdaysShort",7,"day")}function kc(a,b){return fc(a,b,"weekdaysMin",7,"day")}function lc(){var a=this._data;return this._milliseconds=Rd(this._milliseconds),this._days=Rd(this._days),this._months=Rd(this._months),a.milliseconds=Rd(a.milliseconds),a.seconds=Rd(a.seconds),a.minutes=Rd(a.minutes),a.hours=Rd(a.hours),a.months=Rd(a.months),a.years=Rd(a.years),this}function mc(a,b,c,d){var e=Va(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function nc(a,b){return mc(this,a,b,1)}function oc(a,b){return mc(this,a,b,-1)}function pc(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;return g.milliseconds=d%1e3,a=fb(d/1e3),g.seconds=a%60,b=fb(a/60),g.minutes=b%60,c=fb(b/60),g.hours=c%24,e+=fb(c/24),h=fb(qc(e)),e-=fb(rc(h)),f+=fb(e/30),e%=30,h+=fb(f/12),f%=12,g.days=e,g.months=f,g.years=h,this}function qc(a){return 400*a/146097}function rc(a){return 146097*a/400}function sc(a){var b,c,d=this._milliseconds;if(a=z(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+12*qc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(rc(this._months/12)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function tc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*p(this._months/12)}function uc(a){return function(){return this.as(a)}}function vc(a){return a=z(a),this[a+"s"]()}function wc(a){return function(){return this._data[a]}}function xc(){return fb(this.days()/7)}function yc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function zc(a,b,c){var d=Va(a).abs(),e=fe(d.as("s")),f=fe(d.as("m")),g=fe(d.as("h")),h=fe(d.as("d")),i=fe(d.as("M")),j=fe(d.as("y")),k=e0,k[4]=c,yc.apply(null,k)}function Ac(a,b){return void 0===ge[a]?!1:void 0===b?ge[a]:(ge[a]=b,!0)}function Bc(a){var b=this.localeData(),c=zc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Cc(){var a=he(this.years()),b=he(this.months()),c=he(this.days()),d=he(this.hours()),e=he(this.minutes()),f=he(this.seconds()+this.milliseconds()/1e3),g=this.asSeconds();return g?(0>g?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"}var Dc,Ec,Fc=a.momentProperties=[],Gc=!1,Hc={},Ic={},Jc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,Kc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Lc={},Mc={},Nc=/\d/,Oc=/\d\d/,Pc=/\d{3}/,Qc=/\d{4}/,Rc=/[+-]?\d{6}/,Sc=/\d\d?/,Tc=/\d{1,3}/,Uc=/\d{1,4}/,Vc=/[+-]?\d{1,6}/,Wc=/\d+/,Xc=/[+-]?\d+/,Yc=/Z|[+-]\d\d:?\d\d/gi,Zc=/[+-]?\d+(\.\d{1,3})?/,$c=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,_c={},ad={},bd=0,cd=1,dd=2,ed=3,fd=4,gd=5,hd=6;G("M",["MM",2],"Mo",function(){return this.month()+1}),G("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),G("MMMM",0,0,function(a){return this.localeData().months(this,a)}),y("month","M"),L("M",Sc),L("MM",Sc,Oc),L("MMM",$c),L("MMMM",$c),O(["M","MM"],function(a,b){b[cd]=p(a)-1}),O(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[cd]=e:j(c).invalidMonth=a});var id="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),jd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),kd={};a.suppressDeprecationWarnings=!1;var ld=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,md=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],nd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],od=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=$("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":""))}),G(0,["YY",2],0,function(){return this.year()%100}),G(0,["YYYY",4],0,"year"),G(0,["YYYYY",5],0,"year"),G(0,["YYYYYY",6,!0],0,"year"),y("year","y"),L("Y",Xc),L("YY",Sc,Oc),L("YYYY",Uc,Qc),L("YYYYY",Vc,Rc),L("YYYYYY",Vc,Rc),O(["YYYY","YYYYY","YYYYYY"],bd),O("YY",function(b,c){c[bd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return p(a)+(p(a)>68?1900:2e3)};var pd=B("FullYear",!1);G("w",["ww",2],"wo","week"),G("W",["WW",2],"Wo","isoWeek"),y("week","w"),y("isoWeek","W"),L("w",Sc),L("ww",Sc,Oc),L("W",Sc),L("WW",Sc,Oc),P(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=p(a)});var qd={dow:0,doy:6};G("DDD",["DDDD",3],"DDDo","dayOfYear"),y("dayOfYear","DDD"),L("DDD",Tc),L("DDDD",Pc),O(["DDD","DDDD"],function(a,b,c){c._dayOfYear=p(a)}),a.ISO_8601=function(){};var rd=$("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return this>a?this:a}),sd=$("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return a>this?this:a});Ga("Z",":"),Ga("ZZ",""),L("Z",Yc),L("ZZ",Yc),O(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ha(a)});var td=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var ud=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,vd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Va.fn=Ea.prototype;var wd=Za(1,"add"),xd=Za(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var yd=$("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});G(0,["gg",2],0,function(){return this.weekYear()%100}),G(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ab("gggg","weekYear"),Ab("ggggg","weekYear"),Ab("GGGG","isoWeekYear"),Ab("GGGGG","isoWeekYear"),y("weekYear","gg"),y("isoWeekYear","GG"),L("G",Xc),L("g",Xc),L("GG",Sc,Oc),L("gg",Sc,Oc),L("GGGG",Uc,Qc),L("gggg",Uc,Qc),L("GGGGG",Vc,Rc),L("ggggg",Vc,Rc),P(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=p(a)}),P(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),G("Q",0,0,"quarter"),y("quarter","Q"),L("Q",Nc),O("Q",function(a,b){b[cd]=3*(p(a)-1)}),G("D",["DD",2],"Do","date"),y("date","D"),L("D",Sc),L("DD",Sc,Oc),L("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),O(["D","DD"],dd),O("Do",function(a,b){b[dd]=p(a.match(Sc)[0],10)});var zd=B("Date",!0);G("d",0,"do","day"),G("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),G("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),G("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),G("e",0,0,"weekday"),G("E",0,0,"isoWeekday"),y("day","d"),y("weekday","e"),y("isoWeekday","E"),L("d",Sc),L("e",Sc),L("E",Sc),L("dd",$c),L("ddd",$c),L("dddd",$c),P(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:j(c).invalidWeekday=a}),P(["d","e","E"],function(a,b,c,d){b[d]=p(a)});var Ad="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Bd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Cd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");G("H",["HH",2],0,"hour"),G("h",["hh",2],0,function(){return this.hours()%12||12}),Pb("a",!0),Pb("A",!1),y("hour","h"),L("a",Qb),L("A",Qb),L("H",Sc),L("h",Sc),L("HH",Sc,Oc),L("hh",Sc,Oc),O(["H","HH"],ed),O(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),O(["h","hh"],function(a,b,c){b[ed]=p(a),j(c).bigHour=!0});var Dd=/[ap]\.?m?\.?/i,Ed=B("Hours",!0);G("m",["mm",2],0,"minute"),y("minute","m"),L("m",Sc),L("mm",Sc,Oc),O(["m","mm"],fd);var Fd=B("Minutes",!1);G("s",["ss",2],0,"second"),y("second","s"),L("s",Sc),L("ss",Sc,Oc),O(["s","ss"],gd);var Gd=B("Seconds",!1);G("S",0,0,function(){return~~(this.millisecond()/100)}),G(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Tb("SSS"),Tb("SSSS"),y("millisecond","ms"),L("S",Tc,Nc),L("SS",Tc,Oc),L("SSS",Tc,Pc),L("SSSS",Wc),O(["S","SS","SSS","SSSS"],function(a,b){b[hd]=p(1e3*("0."+a))});var Hd=B("Milliseconds",!1);G("z",0,0,"zoneAbbr"),G("zz",0,0,"zoneName");var Id=n.prototype;Id.add=wd,Id.calendar=_a,Id.clone=ab,Id.diff=gb,Id.endOf=sb,Id.format=kb,Id.from=lb,Id.fromNow=mb,Id.to=nb,Id.toNow=ob,Id.get=E,Id.invalidAt=zb,Id.isAfter=bb,Id.isBefore=cb,Id.isBetween=db,Id.isSame=eb,Id.isValid=xb,Id.lang=yd,Id.locale=pb,Id.localeData=qb,Id.max=sd,Id.min=rd,Id.parsingFlags=yb,Id.set=E,Id.startOf=rb,Id.subtract=xd,Id.toArray=wb,Id.toDate=vb,Id.toISOString=jb,Id.toJSON=jb,Id.toString=ib,Id.unix=ub,Id.valueOf=tb,Id.year=pd,Id.isLeapYear=ga,Id.weekYear=Cb,Id.isoWeekYear=Db,Id.quarter=Id.quarters=Gb,Id.month=W,Id.daysInMonth=X,Id.week=Id.weeks=la,Id.isoWeek=Id.isoWeeks=ma,Id.weeksInYear=Fb,Id.isoWeeksInYear=Eb,Id.date=zd,Id.day=Id.days=Mb,Id.weekday=Nb,Id.isoWeekday=Ob,Id.dayOfYear=oa,Id.hour=Id.hours=Ed,Id.minute=Id.minutes=Fd,Id.second=Id.seconds=Gd,Id.millisecond=Id.milliseconds=Hd,Id.utcOffset=Ka,Id.utc=Ma,Id.local=Na,Id.parseZone=Oa,Id.hasAlignedHourOffset=Pa,Id.isDST=Qa,Id.isDSTShifted=Ra,Id.isLocal=Sa,Id.isUtcOffset=Ta,Id.isUtc=Ua,Id.isUTC=Ua,Id.zoneAbbr=Ub,Id.zoneName=Vb,Id.dates=$("dates accessor is deprecated. Use date instead.",zd),Id.months=$("months accessor is deprecated. Use month instead",W),Id.years=$("years accessor is deprecated. Use year instead",pd),Id.zone=$("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",La);var Jd=Id,Kd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Ld={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"},Md="Invalid date",Nd="%d",Od=/\d{1,2}/,Pd={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"},Qd=r.prototype;Qd._calendar=Kd,Qd.calendar=Yb,Qd._longDateFormat=Ld,Qd.longDateFormat=Zb,Qd._invalidDate=Md,Qd.invalidDate=$b,Qd._ordinal=Nd,Qd.ordinal=_b,Qd._ordinalParse=Od,Qd.preparse=ac,Qd.postformat=ac,Qd._relativeTime=Pd,Qd.relativeTime=bc,Qd.pastFuture=cc,Qd.set=dc,Qd.months=S,Qd._months=id,Qd.monthsShort=T,Qd._monthsShort=jd,Qd.monthsParse=U,Qd.week=ia,Qd._week=qd,Qd.firstDayOfYear=ka,Qd.firstDayOfWeek=ja,Qd.weekdays=Ib,Qd._weekdays=Ad,Qd.weekdaysMin=Kb,Qd._weekdaysMin=Cd,Qd.weekdaysShort=Jb,Qd._weekdaysShort=Bd,Qd.weekdaysParse=Lb,Qd.isPM=Rb,Qd._meridiemParse=Dd,Qd.meridiem=Sb,v("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===p(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=$("moment.lang is deprecated. Use moment.locale instead.",v),a.langData=$("moment.langData is deprecated. Use moment.localeData instead.",x);var Rd=Math.abs,Sd=uc("ms"),Td=uc("s"),Ud=uc("m"),Vd=uc("h"),Wd=uc("d"),Xd=uc("w"),Yd=uc("M"),Zd=uc("y"),$d=wc("milliseconds"),_d=wc("seconds"),ae=wc("minutes"),be=wc("hours"),ce=wc("days"),de=wc("months"),ee=wc("years"),fe=Math.round,ge={s:45,m:45,h:22,d:26,M:11},he=Math.abs,ie=Ea.prototype;ie.abs=lc,ie.add=nc,ie.subtract=oc,ie.as=sc,ie.asMilliseconds=Sd,ie.asSeconds=Td,ie.asMinutes=Ud,ie.asHours=Vd,ie.asDays=Wd,ie.asWeeks=Xd,ie.asMonths=Yd,ie.asYears=Zd,ie.valueOf=tc,ie._bubble=pc,ie.get=vc,ie.milliseconds=$d,ie.seconds=_d,ie.minutes=ae,ie.hours=be,ie.days=ce,ie.weeks=xc,ie.months=de,ie.years=ee,ie.humanize=Bc,ie.toISOString=Cc,ie.toString=Cc,ie.toJSON=Cc,ie.locale=pb,ie.localeData=qb,ie.toIsoString=$("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Cc),ie.lang=yd,G("X",0,0,"unix"),G("x",0,0,"valueOf"),L("x",Xc),L("X",Zc),O("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),O("x",function(a,b,c){c._d=new Date(p(a))}),a.version="2.10.3",b(Aa),a.fn=Jd,a.min=Ca,a.max=Da,a.utc=h,a.unix=Wb,a.months=gc,a.isDate=d,a.locale=v,a.invalid=l,a.duration=Va,a.isMoment=o,a.weekdays=ic,a.parseZone=Xb,a.localeData=x,a.isDuration=Fa,a.monthsShort=hc,a.weekdaysMin=kc,a.defineLocale=w,a.weekdaysShort=jc,a.normalizeUnits=z,a.relativeTimeThreshold=Ac;var je=a;return je}); \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.js index 584b2ce0d..b6ac6b5f8 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.js +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.js @@ -16,7 +16,7 @@ * under the License. */ -function onRequest(context) { +function onRequest() { // var log = new Log("mdm.unit.device.operation-bar"); var userModule = require("/app/modules/business-controllers/user.js")["userModule"]; var viewModel = {}; @@ -27,10 +27,10 @@ function onRequest(context) { if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/ring")) { permissions["android"].push("DEVICE_RING"); } - if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/lock-devices")) { + if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/lock")) { permissions["android"].push("DEVICE_LOCK"); } - if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/unlock-devices")) { + if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/unlock")) { permissions["android"].push("DEVICE_UNLOCK"); } if (userModule.isAuthorized("/permission/admin/device-mgt/devices/owning-device/operations/android/location")) { diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js index b0d588f2e..402607909 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js @@ -1182,7 +1182,7 @@ var operationModule = function () { "WIPE_DATA": "wipe-devices" }; //return "/mdm-windows-agent/services/windows/operation/" + featureMap[operationCode]; - return "/api/device-mgt/windows/v1.0/admin/devices/" + featureMap[operationCode]; + return "/api/device-mgt/windows/v1.0/services/windows/admin/devices/" + featureMap[operationCode]; }; /** * Get the icon for the featureCode diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.view/public/js/device-detail.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.view/public/js/device-detail.js index 87d902e44..155c2568e 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.view/public/js/device-detail.js +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.view/public/js/device-detail.js @@ -44,7 +44,7 @@ var InitiateViewOption = null; // error-callback function () { var defaultInnerHTML = - "

Device data may not have been updated. Please refresh to try again.

"; + "

 Device data may not have been updated. Please refresh to try again.

"; $(".panel-body").append(defaultInnerHTML); } ); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/business-controllers/device.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/business-controllers/device.js index dbc76aabc..3dce168f4 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/business-controllers/device.js +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/business-controllers/device.js @@ -312,7 +312,7 @@ deviceModule = function () { var url; var license; if (deviceType == "windows") { - url = devicemgtProps["httpURL"] + "/mdm-windows-agent/services/device/license"; + url = devicemgtProps["httpURL"] + "/api/device-mgt/windows/v1.0/services/configuration/license"; } else if (deviceType == "ios") { url = devicemgtProps["httpsURL"] + "/ios-enrollment/license/"; } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-controller.jag b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-controller.jag index f76bcf925..eaa84869e 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-controller.jag +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-controller.jag @@ -63,7 +63,7 @@ if (platform != "Windows Phone") { var status = restAPIResponse["status"]; if (status == 200) { session.put("authenticatedUser", username); - session.put("windowsBinaryToken", parse(xmlHttpRequest["responseText"]).UserToken); + session.put("windowsBinaryToken", parse(restAPIResponse["responseText"]).UserToken); response.sendRedirect(mdmProps["appContext"] + "enrollments/windows/license-agent"); } else if (status == 403) { response.sendRedirect(mdmProps["appContext"] + "enrollments/windows/login-agent?error=auth-failed"); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-enroll.jag b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-enroll.jag index 1ad693001..66a4eed09 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-enroll.jag +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/emm-web-agent/app/modules/enrollments/windows/agent-enroll.jag @@ -36,10 +36,10 @@ if (platform != "Windows Phone") { if (!authenticatedUser) { response.sendRedirect(mdmProps["appContext"] + "enrollments/error/unintentional-request"); } else { - var enrollmentUtils = require("/modules/enrollments/util/utils.js")["methods"]; - var Handlebars = require("/lib/handlebars-v2.0.0.js")["Handlebars"]; + var enrollmentUtils = require("/app/modules/enrollments/util/utils.js")["methods"]; + var Handlebars = require("/lib/modules/handlebars/handlebars-v2.0.0.js")["Handlebars"]; var template = Handlebars.compile(enrollmentUtils. - getResource("/modules/enrollments/windows/config/workplace-switch-request-template.hbs")); + getResource("/app/modules/enrollments/windows/config/workplace-switch-request-template.hbs")); var windowsWorkplaceAppID = session.get("windowsWorkplaceAppID"); var windowsBinaryToken = session.get("windowsBinaryToken"); diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/PluginConstants.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/PluginConstants.java index 6e57b1be1..734c5c901 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/PluginConstants.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/PluginConstants.java @@ -263,6 +263,13 @@ public final class PluginConstants { } public static final int MULTI_STATUS_HTTP_CODE = 207; + + } + + public final class WindowsConstant { + public static final String DEVICE_TYPE_WINDOWS = "windows"; + public static final String HEADER_CONTENT_TYPE = "Content-Type"; + public static final String APPLICATION_JSON = "application/json"; } /** @@ -282,6 +289,7 @@ public final class PluginConstants { public static final String DEFAULT_AUTH_POLICY = "Federated"; } + /** * Policy Configuration related constants. */ diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorDTO.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorDTO.java new file mode 100644 index 000000000..84fe7ea49 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorDTO.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.device.mgt.mobile.windows.api.common.beans; + +import java.util.ArrayList; +import java.util.List; + +public class ErrorDTO { + + private Long code = null; + private String message = null; + private String description = null; + + public void setMoreInfo(String moreInfo) { + this.moreInfo = moreInfo; + } + + public void setCode(Long code) { + this.code = code; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setError(List error) { + this.error = error; + } + + private String moreInfo = null; + + public String getMessage() { + return message; + } + + public Long getCode() { + return code; + } + + public String getDescription() { + return description; + } + + public String getMoreInfo() { + return moreInfo; + } + + public List getError() { + return error; + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("class ErrorDTO {\n"); + stringBuilder.append(" code: ").append(code).append("\n"); + stringBuilder.append(" message: ").append(message).append("\n"); + stringBuilder.append(" description: ").append(description).append("\n"); + stringBuilder.append(" moreInfo: ").append(moreInfo).append("\n"); + stringBuilder.append(" error: ").append(error).append("\n"); + stringBuilder.append("}\n"); + return stringBuilder.toString(); + } + + private List error = new ArrayList<>(); + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorListItem.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorListItem.java new file mode 100644 index 000000000..45571ced4 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorListItem.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.wso2.carbon.device.mgt.mobile.windows.api.common.beans; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +@ApiModel(description = "") +public class ErrorListItem { + + @NotNull + private String code = null; + @NotNull + private String message = null; + + @ApiModelProperty(required = true, value = "") + @JsonProperty("code") + public String getCode() { + return code; + } + public void setCode(String code) { + this.code = code; + } + + public ErrorListItem() {} + + public ErrorListItem(String code, String msg) { + this.code = code; + this.message = msg; + } + + + /** + * Description about individual errors occurred + **/ + @ApiModelProperty(required = true, value = "Description about individual errors occurred") + @JsonProperty("message") + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("errorItem {\n"); + + sb.append(" code: ").append(code).append("\n"); + sb.append(" message: ").append(message).append("\n"); + sb.append("}\n"); + return sb.toString(); + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorResponse.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorResponse.java new file mode 100644 index 000000000..e983abd64 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/beans/ErrorResponse.java @@ -0,0 +1,167 @@ +package org.wso2.carbon.device.mgt.mobile.windows.api.common.beans; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; + +import java.util.ArrayList; +import java.util.List; + +public class ErrorResponse { + private Long code = null; + private String message = null; + private String description = null; + private String moreInfo = null; + private List errorItems = new ArrayList<>(); + + @JsonProperty(value = "code") + @ApiModelProperty(required = true, value = "") + public Long getCode() { + return code; + } + + public void setCode(Long code) { + this.code = code; + } + + @JsonProperty(value = "message") + @ApiModelProperty(required = true, value = "ErrorResponse message.") + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @JsonProperty(value = "description") + @ApiModelProperty(value = "A detail description about the error message.") + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @JsonProperty(value = "moreInfo") + @ApiModelProperty(value = "Preferably an url with more details about the error.") + public String getMoreInfo() { + return moreInfo; + } + + public void setMoreInfo(String moreInfo) { + this.moreInfo = moreInfo; + } + + public void addErrorListItem(ErrorListItem item) { + this.errorItems.add(item); + } + + /** + * If there are more than one error list them out. \nFor example, list out validation errors by each field. + */ + @JsonProperty(value = "errorItems") + @ApiModelProperty(value = "If there are more than one error list them out. \n" + + "For example, list out validation errors by each field.") + public List getErrorItems() { + return errorItems; + } + + public void setErrorItems(List error) { + this.errorItems = error; + } + + @Override + public String toString() { +// StringBuilder sb = new StringBuilder(); +// sb.append("{"); +// boolean cont = false; +// if (code != null) { +// cont = true; +// sb.append(" \"code\": ").append(code); +// } +// if (message != null) { +// if (cont) { +// sb.append(","); +// } +// cont = true; +// sb.append(" \"message\": \"").append(message).append("\""); +// } +// if (description != null) { +// if (cont) { +// sb.append(","); +// } +// cont = true; +// sb.append(" \"description\": ").append(description).append("\""); +// } +// if (moreInfo != null) { +// if (cont) { +// sb.append(","); +// } +// cont = true; +// sb.append(" \"moreInfo\": \"").append(moreInfo).append("\""); +// } +// if (error != null && error.size() > 0) { +// if (cont) { +// sb.append(","); +// } +// sb.append(" \"errorItems\": ").append(error); +// } +// sb.append("}"); +// return sb.toString(); + return null; + } + + public static class ErrorResponseBuilder { + + private Long code = null; + private String message = null; + private String description = null; + private String moreInfo = null; + private List error; + + + public ErrorResponseBuilder() { + this.error = new ArrayList<>(); + } + + public ErrorResponseBuilder setCode(long code) { + this.code = code; + return this; + } + + public ErrorResponseBuilder setMessage(String message) { + this.message = message; + return this; + } + + public ErrorResponseBuilder setDescription(String description) { + this.description = description; + return this; + } + + public ErrorResponseBuilder setMoreInfo(String moreInfo) { + this.moreInfo = moreInfo; + return this; + } + + public ErrorResponseBuilder addErrorItem(String code, String msg) { + ErrorListItem item = new ErrorListItem(); + item.setCode(code); + item.setMessage(msg); + this.error.add(item); + return this; + } + + public ErrorResponse build() { + ErrorResponse errorResponse = new ErrorResponse(); + errorResponse.setCode(code); + errorResponse.setMessage(message); + errorResponse.setErrorItems(error); + errorResponse.setDescription(description); + errorResponse.setMoreInfo(moreInfo); + return errorResponse; + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/BadRequestException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/BadRequestException.java index 5f17627ce..c0f933892 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/BadRequestException.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/BadRequestException.java @@ -18,10 +18,9 @@ package org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions; -import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.Message; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorResponse; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; /** @@ -29,8 +28,7 @@ import javax.ws.rs.core.Response; */ public class BadRequestException extends WebApplicationException { - public BadRequestException(Message message, MediaType mediaType) { - super(Response.status(Response.Status.BAD_REQUEST).entity(message). - type(mediaType).build()); + public BadRequestException(ErrorResponse error) { + super(Response.status(Response.Status.BAD_REQUEST).entity(error).build()); } } \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/UnexpectedServerErrorException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/UnexpectedServerErrorException.java new file mode 100644 index 000000000..6643f01d0 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/exceptions/UnexpectedServerErrorException.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions; + +import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorDTO; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorResponse; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; + +public class UnexpectedServerErrorException extends WebApplicationException { + private String message; + private static final long serialVersionUID = 147943579458906890L; + + public UnexpectedServerErrorException(ErrorResponse error) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build()); + } + public UnexpectedServerErrorException(ErrorDTO errorDTO) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(errorDTO) + .header(PluginConstants.WindowsConstant.HEADER_CONTENT_TYPE, PluginConstants.WindowsConstant.APPLICATION_JSON) + .build()); + message = errorDTO.getDescription(); + } + + @Override + public String getMessage() { + return message; + } + + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsAPIUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsAPIUtils.java index a782272b7..a20d9ba53 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsAPIUtils.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsAPIUtils.java @@ -18,18 +18,24 @@ package org.wso2.carbon.device.mgt.mobile.windows.api.common.util; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; +import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorResponse; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.BadRequestException; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.policy.mgt.core.PolicyManagerService; @@ -42,6 +48,7 @@ import org.wso2.carbon.webapp.authenticator.framework.config.AuthenticatorConfig import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.ArrayList; import java.util.List; /** @@ -49,6 +56,8 @@ import java.util.List; */ public class WindowsAPIUtils { + private static Log log = LogFactory.getLog(WindowsAPIUtils.class); + public static DeviceIdentifier convertToDeviceIdentifierObject(String deviceId) { DeviceIdentifier identifier = new DeviceIdentifier(); identifier.setId(deviceId); @@ -87,21 +96,25 @@ public class WindowsAPIUtils { return responseMediaType; } - public static Response getOperationResponse(List deviceIDs, Operation operation, - Message message, MediaType responseMediaType) - throws DeviceManagementException, OperationManagementException { - WindowsDeviceUtils deviceUtils = new WindowsDeviceUtils(); - DeviceIDHolder deviceIDHolder = deviceUtils.validateDeviceIdentifiers(deviceIDs, - message, responseMediaType); -// getDeviceManagementService().addOperation(operation, deviceIDHolder.getValidDeviceIDList()); - if (!deviceIDHolder.getInvalidDeviceIdList().isEmpty()) { - return Response.status(PluginConstants.StatusCodes. - MULTI_STATUS_HTTP_CODE).type( - responseMediaType).entity(deviceUtils. - convertErrorMapIntoErrorMessage(deviceIDHolder.getInvalidDeviceIdList())).build(); + public static Response getOperationResponse(List deviceIDs, Operation operation) + throws DeviceManagementException, OperationManagementException, InvalidDeviceException { + if (deviceIDs == null || deviceIDs.size() == 0) { + String errorMessage = "Device identifier list is empty"; + log.error(errorMessage); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); + } + DeviceIdentifier deviceIdentifier; + List deviceIdentifiers = new ArrayList<>(); + for (String deviceId : deviceIDs) { + deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(PluginConstants.WindowsConstant.DEVICE_TYPE_WINDOWS); + deviceIdentifiers.add(deviceIdentifier); } - return Response.status(Response.Status.CREATED). - type(responseMediaType).build(); + Activity activity = getDeviceManagementService().addOperation( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, operation, deviceIdentifiers); + return Response.status(Response.Status.CREATED).entity(activity).build(); } public static PolicyManagerService getPolicyManagerService() { @@ -126,8 +139,8 @@ public class WindowsAPIUtils { throws OperationManagementException, DeviceManagementException { List pendingDataOperations; pendingDataOperations = org.wso2.carbon.device.mgt.mobile.windows.api.common.util.WindowsAPIUtils. - getDeviceManagementService().getOperationsByDeviceAndStatus( - deviceIdentifier, Operation.Status.PENDING); + getDeviceManagementService().getOperationsByDeviceAndStatus( + deviceIdentifier, Operation.Status.PENDING); return pendingDataOperations; } diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsDeviceUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsDeviceUtils.java deleted file mode 100644 index 77d069228..000000000 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/common/util/WindowsDeviceUtils.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * you may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.device.mgt.mobile.windows.api.common.util; - -import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.device.mgt.common.Device; -import org.wso2.carbon.device.mgt.common.DeviceIdentifier; -import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants; -import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.BadRequestException; - -import javax.ws.rs.core.MediaType; -import java.util.ArrayList; -import java.util.List; - -/** - * Class for get windows device utilities. - */ -public class WindowsDeviceUtils { - - private static final String COMMA_SEPARATION_PATTERN = ", "; - - public DeviceIDHolder validateDeviceIdentifiers(List deviceIDs, - Message message, MediaType responseMediaType) { - if (deviceIDs == null) { - message.setResponseMessage("Device identifier list is empty"); - throw new BadRequestException(message, responseMediaType); - } - List errorDeviceIdList = new ArrayList<>(); - List validDeviceIDList = new ArrayList<>(); - int deviceIDCounter = 0; - - for (String deviceID : deviceIDs) { - deviceIDCounter++; - if (deviceID == null || deviceID.isEmpty()) { - errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, - deviceIDCounter)); - continue; - } - try { - DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); - deviceIdentifier.setId(deviceID); - deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes. - MOBILE_DEVICE_TYPE_WINDOWS); - Device device = WindowsAPIUtils.getDeviceManagementService(). - getDevice(deviceIdentifier); - if (device == null || device.getDeviceIdentifier() == null || - device.getDeviceIdentifier().isEmpty()) { - errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, - deviceIDCounter)); - continue; - } - validDeviceIDList.add(deviceIdentifier); - } catch (DeviceManagementException e) { - errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_SERVICE_NOT_FOUND, - deviceIDCounter)); - } - } - DeviceIDHolder deviceIDHolder = new DeviceIDHolder(); - deviceIDHolder.setValidDeviceIDList(validDeviceIDList); - deviceIDHolder.setInvalidDeviceIdList(errorDeviceIdList); - return deviceIDHolder; - } - - public String convertErrorMapIntoErrorMessage(List errorDeviceIdList) { - return StringUtils.join(errorDeviceIdList.iterator(), COMMA_SEPARATION_PATTERN); - } - -} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/ConfigurationMgtService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/ConfigurationMgtService.java index 8c3129d7b..10f731b15 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/ConfigurationMgtService.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/ConfigurationMgtService.java @@ -18,7 +18,7 @@ package org.wso2.carbon.device.mgt.mobile.windows.api.services; -import io.swagger.annotations.Api; +import io.swagger.annotations.*; import org.wso2.carbon.apimgt.annotations.api.API; import org.wso2.carbon.apimgt.annotations.api.Permission; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; @@ -27,6 +27,8 @@ import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.Message; import javax.jws.WebService; import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; /** * Windows Platform Configuration REST-API implementation. @@ -42,25 +44,47 @@ import javax.ws.rs.*; @Produces({"application/json", "application/xml"}) @Consumes({"application/json", "application/xml"}) public interface ConfigurationMgtService { - - /** - * Save Tenant configurations. - * - * @param configuration Tenant Configurations to be saved. - * @return Message type object for the provide save status. - * @throws WindowsConfigurationException - */ - @POST - @Permission(name = "Manage Configurations", permission = "/device-mgt/platform-configurations/manage") - Message ConfigureSettings(PlatformConfiguration configuration) throws WindowsConfigurationException; - - /** - * Retrieve Tenant configurations according to the device type. - * - * @return Tenant configuration object contains specific tenant configurations. - * @throws WindowsConfigurationException - */ + @GET + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Windows Platform Configurations", + notes = "Get the Windows platform configuration details using this REST API", + response = PlatformConfiguration.class, + tags = "Windows Configuration Management" + ) + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully fetched Windows platform configuration.", + response = PlatformConfiguration.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "Content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource has been modified the last time.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 304, + message = "Not Modified. \n Empty body because the client has already the latest version of the requested resource."), + @ApiResponse( + code = 404, + message = "Not Found. \n Resource to be deleted does not exist."), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching Windows platform configuration.") + }) @Permission(name = "View Configurations", permission = "/device-mgt/platform-configurations/view") PlatformConfiguration getConfiguration() throws WindowsConfigurationException; @@ -72,6 +96,98 @@ public interface ConfigurationMgtService { * @throws WindowsConfigurationException */ @PUT - @Permission(name = "Manage Configurations", permission = "/device-mgt/platform-configurations/manage") - Message updateConfiguration(PlatformConfiguration configuration) throws WindowsConfigurationException; + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "PUT", + value = "Updating Windows Platform Configuration.", + notes = "Update the Windows platform configurations using this REST API.", + tags = "Windows Configuration Management" + ) + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK. \n Windows platform configuration has been updated successfully", + responseHeaders = { + @ResponseHeader( + name = "Content-Location", + description = "URL of the updated Windows platform configuration."), + @ResponseHeader( + name = "Content-Type", + description = "Content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource has been modified the last time.\n" + + "Used by caches, or in conditional requests.")}), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error."), + @ApiResponse( + code = 404, + message = "Not Found. \n Resource to be deleted does not exist."), + @ApiResponse( + code = 415, + message = "Unsupported media type. \n The entity of the request was in a not supported format."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while modifying Windows platform configuration.") + }) + @Permission(name = "Manage Configurations", permission = "/device-mgt/configurations/manage") + Message updateConfiguration( @ApiParam(name = "configuration", + value = "PlatformConfiguration")PlatformConfiguration configuration) throws WindowsConfigurationException; + + @GET + @Path("license") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation( + produces = MediaType.TEXT_PLAIN, + httpMethod = "GET", + value = "Getting the License Agreement for Windows Device Registration", + notes = "Use this REST API to retrieve the license agreement that is used for the Windows device " + + "registration process", + response = String.class, + tags = "Windows Configuration Management") + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully fetched Windows license configuration.", + response = String.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "Content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource has been modified the last time.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 304, + message = "Not Modified. \n Empty body because the client has already the latest version of the requested resource."), + @ApiResponse( + code = 404, + message = "Not Found. \n Resource to be deleted does not exist."), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching Windows license configuration.") + }) + Response getLicense( + @ApiParam( + name = "If-Modified-Since", + value = "Validates if the requested variant has not been modified since the time specified", + required = false) + @HeaderParam("If-Modified-Since") String ifModifiedSince) throws WindowsConfigurationException; + } diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/ConfigurationMgtServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/ConfigurationMgtServiceImpl.java index 0b911d7e8..1802df8dc 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/ConfigurationMgtServiceImpl.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/ConfigurationMgtServiceImpl.java @@ -26,6 +26,8 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorResponse; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.UnexpectedServerErrorException; import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WindowsConfigurationException; import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.Message; import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.WindowsAPIUtils; @@ -46,58 +48,6 @@ public class ConfigurationMgtServiceImpl implements ConfigurationMgtService { private static Log log = LogFactory.getLog( org.wso2.carbon.device.mgt.mobile.windows.api.services.impl.ConfigurationMgtServiceImpl.class); - /** - * Save Tenant configurations. - * - * @param configuration Tenant Configurations to be saved. - * @return Message type object for the provide save status. - * @throws WindowsConfigurationException - */ - @POST - public Message ConfigureSettings(PlatformConfiguration configuration) throws WindowsConfigurationException { - Message responseMsg = new Message(); - ConfigurationEntry licenseEntry = null; - String message; - - try { - configuration.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); - if (!configuration.getConfiguration().isEmpty()) { - List configs = configuration.getConfiguration(); - for (ConfigurationEntry entry : configs) { - if (PluginConstants.TenantConfigProperties.LICENSE_KEY.equals(entry.getName())) { - License license = new License(); - license.setName(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); - license.setLanguage(PluginConstants.TenantConfigProperties.LANGUAGE_US); - license.setVersion("1.0.0"); - license.setText(entry.getValue().toString()); - WindowsAPIUtils.getDeviceManagementService().addLicense(DeviceManagementConstants. - MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, license); - licenseEntry = entry; - } - } - - if (licenseEntry != null) { - configs.remove(licenseEntry); - } - configuration.setConfiguration(configs); - WindowsAPIUtils.getDeviceManagementService().saveConfiguration(configuration); - Response.status(Response.Status.CREATED); - responseMsg.setResponseMessage("Windows platform configuration saved successfully."); - responseMsg.setResponseCode(Response.Status.CREATED.toString()); - return responseMsg; - } else { - Response.status(Response.Status.BAD_REQUEST); - responseMsg.setResponseMessage("Windows platform configuration can not be saved."); - responseMsg.setResponseCode(Response.Status.CREATED.toString()); - } - } catch (DeviceManagementException e) { - message = "Error Occurred while configuring Windows Platform."; - log.error(message, e); - throw new WindowsConfigurationException(message, e); - } - return responseMsg; - } - /** * Retrieve Tenant configurations according to the device type. * @@ -182,4 +132,24 @@ public class ConfigurationMgtServiceImpl implements ConfigurationMgtService { } return responseMsg; } + + @GET + @Path("/license") + public Response getLicense( + @HeaderParam("If-Modified-Since") String ifModifiedSince) { + License license; + try { + license = + WindowsAPIUtils.getDeviceManagementService().getLicense( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, + DeviceManagementConstants.LanguageCodes.LANGUAGE_CODE_ENGLISH_US); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the license configured for Windows device enrolment"; + log.error(msg, e); + throw new UnexpectedServerErrorException( + new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(msg).build()); + } + return Response.status(Response.Status.OK).entity(license).build(); + } } + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/DeviceManagementAdminServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/DeviceManagementAdminServiceImpl.java index 7cc14838c..5f6e4e082 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/DeviceManagementAdminServiceImpl.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/api/services/impl/DeviceManagementAdminServiceImpl.java @@ -22,10 +22,13 @@ import com.ibm.wsdl.OperationImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation; import org.wso2.carbon.device.mgt.mobile.windows.api.common.PluginConstants; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.beans.ErrorResponse; +import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.BadRequestException; import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WindowsDeviceEnrolmentException; import org.wso2.carbon.device.mgt.mobile.windows.api.common.exceptions.WindowsOperationsException; import org.wso2.carbon.device.mgt.mobile.windows.api.common.util.Message; @@ -69,7 +72,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe operation.setCode(PluginConstants.OperationCodes.DEVICE_LOCK); operation.setType(Operation.Type.COMMAND); operation.setEnabled(true); - return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation); } catch (OperationManagementException e) { String errorMessage = "Issue in retrieving operation management service instance"; message.setResponseMessage(errorMessage); @@ -82,6 +85,11 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); log.error(errorMessage, e); throw new WindowsOperationsException(message, responseMediaType); + } catch (InvalidDeviceException e) { + String errorMessage = "Invalid Device Identifiers found."; + log.error(errorMessage, e); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); } } @@ -105,7 +113,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe operation.setType(Operation.Type.COMMAND); operation.setEnabled(true); try { - return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation); } catch (OperationManagementException e) { String errorMessage = "Issue in retrieving operation management service instance"; message.setResponseMessage(errorMessage); @@ -118,7 +126,12 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); log.error(errorMessage, e); throw new WindowsOperationsException(message, responseMediaType); - } + } catch (InvalidDeviceException e) { + String errorMessage = "Invalid Device Identifiers found."; + log.error(errorMessage, e); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); + } } /** @@ -143,7 +156,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe operation.setCode(PluginConstants.OperationCodes.WIPE_DATA); operation.setType(Operation.Type.COMMAND); try { - return WindowsAPIUtils.getOperationResponse(deviceids, operation, message, responseMediaType); + return WindowsAPIUtils.getOperationResponse(deviceids, operation); } catch (OperationManagementException e) { String errorMessage = "Issue in retrieving operation management service instance"; message.setResponseMessage(errorMessage); @@ -156,6 +169,11 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); log.error(errorMessage, e); throw new WindowsOperationsException(message, responseMediaType); + } catch (InvalidDeviceException e) { + String errorMessage = "Invalid Device Identifiers found."; + log.error(errorMessage, e); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); } } @@ -181,7 +199,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe CommandOperation operation = new CommandOperation(); operation.setCode(PluginConstants.OperationCodes.DEVICE_RING); operation.setType(Operation.Type.COMMAND); - return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation); } catch (OperationManagementException e) { String errorMessage = "Issue in retrieving operation management service instance"; message.setResponseMessage(errorMessage); @@ -194,6 +212,11 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); log.error(errorMessage, e); throw new WindowsOperationsException(message, responseMediaType); + } catch (InvalidDeviceException e) { + String errorMessage = "Invalid Device Identifiers found."; + log.error(errorMessage, e); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); } } @@ -224,7 +247,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe CommandOperation operation = new CommandOperation(); operation.setCode(PluginConstants.OperationCodes.LOCK_RESET); operation.setType(Operation.Type.COMMAND); - return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation); } catch (OperationManagementException e) { String errorMessage = "Issue in retrieving operation management service instance"; message.setResponseMessage(errorMessage); @@ -237,6 +260,11 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); log.error(errorMessage, e); throw new WindowsOperationsException(message, responseMediaType); + } catch (InvalidDeviceException e) { + String errorMessage = "Invalid Device Identifiers found."; + log.error(errorMessage, e); + throw new BadRequestException( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); } } }